I'd like to declare a struct in C without defining it at the same time (i.e. to separate interface and implementation) so others can include this in their projects and define it to their needs (it is only used as a parameter in my code). Thus, I'd like to know if this is:
A) Possible (maybe just using macros)?
B) Considered good practise (in my particular circumstance)?
B would be hard to answer without context (and is still subjective) so I'd only like it examined against any common pre-existing patterns in C for addressing the given context (if any). I have the following code:
typedef struct {
bool logged_in;
} Foo;
That I would like as this (pseudo code):
typedef struct Foo;
So this declaration can then be defined by the person who is including this in their project. In my code I am only using it as a parameter without trying to access the properties it contains, like so:
bool bar(Foo* foo) {
//...
}
Thanks.
Forward-declare it like this:
typedef struct Foo Foo;
Then define it with it's ‘full name’:
struct Foo {
…
};
Or you can just forward-declare the ‘full name’:
struct Foo;
And use that:
bool bar(struct Foo *foo) {
…
}
Did you try it? This compiles for me with no warnings on GCC:
typedef struct Foo_ Foo;
int bar( Foo *foop )
{
return 1;
}
I don't know any reason why you wouldn't want to do it.
Related
In order to declare a struct in C, I have been using
typedef struct Foo Foo;
and then defining it at some point below.
Why do I have to specify the name of the struct (Foo) twice?
The format is
typedef old_type new_type
so for
typedef struct Foo Foo;
struct Foo is the old type and Foo is the new type, so whenever you type Foo it is really an alias for struct Foo.
struct Foo is the type that are creating a new type alias for. The last Foo is the name of the new type. If your struct declaration is visible, then you can write the type definition and struct declaration combination like this to avoid the duplicated Foo:
typedef struct {
...
} Foo;
You don't have to specify two names. You can introduce an incomplete struct type just like this:
struct Foo;
that's it. Or a complete one:
struct Foo { int x; };
Neither of these declarations introduce a name into the scope; they introduce a struct tag.
If you introduce a struct tag, you must use the struct keyword everywhere to refer to it, e.g.
struct Foo f;
void fun(struct Foo *param);
The typedef is used in order not to have to write struct Foo everywhere. The type name doesn't have to be the same as the tag:
typedef struct Foo_s Foo;
Foo f;
void fun(Foo *param);
The C++ dialect of C changes the rules; in C++ struct Foo introduces Foo into the scope as a type name, and as a tag (for C compatibility).
One reason you might see typedef struct Foo Foo might be that the code started as C++, looking like this:
struct Foo; // Originally C++ only header file.
void fun(Foo *param);
Then a requirement came along that C had to be supported, at least in header files. In C, the Foo type is not declared:
typedef struct Foo Foo; // Fix for C.
#ifdef __cplusplus
#define extern_c extern "C" // C compatible linkage for fun
#endif
void fun(Foo *param);
#ifdef __cplusplus
}
#endif
Though C++ may seem more convenient in this regard, its object system absolutely punishes the user with repetitions of the same identifier, like you wouldn't believe.
To define a basic class skeleton with a constructor and destructor which are not inlined in the class declaration, we have to repeat the name seven times:
class foo {
public:
foo();
~foo();
};
foo::foo()
{
}
foo::~foo()
{
}
Good thing the C++ programmer is at least spared from having to write class foo *fooptr everywhere, right?
How can I typedef a struct but still keep the new type namespaced under the keyword 'struct'?
example:
struct foo {
int x;
};
typedef struct foo struct bar;
int main(void) {
struct bar bar;
bar.x = 10;
return 0;
}
but this doesn't work obviously.
Here are the errors if anyone is curious:
main.c:5:20: error: two or more data types in declaration specifiers
typedef struct foo struct bar;
^
main.c:5:27: warning: useless storage class specifier in empty declaration
typedef struct foo struct bar;
^
main.c: In function 'main':
main.c:9:13: error: storage size of 'bar' isn't known
struct bar bar;
How can I typedef a struct but still keep the new type namespaced under the keyword 'struct'?
So, it seems that you want to define a structure alias for another structure type.
This is not possible with typedef as it creates a single word alias. The new alias can't be consisted of multiple white space separated words.
But you can use a single name like struct_bar with struct implemented inside of the name to show that bar is a structure.
#include <stdio.h>
struct foo {
int x;
};
typedef struct foo struct_bar;
int main(void) {
struct_bar bar;
bar.x = 10;
return 0;
}
How can I typedef a struct but still keep the new type namespaced under the keyword 'struct'?.
You cannot. A namespace is a declarative region that provides a scope to the identifiers (names of the types, function, variables etc) inside it. The concept of Namespace as it is defined within C++, is not inherent in C.
So, if you are okay with minor changes in your requirements, instead of doing something unnatural, use a simple typedef:
Instead of this:
struct foo {
int x;
};
do this:
typedef struct {
int x;
}foo;
Then this will work:
typedef foo bar;
int main(void )
{
bar b;
b.x = 10;
return 0;
}
Note: Although namespaces are not inherent in in C, as they are in C++, there are some interpretations eg: as discussed here, that argue the point.
C doesn't have any type of support for namespaces (at least not in the sense that C++ does).
When you create a typedef, the new type name is a single identifier, not multiple words. So struct bar can't be an alias for another type. You would have to call it bar or some other one-word name.
You can't. This isn't how it works.
You cannot "create" a type whose name is more than one word, nor can you refer to a type alias using the keyword struct.
The purpose of writing struct, in this context, is to refer to a struct type by a name that wasn't introduced as an alias. The keyword is there to say that that's what you want to do. But it's not part of the name; it cannot be part of the name.
Fortunately, there's no reason to need or even want this.
I found a solution that works for cygwin:
struct foo {
int x;
};
struct bar {
struct foo;
};
I'm trying to manually implement a polymorphic behavior in C by creating a generic struct, and then derived structs (if you will) which can be told apart by the value of an enum, so that I can have a pointer to the generic type, dereference it as the generic type, figure out what type it is, and then dereference it as the more specific type.
typedef struct{
enum type structType;
//... other stuff all the structs share
}generic;
typedef struct{
generic; //does not work, obviously, nor does (generic){};
//... other stuff unique to struct type A
}typeA;
I understand that I could just declare a named instance of the generic struct in the derived struct, but this seems a little messy, and I would prefer not to if there's a neat and tidy way around it.
You can't always get what you want, but if you try sometimes, well, you might find, you get what you need ...
There are two basic ways, with a slight bit of trickery:
Using an include file (e.g.): generic.h
Using a CPP macro (e.g): GENERIC
I've used both methods at various times.
Here's the method with the include file (generic.h):
enum type structType;
int com_fd;
void *com_buf;
And, here's a .c file that uses it:
typedef struct {
#include <generic.h>
} generic;
typedef struct {
#include <generic.h>
// other stuff unique to struct type A ...
int typea_value;
} typeA;
Here's the method using a macro:
#define GENERIC \
enum type structType; \
int com_fd; \
void *com_buf
typedef struct {
GENERIC;
} generic;
typedef struct {
GENERIC;
// other stuff unique to struct type A ...
int typea_value;
} typeA;
Can you declare an anonymous instance of a named struct?
No.
Yet code can make-up a name based on the line number, to keep it unique and with some level of animosity.
Now code should not try to reference var.member11 as the member's name changes as the code for typeA definition moves about in the file.
#define ANON_1(A,B) A##B
#define ANON_2(A,B) ANON_1(A,B)
#define ANON ANON_2(member, __LINE__)
typedef struct{
int x;
} generic;
typedef struct{
generic ANON; // name will be something like: member10
generic ANON; // name will be something like: member11
int y;
} typeA;
int main() {
typeA var;
(void) var;
return 0;
}
I suspect though to achieve OP's higher goal, a better approach is possible.
I have the following c code:
struct {
short s;
int n;
} variableName;
I want to write a function to capture this variable like so
void func(MyStruct* var){
//do stuff
}
func(&variableName);
I would like to do this without providing a definition for the struct. Is there a way to capture variableName?
No, you can't pass an "anonymous" struct into a function in C. You could of course define your function to accept the arguments individually:
void func(short s, int n) { ... }
Or you can define the MyStruct structure in a place that both the function and the calling code has visibility to. Note that the whole struct is passed by value (copy) when you do that, which may be the behavior you want here (or may not be).
You may be looking for something more like a "dictionary" or "associative array" or "hash" type that many other languages provide, with arbitrary key value pairs in it. Pure C does not have a facility for this; the compiler wants to know the layout of a structure in advance.
(I'm not sure if you might be asking about a slightly more esoteric idea, which is hiding the composition of a structure and passing around an "opaque handle" out of and into an API. There are ways to structure that in C, but please say so if that's what you're talking about.)
Completely overlooked "I would like to do this without providing a definition for the struct. Is there a way to capture variableName?" in the OP, unless it was edited after. The question makes less sense now, but heres how you could normally pass a struct to a function for future readers.
#include <stdio.h>
struct StructName{
short s;
int n;
};
void func(struct StructName struct_var){
printf("Param values are: %4X %4X\n", struct_var.s & 0xFFFF, struct_var.n & 0xFFFF);
}
int main(){
struct StructName struct_var;
struct_var.s = 0xDEAD;
struct_var.n = 0xBEEF;
func(struct_var);
}
//It looks like you are trying to use the definition as a variable. Here the definition is StructName and the variable is struct_var.
this sample code outputs:
Param values are: DEAD BEEF
If you use clang or gcc, you may be able to use typeof:
struct foo {
struct {
int i;
} anon;
} foo;
void do_something(typeof(foo.anon)* member) {
member->i = 1;
}
If there is no global instance of your type, you may be able to use typeof((struct foo){}.anon).
This comes with a lot of downsides. The most obvious ones are that:
it's not standard, and it ties you to clang/gcc
it's pretty darn ugly
it might not behave as you expect anyway
For instance, structurally-equivalent anonymous types do not have the same type, so in something like this:
struct foo {
struct {
int i;
} anon1;
struct {
int i;
} anon2;
} foo;
anon1 and anon2 both have a different type, meaning that typeof one of them cannot be used to refer to both.
In the long run, you will almost certainly find that it's worth naming the structures, especially if you use them as function arguments. For instance, if you want to make your variable available from a header, I think that you'll have to work pretty hard to keep it anonymous.
Although it's not particularly pretty and not compatible with C++, C puts the name of nested declarations in the global namespace, so this is portable and it's not a very big code change to front-load:
struct {
struct not_anon {
int i;
} anon;
} foo;
void do_something(struct not_anon* member) {
member->i = 1;
}
I am a little bit surprised the following code does not compile. Can you shed some light on it? (header file)
enum CarType_e {
CAR_BMW = 0,
CAR_KIA,
CAR_HONDA,
CAR_FORD,
CAR_MERCEDES
};
int build_car(CarType_e type);
and then I get the following error:
In file included from car.c:19:0:
car.h:35:16: error: unknown type name ‘CarType_e’
This is gcc version 4.7.3
You have two choices, use
typedef enum {
CAR_BMW = 0,
CAR_KIA,
CAR_HONDA,
CAR_FORD,
CAR_MERCEDES
} CarType_e;
Or, you can use -
int build_car(enum CarType_e type);
I tested both with gcc on linux.
In C, custom types (enums, unions, and structs) each have their own naming scope.
You need to write int build_car(enum CarType_e type);.
This also means there is no point in the _e suffix.
Alternatively, you can use typedef.
You need to say enum CarType_e wherever you use it:
int build_car(enum CarType_e type);
Or typedef the enum.
typedef enum {
CAR_BMW = 0,
CAR_KIA,
CAR_HONDA,
CAR_FORD,
CAR_MERCEDES
} CarType_e;
You need to tell the compiler that you are using an enum by specifying its tag along with the enum keyword. Otherwise how would the compiler resolve an ambiguity like
struct foo { int x; char y; };
enum foo { CAR, BIKE, ROCKET };
union foo { int x; char y; };
int build_car (foo x); /* A struct foo or an enum foo or a union foo? */
Note that structs, enums and unions all have a separate tag name space, so I am free to reuse the same tag name for each of them as shown above.
Requiring the tag name as in
int build_car (enum foo x);
int build_bike (struct foo x);
int build_rocket (union foo x);
makes this non-ambiguous for the compiler.
And don't bother with typedefs for structs/unions; they are useless and only the unenlightened would consider them. Yes, that's a strong opinion. All they do is save you from writing struct in a few places--that's some information you rather want to know about.