0

I have taken code from https://www.geeksforgeeks.org/the-offsetof-macro/.

I ran the code in ide provided in gfg itself.

I have edited code a bit , sizeof(int) is showing 4 but it is shown to take 8 bytes in struct through offset

#include <stdio.h> 

#define OFFSETOF(TYPE, ELEMENT) ((size_t)&(((TYPE *)0)->ELEMENT)) 

typedef struct PodTag 
{ 
    int   i; 
    double d; 
    char  c; 
} PodType; 

int main() 
{ 
    printf("%ld", OFFSETOF(PodType, d) ); 

    getchar(); 
    return 0; 
} 
WedaPashi
  • 3,561
  • 26
  • 42
Abhishek Garg
  • 308
  • 2
  • 11
  • 1
    What's your OS/architecture? – txtechhelp Mar 01 '19 at 07:42
  • @txtechhelp edited my ques please check – Abhishek Garg Mar 01 '19 at 07:43
  • 7
    Extremely related: [Why isn't sizeof for a struct equal to the sum of sizeof of each member?](https://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member) – Some programmer dude Mar 01 '19 at 07:44
  • 3
    It doesn't. Issue is the *double* member, it needs to be aligned to 8. So the compiler needs to use 4 bytes of unused space (aka padding). Padding is also added to the end of the struct so the double is still aligned to 8 when the struct is used in an array. Google "c structure member alignment" to learn more. – Hans Passant Mar 01 '19 at 07:47
  • 1
    What is that OFFSETOF macro? That can't possibly compile. You are casting 0 to the address of a struct of type PodType. – Fredrik Mar 01 '19 at 07:49
  • There are 4 bytes of padding in the structure between the end of the `int` and the start of the `double`. There are also 7 bytes of padding after the `char`. If you reordered the members, you'd be able to reduce the padding to 3 bytes. – Jonathan Leffler Mar 01 '19 at 07:50
  • 5
    You shouldn't invent trashy macros like this. `offsetof` is part of the standard. The tutorial site you link has a bad reputation and I wouldn't recommend using it. – Lundin Mar 01 '19 at 07:50
  • 1
    @Fredrik: It can possibly compile — that is the core of the implementation of many an `offsetof()` macro from the C standard. It may not be a particularly good idea to use that macro (in fact, it isn't a good idea given that `` contains `offsetof`). But it can compile on some compilers, probably even many compilers. – Jonathan Leffler Mar 01 '19 at 07:51
  • 1
    @JonathanLeffler But it's dereferncing a NULL pointer? – Fredrik Mar 01 '19 at 07:53
  • @Fredrik the OFFSETOF macro in that link is a non-standard one, but there's the one in [`cstddef`](http://www.cplusplus.com/reference/cstddef/offsetof/) .. also, `((TYPE *)0)` does not de-reference anything, it gets the address of a pointer located at `0`, then adds X bytes based on the member passed to the macro and casts that address to a `size_t` (and assumes memory addressing based on certain layouts). It looks like a de-reference at first. – txtechhelp Mar 01 '19 at 07:55
  • @Fredrik — It adds the offset of the element to the null pointer (address zero) and uses that as an address — it isn't fully dereferencing it to read the value at the address, or to write to the address. Once upon 3 decades or so ago, the 386/IX 'ANSI Compiler' came with a macro equivalent to that as its `offsetof`, and it did manage to crash. I was able to work around it by using 1024 instead of 0 as the base address, and then subtracting 1024 from the answer. This was on an 80486 box; cutting edge at the time. – Jonathan Leffler Mar 01 '19 at 07:55
  • 1
    @txtechhelp The "->Element" part is dereferencing – Fredrik Mar 01 '19 at 07:57
  • Well I'm surprised there is something like this in the standard library ^^ I will stay far away from it. – Fredrik Mar 01 '19 at 07:58
  • @Fredrik: when you need it, it is invaluable. Most of the time you don't need it, and staying well clear is a good idea. – Jonathan Leffler Mar 01 '19 at 07:58
  • @Fredrik .. `&(((TYPE *)0)->ELEMENT)` gets the address of that element; it doesn't actually access that element in assembly, thus not a 'full' de-reference .. and also not necessarily a guarantee ... it ain't pretty :/ – txtechhelp Mar 01 '19 at 08:00
  • @JonathanLeffler I would create a real object during runtime and use that valid address to calculate the offset, seems more robust. Or maybe there is some caveat to that too? – Fredrik Mar 01 '19 at 08:01
  • 1
    @Fredrik — you can do that if you want to, but the standard provides `offsetof` so that you don’t have to do it. How any particular implementation actually implements it is up to the compiler writers. What’s shown isn’t guaranteed to work by the standard, but it is very close to what compilers have used, and may still use — but they’re not obliged to use that as an implementation. – Jonathan Leffler Mar 01 '19 at 08:05
  • @Fredrik Seems unnecessarily slow. That macro is perfectly fine as far as I'm concerned. – Havenard Mar 01 '19 at 08:06
  • 1
    Just to add on the duplicate answer, you can disable alignment in most modern compilers with `#pragma pack(1)`. This is commonly used when you want to eliminate the memory garbage in between the structure elements for storage or network transfer purposes. – Havenard Mar 01 '19 at 08:11

1 Answers1

1

The next field d requires 8 byte alignment. This means that 4 padding bytes are inserted between the fields.

On other architectures it might be different.

Michael Veksler
  • 8,217
  • 1
  • 20
  • 33