LinuxQuestions.org
View the Most Wanted LQ Wiki articles.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 10-21-2011, 04:51 AM   #1
TheIndependentAquarius
Senior Member
 
Registered: Dec 2008
Posts: 4,619
Blog Entries: 29

Rep: Reputation: 896Reputation: 896Reputation: 896Reputation: 896Reputation: 896Reputation: 896Reputation: 896
C++: Size of a class containing a virtual function


Code:
#include <iostream>
using namespace std;

class Z
{
  public:
    int a;
    virtual void x () {}
};

int main() 
{
  cout << "\nZ's size: "  << sizeof (Z);
}
Int's size: 4
void ptr inserted by virtual function's size: 8

So, the size of Z should be shown 12, isn't it?
But instead, its being shown 16!

What's the point that I am missing?
 
Click here to see the post LQ members have rated as the most helpful post in this thread.
Old 10-21-2011, 05:03 AM   #2
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 1,615

Rep: Reputation: 483Reputation: 483Reputation: 483Reputation: 483Reputation: 483
Quote:
Originally Posted by Anisha Kaul View Post
So, the size of Z should be shown 12, isn't it?
But instead, its being shown 16!
It is 8 on my linux-box.
 
Old 10-21-2011, 05:14 AM   #3
TheIndependentAquarius
Senior Member
 
Registered: Dec 2008
Posts: 4,619
Blog Entries: 29

Original Poster
Rep: Reputation: 896Reputation: 896Reputation: 896Reputation: 896Reputation: 896Reputation: 896Reputation: 896
I have gcc version 4.5.0, with OpenSuse 11.3 (64 bit).
 
Old 10-21-2011, 05:34 AM   #4
millgates
Member
 
Registered: Feb 2009
Location: 192.168.x.x
Distribution: Slackware
Posts: 651

Rep: Reputation: 269Reputation: 269Reputation: 269
As far as I know, the standard doesn't really specify completely the layout of the class in memory. I guess the first 8 bytes or so will be the pointer to vtable for Z, then 4 bytes member a. if you look at the memory (the 16 bytes taken by an instance of Z), you'll see the last 4 bytes are zero(at least they're 0's on my computer). Now if you add one more int member
Code:
class Z
{
  public:
    int a;
    int b;
    virtual void x () {}
};
the b member will take the last 4 bytes of Z and the size of Z will be also 16.
So I guess it's some kind of padding, the compiler uses 16 bytes instead of 12 for Z with the last 4 being unused. Perhaps it's some kind of optimization for x86_64?
 
1 members found this post helpful.
Old 10-21-2011, 05:40 AM   #5
SigTerm
Member
 
Registered: Dec 2009
Distribution: Slackware 12.2
Posts: 379

Rep: Reputation: 233Reputation: 233Reputation: 233
Quote:
Originally Posted by Anisha Kaul View Post
Int's size: 4
void ptr inserted by virtual function's size: 8

So, the size of Z should be shown 12, isn't it?
Wrong. It is implementation-dependent behavior. The size shown can be anything.

Quote:
Originally Posted by Anisha Kaul View Post
What's the point that I am missing?
It is implementation-dependent behavior. Size can be anything (you can expect that it'll be >= sizeof(int), but that's it) and things get really interesting if you use multiple inheritance and the object may have multiple virtual function tables. You should never try to predict how big your virtual class will be. If you need to be sure about size of data, use POD struct for data, and extra class to process the data (or derive that extra class from POD struct).

As for "why it is 16 instead of 12", here are possible scenarios:
  • sizeof(int) == 8, you're on 64bit machine (most likely scenario, by the way)
  • sizeof(int) == 4, you're on 64bit machine, and compiler decided to align structure to 8-byte boundaries.
  • gcc stores extra bytes of data you're not aware of.

Citations from standard:
Quote:
expr.sizeof
...
sizeof(char), sizeof(signed char) and sizeof(unsigned char) are 1; the
result of sizeof applied to any other fundamental type (3.9.1) is implementation-defined.
...
When applied to a class, the result is the number of bytes in an object of that class including any padding required for
placing objects of that type in an array. The size of a most derived class shall be greater than zero
Nothing else is guaranteed.

Last edited by SigTerm; 10-21-2011 at 05:43 AM.
 
1 members found this post helpful.
Old 10-21-2011, 06:09 AM   #6
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 1,615

Rep: Reputation: 483Reputation: 483Reputation: 483Reputation: 483Reputation: 483
Quote:
Originally Posted by SigTerm View Post
sizeof(int) == 8
If by "sizeof (int)" you mean "sizeof (int)", it won't ever be 8. sizeof (long) can be 4 or 8 depending on platform and OS.
 
0 members found this post helpful.
Old 10-21-2011, 06:13 AM   #7
millgates
Member
 
Registered: Feb 2009
Location: 192.168.x.x
Distribution: Slackware
Posts: 651

Rep: Reputation: 269Reputation: 269Reputation: 269
Quote:
Originally Posted by NevemTeve View Post
If by "sizeof (int)" you mean "sizeof (int)", it won't ever be 8. sizeof (long) can be 4 or 8 depending on platform and OS.
On x86_64, 64bit linux and gcc sizeof(int) is 4. But where did you get that sizeof(int) will never be 8? As far as I know, the standard specifies nothing except that sizeof(long) >= sizeof(int) >= sizeof(short)>= sizeof(char).
 
Old 10-21-2011, 06:38 AM   #8
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 1,615

Rep: Reputation: 483Reputation: 483Reputation: 483Reputation: 483Reputation: 483
Quote:
Originally Posted by millgates View Post
On x86_64, 64bit linux and gcc sizeof(int) is 4. But where did you get that sizeof(int) will never be 8?
You're right, I should have written something like this: 'On any existing windows*/unix platform sizeof(int) will be 4'

*: Okay, except for Win16, where sizeof(int)=2
 
0 members found this post helpful.
Old 10-21-2011, 06:41 AM   #9
Sergei Steshenko
Senior Member
 
Registered: May 2005
Posts: 4,481

Rep: Reputation: 453Reputation: 453Reputation: 453Reputation: 453Reputation: 453
Quote:
Originally Posted by Anisha Kaul View Post
[CODE]
...
What's the point that I am missing?
The fundamental thing you are missing is that the standard doesn't prescribe a mechanism to be used to implement virtual functions.
 
2 members found this post helpful.
Old 10-21-2011, 09:59 AM   #10
SigTerm
Member
 
Registered: Dec 2009
Distribution: Slackware 12.2
Posts: 379

Rep: Reputation: 233Reputation: 233Reputation: 233
Quote:
Originally Posted by NevemTeve View Post
If by "sizeof (int)" you mean "sizeof (int)", it won't ever be 8. sizeof (long) can be 4 or 8 depending on platform and OS.
Sorry, thats not true, and and if you keep believing in fairy-tales like that, one day it'll backfire horribly, you'll lose your job, and the next code maintainer will hate you.

Quote:
Originally Posted by NevemTeve View Post
*: Okay, except for Win16, where sizeof(int)=2
Still not true.

There are platforms where int is 64bit, and int is not guaranteed to be 4 bytes big. One of the most important rules in C++ that you should NEVER expect anything except char to have certain size. One of the examples of the problem is that on linux sizeof(wchar_t) == 4, while on windows ms compiler sizeof(wchar_t)==2. Now guess what'll happen when you try to port wchar-related code that has an assumption about sizeof(wchar_t). If you need to be sure about size of certain type, then you should either use types provided by cross-platform framework (such as qint32 in Qt4, or Qint32 in libSDL) OR you should use compiler that supports uint32_t types (they aren't in 2003 standard, but will be added in future). Linux (kernel) provides such types in "types.h" (/usr/include/linux/types.h, I think), but they should be supported by gcc.

Last edited by SigTerm; 10-21-2011 at 10:03 AM.
 
Old 10-21-2011, 10:23 AM   #11
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 1,615

Rep: Reputation: 483Reputation: 483Reputation: 483Reputation: 483Reputation: 483
Quote:
Originally Posted by SigTerm View Post
There are platforms where int is 64bit
Well, I haven't seen such platform yet, and this link doesn't seem to give example.

Quote:
int is not guaranteed to be 4 bytes big. One of the most important rules in C++ that you should NEVER expect anything except char to have certain size.
Very true. I didn't mean one should expect sizeof (int) to be 4 when writing a program -- but when you are DEBUGGING (or "solving a puzzle", like in this topic), you should know that actually sizeof (int) _is_ 4.

Quote:
One of the examples of the problem is that on linux sizeof(wchar_t) == 4, while on windows ms compiler sizeof(wchar_t)==2. Now guess what'll happen when you try to port wchar-related code that has an assumption about sizeof(wchar_t).
Well, I don't think wchar_t would lead anywhere, have never used it myself.

Quote:
If you need to be sure about size of certain type, then you should either use types provided by cross-platform framework (such as qint32 in Qt4, or Qint32 in libSDL) OR you should use compiler that supports uint32_t types (they aren't in 2003 standard, but will be added in future). Linux (kernel) provides such types in "types.h" (/usr/include/linux/types.h, I think), but they should be supported by gcc.
I think every modern compiler has inttypes.h, but if not, it is easy to hack one.

Last edited by NevemTeve; 10-21-2011 at 10:29 AM.
 
0 members found this post helpful.
Old 10-21-2011, 11:00 AM   #12
r.osmanov
LQ Newbie
 
Registered: Feb 2011
Distribution: openSUSE, Ubuntu, Gentoo
Posts: 17

Rep: Reputation: 3
This is because of "space-time tradeoff", data alignment.

Consider the following:

main.c
Code:
#include <stdio.h>
#include <string.h>

typedef struct 
#ifdef PACKED 
__attribute__ ((packed)) 
#endif
{
    char *str;      // 8
    char ch ;       // 1
    int a;          // 4
    int b;          // 4
    int c;          // 4
    // Packed total size should be: 21
    // Aligned total size should be: 24
} test_t;

static void print_sizes(test_t *t)
{
    printf("DATA TYPE SIZES\n");
    printf("char*: %ld\n", sizeof(char*));
    printf("char: %ld\n", sizeof(char));
    printf("int: %ld\n", sizeof(int));

    printf("\nSIZE OF *t: %ld\n", sizeof(*t));
}

int main (int argc, char const* argv[]) {
    test_t t;
    t.str = "test string"; 

    print_sizes(&t);

    return 0;
}
Makefile
Code:
ifeq ($(PACKED), true)
    PACK=-DPACKED
else
    PACK=
endif

ifdef OUT
    OUTFILE=$(OUT)
else
    OUTFILE=test
endif

CC=gcc
CFLAGS=-Wall -c $(PACK)

all: test

test: main.o
    $(CC) main.o -o $(OUT) 

main.o: main.c
    $(CC) $(CFLAGS) main.c -o main.o

clean: 
    rm -f *.o *~
Compile versions with packed and padded memory:

Code:
$ make PACKED=true OUT=test_packed
$ make OUT=test_padded
$ ./test_packed
DATA TYPE SIZES
char*: 8
char: 1
int: 4

SIZE OF *t: 21
$ ./test_padded
DATA TYPE SIZES
char*: 8
char: 1
int: 4

SIZE OF *t: 24
This is on x86_64 Gentoo, gcc (Gentoo 4.4.4-r2 p1.4, pie-0.4.5) 4.4.4

Last edited by r.osmanov; 10-21-2011 at 11:03 AM. Reason: arch
 
Old 10-21-2011, 12:26 PM   #13
SigTerm
Member
 
Registered: Dec 2009
Distribution: Slackware 12.2
Posts: 379

Rep: Reputation: 233Reputation: 233Reputation: 233
Thumbs down

Quote:
Originally Posted by NevemTeve View Post
Well, I haven't seen such platform yet, and this link doesn't seem to give example.
http://www.unix.org/version2/whatsnew/lp64_wp.html
Cray supercomputers.

Quote:
Originally Posted by NevemTeve View Post
you should know that actually sizeof (int) _is_ 4.
Nope. YOu should know that you can ask the debugger what the size of (int) is.

Quote:
Originally Posted by NevemTeve View Post
Well, I don't think wchar_t would lead anywhere, have never used it myself.
wchar_t is char with unicode support. You'll have to use it for every character code that doesn't fit into ASCII.

Quote:
Originally Posted by NevemTeve View Post
I think every modern compiler has inttypes.h, but if not,
This is a C99 header (afaik you need to use stdint.h instead), which means it doesn't need to be available in C++ compiler (it should be available in next standard which isn't here yet). C and C++ are not the same language. MSVC2008 doesn't have it. MSVC2005 doesn't have it. For maximum/minimum values there's std::numeric_limits.

Quote:
Originally Posted by NevemTeve View Post
it is easy to hack one.
Please do not give such advices. Somebody is bound to take it seriously and produce another batch of buggy software as a result.
This implementation is naive and will cause problems. I'd advise to avoid using this particular header at all costs.
MSVC compiler has __int8, __int32 and __int64 type (non-standard), so if you're going to provide typedefs, you should use THEM instead - their size is guaranteed. "Hack one" is a bad idea - header that provides such types should come with a large framework that is frequently updated and reviewed by a team of people - this guarantees that the header is somewhat reliable and should work on whatever obscure compiler your code will be compiled.
"missing header" written by a "unnamed lone hero" is a BAD idea, since it does not guarantee that the header has been tested properly. If you're going to use external header, use the one provided with boost.
 
Old 10-21-2011, 07:25 PM   #14
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 1,615

Rep: Reputation: 483Reputation: 483Reputation: 483Reputation: 483Reputation: 483
Okay, you have some fair points here, others could be argued (maybe in separate topics), but perhaps we go could back to the original question:

Q: Why is sizeof(Z) 16 instead of 12, when sizeof(int) is 4 and sizeof(VMT-pointer) is 8?
A: Because of the alignment requirement: four byte padding added by the compiler.
http://en.wikipedia.org/wiki/Data_structure_alignment
 
1 members found this post helpful.
Old 10-22-2011, 12:06 AM   #15
r.osmanov
LQ Newbie
 
Registered: Feb 2011
Distribution: openSUSE, Ubuntu, Gentoo
Posts: 17

Rep: Reputation: 3
Quote:
Originally Posted by NevemTeve View Post
Okay, you have some fair points here, others could be argued (maybe in separate topics), but perhaps we go could back to the original question:

Q: Why is sizeof(Z) 16 instead of 12, when sizeof(int) is 4 and sizeof(VMT-pointer) is 8?
A: Because of the alignment requirement: four byte padding added by the compiler.
http://en.wikipedia.org/wiki/Data_structure_alignment
That's exactly what I wrote above
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] How can a friend function access a public function from a base class? lesca Programming 1 11-17-2010 01:56 PM
declare virtual function in derived class icecubeflower Programming 3 11-28-2009 09:04 PM
javascript - class / function in function jchambers Programming 3 06-15-2009 10:33 PM
how pass a class to a function aditya1 Programming 2 03-08-2005 09:02 PM
Function Definitoin Outside Templatized Class ashwinipahuja Programming 1 06-15-2004 10:53 AM


All times are GMT -5. The time now is 06:31 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration