I have a struct that might have 2 or 4 members depending on a preprocessor definition.
struct foo {
int m1;
int m2;
#ifdef MORE_MEMBERS
int m3;
int m4;
#endif
}
I have functions that take foo.m3 and foo.m4 as arguments. Because of that, I get a compilation error when MORE_MEMBERS isn't defined.
I'm trying to avoid adding #ifdef at every function call. Is there some way to make m3 and m4 be aliases/dummies when MORE_MEMBERS isn't defined? I'd like to still keep the struct size equal to sizeof(int) * 2.
I agree with Iharob, it's horrible code. It's not too clear what you're after, but it sounds like you could use a union:
struct foo
{
int a;
int b;
};
union bar
{
struct foo m1m2;
struct foo m3m4;
};
void f(union bar *x)
{
printf("%d", x->m1m2.a);
printf("%d", x->m3m4.b);
}
Related
Suppose I have a struct that is defined as the following:
struct entity {
int x;
int y;
};
And a struct that uses it as a member:
struct player {
struct entity position;
char* name;
};
If I write the following code then I get an error:
struct player p;
p.x = 0; //error: 'struct player' has no member named 'x'
What I have been doing so far is writing a function that takes a player struct and returns the value by doing return player.position.x.
Is there a compiler flag, or other method, that allows me to "flatten" (I'm not sure if that's the correct phrase) the struct and allows me to access the x variable like I have shown above? I realize that this might be ambiguous if there is also an integer named x inside player as well as in entity.
Please note I will be using the entity struct in multiple structs and so I cannot use a anonymous struct inside player.
Put succinctly, the answer is "No". This is especially true if you've looked at questions such as What are anonymous structs and unions useful for in C11 and found them not to be the solution.
You can look at C11 §6.7.2.1 Structure and union specifiers for more information about structure and union types in general (and ¶13 specifically for more information about anonymous members, and ¶19 for an example). I agree that they are not what you're after; they involve a newly defined type with no tag and no 'declarator list'.
Using a macro, we can make a type generator:
#define struct_entity(...) \
struct __VA_ARGS__ { \
int a; \
int b; \
}
Then we can instantiate that type as either a tagged or anonymous structure, at will:
struct_entity(entity);
struct player {
struct_entity();
const char *name;
};
int main() {
struct player player;
player.a = 1;
player.b = 2;
player.name = "bar";
}
This code is closer in intent to what you want, and doesn't have the UB problem of the approach of declaring just the structure members in the macro. Specifically, there is a structure member inside of struct player, instead of individual members. This is important, because padding reduction and reordering of members may be performed by the compiler - especially on embedded targets. E.g. composite_1 and composite_2 below do not necessarily have the same layout!:
#include <assert.h>
#include <stddef.h>
typedef struct sub_1 {
int a;
void *b;
char c;
} sub_1;
typedef struct sub_2 {
void *d;
char e;
} sub_2;
typedef struct composite_1 {
int a;
void *b;
char c;
void *d;
char e;
} composite_1;
typedef struct composite_2 {
struct sub_1 one;
struct sub_2 two;
} composite_2;
// Some of the asserts below may fail on some architectures.
// The compile-time asserts are necessary to ensure that the two layouts are
// compatible.
static_assert(sizeof(composite_1) == sizeof(composite_2), "UB");
static_assert(offsetof(composite_1, a) == offsetof(composite_2, one.a), "UB");
static_assert(offsetof(composite_1, b) == offsetof(composite_2, one.b), "UB");
static_assert(offsetof(composite_1, c) == offsetof(composite_2, one.c), "UB");
static_assert(offsetof(composite_1, d) == offsetof(composite_2, two.d), "UB");
static_assert(offsetof(composite_1, e) == offsetof(composite_2, two.e), "UB");
You can define then as MACROs:
#define ENTITY_MEMBERS int x; int y
struct entity{
ENTITY_MEMBERS;
}
struct player {
ENTITY_MEMBERS;
char* name;
};
Actually this is how you mimic C++ single inheritance in C.
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 */
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;
}
header1.h
-----------------
struct A{
int a;
B *b;
};
header2.h
-------------------
#include"header1.h"
typedef struct b{
int aa;
char bb;
int cc;
}B;
main.c
--------------------
#include<header2.h>
main(){
struct A *ace;
ace = malloc(sizeof(struct A));
ace->b = malloc(sizeof(B));
}
The problem: Basically, header1.h needs to use a struct defined in header2.h.
The Dilemma: Since header2.h includes header1.h, If i include header2.h in header1.h I will be introducing a circular dependency.
Some solutions: One way to solve the problem would be use a void pointer, but is there any other way? I tried forward declaring it, but it says "redifining a typedef".
So the problem you have is the pointer
B *b;
in struct A. Since this is a pointer an incomplete type is ok as long as you tell it that's what this is.
typedef struct a {
int a;
struct B *b;
} A;
or you could use the prototype form:
struct B;
typedef struct a {
int a;
B *b;
};
The compiler just wants to know what type of thing the pointer points-to just here, it doesn't actually care what it looks like in more detail until you first start trying to dereference it.
You can easily prevent your header files from being included multiple times by wrapping them like this
#ifndef FOO_H_ /* include guard */
#define FOO_H_
/* * * * * insert foo.h here * * * * */
#endif /* FOO_H_ */
I would suggest to use forward declaration in this case as struct B appears only as a pointer and dont try to access
any members of struct B. The compiler would be happy and I assume only the source code would access the members.
header1.h:
struct B;
struct A{
int a;
B *b;
}
The following code compiles and runs fine:
#include <stdio.h>
typedef int Someint;
typedef int Someint;
int main()
{
Someint b = 4;
printf("%d", b);
return 0;
}
The following code doesn't compile. It's giving me an error conflicting types for 'Somestruct'.
#include <stdio.h>
typedef struct
{
int x;
}
Somestruct;
typedef struct
{
int x;
}
Somestruct;
int main()
{
Somestruct b;
b.x = 4;
printf("%d", b.x);
return 0;
}
Why can I typedef one type (int in first code) twice without error ,but the same thing fails for another type (the structure above)? What is the difference between the two cases?
I'm using the MinGW compiler that came with CodeBlocks 12.11.
The thing is that when you do:
typedef struct
{
} Somestruct;
It creates an anonymous struct - you can expect some hidden implementation-defined guaranteed-unique placeholder identifier to be used - for which you specify the typedef. So, when you do it twice you get a conflict in having the same typedef-ed name asked to refer to two distinct structures. With int, you're simply repeating the original. If you give the struct an actual name then that lets you repeat the typedef:
typedef struct Somestruct
{
} Somestruct;
Because you're defining your typedef using an anonymous struct, both definitions are distinct.
The following doesn't do this, and works. (note that you can still only define the struct once)
#include <stdio.h>
typedef struct foo
{
int x;
}
Somestruct;
typedef struct foo Somestruct;