It is only fit to be used for heap allocation, you allocate the size that you need (i.e. malloc( sizeof(struct video_file2) + ARRAY_SIZE) ). It wouldn't work as a local variable.
edit: I suppose one could use for globals or on the stack by casting a byte array ... I would find that to be unspeakably ugly but I don't write much C.
That's why the usage changes to a struct pointer at that point. The struct pointer just maps parts of an existing data structure (like a video file) to its labels.
Most seasoned C programmers understand every point in this post. Points 2 and 3 are indeed clever tricks, but they're tricks that you eventually have to employ if you're doing low level work. It's part of the beauty and allure of C.
I really really hate it when a posting starts off like this, then proceeds to tell me something anyone who considered themselves a C programmer would know.
Want to write a post about something kind of neat that people outside the field might not be up on? Cool, have fun. But don't start it out by being a rude ass. And this guy dedicates the first hundred words or so of his article to it.
"Well, here's the problem: if padding bytes are involved, you could be entering a world of pain and not even know it. [...] The solution is to use a compiler switch or a #pragma pack to ensure that structs are packed (i.e., no padding applied)."
That's an implementation-defined hack. The correct solution is to explicitly marshal your data between its in-memory format and the required external representation.
Many compilers insert padding bytes into the struct to ensure the fields are byte-aligned. What's worse, they often do this by default.
The way this guy explains it, he makes it sound optional, when it isn't. You can't use misaligned addresses on pretty much every piece of hardware. Compilers make a choice between time and effort, it is much easier to just pad a struct then try to juggle elements around until it takes up the least space. The onus is on the programmer to order their struts properly if they really care heavily about memory.
People like the author of this should be banned from the Internet. Almost everything in that post is wrong or misleading.
1) In C, a struct maps to memory
A struct maps to memory, sure, but not in a defined way. For popular machine architectures, there is usually an ABI standard which specifies the mapping. For less popular ones, each compiler does whatever it wants.
It is correct that a struct representation may include padding, but the author makes several mistakes explaining it. Firstly, there may never be padding at the start of a struct, which is the only rule dictated by the C standard. Secondly, he fails to mention why padding is sometimes used (to achieve natural alignment for all members). Finally, he suggests using implementation-specific pragmas or flags to pack the struct without padding.
Apart from padding, there is a further problem with this approach which the author fails to mention: byte order. If the data file was written with a different byte order than the machine executing this, all multi-byte values will come out wrong.
As another commenter points out, the correct solution to all of the above is to perform explicit marshalling between the struct and a serialised format.
2) In C, structs are allowed to "run off the end" [...] As long as a symbol is backed by real memory, you can do what you want with it -- including running it past its boundaries
Nothing could be more wrong. C very explicitly disallows accessing an address outside a declared object, array, or dynamically allocated block (malloc). Even computing such an address is forbidden. The errors resulting from breaking these rules are often very hard to pinpoint.
The zero-length array suggested is also in violation of the standard, which requires that arrays have a positive size. In C99, structs are allowed to end with a "flexible array member", which is an array with no declared size at all. This array can then be accessed as though it has as many elements as will fit before the end of the containing object or dynamically allocated block.
Declaring a 1-element array and accessing beyond the end of it is invalid even if the resulting address is otherwise within the containing object. Violating this will, again, lead to subtle errors which are hard to find.
3) In C, you can compute an offset within a struct [...]
While the null pointer casting suggested here usually works, offsetof() is the preferred method, and the author even mentions this in a footnote. An important distinction not mentioned is that offsetof() must expand to an integer constant expression, which the address-of expression is not. This means that only the former may be used where an integer constant expression is required, such as (static) array sizes and case labels (using a struct member offset for either of those seems rather unlikely, of course).
13 comments
[ 3.7 ms ] story [ 43.8 ms ] threadedit: I suppose one could use for globals or on the stack by casting a byte array ... I would find that to be unspeakably ugly but I don't write much C.
C99 has its own "zero sized array" thing but it is a different syntax.
"You don't know it yet, but you're...wrong."
I really really hate it when a posting starts off like this, then proceeds to tell me something anyone who considered themselves a C programmer would know.
Want to write a post about something kind of neat that people outside the field might not be up on? Cool, have fun. But don't start it out by being a rude ass. And this guy dedicates the first hundred words or so of his article to it.
Also,
> size_t offset = (size_t) &(((struct s*)0)->thing);
In what universe is that code "ugly"?
"Well, here's the problem: if padding bytes are involved, you could be entering a world of pain and not even know it. [...] The solution is to use a compiler switch or a #pragma pack to ensure that structs are packed (i.e., no padding applied)."
That's an implementation-defined hack. The correct solution is to explicitly marshal your data between its in-memory format and the required external representation.
The way this guy explains it, he makes it sound optional, when it isn't. You can't use misaligned addresses on pretty much every piece of hardware. Compilers make a choice between time and effort, it is much easier to just pad a struct then try to juggle elements around until it takes up the least space. The onus is on the programmer to order their struts properly if they really care heavily about memory.
1) In C, a struct maps to memory
A struct maps to memory, sure, but not in a defined way. For popular machine architectures, there is usually an ABI standard which specifies the mapping. For less popular ones, each compiler does whatever it wants.
It is correct that a struct representation may include padding, but the author makes several mistakes explaining it. Firstly, there may never be padding at the start of a struct, which is the only rule dictated by the C standard. Secondly, he fails to mention why padding is sometimes used (to achieve natural alignment for all members). Finally, he suggests using implementation-specific pragmas or flags to pack the struct without padding.
Apart from padding, there is a further problem with this approach which the author fails to mention: byte order. If the data file was written with a different byte order than the machine executing this, all multi-byte values will come out wrong.
As another commenter points out, the correct solution to all of the above is to perform explicit marshalling between the struct and a serialised format.
2) In C, structs are allowed to "run off the end" [...] As long as a symbol is backed by real memory, you can do what you want with it -- including running it past its boundaries
Nothing could be more wrong. C very explicitly disallows accessing an address outside a declared object, array, or dynamically allocated block (malloc). Even computing such an address is forbidden. The errors resulting from breaking these rules are often very hard to pinpoint.
The zero-length array suggested is also in violation of the standard, which requires that arrays have a positive size. In C99, structs are allowed to end with a "flexible array member", which is an array with no declared size at all. This array can then be accessed as though it has as many elements as will fit before the end of the containing object or dynamically allocated block.
Declaring a 1-element array and accessing beyond the end of it is invalid even if the resulting address is otherwise within the containing object. Violating this will, again, lead to subtle errors which are hard to find.
3) In C, you can compute an offset within a struct [...]
While the null pointer casting suggested here usually works, offsetof() is the preferred method, and the author even mentions this in a footnote. An important distinction not mentioned is that offsetof() must expand to an integer constant expression, which the address-of expression is not. This means that only the former may be used where an integer constant expression is required, such as (static) array sizes and case labels (using a struct member offset for either of those seems rather unlikely, of course).