"Inheritance" in C's structs? - c

Here I'm a bit confused about this code:
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
struct test_struct {
uint8_t f;
uint8_t weird[];
};
int main(void) {
struct {
struct test_struct tst;
uint8_t weird[256];
} test_in = {};
printf("%u\n", test_in.weird[0]); // 0
test_in.tst.weird[0] = 1;
printf("%u\n", test_in.weird[0]); // 1
return 0;
}
I didn't know that it is possible to use struct's fields this way, so I have two questions:
How is it called in C?
And, of course, how does it work? (Why weird field was changed when I don't change it directly, I thought these are two different fields?)

Here I'm a bit confused about this code:
The short answer is: the code has undefined behavior.
How is it called in C? How does it work?
struct test_struct is defined with its last member as an array of unspecified length: uint8_t weird[]; This member is called a flexible array member, not to be confused with a variable length array.
6.7.2 Type specifiers
[...]
20     As a special case, the last member 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.
if you allocate such a structure from the heap with extra space for array elements, these elements can be accessed via the weird member up to the number of elements thus allocated.
The C Standard mandates that such a structure can only be defined as a member of another structure or union if it appears as the last member of said aggregate. In the posted code, the programmer violates this constraint, so accessing elements of test_in.tst.weird has undefined behavior, and so does accessing elements of test_in.weird.
The programmer also assumes that the test_in.tst.weird array and the test_in.weird array overlap exactly, which may be the case but is not guaranteed, nor supported: code relying on this type of aliasing has undefined behavior as well.
In your example, assuming the compiler accepts the empty initializer {} (part of the next C Standard and borrowed from C++), it seems to work as expected, but this is not guaranteed and alignment issues may cause it to fail as shown in the modified version below:
#include <stdint.h>
#include <stdio.h>
struct test_struct {
uint8_t f;
uint8_t weird[];
};
struct test_struct1 {
int x;
uint8_t f;
uint8_t weird[];
};
int main(void) {
struct {
struct test_struct tst;
uint8_t weird[256];
} test_in = {};
struct {
struct test_struct1 tst;
uint8_t weird[256];
} test_in1 = {};
printf("modifying test_in.weird[0]:\n");
printf("%u\n", test_in.weird[0]); // 0
test_in.tst.weird[0] = 1;
printf("%u\n", test_in.weird[0]); // 1
printf("modifying test_in1.weird[0]:\n");
printf("%u\n", test_in1.weird[0]); // 0
test_in1.tst.weird[0] = 1;
printf("%u\n", test_in1.weird[0]); // 0?
return 0;
}
Output:
chqrlie$ make 220930-flexible.run
clang -O3 -std=c11 -Weverything -o 220930-flexible 220930-flexible.c
220930-flexible.c:17:28: warning: field 'tst' with variable sized type 'struct test_struct' not at
the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
struct test_struct tst;
^
220930-flexible.c:19:17: warning: use of GNU empty initializer extension [-Wgnu-empty-initializer]
} test_in = {};
^
220930-flexible.c:22:29: warning: field 'tst' with variable sized type 'struct test_struct1' not
at the end of a struct or class is a GNU extension [-Wgnu-variable-sized-type-not-at-end]
struct test_struct1 tst;
^
220930-flexible.c:24:18: warning: use of GNU empty initializer extension [-Wgnu-empty-initializer]
} test_in1 = {};
^
4 warnings generated.
modifying test_in.weird[0]:
0
1
modifying test_in1.weird[0]:
0
0

struct test_struct {
uint8_t f;
uint8_t weird[];
};
int main(void) {
struct {
struct test_struct tst;
uint8_t weird[256];
} test_in = {};
Effectively, before there were FAM's in the language, what you've declared is:
int main(void) {
struct {
struct { uint8_t f; } tst;
union {
uint8_t weird0[1]; // any non-zero size up to 256
uint8_t weird1[256];
} overlay;
} test_in = {};

On the contrary as described in the comments section above, a declaration like
int array[];
is not a Variable Length Array, it's either called Arrays of unknown size (cppreference) or Arrays of Length Zero (gcc).
An example of a VLA would be:
void foo(size_t n)
{
int array[n]; //n is not available at compile time
}
Based on the comment below (from the cppreference - see provided link):
Within a struct definition, an array of unknown size may appear as the last member (as long as there is at least one other named member), in which case it is a special case known as flexible array member. See struct (section Explanation) for details:
struct s { int n; double d[]; }; // s.d is a flexible array member
struct s *s1 = malloc(sizeof (struct s) + (sizeof (double) * 8)); // as if d was double d[8]

The provided code is just invalid.
You declared a structure with a flexible array member
struct test_struct {
uint8_t f;
uint8_t weird[];
};
From the C Standard (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.
As it is seen from the quote such a member must be the last element of a structure. So the above structure declaration is correct.
However then in main you declared another unnamed structure
int main(void) {
struct {
struct test_struct tst;
uint8_t weird[256];
} test_in = {};
//...
that contains as member an element of the structure with the flexible array element that now is not the last element of the unnamed structure. So such a declaration is invalid.
Secondly, you are using empty braces to initialize an object of the unnamed structure. Opposite to C++ in C you may not use empty braces to initialize objects.

Related

GCC Casting Pointer to Incompatible Type

I have a working C code when compiled using GCC, but I am trying to find out if the code works because of pure luck or because GCC handles this code as I expect by design.
NOTE
I am not trying to "fix" it. I am trying to understand the compiler
Here is what I have:
iexample.h
#ifndef IEXAMPLE_H_
#define IEXAMPLE_H_
/* The interface */
struct MyIf
{
int (* init)(struct MyIf* obj);
int (* push)(struct MyIf* obj, int x);
void (* sort)(struct MyIf* obj);
};
/* The object, can be in different header */
struct Obj1
{
struct MyIf myinterface;
int val1;
int val2;
};
struct Obj1* newObj1();
#endif
iexample.c
#include <stdio.h>
#include <stdlib.h>
#include "iexample.h"
/* Functions here are "equivalent" to methods on the Obj1 struct */
int Obj1_init(struct Obj1* obj)
{
printf("Obj1_init()\n");
return 0;
}
int Obj1_push(struct Obj1* obj, int x)
{
printf("Obj1_push()\n");
return 0;
}
void Obj1_sort(struct Obj1* obj)
{
printf("Obj1_sort()\n");
}
struct Obj1* newObj1()
{
struct Obj1* obj = malloc(sizeof(struct Obj1));
obj->myinterface.init = Obj1_init;
obj->myinterface.push = Obj1_push;
obj->myinterface.sort = Obj1_sort;
return obj;
}
main.c
#include "iexample.h"
int main(int argc, char* argv[])
{
struct MyIf* myIf = (struct MyIf*) newObj1();
myIf->init(myIf);
myIf->push(myIf, 3);
myIf->sort(myIf);
/* ... free, return ... */
}
When I compile, as I expect, I get for assigning the pointers in newObj1(),
warning: assignment from incompatible pointer type
The code works as long as I have the "struct MyIf myinterface" to be the first member of the struct, which is by design (I like to shoot myself in the foot)
Now, although I am assigning incompatible pointer types, and the C spec says behavior is undefined, does GCC or other compilers make any design claim on how this case is handled? I can almost swear that this OUGHT TO WORK due to how struct memory is laid out, but I cannot find the proof.
Thanks
C11 standard 6.7.2.1 Structure and union specifiers:
Within a structure object, the non-bit-field members and the
units in which bit-fields reside have addresses that increase in
the order in which they are declared. A pointer to a structure
object, suitably converted, points to its initial member (or
if that member is a bit-field, then to the unit in which it
resides), and vice versa. There may be unnamed padding within
a structure object, but not at its beginning.
So it should work as long, as you access only first structure member. However, I believe you understand, that this is pretty bad idea. Should you port this code to C++ and make some Obj1 member virtual, this will immediately fail.

Why is initializing C union using "designated initializer" giving random values?

I had a "bug" which I spent quite a while chasing:
typedef union {
struct {
uint8_t mode: 1;
uint8_t texture: 4;
uint8_t blend_mode: 2;
};
uint8_t key;
} RenderKey;
Later this union would be initialized (on stack):
Buffers buffers[128]; // initialized somewhere else
void Foo(int a, int b)
{
//C99 style initialization (all the other values should be 0)
RenderKey rkey = {.blend_mode = 1};
//rkey.key would sometimes be >= 128 thus would write out of array bounds
DoStuffWithBuffer(&buffers[rkey.key]);
}
This seemed to indicate that the last bit of the union bitfield wouldn't be initialized. So I fixed it with adding the unused bit:
typedef union {
struct {
uint8_t mode: 1;
uint8_t texture: 4;
uint8_t blend_mode: 2;
uint8_t unused: 1;
};
uint8_t key;
} RenderKey;
This works, but I don't understand WHY exactly.
That random 1 bit comes from the random garbage on stack before, but why isn't the C99 style initialization working here? Because of the union and the anonymous struct?
This happens on Clang 3.5 and tcc, but not on gcc 4.9.2.
In C11 it is stated at §6.7.9 that
The initialization shall occur in initializer list order, each initializer provided for a particular subobject overriding any previously listed initializer for the same subobject; all subobjects that are not initialized explicitly shall be initialized implicitly the same as objects that have static storage duration.
But the hidden padding bit is not a subobject, it doesn't undergo that constraint because from the anonymous struct point of view it doesn't exist, so the compiler is not initializing something that is not a member of the struct, which isn't that strange after all.
A similar example would be to have something like
#include <stdio.h>
typedef struct {
unsigned char foo;
float value;
} Test;
int main(void) {
Test test = { .foo = 'a', .value = 1.2f};
printf("We expect 8 bytes: %zu\n", sizeof(Test));
printf("We expect 0: %zu\n", (void*)&test.foo - (void*)&test);
printf("We expect 4: %zu\n", (void*)&test.value - (void*)&test);
unsigned char* test_ptr = (unsigned char*) &test;
printf("value of 3rd byte: %d\n", test_ptr[2]);
}
What would expect test_ptr[2] to be? There are 3 bytes of padding between the two members of the struct which are not part of any subobject, initializing them would be a waste of time since in a normal scenario you can't access them.

Can one element in struct access another element of itself in C?

I want to declare a int num in struct S. Then the same struct should also have a array B of size num(So B will access num from it's own struct).
while in a function, I can do,
func(int A)
{
int max=A; //I could use A directly, I am just trying to explain my plan.
int B[max];
}
same won't work for struct as such,
struct S {
int num;
int data[num]; //this is wrong, num is undeclared
};
Is there any way I can do this?
Use a flexible array member:
struct S {
int num;
int data[];
};
int x = 42;
struct S *p = malloc(sizeof (struct S) + sizeof (int [x]));
p->num = x;
There are several problems with
struct S {
int num;
int data[num];
};
that cause it to not work the way you want to.
The first is that the num being used in the array member declaration isn't the same num that's the member of the struct type; the compiler treats the num in the array declaration as a regular identifier (i.e., it assumes there's a different variable named num in the same scope as the struct declaration)1.
The second problem is that a struct or union type may not have a variable-length array as a member2. However, the last member in the struct may have an incomplete array type:
struct S {
int num;
int data[];
};
Unfortunately, you're still kind of stuck here; if you create an instance of struct S like
struct S foo;
it doesn't actually allocate any space for the array. You'd need to allocate the struct dynamically:
/**
* Note that sizeof doesn't try to actually dereference foo below
*/
struct S *foo = malloc( sizeof *foo + N * sizeof *foo->arr );
to allocate space for the array itself. Note that you cannot declare an array of struct S or use it as a member of another structure or union type if the last member has an incomplete array type. 3
Honestly, your best option is to define the struct as
struct S {
size_t num;
int *data;
};
and then allocate the memory for data as a separate operation from allocating memory for the struct object itself:
struct S foo;
foo.num = some_value();
foo.data = malloc( sizeof *foo.data * foo.num );
Since struct S now has a known size, you can declare arrays of it, and you can use it as a member of another struct or union type:
struct S blah[10];
struct T {
struct S s;
...
};
1. C supports four different name spaces - label names (disambiguated by label syntax), struct/union/enum tag names (disambiguated by the presence of the struct, union, or enum keyword), struct and union member names (disambiguated by the . and -> component selection operators), and everything else. Since the num in your array declaration is not an operand of . or ->, the compiler treats it as a regular variable name.
2. 6.7.2.1/9: "A member of a structure or union may have any complete object type other than a variably modified type."
2. 6.2.7.1/3: A structure or union shall not contain a member with incomplete or function type (hence,
a structure shall not contain an instance of itself, but may contain a pointer to an instance
of itself), except that the last member of a structure with more than one named member
may have incomplete array type; such a structure (and any union containing, possibly
recursively, a member that is such a structure) shall not be a member of a structure or an
element of an array.
First of all, the member num is not declared until the end of the struct definition, which ends at the last }.
Second, how would it make sense to set the array size to be the value of an uninitialized variable?
What I think you attempt to do with int B[max] is to create a variable length array (VLA). But that won't work either, as they are explicitly forbidden inside structs. 6.7.2.1/9:
A member of a structure or union may have any complete object type other than a
variably modified type.
What you could do instead is to declare a flexible array member, as demonstrated in the answer by Ouah.
The reason the compiler complains when you "flexibly declare" the array in the struct in global memory, is because global memory can only be allocated (declared) at compile-time and at compile time all sizes must be known. (The value of a variable is not known at compile time by definition.)
The reason it accepts a flexible array in a function, is because the function's local variables are created at the moment the function is entered and then the compiler can accept a variable size. (It boils down to the compiler allocating more memory on the stack and offsetting all accesses to local variables with the size - but different compilers could have a different approach.)
#include <stdio.h>
int size;
struct S {
int num;
int a[size]; // illegal: size must be known at compile time
};
int f(int size)
{
int a[size]; // legal as a is allocated on the stack
....
}
The following would be legal:
#include <stdio.h>
#define A_SIZE 10
struct S {
int num;
int a[A_SIZE]; // legal: A_SIZE is known at compile time
};
P.s.: I am not a C99 programmer; I may have some mistakes here.

Using structure in C and C++

I am new to C and I want to know how to access elements inside a structure which is placed inside a structure.
struct profile_t
{
unsigned char length;
unsigned char type;
unsigned char *data;
};
typedef struct profile_datagram_t
{
unsigned char src[4];
unsigned char dst[4];
unsigned char ver;
unsigned char n;
struct profile_t profiles[MAXPROFILES];
} header;
How to access elements inside profile_t??
struct profile_t;
The above statement doesn't create an object of type profile_t. What you need to do is -
struct profile_t inObj ;
Then create object for profile_datagram_t. i.e.,
header outObj ; // header typedef for profile_datagram_t
Now you can access elements like -
outObj.inObj.type = 'a' ; // As an example
In C++, while creation of object for a structure, struct key word isn't necessary.
On your question edit and comment :
struct profile_t profiles[MAXPROFILES];
profiles is an array of objects of type profile_t. To access the individual object, just use the [] operator. i.e.,
header obj ;
obj.profiles[0].type = 'a' ; // Example
obj.profiles[i], where i can take values from 0 to MAXPROFILES - 1, gives the object at index i.
Not sure what happends in C, but in C++, rest of the stuff aside, the following declares two types.
struct profile_datagram_t
{
struct profile_t;
};
One type is named profile_datagram_t and the other is called profile_datagram_t::profile_t. The inner type declaration is just a forward declaration, so you'll need to define the type after.
struct profile_datagram_t::profile_t
{
// ...
};
Then, you can use the struct as follows:
int main ( int, char ** )
{
profile_datagram_t::profile_t profile;
}
Some compilers support a nonstandard extension to the C language (that I actually rather like, despite it being nonstandard) called anonymous structs (or unions). Code demonstration:
struct x {
int i;
};
struct y {
struct x;
};
int main(void)
{
struct y;
y.i = 1; // this accesses member i of the struct x nested in struct y
return 0;
}
In a nutshell, if you don't give the struct (or union) member a name, you can access its members directly from the containing struct (or union). This is useful in situations where you might have given it the name _, and had to do y._.i - the anonymous struct syntax is much simpler. However, it does mean that you have to remember the names of all members of both structs and ensure they never clash.
This is all, of course, a nonstandard extension, and should be used with caution. I believe it works on MSVC and can be enabled in GCC with a switch. Don't know about any other compilers. If you're worried about portability, give the member a proper name.
EDIT: According to the GCC reference (below) this behavior is being added to the upcoming C1X standard, so it won't be nonstandard for long. I doubt MSVC will support C1X since they refuse to support C99 as it is, but at least this feature is becoming part of the standard.
However, the behavior shown above is MSVC only. The C1X (and GCC without the -fms-extensions switch) syntax doesn't allow the unnamed struct member to have a name:
struct y {
struct {
int i;
};
};
int main(void) {
struct y;
y.i = 1; // this accesses member i of the struct x nested in struct y
return 0;
}
References for various compilers (they have different names but are the same concept):
GCC (unnamed fields): http://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html'
MSVC (anonymous structs): http://msdn.microsoft.com/en-us/library/z2cx9y4f.aspx
Basically you can use the following format:
variable = profile_t.element
profile_t.element = ?
EDIT: In your declaration of profile_datagram_t, the proper definition for struct profile_t should be:
struct profile_t someProfile;
Let's say you have:
header profileDiagram1;
struct profile_t profile1;
profileDiagram1.someProfile = profile1;
To access length, type or *data from profile_t:
profileDiagram1.someProfile.type;
profileDiagram1.someProfile.length;
...

Variable as array size in struct

I implement a file's struct in my program but for some arrays in the struct I don't know the size. The size of the array is stored in another variable but it's unknown before the struct is filled in.
struct Vertex {
float x;
float y;
float z;
};
struct myFile {
ulong nVertices;
Vertex vertices[nVertices];
};
That gives an error: "error C2065: 'nVertices' : undeclared identifier".
You should store a pointer in your struct:
Vertex *vertices;
Then allocate the memory at runtime:
myFile f;
f.vertices = malloc(nVertices * sizeof(Vertex));
if (f.vertices == 0)
handle_out_of_memory();
f.nVertices = nVertices;
Remember to free the memory when done:
free(f.vertices);
C99 introduces 'flexible array members', which may be what you want to use. Your code still ends up looking remarkably like the code suggested by #frast, but is subtly different.
§6.7.2.1 Structure and union specifiers
A structure or union shall not contain a member with incomplete or function type (hence,
a structure shall not contain an instance of itself, but may contain a pointer to an instance
of itself), except that the last member of a structure with more than one named member
may have incomplete array type; such a structure (and any union containing, possibly
recursively, a member that is such a structure) shall not be a member of a structure or an
element of an array.
[...]
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. With two
exceptions, the flexible array member is ignored. First, the size of the structure shall be
equal to the offset of the last element of an otherwise identical structure that replaces the
flexible array member with an array of unspecified length.106) Second, 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.
EXAMPLE Assuming that all array members are aligned the same, after the declarations:
struct s { int n; double d[]; };
struct ss { int n; double d[1]; };
the three expressions:
sizeof (struct s)
offsetof(struct s, d)
offsetof(struct ss, d)
have the same value. The structure struct s has a flexible array member d.
If sizeof (double) is 8, then after the following code is executed:
struct s *s1;
struct s *s2;
s1 = malloc(sizeof (struct s) + 64);
s2 = malloc(sizeof (struct s) + 46);
and assuming that the calls to malloc succeed, the objects pointed to by s1 and s2 behave as if the
identifiers had been declared as:
struct { int n; double d[8]; } *s1;
struct { int n; double d[5]; } *s2;
Following the further successful assignments:
s1 = malloc(sizeof (struct s) + 10);
s2 = malloc(sizeof (struct s) + 6);
they then behave as if the declarations were:
struct { int n; double d[1]; } *s1, *s2;
and:
double *dp;
dp = &(s1->d[0]); // valid
*dp = 42; // valid
dp = &(s2->d[0]); // valid
*dp = 42; // undefined behavior
The assignment:
*s1 = *s2;
only copies the member n and not any of the array elements. Similarly:
struct s t1 = { 0 }; // valid
struct s t2 = { 2 }; // valid
struct ss tt = { 1, { 4.2 }}; // valid
struct s t3 = { 1, { 4.2 }}; // invalid: there is nothing for the 4.2 to initialize
t1.n = 4; // valid
t1.d[0] = 4.2; // undefined behavior
106) The length is unspecified to allow for the fact that implementations may give array members different
alignments according to their lengths.
The example is from the C99 standard.

Resources