This question already has answers here:
Is it a good idea to typedef pointers?
(15 answers)
Closed 4 years ago.
typedef struct llist {
int valor;
struct lligada *prox;
} *LInt;
So this is how linked lists are implemented in C at my university and I have been wondering why in the last line they put a pointer to LInt instead of just LInt.
typedef struct lligada {
int valor;
struct lligada *prox;
} LInt;
Wouldn't this be simpler? I mean it's this last example that I see in tutorials around the web and if we want a pointer to the struct we would just write something like
LInt *foo = ...;
What confuses me is that they declare the pointer in the struct and in the exercises they still do the declaration above. Is there any special reason for this? Is this normal? They also do this for binary trees.
typedef struct llist {
int valor;
struct lligada *prox;
} *LInt;
makes LInt equivalent to struct llist* (with the star included).
This practice of typedefing pointers is pretty much discouraged in all modern resources
on C I've come across but it has been used historically, notably the lcc compiler
uses this practice a lot (their convention capitalizes the pointer typedefed name as well).
The problem with typedefing pointers is that it's potentially confusing and
you can suddenly pass 0 (as NULL) with a special value through them, however if you
have a naming convention (such as capitalizing each pointer typedef) then
the star is effectively not hidden but just expressed as an upper case letter,
although it might still be confusing to someone foreign to your codebase.
So to summarize, with
typedef struct llist {
int valor;
struct lligada *prox;
} *LInt;
you'd then use it like so:
LInt foo = NULL;
whereas without the star in the typedef, the above would be:
LInt *foo = NULL;
Related
This question already has answers here:
Is it optional to use struct keyword before declaring a structure object?
(3 answers)
Closed 2 years ago.
I tried typing the following code in a simple C project, but it keeps saying that MyStruct is undefined – unless I add struct before every MyStruct (i.e. struct MyStruct my_struct; which just feels wrong?).
struct MyStruct {
int my_int;
}
int main() {
MyStruct my_struct;
my_struct->my_int = 1;
return 0;
}
It’s not wrong, it’s the way C works. Type name is struct MyStruct (it would be simply MyStruct in C++). If you feel that inconvenient, make a typedef, like:
typedef struct MyStruct { ... } MyStruct;
That may or may not be considered a good practice, though.
Also note that a struct (but not a typedef) and a function can have the same name (without the struct prefix). sigaction is a real-word example of that.
I have a C template which is given me as homework. But before doing homework, I need to understand the usage of "typedef" and "struct" clearly to move on coding. Here is the code;
typedef struct NODE_s *NODE;
typedef struct NODE_s
{
NODE right;
NODE left;
unsigned long data;
int height;
} NODE_t[1];
typedef struct TREE_s *TREE;
typedef struct TREE_s
{
NODE root;
} TREE_t[1];
TREE tree_init();
NODE node_init(unsigned long data);
First of all, what is the line typedef struct NODE_s *NODE; is doing here? Why it is named like a pointer with a *?
Then, after the struct definition, what is the purpose of creating a variable named NODE_t[1], is the square brackets with the number "1" something connected with an array, or it is just something else?
Lastly, when the tree_init(); and node_init(unsigned long data); functions are declared, why the TREE and NODE datatype names are used to the contrary they were declared as *TREE and *NODE before the struct definitions? Thank you for the answers.
The template you were given is this, where I've added numbers to some of the lines for ease of reference:
typedef struct NODE_s *NODE; // 1
typedef struct NODE_s // 2
{
NODE right; // 3
NODE left;
unsigned long data;
int height;
} NODE_t[1]; // 4
typedef struct TREE_s *TREE;
typedef struct TREE_s
{
NODE root;
} TREE_t[1];
TREE tree_init(); // 5
NODE node_init(unsigned long data);
What are the problems here?
As noted in comments, the SO Q&A Is it a good idea to typedef pointers suggests that it is not a good idea to typedef pointers, with limited exceptions for 'pointers to functions' (not relevant here) and perhaps (but probably not) for opaque types. This line does two things: (1) it says "there is a structure type with the tag NODE_s; (2) the name NODE is a synonym for struct NODE_s *. The structure type is incomplete at the moment; no details are known about its members.
This line starts a new typedef, but also starts the definition of the type struct NODE_s (because of the { that follows on the next line).
The type NODE is already known; it can be used here. It means the same as if you wrote struct NODE_s *right;.
The name NODE_t is an alias for the type struct NODE_s[1], an array of 1 struct NODE_s. It isn't clear what this is going to be used for. I have reservations (at best) about its existence. (You can also apply the discussion in points 1, 2, 4 to the struct TREE_s type, mutatis mutandis.)
This is a function declaration, but it is not a prototype declaration. It says that the tree_init() function can be called with any number of arguments of any type because no information is specified about the number or type of those arguments. We do know it is not a variadic function (variable argument list, like printf()) because those must have a full prototype declaration ending with , ...) in scope before they're used. If you want to specify that the function takes no arguments, say so: TREE tree_init(void);.
I think the intent behind the NODE_t and TREE_t types is to allow you to write, for example:
int main(void)
{
TREE_t x = { 0 };
if (x->root != 0)
return 1;
return 0;
}
I'm not convinced whether that's sufficiently helpful to warrant the type compared with using struct NODE_s x and using x.root in the test. It does save you from having to add an & when passing a pointer to a function; again, I'm not sure it is really sufficiently helpful to warrant its existence.
What I would prefer to see as the template is:
typedef struct NODE_s NODE;
struct NODE_s
{
NODE *right;
NODE *left;
unsigned long data;
int height;
};
typedef struct TREE_s TREE;
struct TREE_s
{
NODE *root;
};
extern TREE *tree_init(void);
extern NODE *node_init(unsigned long data);
This removes the pointers from the typedef statements, avoids the somewhat peculiar array types, and uses an explicit prototype for tree_init(). I personally prefer to have function declarations marked with extern; in a header, they'll match the extern on those rare global variables that are declared in the header. Many people prefer not to use extern because the compiler assumes that anyway — so be it; the most important thing is consistency.
The code in main() would now be written:
int main(void)
{
TREE x = { 0 };
if (x.root != 0)
return 1;
return 0;
}
The difference? An arrow -> changed to a dot .. Not a lot of problem there. However, when calling functions, you'd probably use &x whereas with the TREE_t type, you would just write x (because it's an array).
In C, is there any effective difference between declaring a struct as
typedef struct {...} Foo;
and
struct Foo {...};
I know the second requires you to prefix uses with struct, but what are the differences between these two definitions that I'll notice when writing or executing the program? What about with enums?
Update: please see comments attached to answer for clarification.
Original post.
Besides having to write "struct" everywhere, something else of note is that using a typedef will allow you to avoid subtle syntax errors when working with pointers:
Quote:
Typedefs can also simplify declarations for pointer types. Consider
this:
struct Node {
int data;
struct Node *nextptr;
};
Using typedef, the above code can be rewritten like this:
typedef struct Node Node;
struct Node {
int data;
Node *nextptr;
};
In C, one can declare multiple variables of the same type in a single
statement, even mixing pointer and non-pointers. However, one would
need to prefix an asterisk to each variable to designate it as a
pointer. In the following, a programmer might assume that errptr was
indeed a Node *, but a typographical error means that errptr is a
Node. This can lead to subtle syntax errors.
struct Node *startptr, *endptr, *curptr, *prevptr, errptr, *refptr;
By defining a Node * typedef, it is assured that all the variables
will be pointer types.
typedef struct Node *NodePtr;
...
NodePtr startptr, endptr, curptr, prevptr, errptr, refptr;
If you write
typedef struct {...} foo;
It saves you from having to write struct foo everywhere: you can just write foo.
(You get this notational convenience for free in C++ by the way).
I would look at this SO question and then summarize that there is no appreciable functional difference between struct { ... } and typedef struct { ... } although the latter may make your code less cumbersome and easier to understand if used correctly.
typedef struct node{
int term;
struct node *next;
}node;
typedef void(*PTR )(void *);
typedef void(*PTR1)(void *,int,int);
typedef int(*PTR2)(void *,int);
typedef void(*PTR3)(void *,int);
typedef void(*PTR4)(void *,void *,void *);
typedef struct list{
node *front,*rear;
PTR3 INSERT;
PTR *MANY;
PTR DISPLAY,SORT,READ;
PTR4 MERGE;
}list;
void constructor(list **S)
{
(*S)=calloc(1,sizeof(list));
(*S)->front=(*S)->rear=NULL;
(*S)->INSERT=push_with_value;
(*S)->READ=read;
(*S)->SORT=sort;
(*S)->DISPLAY=display;
(*S)->MERGE=merger;
(*S)->MANY=calloc(2,sizeof(PTR));
(*S)->MANY[1]=read;
}
int main()
{
list *S1,*S2,*S3;
constructor(&S1);
constructor(&S2);
constructor(&S3);
S1->MANY[1](S1);
S1->SORT(S1);
S1->DISPLAY(S1);
return 0;
}
The void * parameter in all such functions gets typecast to list * inside the function.
Is there any way through which I can call S1->READIT; by changing the MANY[1] to another name like READ_IT;?
I intend to create a common header file, so that I can use it for all my programs.
Since I don't know how many function pointers I will need I intend to create a dynamic array of each function pointer type.
typedef struct list{
node *front,*rear;
PTR3 INSERT;
PTR READIT;
PTR DISPLAY,SORT,READ;
PTR4 MERGE;
}list;
...
(*S)->READIT = read;
...
S1->READIT(S1);
Take a look at the Linux kernel implementation of (doubly linked) lists, as defined here (and following/referenced files). They are used all over the place. Most of the manipulation is done in macros to e.g. run an operation on all nodes of the list.
If what you are trying to define is getting too complicated, step back and look for simpler alternatives. Don't generalize beforehand; if the generalization isn't used it is a waste; if something (slightly) different is later needed, it is a poor match that requires workarounds or even reimplementation.
Take a look at the interfaces exposed by the C++ STL list, those folks have thought long and hard on the matter (in a different setting, though).
Or just bite the bullet and use C++ if you want full-fledged OOP.
I am working on an embedded system and I need to implement a linked list.
So I used a struct to construct a node
typedef struct A
{
... //some data
struct A *next;
struct A *prev;
} A;
I think on PC (gcc) this works fine. However, the embedded system compiler complains that "identifier A is not declared"...
What is the best solution for this?
You should add a separate forward declaration of the struct:
struct A;
typedef struct A
{
... //some data
struct A *next;
struct A *prev;
} A;
Some compilers do take your definition the way you posted it, but I've seen older compilers that require a separate forward declaration. This may be related to an older standard, or an incomplete standard implementation. In fact, on a project where we needed to write code that runs on five platforms with different compilers, we made it a companywide coding standard requirement to have the forward declaration separate from the struct's typedef.
You can split it out:
typedef struct A A;
struct A {
... //some data
struct A *next;
struct A *prev;
};
The original code should compile just fine. You are probably using a non-standard compiler. As an alternative to the other suggestions, you can try this code:
typedef struct a
{
... //some data
struct a *next;
struct a *prev;
} A;
This way, you shouldn't need a forward declaration.