-2
#include<stdio.h>
struct krishna {
        int i,j,k,l,m;
    char c;
    double d;
    char g[48];
};
int main() {
struct krishna *me={0};
printf("%ld %ld\n",sizeof(me),sizeof(*me));//output is 8 80 how??
return 0;
}

Hello everyone I am new here and the compiler I use is gcc compiler in the above code can anyone explain why

1) pointer irrespective of any type is allocated 8 ?

2) sizeof the above struct is 80 ? Can anyone explain to me in general for any structure how can one determine the structure size , I am getting confused each time I expect one value but getting a different answer and I have also read other questions and answers in stack overflow regarding this and I am still not getting it.Please help.

  • To answer #1: No. The size of a pointer **on a specific target** is the same for every type, though. – Richard J. Ross III Aug 14 '13 at 18:21
  • cant get you mr @RichardJ.RossIII – Krishna sundar Aug 14 '13 at 18:22
  • 1
    The size of a pointer according to the standards is implementation defined. In practice, the size of a pointer, when compiling for a specific target (in your case, probably x86_64), is the same, regardless of type. For a different target (e.g. x86), you might get a different pointer size, like 4 (32 bits). – Richard J. Ross III Aug 14 '13 at 18:23
  • @RichardJ.RossIII can you explain in detail for the second case then please how it gets affected if not padded and why how can i determine the sizeof any structures in general can you explain with some sample cases and in each case how it may differ the output ?? i am happy with answer for first one. – Krishna sundar Aug 14 '13 at 18:35
  • 3
    @RichardJ.RossIII: In fact it's perfectly legal for different pointer types to have different sizes on the same implementation. For *most* compilers, all pointers are the same size (which is typically either 4 or 8 bytes), but the C standard permits more latitude. For example, on a word-addressed machine, a byte pointer (`char*`, `void*`) might require extra information to specify which byte within a word is referred to. – Keith Thompson Aug 14 '13 at 18:39
  • @KeithThompson can you explain for the second case in detail then why it is needed ? how it affects things ? and how can one in general say the sizeof struct in general ? – Krishna sundar Aug 14 '13 at 18:43
  • 1
    BTW: Rather than use `%ld` for `sizeof()` integers, recommend `printf("%zu %zu\n",sizeof(me), ...` or `printf("%lu %lu\n", (unsigned long) sizeof(me), ...` – chux - Reinstate Monica Aug 14 '13 at 18:44
  • @Krishnasundar: See the answer I just posted. But for the most part, you don't really need to know the details; if you need to know the size of a structure, use `sizeof`. – Keith Thompson Aug 14 '13 at 18:55
  • possible duplicate of [Get size of pointer in C](http://stackoverflow.com/questions/9760113/get-size-of-pointer-in-c) and of [Can the Size of Pointers Vary Depending on what's Pointed To?](http://stackoverflow.com/questions/1473935/can-the-size-of-pointers-vary-depending-on-whats-pointed-to) and of [Why isn't sizeof for a struct equal to the sum of sizeof of each member?](http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member) –  Aug 14 '13 at 19:04
  • no mr @H2CO3 i just came across the structures and while messing with size i couldn't get it but for other pointers i usually have 8 as the size while checking it for structure pointer it was the same so i thought getting it along with structures and pointers would be better.The question doesn't meant to be useless i believe . – Krishna sundar Aug 14 '13 at 19:10
  • @H2CO3 anyway thanks for the other 2 links :) – Krishna sundar Aug 14 '13 at 19:11

4 Answers4

3

This is because:

sizeof( me ) // is a pointer.

... me is a pointer. The size of a pointer is a multiple of the word on your environment, hence it's common that on 32-bit environments a pointer is 4 bytes whereas on a 64-bit environment a pointer is 8 bytes (but not written in stone). If you were to go back a couple years, a 16-bit environment would have a 2 byte pointer. Looking at the next sizeof:

sizeof( *me ) // is a struct krishna, hence 80 bytes are needed to store it in memory.

... is a structure and the size of the structure krishna is 80 bytes. If you look at the structure:

struct krishna {
  int i,j,k,l,m; // sizeof( int ) * 5
  char c; // sizeof( char ) * 1
  double d; // sizeof( double ) * 1
  char g[48]; // sizeof( char ) * 48
  // padding for memory address offset would be here.
};

... if you add up the amount of bytes required for each field and include the appropriate data structure alignment for the memory address offset then it will total 80 bytes (as expected). The reason it adds an extra 3 unused bytes is because to store a structure in memory it must be in a continuous block of memory that is allocated for the structure. For performance reasons, it will pad any size issues to ensure that the memory addresses are always a multiple of the word. The tradeoff of the 3 bytes for performance improvements is worth it, 3 bytes nowadays is not as impactful as the performance improvements the processor has when data alignment is guaranteed.

Jacob Pollack
  • 3,703
  • 1
  • 17
  • 39
  • 1
    And note that the size of the struct is 80 and not 77 due to padding. There will be 3 bytes following the 'c' element, so that the double lines up on a nice boundary. – josh poley Aug 14 '13 at 18:25
  • 1
    Saying that a pointer is either 4 or 8 bytes is **wrong**. It is implementation defined by the standard, and whilst the most common sizes in practice today are 32 and 64 bits, historically, there were 16 bit systems as well, and other models do exist too. – Richard J. Ross III Aug 14 '13 at 18:25
  • @josh, I included that already, :) but fair point (you commented before my edit). – Jacob Pollack Aug 14 '13 at 18:25
  • @RichardJ.RossIII, added clarification but that was the point I was attempting to communicate. – Jacob Pollack Aug 14 '13 at 18:27
  • 1
    `` 16 bit pointers are not history, try to work on current microcontrollers and you'll often have `sizeof(void *) == 2` `` – Matteo Italia Aug 14 '13 at 19:00
3

All pointers are addresses, and all addresses are the same size on a given system, usually 4 bytes on a 32 bit system and 8 bytes on a 64 bit system. Since you are getting 8, you must be on a 64 bit system.

The size of a struct depends on how the compiler "packs" the individual fields of the struct together into a single block of memory to contain the entire struct. In your case, your struct has 5 int fields (4 bytes each), a single char field (1 byte), a single double field (8 bytes), and a 48 character array. Add all that up and you get 20 + 1 + 8 + 48 = 77 bytes to store your data. The actual size is 80 because the compiler is "padding" the 1 byte char field with 3 extra unused bytes in order to keep all fields in the struct aligned to a 4-byte memory address, which is needed for good performance.

Hope that helps!

ObjetDart
  • 343
  • 3
  • 6
  • can you explain then how it may affect the performance in detail why padded only for char – Krishna sundar Aug 14 '13 at 18:30
  • 1
    Most modern CPU architectures are optimized to access memory on 4 byte boundaries. By making sure all individual fields in your struct are on a 4 byte boundary, that ensures that any code which access the field will be fast. If the char field were not padded, every field after it would not be on a 4-byte boundary and thus would be slower to access. – ObjetDart Aug 14 '13 at 18:42
  • 1
    Actually, the 1 byte char field is padded to an 8-byte aligned address (doubles are 8 bytes). But in this case, it's the same since the char field happens to be at offset 20, and the next 8-byte aligned address is 24. What actually happens when you access a misaligned entity is that the CPU loads two properly aligned chunks of memory and throws away the unwanted rest. Consequently, it takes at least twice as much time as a properly aligned access. At least - the penalty may be much higher depending on the hardware. – cmaster - reinstate monica Aug 14 '13 at 18:46
  • 3
    "All pointers are addresses, and all addresses are the same size on a given system" is not universal nor specified by C. Though it is common. Situations where function pointers and data pointers differ come to mind. – chux - Reinstate Monica Aug 14 '13 at 18:46
  • Richard Ross is correct in his comment above, I should have said target, not system. 64 bit systems can run code compiled for either 32- or 64-bit systems, so the size of a pointer actually depends on what target architecture the code was compiled for, not what system it is running on (sorry, I've been spending most of my time in the .NET world lately, where pointer sizes can change depending on the system running the code.) – ObjetDart Aug 14 '13 at 18:49
  • 1
    @ObjetDart The size of a pointer for a function and a pointer for data on the _same_ target (program) may differ. – chux - Reinstate Monica Aug 14 '13 at 18:54
  • @cmaster so as you say (20 bits for 5 integers)-------------------| then next character 20+1 that 21 would lead to a mispenality later i cant get you clearly can u explain in detail clearly – Krishna sundar Aug 14 '13 at 18:54
  • 2
    "and all addresses are the same size on a given system" is just plain wrong. –  Aug 14 '13 at 19:00
  • 1
    C11 6.2.5 28 "... Pointers to other types need _not_ have the same representation or alignment requirements." – chux - Reinstate Monica Aug 14 '13 at 19:02
  • 2
    @Krishnasundar: You have 5 ints, that's 20 bytes, next variable goes at an offset of at least 20. You have 1 char, that's 1 byte, and it needs no alignment, so its offset is 20, next variable goes at an offset of at least 21. You have 1 double, that's 8 bytes, and it needs 8 byte alignment, so it's offset is rounded up to 24. It's 24 because 24 = 3*8 (eight byte alignment), not because 24 = 6*4 (four byte alignment). – cmaster - reinstate monica Aug 14 '13 at 19:15
  • yes i get it so if there were 6 integers above then a character this means 24+1=25 then it would lead to a padding of 3 bytes to make it 28 then so on am i getting things correct @cmaster – Krishna sundar Aug 14 '13 at 19:26
  • @Krishnasundar: No, if the next variable is a double, it will likely go to an offset of 32 bytes because 8 is not a factor in 28. That means, you would loose 7 bytes due to padding. – cmaster - reinstate monica Aug 14 '13 at 19:33
  • #include struct krishna { int i,j,k,l,m,p; char c; double d; char g[48]; }; int main() { struct krishna *me={0}; printf("%ld %ld\n",sizeof(me),sizeof(*me));//output is 8 88 return 0; } Yes I perfectly get it now, you are correct it pads additional 7 bits.I understand now.@cmaster – Krishna sundar Aug 14 '13 at 19:37
3
printf("%ld %ld\n",sizeof(me),sizeof(*me));//output is 8 80 how??

Actually that should be:

printf("%zu %zu\n",sizeof(me),sizeof(*me));//output is 8 80 how??

"%zu" is the correct format string for a size_t value, such as the value you get from sizeof. "%ld" may happen to work on some systems (and apparently it does on yours), but you shouldn't count on that.

If your compiler doesn't support "%zu", you can use "%lu" (which expects an unsigned long argument) and explicitly convert the arguments:

printf("%lu %lu\n", (unsigned long)sizeof(me), (unsigned long)sizeof(*me));

You're getting 8 for sizeof(me) because that happens to be the size of a pointer on the compiler you're using (8 bytes, 64 bits). If you compiled and ran your program on a different system, you might get 4, because a lot of systems have 32-bit pointers. (And this assumes a byte is 8 bits, which is true for most systems but not guaranteed by the language.)

Most compilers make all pointers the same size, but that's not guaranteed by the language either. For example, on a word-addressed machine, an int* pointer could be just a machine-level address, but a char* pointer might need additional information to specify which byte within the word it points to. You're not very likely to run into a system with varying pointer sizes, but there's still no point in assuming that all pointers are the same size.

As for the size of the structure, that also can vary from one compiler to another. Here's your structure again:

struct krishna {
    int i,j,k,l,m;
    char c;
    double d;
    char g[48];
};

char is always exactly 1 byte, and char[48] is always exactly 48 bytes.

The number of bytes in an int can vary from one system to another; 4 bytes is most common these days.

The size of a double is typically 8 bytes, but this can also vary (though I don't think I've ever seen a system where sizeof (double) isn't 8 bytes.)

Structure members are laid out in the order in which they're declared, so your i will be at the very beginning of the structure, followed by j, k, and so forth.

Finally, the compiler will often insert padding bytes between members, or after the last member, so that each member is properly aligned. For example, on many systems a 4-byte int needs to be aligned at an offset that's a multiple of 4 bytes; if it's misaligned, access to it may be slow and/or very difficult.

The fact that sizeof (struct krishna) happens to be 80 bytes on your system isn't really all that important. It's more important to understand (a) the general rules compilers use to determine how structures are laid out, and (b) the fact that those rules can result in different layouts for different systems.

The language definition and your compiler guarantee that you can have objects of type struct krishna, and that you can access those objects and their members, getting back whatever values you stored in them. If you need to know how big a struct krishna is, the answer is simply sizeof (struct krishna). If, for some reason, you need to know more details than that (say, if you need to match some externally imposed layout), you can do some experiments and/or consult your compiler's documentation -- but be aware that the specifics will apply only to the compiler you're using on the system where you're using it. (Often an ABI for your system will constrain the compiler's choices.)

You can also use sizeof and offsetof (look it up) to find out where each member is allocated.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • "Most compilers make all pointers the same size, but that's not guaranteed by the language either. For example, on a word-addressed machine, an int* pointer could be just a machine-level address, but a char* pointer might need additional information to specify which byte within the word it points to. You're not very likely to run into a system with varying pointer sizes, but there's still no point in assuming that all pointers are the same size." can you explain this paragraph alone , it is an excellent answer I get it now .Thanks. – Krishna sundar Aug 14 '13 at 19:05
  • @Krishnasundar: I'm not sure what you're asking me to explain. Is there something in particular that you don't understand? – Keith Thompson Aug 14 '13 at 19:06
  • the first line says that compilers view of pointers differ from the language. "but a char* pointer might need additional information to specify which byte within the word it points to" you are referring to the array of characters here rite and here you are saying that in this case i am not varying my pointer char* ,not dynamic. so how these statements relate to the assumption of not taking all pointers to the same size,or lol am i complicating things here a bit Am i getting things what you said @Keith Thompson ? – Krishna sundar Aug 14 '13 at 19:19
  • Sample of sizeof(double) != 8 occurs when a (lazy) compiler does not want to support "float" and "double" as so uses "float" for both. Allowed by C. Seen in embedded micros. – chux - Reinstate Monica Aug 14 '13 at 19:22
  • 1
    @Krishnasundar: Suppose a machine-level address can only refer to a 64-bit word, and suppose `int` is 64 bits. Then an `int*` ((pointer to `int`), can be implemented simply as a machine-level address. But if you want to have a `char*` pointer to an individual byte, you need both a machine-level pointer (to specify the word containing the byte), and an offset to specify which of the 8 bytes within the word you're pointing to. That's just one possible example. The real point is that the C language standard doesn't say that all pointers are the same size. – Keith Thompson Aug 14 '13 at 19:23
  • 1
    @Krishnasundar: Most modern systems happen to be byte-addressed, and so they can use the same representation for all pointer types. – Keith Thompson Aug 14 '13 at 19:23
0

Just to add to answers of @Jacob Pollack and @ObjetDart, you can find more about structure padding at Structure padding in C.

Community
  • 1
  • 1
0xF1
  • 6,046
  • 2
  • 27
  • 50