nested structure name visibility - c

I wonder if the the following C code is valid:
struct A {
struct B {
int value;
} b;
};
struct B;
void func1(struct B* b) {
b->value = 42;
}
void func2() {
struct A a;
func1(&a.b);
}
This code compiles with gcc and works as one might expect whereas a code checker complains and I wonder who is right and if this is acceptable by the standard (C90 or C99) to refer to struct B in this form.

Yes you can but you will have an error if you want use Struct B outside Struct A.

Related

Reaching named struct in Unnamed union in C

I have the following structure of union and structs
union ab {
struct {
int a;
} a_st;
struct {
int b;
} b_st;
};
typedef struct c {
union ab;
} c_st;
when trying to "reach" the union elements directly:
c_st c;
printf("%d\n", c.a_st.a);
the following compilation error raised:
error: 'c_st' {aka 'struct c'} has no member named 'a_st'
if I provide the union name inside of the 'c_st' struct (e.g. ab_un), it works, but then I need to call c.ab_un.a_st.a, which is less desired.
is it necessary evil or have I missed something here?
Thanks in advance
Per this answer, the solution for gcc is to compile with -fms-extensions.
Here is an example. Tested with Visual C++ and MSYS2 gcc 10.2.
With this version of gcc, the -fms-extensions seems to be implied, and I get an error as mentionned in the comments if I compile instead with -fno-ms-extensions.
#include <stdio.h>
union ab {
struct {
int a;
} a_st;
struct {
int b;
} b_st;
};
typedef struct d {
union ab;
struct {
int c;
} c_st;
} d_st;
int main(void) {
d_st x;
printf("%zu\n", sizeof(d_st));
x.a_st.a = 1;
x.b_st.b = 2;
x.c_st.c = 3;
printf("a_st = %d\n", x.a_st.a);
printf("b_st = %d\n", x.b_st.b);
printf("c_st = %d\n", x.c_st.c);
return 0;
}
As an extension MSVC compiler (see Microsoft Specific Anonymous Structures) and gcc compiler with -fms-extensions (see gcc docs unnamed fields) support the syntax of unnamed structures. When using this extension it allows the code to compiler and access the unnamed structure members as if they were members of the containing structure.
If using this extension, the code will compile and access is fine, you just made a typo c_st should be d_st.
#include <stdio.h>
union ab {
struct {
int a;
} a_st;
struct {
int b;
} b_st;
};
typedef struct d {
union ab;
} d_st;
int main(void) {
d_st c;
printf("%d\n", c.a_st.a);
}
Without using this extension, the code will not compile, as explained below.
is it necessary evil or have I missed something here?
I would say it's just evil. The problem is with the following part:
struct c {
union ab;
};
It's the same as writing:
struct c {
};
You can put any type and follow it with a ;, like:
struct d {
int; float; unsigned long long; FILE *; some_other_type;
};
union ab is just a type. The some_type ; doesn't declare anything, nothing happens. The language grammar just allows you to write just a type as an expression without an identifier (ie. it's used in function declaration like void func(char*, int)), but nothing happens and such expression has no meaning. Your struct c is just empty, it has no members, it's undefined behavior.
trying to "reach" the union elements directly:
You can't access them, because they don't exists. There are no elements inside struct c - it's empty.
You may duplicate code (possibly with a macro):
struct c {
union { // anonymous union
struct {
int a;
} a_st;
struct {
int b;
} b_st;
};
};
and access via:
struct c C;
printf("%d\n", C.a_st.a);

typedef, structure and type compatibiliy

If I have these two structs:
struct
{
int x;
} A;
struct
{
int x;
} B;
then making A = B; results in a compilation error because the two anonymous structs are not compatible.
However if I do:
typedef struct
{
int x;
} S;
S A;
S B;
A = B; is a legal assignment because they are compatible.
But why? With typedef I understand that the compiler makes this when meet S A and S B:
struct { int x; } A;
struct { int x; } B;
so A and B should not be compatible...
Each anonymous struct declaration is a distinct type; this is why you get a type mismatch when trying to assign one to the other.
A typedef, however, declares an alias (i.e. a new name for something that already exists) for a type (it does not create a new type).
A typedef is also not a simple text replacement, like a preprocessor macro. Your statement
I understand that the compiler make this when meet S A and S B:
struct { int x; } A;
struct { int x; } B;
is where your understanding is wrong.
When you use the type alias S, as in
S A;
S B;
the types of both objects A and B are the same by definition and assigning one to the other is possible.
This is because C treats every untagged struct as a new kind of struct, regardless of the memory layout. However, typedef struct { } name; cannot be used if you want to use the struct in a linked list. You'll need to stick with defining a structure tag in this case, and typedef the tagged struct instead.
struct DistanceInMeter /* Anonymous 1 */
{
int x; /* distance */
};
struct VolumeInCC /* Anonymous 2 */
{
int x; /* volume */
};
struct DistanceInMeter A;
struct VolumeInCC B;
...
A = B; /* Something is wrong here */
Equating different type doesn't always make sense and thus is not allowed.
typedef struct DistanceInMeter /* Anonymous 1 */
{
int x; /* distance */
} Dist_t;
Dist_t C, D;
...
C = D; /* Alright, makes sense */

C macro to ensure element is at start of struct

Is there a way to design a macro that could ensure an element is at the start of a struct during it's definition? For example:
typedef struct {
START(int a);
} b;
// Becomes
typedef struct {
int a;
} b;
But generate a compiletime error when it isn't the first element?
typedef struct {
int c;
START(int a);
} b;
// Generate an error
I was thinking you could use a combo of the OFFSETOF and BUILD_BUG_ON_ZERO macros but this would require knowing the struct layout while initializing it, and produces an error because the variable is undeclared.
Is this possible in C?
Use a compile time assertion at the locations you actually assume that layout, instead of at the definition site. Of course you will need to actually define it at the start in order to pass the assertion.
Perhaps something like this would work for you:
#define typedef_header(x) typedef struct { x
typedef_header(int a);
int c;
} b;
int main()
{
b x;
}

"Reflection" and incompatible pointer types in C

I'm following a pseudocode snippet in a CompSci paper and trying to implement it in C. In this paper, I have two structs, say A and B. One of them goes something like this:
struct A {
B* next;
int data;
}
while B looks like
struct B {
A* next;
}
Now, for a given instantiation a of A and b of B, at some point the algorithm tells me to do two things:
if a is not B, then do stuff,
a = b
Now, I cannot do reflection in C, and I will obviously get incompatible pointer types for the second requirement. I thought about having a union in the A struct, and perhaps that would help, but I'd like to ask you guys if there's a good design I'm missing.
You are venturing into dangerous territory here. It appears that you are trying to implement polymorphism in a language which has no built in support for it.
There are several schemes you could use which allow you to have an struct A* actually point to memory containing a struct B. A union is probably the least dangerous. But as you point out, there is no reflection. Any pointer only knows that it points to a block of memory, and one way to interpret that block if it is dereferenced. void pointers don't even know that last part. The only way to do type identification is to insert a value identifying the type somewhere in the structure.
Something like this:
struct generic {
enum {ATYPE,BTYPE} type;
union {
struct A a;
struct B b;
};
};
function process(struct generic* a, struct generic* b)
{
if (a.type != BTYPE)
{ //do stuff
}
else
{
*a = *b;
}
}
-edit-
on the other hand, if the content of the structures is as simple as you describe, you could
simply add an isB member to struct a, and only use one type.
I have no idea what this is supposed to do, but here is what you do to make it compile:
struct a a;
struct b b;
typedef struct a
{
struct b* next;
int data;
} A;
typedef struct b
{
A* next;
} B;
int main()
{
A a;
B b;
}
Now, if your struct's are defined in the correct way, then your algorithm should be described that way:
if (a != b->next) then do stuff
a=b->next;
But in this case, the assignment of a=b->next makes only sense if a!=b->next, so it should be moved into the "do stuff"-thing
To make it compilable, you just can add a forward-decl to B in front of the A-definition:
struct B;
struct A {
B* next;
int data;
};
struct B {
A* next;
};
int main () {
A *a=...;
B *b=...;
if (a!=b->next) {
//do stuff
}
a = b->next;
}

What is this operator(->) in C? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Arrow operator (->) usage in C
As far as i know only C++ can use classes(obj->something) however i have seen this operator in numerous C applications.
And a small side-question. Usually one uses structures in C like this:
structname.somevariable
However i have seen them used like:
structname.something1.something2
Does it have something to do with the keyword union?
struct A
{
int b;
};
struct A *a;
a->b == (*a).b;
And no, that has nothing to do with unions. It's just getting a member of a member.
if you have a pointer to a struct object, like
struct P * p;
you access members with ->
p->member
if p is not a pointer, you access members with .
struct P p;
p.member
Any C book covers this :P
Operator -> is used to access a member of a struct through a pointer to that structure. The second part of your question is used when accessing nested structures, it is not restricted to the use of unions. For instance:
struct A {
int a;
};
struct B {
struct A baz;
};
int main()
{
struct A foo;
struct B bar;
(&foo)->a = 10;
bar.baz.a = 20;
return 0;
}
C++ classes are an extension of C structs, and an object is just a pointer to a struct. C++ didn't actually invent a whole lot of new stuff; it's called C ++ for a reason.
structs can be nested. Given
struct a {
int a_a;
int a_b;
}
struct b {
int b_a;
struct a b_b;
} a;
you can refer to a.b_b.a_b.
A union uses similar syntax to a struct, but all the members overlap each other. This is useful when you need to interpret a chunk of memory in multiple ways.
I strongly suggest picking up a C book.
x.y.z is used when you want to access a member of a struct that is itself a member of another struct.
typedef struct _POINT
{
int x;
int y;
} POINT;
typedef struct _RECT
{
POINT topLeft;
POINT bottomRight;
} RECT;
int main()
{
RECT r;
r.topLeft.x = 0;
t.topLeft.y = 0;
int width = r.bottomRight.x - r.topLeft.x;
}
I've written a small example in C.
#include <stdio.h>
#include <stdlib.h>
struct a_t {
int a;
/* ... */
};
struct b_t {
struct a_t a;
/* ... */
};
int main()
{
struct a_t a;
struct a_t *b;
b = malloc(sizeof(struct a_t));
a.a = 1;
b->a = 2;
printf("%d; %d;\n", a.a, b->a);
(&a)->a = 3;
(*b).a = 4;
printf("%d; %d;\n", a.a, b->a);
free(b);
struct b_t c;
c.a.a = 5;
printf("%d;\n", c.a.a);
return 0;
}
If I remember correctly, in C++
class IDENTIFIER {
// stuff, possibly including functions
};
is exactly the same as
struct IDENTIFIER {
private:
// stuff, possibly including functions
};
and
struct IDENTIFIER {
// stuff, possibly including functions
};
is exactly the same as
class IDENTIFIER {
public:
// stuff, possibly including functions
};

Resources