We recently found some code submitted to our codebase, along the following lines:
#pragma pack(push,1)
struct xyzzy {
BITMAPINFOHEADER header;
char plugh;
long twisty;
} myVar;
My question is: does the packing apply only to the immediate structure or might it affect the packing of the BITMAPINFOHEADER as well. I can't see the latter case being very useful since it would make the structure different to what you would get from the Windows API calls, for example. Case in point, let's assume the structure is:
typedef struct {
char aChar;
DWORD biSize;
} BITMAPINFOHEADER;
That structure would be vastly different with a packing of one rather than the default eight for Windows (32-bit anyway, may be sixteen for 64-bit).
Is the BITMAPINFOHEADER "protected" from the packing by virtue of the fact it's almost certainly be declared earlier? If it was declared as part of the outer declaration, would it be subject to the packing then?
From the relevant documentation:
pack takes effect at the first struct, union, or class declaration after the pragma is seen. pack has no effect on definitions.
header is a member definition, so it isn't affected.
it was declared as part of the outer declaration, would it be subject to the packing then?
Yes, as it would be a struct declaration.
Also, as Lightness Races in Orbit remarks in a comment, a more convincing wording can be found immediately before:
To pack a class is to place its members directly after each other in memory.
i.e. it says nothing about what those members themselves contain, which may be data and/or padding. The fact that (as explored above) packedness is attached to a type would seem to reinforce that
Still, the documentation is vague enough, so it's best to test that this interpretation is correct; both gcc and VC++ behave as expected. Not that I'm particularly surprised - anything different would break havoc in the type system (taking a pointer to a member of a packed structure would actually provide a pointer to something different than its type says1).
The general idea is: once you finish defining a struct, its binary layout is fixed, and any of its instantiations will conform to it, including subobjects of packed structures. The current #pragma pack value is considered only when defining new structures, and when doing so the binary layout of the members is a fixed black box.
Notes
To be honest, this is a bit of an x86-centric view; machines with stronger alignment requirements would object that even pointers to layout-correct but misaligned structures aren't kosher: although the offsets of fields relative to the given pointer are correct, they aren't really pointers that can be used as they are.
OTOH, given a pointer to an unaligned object you can always detect that it's unaligned and memcpy it to a correctly-aligned location, so it's not as bad as a hypothetical pointer to a packed object, whose layout is effectively unknown unless you happen to know the packing of its parent.
From what I have seen, it only applies to immediate structure.
Take a look at the snippet below:
#include <stdio.h>
struct /*__attribute__((__packed__))*/ struct_Inner {
char a;
int b;
char c;
};
struct __attribute__((__packed__)) struct_Outer {
char a;
int b;
char c;
struct struct_Inner stInner;
};
int main()
{
struct struct_Inner oInner;
struct struct_Outer oOuter;
printf("\n%zu Bytes", sizeof(oInner));
printf("\n%zu Bytes", sizeof(oOuter));
}
Prints:
12 Bytes
18 Bytes
When I pack the struct_Inner it prints:
6 Bytes
12 Bytes
This is when using GCC 7.2.0.
Again, this is not specific to C standard by any means (I just had to read), its more to do with what compilers do.
Is the BITMAPINFOHEADER "protected" from the packing by virtue of the fact it's almost certainly be declared earlier?
I guess yes. It would entirely depend upon the way BITMAPINFOHEADER is declared.
Assuming GCC (or Clang emulating GCC), you can find some relevant information at Structure Layout Pragmas, where it says that the presence of the push preserves the current packing state on a stack of states:
For compatibility with Microsoft Windows compilers, GCC supports a set of #pragma directives that change the maximum alignment of members of structures (other than zero-width bit-fields), unions, and classes subsequently defined. The n value below always is required to be a small power of two and specifies the new alignment in bytes.
#pragma pack(n) simply sets the new alignment.
#pragma pack() sets the alignment to the one that was in effect when compilation started (see also command-line option -fpack-struct[=n] see Code Gen Options).
#pragma pack(push[,n]) pushes the current alignment setting on an internal stack and then optionally sets the new alignment.
#pragma pack(pop) restores the alignment setting to the one saved at the top of the internal stack (and removes that stack entry). Note that #pragma pack([n]) does not influence this internal stack; thus it is possible to have #pragma pack(push) followed by multiple #pragma pack(n) instances and finalized by a single #pragma pack(pop).
Thus, the #pragma in the code added affects all subsequent structure definitions too, until countermanded by #pragma pack(pop). I'd be worried about that.
The documentation doesn't say what happens if you do #pragma pack(pop) when there is no state on the internal stack. Most likely, it falls back to the setting when compilation started.
According to GCC reference:
In the following example struct my_packed_struct's members are
packed closely together, but the internal layout of its s member is
not packed - to do that, struct my_unpacked_struct would need to
be packed too.
struct my_unpacked_struct
{
char c;
int i;
};
struct my_packed_struct __attribute__ ((__packed__))
{
char c;
int i;
struct my_unpacked_struct s;
};
You may only specify this attribute on the definition of a enum, struct or union, not on a typedef which does not also define the
enumerated type, structure or union.
This does not directly answer the question, but might offer an idea why existing compilers decided not to pack sub-structs, and why future compilers are unlikely to change that.
A packing that transitively affected sub-structures would break the type system in subtle ways.
Consider:
//Header A.h
typedef struct {
char aChar;
DWORD biSize;
} BITMAPINFOHEADER;
// File A.c
#include <A.h>
void doStuffToHeader(BITMAPINFOHEADER* h)
{
// compute stuff based on data stored in h
// ...
}
// File B.c
#include <A.h>
#pragma pack(push,1)
struct xyzzy {
BITMAPINFOHEADER header;
char plugh;
long twisty;
} myVar;
void foo()
{
doStuffToHeader(&myVar.header);
}
I pass a pointer to a packed struct to a function that is not aware of the packing. Any attempts by the function to read or write data from the struct will easily break in horrible ways. If a compiler deems this unacceptable, it has two possibilities for fixing the problem:
Transparently unpack the sub-struct into a temporary for the function call and re-pack the result later.
Internally change the type of the header field in xyzzy to something that indicates that it's now a packed type and incompatible with normal BITMAPINFOHEADER.
Both of these are obviously problematic. With this reasoning, even if I wanted to write a compiler that supported packing of sub-structs, I would run into numerous follow-up problems. I'd expect my users to start questioning my design decisions in this regard very soon.
I have a C project that is designed to be portable to various (PC and embedded) platforms.
Application code will use various calls that will have platform-specific implementations, but share a common (generic) API to aid in portability. I'm trying to settle on the most appropriate way to declare the function prototypes and structures.
Here's what I've come up with so far:
main.c:
#include "generic.h"
int main (int argc, char *argv[]) {
int ret;
gen_t *data;
ret = foo(data);
...
}
generic.h: (platform-agnostic include)
typedef struct impl_t gen_t;
int foo (gen_t *data);
impl.h: (platform-specific declaration)
#include "generic.h"
typedef struct impl_t {
/* ... */
} gen_t;
impl.c: (platform-specific implementation)
int foo (gen_t *data) {
...
}
Build:
gcc -c -fPIC -o platform.o impl.c
gcc -o app main.c platform.o
Now, this appears to work... in that it compiles OK. However, I don't usually tag my structures since they're never accessed outside of the typedef'd alias. It's a small nit-pick, but I'm wondering if there's a way to achieve the same effect with anonymous structs?
I'm also asking for posterity, since I searched for a while and the closest answer I found was this: (Link)
In my case, that wouldn't be the right approach, as the application specifically shouldn't ever include the implementation headers directly -- the whole point is to decouple the program from the platform.
I see a couple of other less-than-ideal ways to resolve this, for example:
generic.h:
#ifdef PLATFORM_X
#include "platform_x/impl.h"
#endif
/* or */
int foo (struct impl_t *data);
Neither of these seems particularly appealing, and definitely not my style. While I don't want to swim upstream, I also don't want conflicting style when there might be a nicer way to implement exactly what I had in mind. So I think the typedef solution is on the right track, and it's just the struct tag baggage I'm left with.
Thoughts?
Your current technique is correct. Trying to use an anonymous (untagged) struct defeats what you're trying to do — you'd have to expose the details of definition of the struct everywhere, which means you no longer have an opaque data type.
In a comment, user3629249 said:
The order of the header file inclusions means there is a forward reference to the struct by the generic.h file; that is, before the struct is defined, it is used. It is unlikely this would compile.
This observation is incorrect for the headers shown in the question; it is accurate for the sample main() code (which I hadn't noticed until adding this response).
The key point is that the interface functions shown take or return pointers to the type gen_t, which in turn maps to a struct impl_t pointer. As long as the client code does not need to allocate space for the structure, or dereference a pointer to a structure to access a member of the structure, the client code does not need to know the details of the structure. It is sufficient to have the structure type declared as existing. You could use either of these to declare the existence of struct impl_t:
struct impl_t;
typedef struct impl_t gen_t;
The latter also introduces the alias gen_t for the type struct impl_t. See also Which part of the C standard allows this code to compile? and Does the C standard consider that there are one or two struct uperms entry types in this header?
The original main() program in the question was:
int main (int argc, char *argv[]) {
int ret;
gen_t data;
ret = foo(&data);
…
}
This code cannot be compiled with gen_t as an opaque (non-pointer) type. It would work OK with:
typedef struct impl_t *gen_t;
It would not compile with:
typedef struct impl_t gen_t;
because the compiler must know how big the structure is to allocate the correct space for data, but the compiler cannot know that size by definition of what an opaque type is. (See Is it a good idea to typedef pointers? for typedefing pointers to structures.)
Thus, the main() code should be more like:
#include "generic.h"
int main(int argc, char **argv)
{
gen_t *data = bar(argc, argv);
int ret = foo(data);
...
}
where (for this example) bar() is defined as extern gen_t *bar(int argc, char **argv);, so it returns a pointer to the opaque type gen_t.
Opinion is split over whether it is better to always use struct tagname or to use a typedef for the name. The Linux kernel is one substantial body of code that does not use the typedef mechanism; all structures are explicitly struct tagname. On the other hand, C++ does away with the need for the explicit typedef; writing:
struct impl_t;
in a C++ program means that the name impl_t is now the name of a type. Since opaque structure types require a tag (or you end up using void * for everything, which is bad for a whole legion of reasons, but the primary reason is that you lose all type safety using void *; remember, typedef introduces an alias for an underlying type, not a new distinct type), the way I code in C simulates C++:
typedef struct Generic Generic;
I avoid using the _t suffix on my types because POSIX reserves the _t for the implementation to use* (see also What does a type followed by _t represent?). You may be lucky and get away with it. I've worked on code bases where types like dec_t and loc_t were defined by the code base (which was not part of the implementation — where 'the implementation' means the C compiler and its supporting code, or the C library and its supporting code), and both those types caused pain for decades because some of the systems where the code was ported defined those types, as is the system's prerogative. One of the names I managed to get rid of; the other I didn't. 'Twas painful! If you must use _t (it is a convenient way to indicate that something is a type), I recommend using a distinctive prefix too: pqr_typename_t for some project pqr, for example.
* See the bottom line of the second table in The Name Space in the POSIX standard.
I have a situation where two of my header files require the data structures defined in either one, i.e. no matter which order you include them it won't compile
however, one of the problem data structures only contains pointers to the data structure declared in the other header file so I would have though that technically it doesn't need to know at this point how big the data structure is so it shouldn't be complaining
A simplified example of what I mean is outlined below. I would have thought that the array of modes in Library doesn't need to know how big a Mode is, only how big a pointer to a Mode is therefore the compiler shouldn't complain if it hasn't yet seen the declaration of Mode in the other header file.
header_1.h
typedef struct
{
Mode **modes;
} Library;
header_2.h
typedef struct
{
int number;
char *name;
} Mode;
It doesn't need to know the size, but it must have seen a declaration. A forward declaration
typedef struct Mode Mode;
before the definition of struct Library suffices.
As currently written, your example does not show the mutual cross-referencing that you mention in the question.
The compiler must be told something about each type it uses. You could use in header_1.h just:
typedef struct Mode Mode;
typedef struct
{
Mode **modes;
} Library;
That would make it compile, at least. The compiler doesn't need the details, but it does need to know that Modes is a type.
Edit:
Note that header_2.h should be modified for this to work. You have to ensure that each typedef appears just once. After you have the typedefs in place, you specify the structure content (definition) once, and you omit the keyword typedef and the typedef name from the structure definition. And you have to decide on exactly the cross-references will be managed. For example, should header_1.h include header_2.h anyway.
I don't remember encountering a case where I really needed mutually referencing structures (in quite a long time programming — long enough that I could have forgotten a example). I do now remember a case of structures mutually referencing each other; it was in a version of make originally written for Minix. I still regard such a requirement as somewhat 'pathological' (or, if you prefer, as a 'code smell') and as something to be avoided whenever possible. If you really must manage it, then the section below explains how I'd go about doing it (and more or less how the make program did go about it).
Mutually-referencing structures
If you truly have two mutually referencing structures, you should (re)consider why you think two headers are better than one. If you still need two headers, you use an idiom like:
header_1.h
#ifndef HEADER_1_H_INCLUDED
#define HEADER_1_H_INCLUDED
#ifndef TYPEDEF_MODE
#define TYPEDEF_MODE
typedef struct Mode Mode;
#endif
#ifndef TYPEDEF_LIBRARY
#define TYPEDEF_LIBRARY
typedef struct Library Library;
#endif
struct Library
{
...
Mode **modes;
...
};
#endif /* HEADER_1_H_INCLUDED */
header_2.h
#ifndef HEADER_2_H_INCLUDED
#define HEADER_2_H_INCLUDED
#ifndef TYPEDEF_MODE
#define TYPEDEF_MODE
typedef struct Mode Mode;
#endif
#ifndef TYPEDEF_LIBRARY
#define TYPEDEF_LIBRARY
typedef struct Library Library;
#endif
struct Mode
{
...
Library **liblist;
...
};
#endif /* HEADER_2_H_INCLUDED */
The repeated typedef 'detection' code is not nice; a single header is better, in my estimation. However, you can include header_1.h and header_2.h above in either order and it should compile.
I believe this is happening because "Mode" is a type defined using typedef and its not the name of the struct. You will either need to explicitly forward declare it or you can try using the code structured as follows:
header_1.h
typedef struct
{
struct _Mode_t **modes;
} Library;
header_2.h
typedef struct _Mode_t
{
int number;
char *name;
} Mode;
If I declare and never use variable then gcc will give me a warning.
But if I have a struct with several members and some of those are not used, gcc will not warn about it...
Is there an option (or another method) to check these?
(Of course I can manually delete some entries and try to compile again, but I am looking for this kind of approach).
Thanks
No GCC won't warn about this. Mostly because in the majority case whether or not a member is used can't be determined. A good portion of struct are defined in a header file. This can be used by not just your application but by any other application referencing your .lib or using the same header file. Hence just because the current piece of code being compiled doesn't use the member it doesn't mean that the member is not used by some other piece of code.
Local variables are different. Whether or not they are used easily determined by compiling only the function in question. Hence GCC, and many other compilers, give a warning.
You can legally and portably access the first member of a struct without using its name, simply by casting the struct to the type of the first member.
typedef struct {
int x;
} mystruct;
mystruct s;
*(int*)&s = 3;
You can also non-portably, but with virtually 100% reliability, access any field in the struct without using its name by casting the struct to another struct type with a compatible structure.
typedef struct {
int x;
char y;
} mystruct;
typedef struct {
int a;
char b;
} otherstruct;
mystruct s;
((otherstruct*)&s)->b = 'C';
I'm afraid that this means that neither searching the source for the field's name, nor removing it, are completely reliable.
I have seen many programs consisting of structures like the one below
typedef struct
{
int i;
char k;
} elem;
elem user;
Why is it needed so often? Any specific reason or applicable area?
As Greg Hewgill said, the typedef means you no longer have to write struct all over the place. That not only saves keystrokes, it also can make the code cleaner since it provides a smidgen more abstraction.
Stuff like
typedef struct {
int x, y;
} Point;
Point point_new(int x, int y)
{
Point a;
a.x = x;
a.y = y;
return a;
}
becomes cleaner when you don't need to see the "struct" keyword all over the place, it looks more as if there really is a type called "Point" in your language. Which, after the typedef, is the case I guess.
Also note that while your example (and mine) omitted naming the struct itself, actually naming it is also useful for when you want to provide an opaque type. Then you'd have code like this in the header, for instance:
typedef struct Point Point;
Point * point_new(int x, int y);
and then provide the struct definition in the implementation file:
struct Point
{
int x, y;
};
Point * point_new(int x, int y)
{
Point *p;
if((p = malloc(sizeof *p)) != NULL)
{
p->x = x;
p->y = y;
}
return p;
}
In this latter case, you cannot return the Point by value, since its definition is hidden from users of the header file. This is a technique used widely in GTK+, for instance.
UPDATE Note that there are also highly-regarded C projects where this use of typedef to hide struct is considered a bad idea, the Linux kernel is probably the most well-known such project. See Chapter 5 of The Linux Kernel CodingStyle document for Linus' angry words. :) My point is that the "should" in the question is perhaps not set in stone, after all.
It's amazing how many people get this wrong. PLEASE don't typedef structs in C, it needlessly pollutes the global namespace which is typically very polluted already in large C programs.
Also, typedef'd structs without a tag name are a major cause of needless imposition of ordering relationships among header files.
Consider:
#ifndef FOO_H
#define FOO_H 1
#define FOO_DEF (0xDEADBABE)
struct bar; /* forward declaration, defined in bar.h*/
struct foo {
struct bar *bar;
};
#endif
With such a definition, not using typedefs, it is possible for a compiland unit to include foo.h to get at the FOO_DEF definition. If it doesn't attempt to dereference the 'bar' member of the foo struct then there will be no need to include the "bar.h" file.
Also, since the namespaces are different between the tag names and the member names, it is possible to write very readable code such as:
struct foo *foo;
printf("foo->bar = %p", foo->bar);
Since the namespaces are separate, there is no conflict in naming variables coincident with their struct tag name.
If I have to maintain your code, I will remove your typedef'd structs.
From an old article by Dan Saks (http://www.ddj.com/cpp/184403396?pgno=3):
The C language rules for naming
structs are a little eccentric, but
they're pretty harmless. However, when
extended to classes in C++, those same
rules open little cracks for bugs to
crawl through.
In C, the name s appearing in
struct s
{
...
};
is a tag. A tag name is not a type
name. Given the definition above,
declarations such as
s x; /* error in C */
s *p; /* error in C */
are errors in C. You must write them
as
struct s x; /* OK */
struct s *p; /* OK */
The names of unions and enumerations
are also tags rather than types.
In C, tags are distinct from all other
names (for functions, types,
variables, and enumeration constants).
C compilers maintain tags in a symbol
table that's conceptually if not
physically separate from the table
that holds all other names. Thus, it
is possible for a C program to have
both a tag and an another name with
the same spelling in the same scope.
For example,
struct s s;
is a valid declaration which declares
variable s of type struct s. It may
not be good practice, but C compilers
must accept it. I have never seen a
rationale for why C was designed this
way. I have always thought it was a
mistake, but there it is.
Many programmers (including yours
truly) prefer to think of struct names
as type names, so they define an alias
for the tag using a typedef. For
example, defining
struct s
{
...
};
typedef struct s S;
lets you use S in place of struct s,
as in
S x;
S *p;
A program cannot use S as the name of
both a type and a variable (or
function or enumeration constant):
S S; // error
This is good.
The tag name in a struct, union, or
enum definition is optional. Many
programmers fold the struct definition
into the typedef and dispense with the
tag altogether, as in:
typedef struct
{
...
} S;
The linked article also has a discussion about how the C++ behavior of not requireing a typedef can cause subtle name hiding problems. To prevent these problems, it's a good idea to typedef your classes and structs in C++, too, even though at first glance it appears to be unnecessary. In C++, with the typedef the name hiding become an error that the compiler tells you about rather than a hidden source of potential problems.
Using a typedef avoids having to write struct every time you declare a variable of that type:
struct elem
{
int i;
char k;
};
elem user; // compile error!
struct elem user; // this is correct
One other good reason to always typedef enums and structs results from this problem:
enum EnumDef
{
FIRST_ITEM,
SECOND_ITEM
};
struct StructDef
{
enum EnuumDef MyEnum;
unsigned int MyVar;
} MyStruct;
Notice the typo in EnumDef in the struct (EnuumDef)? This compiles without error (or warning) and is (depending on the literal interpretation of the C Standard) correct. The problem is that I just created an new (empty) enumeration definition within my struct. I am not (as intended) using the previous definition EnumDef.
With a typdef similar kind of typos would have resulted in a compiler errors for using an unknown type:
typedef
{
FIRST_ITEM,
SECOND_ITEM
} EnumDef;
typedef struct
{
EnuumDef MyEnum; /* compiler error (unknown type) */
unsigned int MyVar;
} StructDef;
StrructDef MyStruct; /* compiler error (unknown type) */
I would advocate ALWAYS typedef'ing structs and enumerations.
Not only to save some typing (no pun intended ;)), but because it is safer.
Linux kernel coding style Chapter 5 gives great pros and cons (mostly cons) of using typedef.
Please don't use things like "vps_t".
It's a mistake to use typedef for structures and pointers. When you see a
vps_t a;
in the source, what does it mean?
In contrast, if it says
struct virtual_container *a;
you can actually tell what "a" is.
Lots of people think that typedefs "help readability". Not so. They are useful only for:
(a) totally opaque objects (where the typedef is actively used to hide what the object is).
Example: "pte_t" etc. opaque objects that you can only access using the proper accessor functions.
NOTE! Opaqueness and "accessor functions" are not good in themselves. The reason we have them for things like pte_t etc. is that there really is absolutely zero portably accessible information there.
(b) Clear integer types, where the abstraction helps avoid confusion whether it is "int" or "long".
u8/u16/u32 are perfectly fine typedefs, although they fit into category (d) better than here.
NOTE! Again - there needs to be a reason for this. If something is "unsigned long", then there's no reason to do
typedef unsigned long myflags_t;
but if there is a clear reason for why it under certain circumstances might be an "unsigned int" and under other configurations might be "unsigned long", then by all means go ahead and use a typedef.
(c) when you use sparse to literally create a new type for type-checking.
(d) New types which are identical to standard C99 types, in certain exceptional circumstances.
Although it would only take a short amount of time for the eyes and brain to become accustomed to the standard types like 'uint32_t', some people object to their use anyway.
Therefore, the Linux-specific 'u8/u16/u32/u64' types and their signed equivalents which are identical to standard types are permitted -- although they are not mandatory in new code of your own.
When editing existing code which already uses one or the other set of types, you should conform to the existing choices in that code.
(e) Types safe for use in userspace.
In certain structures which are visible to userspace, we cannot require C99 types and cannot use the 'u32' form above. Thus, we use __u32 and similar types in all structures which are shared with userspace.
Maybe there are other cases too, but the rule should basically be to NEVER EVER use a typedef unless you can clearly match one of those rules.
In general, a pointer, or a struct that has elements that can reasonably be directly accessed should never be a typedef.
It turns out that there are pros and cons. A useful source of information is the seminal book "Expert C Programming" (Chapter 3). Briefly, in C you have multiple namespaces: tags, types, member names and identifiers. typedef introduces an alias for a type and locates it in the tag namespace. Namely,
typedef struct Tag{
...members...
}Type;
defines two things. 1) Tag in the tag namespace and 2) Type in the type namespace. So you can do both Type myType and struct Tag myTagType. Declarations like struct Type myType or Tag myTagType are illegal. In addition, in a declaration like this:
typedef Type *Type_ptr;
we define a pointer to our Type. So if we declare:
Type_ptr var1, var2;
struct Tag *myTagType1, myTagType2;
then var1,var2 and myTagType1 are pointers to Type but myTagType2 not.
In the above-mentioned book, it mentions that typedefing structs are not very useful as it only saves the programmer from writing the word struct. However, I have an objection, like many other C programmers. Although it sometimes turns to obfuscate some names (that's why it is not advisable in large code bases like the kernel) when you want to implement polymorphism in C it helps a lot look here for details. Example:
typedef struct MyWriter_t{
MyPipe super;
MyQueue relative;
uint32_t flags;
...
}MyWriter;
you can do:
void my_writer_func(MyPipe *s)
{
MyWriter *self = (MyWriter *) s;
uint32_t myFlags = self->flags;
...
}
So you can access an outer member (flags) by the inner struct (MyPipe) through casting. For me it is less confusing to cast the whole type than doing (struct MyWriter_ *) s; every time you want to perform such functionality. In these cases brief referencing is a big deal especially if you heavily employ the technique in your code.
Finally, the last aspect with typedefed types is the inability to extend them, in contrast to macros. If for example, you have:
#define X char[10] or
typedef char Y[10]
you can then declare
unsigned X x; but not
unsigned Y y;
We do not really care for this for structs because it does not apply to storage specifiers (volatile and const).
I don't think forward declarations are even possible with typedef. Use of struct, enum, and union allow for forwarding declarations when dependencies (knows about) is bidirectional.
Style:
Use of typedef in C++ makes quite a bit of sense. It can almost be necessary when dealing with templates that require multiple and/or variable parameters. The typedef helps keep the naming straight.
Not so in the C programming language. The use of typedef most often serves no purpose but to obfuscate the data structure usage. Since only { struct (6), enum (4), union (5) } number of keystrokes are used to declare a data type there is almost no use for the aliasing of the struct. Is that data type a union or a struct? Using the straightforward non-typdefed declaration lets you know right away what type it is.
Notice how Linux is written with strict avoidance of this aliasing nonsense typedef brings. The result is a minimalist and clean style.
Let's start with the basics and work our way up.
Here is an example of Structure definition:
struct point
{
int x, y;
};
Here the name point is optional.
A Structure can be declared during its definition or after.
Declaring during definition
struct point
{
int x, y;
} first_point, second_point;
Declaring after definition
struct point
{
int x, y;
};
struct point first_point, second_point;
Now, carefully note the last case above; you need to write struct point to declare Structures of that type if you decide to create that type at a later point in your code.
Enter typedef. If you intend to create new Structure ( Structure is a custom data-type) at a later time in your program using the same blueprint, using typedef during its definition might be a good idea since you can save some typing moving forward.
typedef struct point
{
int x, y;
} Points;
Points first_point, second_point;
A word of caution while naming your custom type
Nothing prevents you from using _t suffix at the end of your custom type name but POSIX standard reserves the use of suffix _t to denote standard library type names.
The name you (optionally) give the struct is called the tag name and, as has been noted, is not a type in itself. To get to the type requires the struct prefix.
GTK+ aside, I'm not sure the tagname is used anything like as commonly as a typedef to the struct type, so in C++ that is recognised and you can omit the struct keyword and use the tagname as the type name too:
struct MyStruct
{
int i;
};
// The following is legal in C++:
MyStruct obj;
obj.i = 7;
typedef will not provide a co-dependent set of data structures. This you cannot do with typdef:
struct bar;
struct foo;
struct foo {
struct bar *b;
};
struct bar {
struct foo *f;
};
Of course you can always add:
typedef struct foo foo_t;
typedef struct bar bar_t;
What exactly is the point of that?
A>
a typdef aids in the meaning and documentation of a program by allowing creation of more meaningful synonyms for data types. In addition, they help parameterize a program against portability problems (K&R, pg147, C prog lang).
B>
a structure defines a type. Structs allows convenient grouping of a collection of vars for convenience of handling (K&R, pg127, C prog lang.) as a single unit
C>
typedef'ing a struct is explained in A above.
D> To me, structs are custom types or containers or collections or namespaces or complex types, whereas a typdef is just a means to create more nicknames.
In 'C' programming language the keyword 'typedef' is used to declare a new name for some object(struct, array, function..enum type). For example, I will use a 'struct-s'.
In 'C' we often declare a 'struct' outside of the 'main' function. For example:
struct complex{ int real_part, img_part }COMPLEX;
main(){
struct KOMPLEKS number; // number type is now a struct type
number.real_part = 3;
number.img_part = -1;
printf("Number: %d.%d i \n",number.real_part, number.img_part);
}
Each time I decide to use a struct type I will need this keyword 'struct 'something' 'name'.'typedef' will simply rename that type and I can use that new name in my program every time I want. So our code will be:
typedef struct complex{int real_part, img_part; }COMPLEX;
//now COMPLEX is the new name for this structure and if I want to use it without
// a keyword like in the first example 'struct complex number'.
main(){
COMPLEX number; // number is now the same type as in the first example
number.real_part = 1;
number.img)part = 5;
printf("%d %d \n", number.real_part, number.img_part);
}
If you have some local object(struct, array, valuable) that will be used in your entire program you can simply give it a name using a 'typedef'.
Turns out in C99 typedef is required. It is outdated, but a lot of tools (ala HackRank) use c99 as its pure C implementation. And typedef is required there.
I'm not saying they should change (maybe have two C options) if the requirement changed, those of us studing for interviews on the site would be SOL.
At all, in C language, struct/union/enum are macro instruction processed by the C language preprocessor (do not mistake with the preprocessor that treat "#include" and other)
so :
struct a
{
int i;
};
struct b
{
struct a;
int i;
int j;
};
struct b is expended as something like this :
struct b
{
struct a
{
int i;
};
int i;
int j;
}
and so, at compile time it evolve on stack as something like:
b:
int ai
int i
int j
that also why it's dificult to have selfreferent structs, C preprocessor round in a déclaration loop that can't terminate.
typedef are type specifier, that means only C compiler process it and it can do like he want for optimise assembler code implementation. It also dont expend member of type par stupidly like préprocessor do with structs but use more complex reference construction algorithm, so construction like :
typedef struct a A; //anticipated declaration for member declaration
typedef struct a //Implemented declaration
{
A* b; // member declaration
}A;
is permited and fully functional. This implementation give also access to compilator type conversion and remove some bugging effects when execution thread leave the application field of initialisation functions.
This mean that in C typedefs are more near as C++ class than lonely structs.