Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 months ago.
Improve this question
Please give me the answer. Thanks
struct ZMessage {
uint8_t id[sizeof(struct ZID)];
struct ZBlock block[1]; //what different 'ZBlock block'
};
C and C++ are different languages.
struct ZBlock block[1]; is a C syntax.
In classic C a name of struct is ... not a type. It's a name of block (of variables). C got concept of anonymous struct. Anonymous structs allowed to create separate block of variables or fields with proper alignment, i.e following Test would have field b started from a new word, i.e. size of block will be 4 if size of short is 2.
// this is correct ONLY in C
int main(void)
{
struct Test {
short a : 5;
struct {
short b : 5;
short c : 6;
};
};
// you can have a name of variable matching a name of block.
// regardless of name, declaration without struct is forbidden
struct Test Test;
Test.b = 3;
printf("Test.b equals to %d, size of test %d", Test.b, sizeof(Test));
// Output: Test.b equals to 3, size of test 4
return EXIT_SUCCESS;
}
Therefore in any context where you declare a variable or function parameter you have to precede struct-id by keyword struct to create a type-id.
In C++ struct is a class-type. It's name can be used as type-id, so you don't need a keyword struct. C++ doesn't allow anonymous structs but allows anonymous unions and anonymous namespace.
In fact that you declare ZMessage without a typedef suggest that it is C++ context or a recent C version. C syntax is supported for backward compatibility of header files.
About array of size 1. In that case expression consisting out of name block is a pointer to array of ZBlock. Using size 1 to declare a flexible array according to C standard is no longer correct.
C had a special rule that you can use pointer arithmetics (and operator[] as extent of that) to access implicitly allocated memory after this struct, if array is the last member of struct and got incomplete type.
In most situations, the flexible array member is ignored. In
particular, the size of the structure is as if the flexible array
member were omitted except that it may have more trailing padding than
the omission would imply
Creation of such might look like this:
// might have size 4 or size 8 - greater than sizeof(short)
struct Test {
short size;
short data[]; // Incomplete array type - C11.
// `short data[1]; is NO longer a flexible array.
};
int count = 10;
// note: C doesn't support Test::data construct
// C++ would require a type cast (Test*)
struct Test* pack = malloc(sizeof(struct Test) + count*sizeof(short));
pack->size = count;
pack->data[0] = 4;
pack->data[1] = 8;
...
Here is a problem with padding. We most likely allocate more memory than we need. correct way is to determine offset of address beyond last element of data[]. In C, while sizeof(Test) can be, e.g. 8, offset of data[0] can be still 2.
// such usage of offsetof is undefined in C++
struct Test* pack = malloc(offsetof(struct Test, data[count]));
C++ explicitly doesn't allow to go beyond boundary of object, i.e. beyond boundary of struct. But some compilers support it as extension, usually with no array size declared in that case or with size 1 in case of some compilers. Caveat with those is that it's not consistent if compiler assumes struct to include first member of single array or array can have a zero length.
Related
I am new to C programming and in the development of this exercise I encountered this error that I cannot resolve:
Fields must have a constant size: 'variable length array in structure' extension will never be supported
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]) {
int nChapters = 2;
typedef struct {
char title[50];
char author[50];
} Heading;
typedef struct {
char title[50];
int number_pages;
} Chapter;
typedef struct {
Heading heading;
Chapter chapters[nChapters]; //Fields must have a constant size: 'variable length array in structure' extension will never be supported
} Book;
printf("\n");
system("read -p 'Press enter to continue...' ");
printf("Hello, World!\n");
return 0;
}
If I replace chapters[nChapters] with an int like chapters[2], program run without problems. Thanks in advance!
In C you have to declare arrays using a fixed length, your nChapters variable is indeed, a variable. You can turn it into a constant variable by simply adding the const keyword:
const int nChapters = 2
You can use the preprocessor directive #define:
#define nChapters 2
The issue is that you are assuming that it is obvious
Chapter chapters[nChapters];
that value of nChapters is 2.
It works that way for a array which is not within a struct or a union.
This is supported by weird, non-standard, non-GCC (but accepted as an extension by GCC in C90 onwards), not recommended feature called as VLA or Variable Length Arrays. Using these, one can allocate a auto class array.
Referring to GNU/GCC documentation, section 6.20, It is trivial to note that,
The storage is allocated at the point of declaration and deallocated when the block scope containing the declaration exits.
C99 recommends a better way to deal with this requirement - by using flexible length array.
§6.7.2.1 Structure and union specifiers
¶18 As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply. However, when a . (or ->) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed; the offset of the array shall remain that of the flexible array member, even if this would differ from that of the replacement array. If this array would have no elements, it behaves as if it had one element but the behavior is undefined if any attempt is made to access that element or to generate a pointer one past it.
So, that would change your struct to:
typedef struct {
Heading heading;
Chapter chapters[];
} Book;
And then allocate the memory dynamically from heap - using malloc.
The size of the array member of the struct has to be a constant expression (skip "flexible member" case and GCC's VLA-in-struct extension).
In the C standard the only portable way to have a true named integer constant is using enums.
Just replace:
int nChapters = 2;
with this:
enum { nChapters = 2 };
I was looking to make a struct which was an arbitrary size, known at compile time. (for use in a macro).
eg:
/* assume sizeof(SomeStruct) could be an odd number,
* if it is using GCC's 'packed' attribute for eg */
struct {
unsigned char data[sizeof(SomeStruct)];
} a, *tmp;
tmp = (void *)some_data
a = *tmp;
However I was concerned that struct padding may increase the size of the struct so it is larger than the member, I was assured that the size of a single member struct will always be the size of its member.
So my question is:
Can I rely on single member structs always being the same size as their member? Is this apart of the C spec? or is it just how most compilers behave?
C11 6.7.2.1 paragraph 17:
There may be unnamed padding at the end of a structure or union.
No special case is listed for structs with only one member. This is implementation-defined.
It's not obvious why a compiler would put padding there though, since the size of the member should already be as padded as is necessary for all purposes, as it has a complete type of its own.
For your usage though, you don't need to rely on the compiler's behaviour - you can enforce it yourself by adding a static assertion to your macro that sizeof *tmp == sizeof (SomeStruct). If you have an up-to-date compiler and your macro allows for declaration statements, just use _Static_assert; there are also several C99-compatible hacks you can use, such as:
#define STATIC_EXPR_ASSERT(COND) (sizeof (char[(COND) ? 1 : -1]))
... which you can use as the lhs of a comma-expression.
You should also note that if the body of the temporary struct is made up of a char array, it may not have sufficient alignment to represent the incoming data correctly. From C11 onwards you should specify the alignment of the array with _Alignas:
struct {
_Alignas (max_align_t) unsigned char data[sizeof(SomeStruct)];
} a, *tmp;
...which will ensure it can safely store the data for any type regardless of alignment. In C99 you don't have any way to explicitly request max alignment, but you can force the alignment to match a named type by making the temporary struct a member of a union alongside it (you might try long double and hope that's the most-aligned type).
struct s{
int a;
struct s b;
};
The above code segment throws the error error: field 'b' has incomplete type while
struct s{
int a;
struct s *b;
};
doesn't give any error. I don't understand why this is allowed for pointers but not for the non-pointer variable !!
Class members must have a complete type when they are declared, so that their size can be used to determine the class layout.
Within the class definition, the class itself is incomplete, so you can't declare a member of the same type. That would be impossible anyway (at least if there are any other members), since the class would have to be larger than itself.
A pointer is a complete type, even if the type it points to isn't, so you can declare a class member to be a pointer to the class type.
(Note: I use the word "class" since I'm a C++ programmer. I just noticed that the question is also tagged C, and C++ has since been removed. I believe the answer is still correct in that language, if you replace "class" with "structure", but I'm not completely sure since they are different languages. It would be better if you only asked about one language, since there are differences (sometimes major, sometimes subtle) between languages.)
Q: What are incomplete types?
A: An incomplete type is a type which has the identifier but lacks information needed to determine the size of the identifier.
The ‘void’ type is an incomplete type.
A union/structure type whose members which are not yet specified.
‘void’ type cannot be completed.
To complete an incomplete type, we need to specify the missing
information.
Example:
struct Employee *ptr; // Here 'Employee' is incomplete
C/C++ allows pointers to incomplete types.
To make 'Employee' complete, we need to specify missing information like shown below
typedef struct Employee
{
char name[25];
int age;
int employeeID;
char department[25];
}EMP;
In your case,
struct s
{
int a;
struct s b; // Structure is incomplete.
}// Till this point the structure is incomplete.
The struct s b; the structure s is incomplete. We can declare a pointer to incomplete type not a variable.
To adequately define s, the compiler needs to know the size of s. In the first example, the size of s depends on the size of s, but not in the second.
In the first example, by defintion, sizeof(s) = sizeof(int) + sizeof(s) + padding. If we try to solve this equation for sizeof(s), we get 0 = sizeof(int) + padding, which clearly is impossible.
In the second, sizeof(s) = sizeof(int) + sizeof(s*) + padding. If we assume that sizeof(s*) ~= sizeof(int), then sizeof(s) = 2*sizeof(int) + padding.
I'm going to assume that the extra asterisks in struct s **b** are given for emphasis and not as some kind of demented pointer declaration. (Please don't do that! It's much easier to analyze someone's code if it's presented exactly as it runs.)
When you do this without declaring b as a pointer:
struct s{
int a;
struct s b;
};
the compiler doesn't know how much space it needs to allocate for the b field, since at that point you haven't finished defining struct s. In fact, it would be impossible for the compiler to define this particular structure: no matter how many bytes it allocated for struct s, it would have to add 4 more to make room for the int a field.
Declaring b to be a pointer to struct s makes things easier:
struct s{
int a;
struct s *b;
};
No matter how many fields you add to struct s, the compiler knows that the b field only needs to contain the address of the struct, and that doesn't change based on how large the struct itself it.
struct test{
unsigned long int asd[][3][6];
};
sizeof(struct test) returns 0. So, if that is an exact alias of
struct test{
unsigned long int asd[0][3][6];
};
is there any practical use for such a field declaration? You may consider also the template metaprogramming stuff, which is always surprising.
The first example demonstrates the use of a flexible array member, a feature of C99. However in order to get that snippet to compile, you need to have another member in your struct, ie:
struct test{
int a;
unsigned long int asd[][3][6];
};
This documentation on gcc tells you why sizeof evaulates to zero, and the syntactical difference of a normal array:
In ISO C90, you would have to give contents a length of 1, which means
either you waste space or complicate the argument to malloc.
In ISO C99, you would use a flexible array member, which is slightly
different in syntax and semantics:
Flexible array members are written as contents[] without the 0.
Flexible array members have incomplete type, and so the sizeof operator may not be applied. As a quirk of the original implementation
of zero-length arrays, sizeof evaluates to zero.
Flexible array members may only appear as the last member of a struct that is otherwise non-empty.
A structure containing a flexible array member, or a union containing such a structure (possibly recursively), may not be a
member of a structure or an element of an array. (However, these uses
are permitted by GCC as extensions.)
It's a "flexible array member", described in section 6.7.2.1 paragraph 16 of the C99 standard (3.7MB PDF).
This is a new feature in C99; some compilers (particularly Microsoft's) might not support it.
Note that a flexible array member must be the last member of a struct, and it cannot be the only member.
It's a replacement for the "struct hack", described in question 2.6 of the comp.lang.c FAQ.
You might want to use undimensioned arrays in systems with custom memory allocators where you have limited ammount of memory. Say, in embedded software.
If you have a struct defined as:
struct test
{
int a;
unsigned long int asd[][6][3];
};
and a memory pool:
int *b = new unsigned long int[1000];
you can 'allocate' memory and use the structure as follows:
test *t;
t = (test*)b;
t->asd[1][2][3] = 1;
This approach is more flexible than making an array of specified dimensions. Of course you can always use a structure like
struct test2
{
int a;
unsigned long int ***asd;
};
but you'll need to initialize the pointer separately and the pointer itself needs 4 bytes.
As a bonus of not using a pointer the structure is represented as a linear memory chunk and can be serialized as is.
This question already has answers here:
Closed 11 years ago.
The community reviewed whether to reopen this question 9 months ago and left it closed:
Original close reason(s) were not resolved
Possible Duplicate:
Why does this C code work?
How do you use offsetof() on a struct?
I read about this offsetof macro on the Internet, but it doesn't explain what it is used for.
#define offsetof(a,b) ((int)(&(((a*)(0))->b)))
What is it trying to do and what is the advantage of using it?
R.. is correct in his answer to the second part of your question: this code is not advised when using a modern C compiler.
But to answer the first part of your question, what this is actually doing is:
(
(int)( // 4.
&( ( // 3.
(a*)(0) // 1.
)->b ) // 2.
)
)
Working from the inside out, this is ...
Casting the value zero to the struct pointer type a*
Getting the struct field b of this (illegally placed) struct object
Getting the address of this b field
Casting the address to an int
Conceptually this is placing a struct object at memory address zero and then finding out at what the address of a particular field is. This could allow you to figure out the offsets in memory of each field in a struct so you could write your own serializers and deserializers to convert structs to and from byte arrays.
Of course if you would actually dereference a zero pointer your program would crash, but actually everything happens in the compiler and no actual zero pointer is dereferenced at runtime.
In most of the original systems that C ran on the size of an int was 32 bits and was the same as a pointer, so this actually worked.
It has no advantages and should not be used, since it invokes undefined behavior (and uses the wrong type - int instead of size_t).
The C standard defines an offsetof macro in stddef.h which actually works, for cases where you need the offset of an element in a structure, such as:
#include <stddef.h>
struct foo {
int a;
int b;
char *c;
};
struct struct_desc {
const char *name;
int type;
size_t off;
};
static const struct struct_desc foo_desc[] = {
{ "a", INT, offsetof(struct foo, a) },
{ "b", INT, offsetof(struct foo, b) },
{ "c", CHARPTR, offsetof(struct foo, c) },
};
which would let you programmatically fill the fields of a struct foo by name, e.g. when reading a JSON file.
It's finding the byte offset of a particular member of a struct. For example, if you had the following structure:
struct MyStruct
{
double d;
int i;
void *p;
};
Then you'd have offsetOf(MyStruct, d) == 0, offsetOf(MyStruct, i) == 8, and offsetOf(MyStruct, p) == 12 (that is, the member named d is 0 bytes from the start of the structure, etc.).
The way that it works is it pretends that an instance of your structure exists at address 0 (the ((a*)(0)) part), and then it takes the address of the intended structure member and casts it to an integer. Although dereferencing an object at address 0 would ordinarily be an error, it's ok to take the address because the address-of operator & and the member dereference -> cancel each other out.
It's typically used for generalized serialization frameworks. If you have code for converting between some kind of wire data (e.g. bytes in a file or from the network) and in-memory data structures, it's often convenient to create a mapping from member name to member offset, so that you can serialize or deserialize values in a generic manner.
The implementation of the offsetof macro is really irrelevant.
The actual C standard defines it as in 7.17.3:
offsetof(type, member-designator)
which expands to an integer constant expression that has type size_t, the value of which is the offset in bytes, to the structure member (designated by member-designator), from the beginning of its structure (designated by type). The type and member designator shall be such that given static type t;.
Trust Adam Rosenfield's answer.
R is completely wrong, and it has many uses - especially being able to tell when code is non-portable among platforms.
(OK, it's C++, but we use it in static template compile time assertions to make sure our data structures do not change size between platforms/versions.)