Could you explain this typedef to me?

F

fl

Hi,
I am puzzled by the following typedef under the dot line. It has two MsgObj. Then it also has a pointer definition. I think that the pointer can be defined as:

MsgObj *Msg;

Could you explain the part on MsgObj to me?


Thanks,





.................
typedef struct MsgObj {
QUE_Elem elem; /* first field for QUE */
Int id; /* writer task id */
Char val; /* message value */
} MsgObj, *Msg;
 
R

Robbie Brown

Hi,
I am puzzled by the following typedef under the dot line. It has two MsgObj. Then it also has a pointer definition. I think that the pointer can be defined as:

MsgObj *Msg;

Could you explain the part on MsgObj to me?


Thanks,

................
typedef struct MsgObj {
QUE_Elem elem; /* first field for QUE */
Int id; /* writer task id */
Char val; /* message value */
} MsgObj, *Msg;


Well I'm taking my life in my hands here as I'm a beginner myself.
This provides two 'types' allowing you to do the following

MsgObj mo; //allocate an instance of MsgObj on the stack

you can now do

mo.id = 99;

or

Msg m = malloc(sizeof(m)) //allocate an instance of MsgObj on the heap
and assign the pointer to m

now you can do

m -> id = 89;

Haven't quite figured out *why* you might want to do this yet but I
tested it and it seems to work (notice I don't add 'as expected' :)
 
R

Robbie Brown

Well I'm taking my life in my hands here as I'm a beginner myself.
This provides two 'types' allowing you to do the following

MsgObj mo; //allocate an instance of MsgObj on the stack

you can now do

mo.id = 99;

or

Msg m = malloc(sizeof(m)) //allocate an instance of MsgObj on the heap
and assign the pointer to m

now you can do

m -> id = 89;

Haven't quite figured out *why* you might want to do this yet but I
tested it and it seems to work (notice I don't add 'as expected' :)
Actually I think that should be Msg m = malloc(sizeof(*m))
 
E

Eric Sosman

Hi,
I am puzzled by the following typedef under the dot line. It has two MsgObj. Then it also has a pointer definition. I think that the pointer can be defined as:

MsgObj *Msg;

Could you explain the part on MsgObj to me?


Thanks,





................
typedef struct MsgObj {
QUE_Elem elem; /* first field for QUE */
Int id; /* writer task id */
Char val; /* message value */
} MsgObj, *Msg;

This declares a `struct MsgObj' type, and the elements that
make it up. It also declares `MsgObj' as an alias for that type;
hereafter, `MsgObj' and `struct MsgObj' mean exactly the same
thing, and can be used interchangeably. Finally, it declares
`Msg' as an alias for a pointer type that can also be written
as `MsgObj*' or `struct MsgObj*'.

The reason that `MsgObj' can be an alias for `struct MsgObj'
(and not be some kind of infinitely recursive nonsense) is that
struct tags are in a different "name space" than other identifiers.
In `struct MsgObj' the compiler knows that the thing after `struct'
has to be a struct tag, so it only looks for those. But when the
compiler sees `MsgObj' all by itself it looks among the ordinary
identifiers and not among the tags. So the two `MsgObj' uses are
distinct, just as `John Smith' and `John Jones' are distinct even
though both are `John'.

The C language actually has four kinds of name spaces:

- statement labels,

- the tags of struct, union, and enum types,

- the members of a struct or union (each struct or union
type has its own name space for its members),

- everything else: variable names, function names, etc.

The context indicates which name space a particular identifier
belongs to: for example, in `goto StIves' the identifier `StIves'
must belong to the name space of labels. Each identifier is
unique *within its name space*, but may be spelled the same as
an identifier in a different name space -- that's why `MsgObj'
(in the "everything else" space) is distinct from `struct MsgObj'
(in the tag space). Identical spellings don't confuse the
compiler, however much they may confuse a human reader.
 
K

Keith Thompson

fl said:
I am puzzled by the following typedef under the dot line. It has two
MsgObj. Then it also has a pointer definition. I think that the
pointer can be defined as:

MsgObj *Msg;

Could you explain the part on MsgObj to me?

................
typedef struct MsgObj {
QUE_Elem elem; /* first field for QUE */
Int id; /* writer task id */
Char val; /* message value */
} MsgObj, *Msg;

Keep in mind that a typedef does not create a new type; it merely
creates a new name for an existing type.

The above declaration defines three things:

1. A structure type named "struct MsgObj";

2. An alias for that structure type, named "MsgObj"; and

3. An alias for the type "struct MsgObj*" (pointer to struct MesObj)
named "Msg".

Defining typedefs for structures is a common practice, but it's not
actually necessary. My own personal preference, unless the type is
meant to be opaque (i.e., code that uses it shouldn't rely on names of
the members) is just to define the type as "struct MsgObj" and refer to
it by that name. But a lot of programmers feel that it's worthwhile to
add a typedef so that the type has a one-word name. Whatever your own
preferences, you'll need to deal with both styles in code written by
others.

Defining a typedef for a pointer type is widely considered to be a bad
idea. It's often better to keep the pointerness of the type explicit.
So even if you have a typedef for the structure, if you want to define a
pointer object you'd still write:

MsgObj *foo;

which means you can tell at a glance that foo is a pointer. But again,
you'll likely have to deal with code that uses typedefs for pointers.

A typedef declaration's syntax is very similar to the syntax of an
object declaration. Adding the "typedef" keyword means you're defining
a typedef name rather than an object name. So this:

struct MsgObj {
/* ... */
} foo, *bar;

defines foo as an object of type struct Msgobj and bar as an object of
type struct MsgObj*. Add the typedef keyword:

typedef struct MsgObj {
/* ... */
} foo, *bar;

and foo and bar are defined as aliases for those same types rather than
as objects of those types. Syntactically, "typedef" is treated as if it
were a storage class specifier like "static" or "extern". It was
defined this way for the sake of convenience ("typedef" was a relatively
late addition to the language).
 
R

Robbie Brown

Hi,
I am puzzled by the following typedef under the dot line.

snip

Loads of excellent advice here.
For some reason however I'm less than confident I fully understand. This
is because I have now suspended all expectation.

I'm going to check my understanding, hopefully someone will put me
straight if I'm wrong. (I have a thick skin).

Given the following code

typedef struct Foobar{
int a;
int b;
}Foobar, *fbar;

struct Barbaz{
int a;
int b;
}Barbaz, *bbaz;

//I can do

Foobar fb;
fb.a = 1;

//but I can't do

Foobar.a = 1;

//I can do

fbar fbp = malloc(sizeof *fbp);

//but I can't do

fbar = malloc(sizeof *fbar);

//I can do

Barbaz.a = 2;

//but I can't do

Barbaz bb;

//I can do

bbaz = malloc(sizeof *bbaz);

//but I can't do

bbaz bbp = malloc(sizeof *bbp)

My compiler (gcc version 4.6.3 64 bit Linux) seems to agree with me but
it's agreed with me in the (recent)past and I've still been wrong which
I have to say is a new experience.

Thank you
 
B

BartC

I've been using C for a while but I've been puzzled by these. I didn't even
know you could have a list of things after a typedef.
typedef struct Foobar{
int a;
int b;
}Foobar, *fbar;

Here you're defining (if my understanding is correct):

- Foobar as an alias for the type 'struct Foobar'
- fbar as an alias for the type 'pointer to struct Foobar'

(The latter I understand isn't considered good practice. Just use Foobar*
when you want to express a pointer to the type.)
struct Barbaz{
int a;
int b;
}Barbaz, *bbaz;

Here you're defining a struct Barbaz (which happens to be compatible with
struct Foobar above, however C will see it as different), and variable
Barbaz of type 'struct Barbaz', and a variable bbaz of type 'pointer to
struct Barbaz'.

That's fine. But you're using Foobar as both a struct name, and typedef
name, and Barbaz as both a struct name, and variable. C allows you to do
this, but that this mean that people will find it easy to read!

This is just my personal preference, but I would write these as:

typedef struct {
int a,b;
} Foobar;

typedef struct {
int a,b;
} Barbaz;

Then I can just write:

Foobar fp;
Foobar *fbp;

Barbaz ..... (here I'd use any variable name that isn't 'Barbaz'!)
Barbaz *bbaz;

(Or you can drop the typedef but then you'd have to write struct Foobar and
struct Barbaz everywhere.)
 
J

James Kuyper

snip

Loads of excellent advice here.
For some reason however I'm less than confident I fully understand. This
is because I have now suspended all expectation.

I'm going to check my understanding, hopefully someone will put me
straight if I'm wrong. (I have a thick skin).

Given the following code

typedef struct Foobar{
int a;
int b;
}Foobar, *fbar;

struct Barbaz{
int a;
int b;
}Barbaz, *bbaz;

//I can do

Foobar fb;
fb.a = 1;

//but I can't do

Foobar.a = 1;

Actually, you can do that - the C standard never prohibits you from
writing any code - all it does is tell you what a conforming
implementation of C is, and is not, required to do when processing such
a program.
That code does violate a constraint. That means that there is only one
requirement: a diagnostic message must be issued. The program need not
be accepted, but it also need not be rejected. If it is accepted, and
the program is executed, the behavior of that entire program is
undefined, which means that the standard does not impose any
requirements on that behavior.

The constraint that has been violated requires that the left operand of
a member-selection operator '.' be an lvalue referring to an object of
struct or union type. Foobar is an alias for a struct type, it is not
the name of a particular object of that type, so it does not qualify as
an lvalue.
 
J

James Kuyper

I've been using C for a while but I've been puzzled by these. I didn't even
know you could have a list of things after a typedef.


Here you're defining (if my understanding is correct):

- Foobar as an alias for the type 'struct Foobar'
- fbar as an alias for the type 'pointer to struct Foobar'

(The latter I understand isn't considered good practice. Just use Foobar*
when you want to express a pointer to the type.)


Here you're defining a struct Barbaz (which happens to be compatible with
struct Foobar above, however C will see it as different),

Yes, C will see them as two different types. More bizarrely, unless they
are defined in different translation units, C will see them as
incompatible types, which means that struct Barbaz cannot be used in any
context where a type compatible with struct Foobar is required.

I think the main purpose of this rule is to discourage duplicate
definitions like these. If you want two different type names to identify
compatible types, make one of them a typedef for the other, which makes
the connection between them explicit.

The exception for definitions in different translation units is needed,
because "All declarations of structure, union, or enumerated types that
have the same scope and use the same tag declare the same type."
Definitions in different translation units are not in the same scope,
and therefore cannot have the same type, even if they are identical.
Allowing such types to be compatible, even though they are not the same
type, and allowing compatible types to be used interchangeably, is the C
standard's solution to this dilemma. Other solutions are possible, such
as modifying the definition of "same type".
 
R

Robbie Brown

Actually, you can do that - the C standard never prohibits you from
writing any code - all it does is tell you what a conforming
implementation of C is, and is not, required to do when processing such
a program.
That code does violate a constraint. That means that there is only one
requirement: a diagnostic message must be issued. The program need not
be accepted, but it also need not be rejected. If it is accepted, and
the program is executed, the behavior of that entire program is
undefined, which means that the standard does not impose any
requirements on that behavior.

Well I don't want to labor the point but my compiler won't produce an
executable if I write Foobar.a = 1. I suppose that means that this
particular version of this particular compiler doesn't accept this
particular code.

It seems bizarre to me that there is a situation where this code might
be 'accepted' and even more bizarre that an executable might be
produced, diagnostic message or not. It's almost as if this language has
been designed to be as opaque as possible. What possible reason can
there be to produce an executable that contains code that is quite
obviously wrong. Very strange.
 
J

James Kuyper

On 03/02/14 12:17, James Kuyper wrote: ....

Well I don't want to labor the point but my compiler won't produce an
executable if I write Foobar.a = 1. I suppose that means that this
particular version of this particular compiler doesn't accept this
particular code.

Correct. There's only one construct a program can contain which requires
a conforming implementation of C to reject it: a #error directive that
survives conditional compilation. Note that, ironically, such a program
MUST be correct written to ensure rejection. Any error in the
preprocessor directives that determine whether the code is conditionally
compiled would give the implementation the freedom to accept the code.
The same is true of any syntax errors in the #error directive itself.
It seems bizarre to me that there is a situation where this code might
be 'accepted' and even more bizarre that an executable might be
produced, diagnostic message or not. It's almost as if this language has
been designed to be as opaque as possible. ...

No, that's what the diagnostic message is for. If you don't want to
wander off the charted path, beware the warning signs that indicate that
you have done so.
... What possible reason can
there be to produce an executable that contains code that is quite
obviously wrong. Very strange.

The key point is that the code is not "obviously wrong" - it might be
perfectly correct code for an extended version of C. The fact that the
standard leaves the behavior undefined gives fully conforming
implementations the freedom to provide their own definition of the
behavior, as an extension. There are other ways to implement extensions:
an option that renders the implementation non-conforming, or a #pragma
that allows for arbitrary implementation-defined behavior. However,
providing defined behavior for constructs that are syntax errors or
constraint violations is one popular ways of implementing extensions.
 
R

Robbie Brown

I've been using C for a while but I've been puzzled by these. I didn't even
know you could have a list of things after a typedef.

OK, well, you learn something new etc etc

snip

This is just my personal preference, but I would write these as:

typedef struct {
int a,b;
} Foobar;

typedef struct {
int a,b;
} Barbaz;

Then I can just write:

Foobar fp;
Foobar *fbp;

Barbaz ..... (here I'd use any variable name that isn't 'Barbaz'!)
Barbaz *bbaz;

(Or you can drop the typedef but then you'd have to write struct Foobar and
struct Barbaz everywhere.)

Hmm, I don't understand this.

If I have the following

typedef struct{
long x;
long y;
}AArdvark;

struct{
char *cp1;
char *cp2;
}Whoami;

then I can do

AArdvark a;
a.y = 8;

AArdvark *ap = malloc(sizeof *ap);
ap -> y = 9;

but I can't do

struct Whoami wai;
struct Whoami *pwai = malloc(sizeof *pwai);

I get

error: storage size of ‘wai’ isn’t known
error: dereferencing pointer to incomplete type

Nor can I do

struct Whoami.cp1 = "foo";

as I get

error: expected identifier or ‘(’ before ‘.’ token

Am I missing something ?

[You said "(Or you can drop the typedef but then you'd have to write
struct Foobar and struct Barbaz everywhere.)"]

Thanks
 
B

BartC

Robbie Brown said:
On 03/02/14 11:08, BartC wrote:

Hmm, I don't understand this.
struct{
char *cp1;
char *cp2;
}Whoami;
but I can't do

struct Whoami wai;
struct Whoami *pwai = malloc(sizeof *pwai);

I get

error: storage size of ‘wai’ isn’t known
error: dereferencing pointer to incomplete type

Sorry, I overlooked the fact that if you don't typedef your struct
definitions, then you have to write them like this (if you want to refer to
the type in another place):

struct Whoami{
char *cp1;
char *cp2;
};

This defines a struct with the tagname 'Whoami', which you can then use as a
type using 'struct Whoami'. With the syntax you used, you create an
anonymous struct, used to declare a variable 'Whoami'.

(There were good reasons why I tend to stick to certain patterns. C structs,
typedefs, tagnames, and variable names, which sometimes have the same names,
do get very confusing!)
 
B

Ben Bacarisse

Robbie Brown said:
Hmm, I don't understand this.

If I have the following
struct{
char *cp1;
char *cp2;
}Whoami;

Can you describe what this does? You telling me what you think this
does will help me a lot.

but I can't do

struct Whoami wai;
struct Whoami *pwai = malloc(sizeof *pwai);

I get

error: storage size of ‘wai’ isn’t known
error: dereferencing pointer to incomplete type

Do you know what a struct tag is?
Nor can I do

struct Whoami.cp1 = "foo";

as I get

error: expected identifier or ‘(’ before ‘.’ token

How did you try to find out for yourself? Are you just typing random
things to see what happens of do you have a book or C reference to hand
that you are learning from? You can find the syntax of C in lots of
places on the internet, and this would have shown you that the above is
not a syntactically valid sequence of tokens.
Am I missing something ?

A book on C would be my guess.
 
R

Robbie Brown

Can you describe what this does? You telling me what you think this
does will help me a lot.

Well it doesn't work and I was responding to another respondent who
suggested it might and yes, I'm fully aware of what a struct tag is
thank you.
How did you try to find out for yourself?

I tried to compile it
Are you just typing random
things to see what happens

I was responding to another respondent who suggested it might work
of do you have a book or C reference to hand
that you are learning from? You can find the syntax of C in lots of
places on the internet, and this would have shown you that the above is
not a syntactically valid sequence of tokens.

Again, I was responding to another respondent who suggested it might work.
A book on C would be my guess.

Then I suggest you don't take up gambling for a living
 
E

Eric Sosman

[...]
Hmm, I don't understand this.

If I have the following

typedef struct{
long x;
long y;
}AArdvark;

This says "There is a tagless (anonymous) struct type with
two elements, and `AArdvark' is an alias for that type." You
can now declare variables and pointers and such by using the
name `AArdvark' -- in fact, that's the only way you can declare
them, because there's no struct tag you could use.
struct{
char *cp1;
char *cp2;
}Whoami;

This says "There is a tagless struct type with two elements,
and `Whoami' is a variable of that type." Since the struct type
has no tag and there is no alias for it, there is no way you can
declare any more instances of it; `Whoami' is the one and only
instance of this type.

(Well, I suppose you could use malloc() to get a similarly-
sized piece of storage and then memcpy() to copy the content of
`Whoami' into it, but you couldn't actually do much with that
allocated storage until you copied it back into `Whoami' again.)
then I can do

AArdvark a;
a.y = 8;

AArdvark *ap = malloc(sizeof *ap);
ap -> y = 9;

but I can't do

struct Whoami wai;
struct Whoami *pwai = malloc(sizeof *pwai);

I get

error: storage size of ‘wai’ isn’t known
error: dereferencing pointer to incomplete type

Right. No `struct Whoami' has been declared. There's a
variable named `Whoami', and that variable is an instance of a
struct type, but there's no `struct Whoami'.

It is legal in C to mention a struct (or union) type without
declaring it; such a type is called "incomplete" until and unless
the details are filled in later. But until the details become
available, there are limitations on what you can do with such a
type: You can't make a variable of that type (because the compiler
doesn't know howbig it is), you can't apply `sizeof' to it (ditto)
you can't copy one instance to another by assignment (ditto), and
although you can form pointers to the type, you can't use them to
get at the unknown insides. This strange state of affairs actually
turns out to be useful when a library wants to use a type that is
"opaque" to the calling code. Much of <stdio.h> traffics in `FILE*'
pointers, but when you call fprintf() you neither know nor care
what's inside a `FILE'. (The example isn't perfect because there's
a strange technicality -- possibly a mistake -- in the C Standard
that forbids an incomplete `FILE', but the intent is the same.)
Nor can I do

struct Whoami.cp1 = "foo";

as I get

error: expected identifier or ‘(’ before ‘.’ token

There are two things wrong here. First, `struct Whoami' is
a type name, not a variable of that type: You can't assign a
value to a type, but only to an instance. Second, `struct Whoami'
is "incomplete" as described above, so the compiler has no idea
of what the type of it's `cp1' field might be, where it's positioned
inside the struct, nor even whether a `cp1' field exists!
 
R

Robbie Brown

[...]
Hmm, I don't understand this.


error: expected identifier or ‘(’ before ‘.’ token

There are two things wrong here. First, `struct Whoami' is
a type name, not a variable of that type: You can't assign a
value to a type, but only to an instance. Second, `struct Whoami'
is "incomplete" as described above, so the compiler has no idea
of what the type of it's `cp1' field might be, where it's positioned
inside the struct, nor even whether a `cp1' field exists!

Actually, I think I just got it wrong, I tried various things but
obviously not the one that mattered ... sigh

struct{
char *cp1;
char *cp2;
}Whoami;

then I *can* do

Whoami.cp1 = "foobarbaz";

can't think why I didn't try that.

So now I appear to have 4 different ways to declare/define a struct.
I wonder how many more there.

Variety is the spice of life etc.
 
B

Ben Bacarisse

Robbie Brown said:
Well it doesn't work and I was responding to another respondent who
suggested it might and yes, I'm fully aware of what a struct tag is
thank you.

But you have no idea what it does, or you do have an idea but don't want
to answer questions, or what? You will get better explanation of you
choose to reveal just a hint or two about your confusion.

I don't think you are a *fully* aware what a struct tag is or you would
not have written the object definition that you wrote (and snipped).
I tried to compile it


I was responding to another respondent who suggested it might work


Again, I was responding to another respondent who suggested it might
work.

Of course I saw that but the BartC didn't suggest you write what you
wrote. If you choose not to explain anything about how you think about
this stuff, it's hard to offer a helpful explanation.
Then I suggest you don't take up gambling for a living

Well that's a start. What C book is it? What is it about its
explanation of struct types that is not clear?
 
J

James Kuyper

On 03/02/14 11:08, BartC wrote: ....

Hmm, I don't understand this.

If I have the following

typedef struct{
long x;
long y;
}AArdvark;

struct{
char *cp1;
char *cp2;
}Whoami;

then I can do

AArdvark a;
a.y = 8;

AArdvark *ap = malloc(sizeof *ap);
ap -> y = 9;

but I can't do

struct Whoami wai;

That's because you have not defined any type named "struct Whoami".
You've defined an object of anonymous struct type named Whoami.
struct Whoami *pwai = malloc(sizeof *pwai);

I get

error: storage size of ‘wai’ isn’t known
error: dereferencing pointer to incomplete type

Nor can I do

struct Whoami.cp1 = "foo";

The keyword struct is not allowed in that context; I'm not sure why you
would expect it to be. Remove that keyword and the code should work.
as I get

error: expected identifier or ‘(’ before ‘.’ token

Am I missing something ?

[You said "(Or you can drop the typedef but then you'd have to write
struct Foobar and struct Barbaz everywhere.)"]

He meant that you could write

struct Foobar { ... };

rather than

typedef struct {... } Foobar;

but that if you did such a rewrite, then in every place where his code
had "Foobar" other than the struct definition, you'd have to replace it
with "struct Foobar".
 
E

Eric Sosman

[...]
So now I appear to have 4 different ways to declare/define a struct.
I wonder how many more there.

I'm not sure what your "4 different ways" are. You can
declare a struct type with or without a tag, you can declare
it with or without its innards ("complete" and "incomplete"
types), but that doesn't amount to four ways because one of
the combinations (tagless incomplete struct) is invalid. Also,
you can use typedef to create aliases for the struct type and
for types (like pointers) derived from it; you can do that in
the same declaration as the struct itself or (if there's a tag)
in a separate declaration.
Variety is the spice of life etc.

I get the impression that you're floundering, which suggests
to me that you need to go back and review the whole notion of
"type" in C. Perhaps it would do you good to stay away from
typedef altogether for a while, as it seems to be confusing you
at this point.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top