More structs

M

mdh

Quick question.
In the code below, omitting the word "word", as in char *word,
produces an error of syntax.

In similar "non-struct" declarations, the expression "char *" should
suffice. ( I think). Is there a reason that one needs to add this? Is
this unique to structs.
Thanks as usual.






struct key {
char *word;
int count;
};

int main (int argc, const char * argv[]) {

struct key keytab[] = {
"auto", 0
};

}
 
J

Jens Thoms Toerring

mdh said:
Quick question.
In the code below, omitting the word "word", as in char *word,
produces an error of syntax.
In similar "non-struct" declarations, the expression "char *" should
suffice. ( I think).

What do you mean with '"non-struct" declarations'? A line with
just

char *;

is always a syntax error, also outside a structure declaration.
Is there a reason that one needs to add this? Is
this unique to structs.

How would you access the 'word' member of the structure if it
wouldn't have a name? Write-only (and that only during initia-
lization) members of a structure hardly make much sense...
struct key {
char *word;
int count;
};
int main (int argc, const char * argv[]) {
struct key keytab[] = {
"auto", 0
};
}
Regards, Jens
 
M

mdh

mdh said:
Quick question.

     If "word" were omitted, how would you make use of the
pointer that it names?  Let's omit a few more identifiers:

        struct {
            char*;
            int;
        };
        int (int, const char*[]) {
            struct [] = {
                "auto", 0
            };
        }

What sense can be made of this (invalid) source code?  It
declares (sort of) a type, a function, two parameters, and
an array variable, but all are unusable.

     Your phrase "similar ``non-struct'' declarations" I find
baffling.  What "similar" declarations do you refer to?



At the risk of further ridicule, I **thought** this a valid
comparison.



void foo ( int a, char c){

int b;
char c;

b = a;

etc

}


Now the declaration, if I am not mistaken, could be

void foo ( int, char);


Clearly, this is different, but now sure why.
 
M

mdh

What do you mean with '"non-struct"  declarations'? A line with
just

Well, as I tried to hopefully explain that in the answer to Eric.


I think what I might be missing is this issue of declaration/
definition, which rjh addressed in another thread...which I will go
back to and look at again.

So, this what I thought.

If I declare a struct thus.

struct key {
char * word;
int count;
};


Then omitting the word "word" could be added later in the
defintion...but clearly this is not the case.

char *;

is always a syntax error, also outside a structure declaration.

I **thought** that


void foo ( char *); as a declaration

is suitable for a definition later as


void foo ( char *c){};

Thanks for your input.
 
C

Chris Torek

[on omitting identifiers in some situations]

The thing being declared here is the function foo(),
and its identifier is present and accounted for. The function
parameters are not declared, and would not be declared even
if you gave names for them. The names, if present, are really
just documentation; all that matters is their number and types.

Right (of course :) ).

Moving the question back a bit, to "why do function prototypes
have optional identifiers in the prototype-scope portion of the
declaration between the parentheses", the answer is: "historical
reasons". (This phrase is sometimes modified into "hysterical
raisins", which might make some think of some classic Claymation:
<
>)

K&R-1 C did not have function prototypes. To declare function
foo, you wrote:

int foo(); /* K&R-1 C also lacked "void" */

which was your directive saying: "hey, Mr Compiler, the name foo
refers to a function with return-type int". You never told the
compiler how many arguments this function would take, or what their
types would be. You never even had the option. The compiler would
just assume that you got all the calls to foo() right, using casts
if needed to get argument types correct.

C++ came along, and changed all this. In every function declaration,
you *had* to tell the compiler the number of arguments and their
types. These were "function prototypes". It was a clear improvement,
since people did in fact get arguments wrong sometimes, sometimes
producing hard-to-debug runtime problems.

C++ was done by a guy with less good taste than Dennis :) and as
a result, the syntax invented for C++ tends to be klunkier than
that for C (not that C's is "non-klunky" in various cases in the
first place -- and to be fair to Bjarne, modifying C while staying
reasonably backward-compatible with it is difficult in the first
place). So he made the identifiers optional.

The C Standards group came along and stole prototypes wholesale
from C++, optional identifiers and all. They did make one more
change, to make the syntax even klunkier: in order to maintain
somewhat more backward compatibility with K&R-1 C, they decreed
that empty parentheses would not mean "no arguments", but rather:
"I, the programmer, refuse to tell you, Mr Compiler, how many
arguments and what their types are." So if you *wanted* to tell
Mr Compiler that there should be no arguments, you had to write:

int func(void);

and not the more-obvious:

int func();

(even though in C++, both of these mean "no arguments").
 
M

mdh

mdh said:
mdh wrote:
Quick question.
     If "word" were omitted, how would you make use of the
pointer that it names?  Let's omit a few more identifiers:
        struct {
            char*;
            int;
        };
        int (int, const char*[]) {
            struct [] = {
                "auto", 0
            };
        }
At the risk of further ridicule, I **thought** this a valid
comparison.

     There was no intent on my part to ridicule you.  When I
wish to ridicule someone, I make sure to leave no doubt (and
I usually regret it afterward).


**Little OT**
Eric...a quick apology at a failed attempt at humor. I should have
added a huge smiley to the sentence.
Eric...you have, when ever you have answered me, been gracious and
informative, and I have always appreciated it ever time and learnt
from it. I am sorry if I implied anything you clearly did not mean.
** End of Little OT**

     Okay, all identifiers in all declarations present and
correct.  No problem.




     The thing being declared here is the function foo(),
and its identifier is present and accounted for.  The function
parameters are not declared....

So these ( ie function parameters) are only declared at the
"definition level".

The parameter names in these declarations declare nothing at
all; only foo itself is declared.

I think I see what I am missing. Now , let me pursue the struct
declaration a little further.

In the example I used,

struct key {
char *word;
int count;
};

one could say that ??

"word", "count" and "key" are identifiers? which will be used later.
 
M

mdh

[on omitting identifiers in some situations]

Eric Sosman   said:
    The thing being declared here is the function foo(),
and its identifier is present and accounted for.  The function
parameters are not declared, and would not be declared even
if you gave names for them.  The names, if present, are really
just documentation; all that matters is their number and types.

Right (of course :) ).

Moving the question back a bit, to "why do function prototypes
have optional identifiers in the prototype-scope portion of the
declaration between the parentheses", the answer is: "historical
reasons".  

K&R-1 C did not have function prototypes.  To declare function

foo, you wrote:

    int foo(); /* K&R-1 C also lacked "void" */

snip...

C++ came along, and changed all this.  
snip.

C++ was done by a guy with less good taste than Dennis
snip

The C Standards group came along and stole prototypes wholesale
from C++, optional identifiers and all.  They did make one more
change, to make the syntax even klunkier:



Thank you Chris for that very nice perspective. Much appreciated.
 
M

mdh

What do you mean with '"non-struct"  declarations'? A line with
just

char *;

is always a syntax error, also outside a structure declaration.


I've had a chance to reflect on all that has been written, and reread
rjh's discussion of definition/declarations. I *think* I have figured
out where I erred, but would like to summarize it here, for some
feedback.

I have a file, k_rfunctions.c where I have collected exercises for re-
use. All the declarations go into k_rfunctions.h

So, when declaring struct key, I placed this in k_rfunctions.h,
thus...



struct key {
char *word;
int count;
};

Then in main, I **thought** I was defining the struct thus...(which I
initially incorrectly stated in my question)

struct key {
char *word;
int count;
}keytab[]= {
"auto", 0,
"break", 0
/*...*/
};


That's why I initially removed the word "word" and "count" from the
declaration, as I thought I would simply add it in later when defining
the struct.

But, I **think** the correct interpretation of what I was doing was to
define a new type, "struct key", which can only be defined once within
the same scope. ( per rjh). I think what I missed was the fact this
new type **is** char *word, int count as opposed to something simple,
up to now like int a, char b etc.
Anyhow, hope this makes a little more sense.
 
K

Keith Thompson

mdh said:
Quick question.
In the code below, omitting the word "word", as in char *word,
produces an error of syntax.

In similar "non-struct" declarations, the expression "char *" should
suffice. ( I think). Is there a reason that one needs to add this? Is
this unique to structs.
Thanks as usual.

struct key {
char *word;
int count;
};

int main (int argc, const char * argv[]) {

struct key keytab[] = {
"auto", 0
};

}

I think your question has been answered fairly thoroughly, but
I'm going to take a shot at it anyway.

The only "non-struct declarations" I can think of in which the
identifier is optional are function declarations. There's some
superficial similarity between a struct declaration and a function
declaration, but they're really two different things.

The parameter names in a function declaration are optional because the
names aren't used in a function call. But the names are needed in the
function definition, and so they're mandatory there.

For example:

void foo(int); /* name not needed by caller */

...

void foo(int x) { ... } /* Here the name needed so the code can
refer to the parameter */

For a struct declaration, on the other hand, there's not much you can
do without referring to the member names; that's why the member names
are mandatory.
 
M

mdh

'.

     In ancient C, all these identifiers inhabited the same
"name space," ...........  Some vestiges of this
restriction can still be seen
snip



     Modern C has a notion of name spaces.........  This means that you
can declare other struct and union types with their own "word"
and "count" elements that have nothing to do with the contents
of a `struct key'.


Thank you Eric. I think I finally get it.
 
M

mdh

I think your question has been answered fairly thoroughly, but
I'm going to take a shot at it anyway.

The only "non-struct declarations" I can think of in which the
identifier is optional are function declarations.

As I thought about it more, this is the **only** situation I could
think of as well.

 There's some
superficial similarity between a struct declaration and a function
declaration, but they're really two different things.

The parameter names in a function declaration are optional because the
names aren't used in a function call.  But the names are needed in the
function definition, and so they're mandatory there.


For a struct declaration, on the other hand, there's not much you can
do without referring to the member names; that's why the member names
are mandatory.


I think where there is a grey zone in semantics, is **even** in a
struct declaration, one is ?? defining a new type?? which is the way I
will remember that all the members need to be *declared* :) in full.
Either way, these things are so intuitive to the more experienced in
the clc, and hopefully I will someday get there and just not worry
about the minutia! :)

Your point though does reinforces what I need to know.
Thanks for your input.
 
B

Ben Bacarisse

Keith Thompson said:
For a struct declaration, on the other hand, there's not much you can
do without referring to the member names; that's why the member names
are mandatory.

Yes, but you need to know quite a bit of C work that out. The OP has
posted lots of "why is C like this" questions so I can image that they
have come up with cases where the member names seem superfluous:

void f(struct S *);

and we can make an array of struct S and call it without using any
member names:

void g(void)
{
struct S { int; double; char *; } my_s[] = {
{1, 1, "one"}, {2, 2, "two"}
};
f(my_s);
}

The reason you can't do this is at least, in part, simply because the
language says you can't. It is not daft to imagine it. It is somewhat
arbitrary that the struct S in g can not be compatible with any struct
S elsewhere. C *could* have decided that two structs are compatible
if they have the same member types in the same order and then some sort
of "anonymous" definition like this would make sense.

[One could go further and speculate that the tag could be omitted in
both places above, with a call being valid provided the shape of the
struct actually pointed to at the call time matched that in effect
when f was defined.]
 
K

Keith Thompson

mdh said:
I think where there is a grey zone in semantics, is **even** in a
struct declaration, one is ?? defining a new type?? which is the way I
will remember that all the members need to be *declared* :) in full.
Either way, these things are so intuitive to the more experienced in
the clc, and hopefully I will someday get there and just not worry
about the minutia! :)

Yes, a struct declaration defines a new type.

But then, a function declaration *also* defines a new type, namely a
function type. (Yes, it really is a type; you can declare a pointer
to it.) And they're superficially similar in that both incorporate a
list of other types:

struct s { int a; double b; };
void f(int a, double b);

And *if* the language allowed you to declare a struct type without
specifying the member names:

struct s { int; double;}; /* not valid C */

then there are still some things you could do with it:

struct s obj1 = { 42, 1.5 };
struct s obj2 = obj1;

There's no *fundamental* reason C had to be defined the way it was.
Some languages let you have a composite type consisting of members
of other types where the members aren't named (e.g., Python's
"tuple"). Some languages require names for function (or procedure,
or subroutine) parameters, and allow you to use those names in
calls; for example, the Ada equivalent of the "f" function above
might be called either as F(42, 1.5) or as F(A => 42, B => 1.5),
or even F(B => 1.5, A => 42).

But since C function calls don't require referring to the parameter
names (and in fact don't allow it), and since most uses of structs do
require the use of the member names, it just made sense to require
names for struct members but not for function parameters.

Except that function parameters must be given names in a function
*definition*, because the code that implements the function can't
refer to the parameters unless their names are visible.

<OT>C++ allows parameter names to be omitted if the parameter
isn't used. This turns out to be useful in C++, but not in C.</OT>

I would have been happier if the language had required consistency
between function declarations and definitions, but we've managed
to muddle along even without a language that follows my every
personal whim.
Your point though does reinforces what I need to know.
Thanks for your input.

I hope I haven't just caused more confusion.
 
M

mdh

There's no *fundamental* reason C had to be defined the way it was.

snip


I hope I haven't just caused more confusion.


No...it helps having it put into perspective. Thank you.
 
T

Tim Rentsch

Keith Thompson said:
Yes, a struct declaration defines a new type.

But then, a function declaration *also* defines a new type, namely a
function type. (Yes, it really is a type; you can declare a pointer
to it.)

I'm not sure what you're meaning to say here. A struct declaration
does define a new type, but a function declaration (or definition)
does not. For example:

struct { int x; } s_one;
struct { int x; } s_two;

int f_one( int, double );
int f_two( int, double );

The type of f_one and the type of f_two are the same type, namely
'int (*)(int,double)'. This type exists independently of any
function declarations.

The type of s_one and the type of s_two are not the same type,
because they are both new types (distinct from every other type
in the program).

These type (non-)equivalences can easily be seen by pointer
comparison:

&f_one == &f_two

&s_one == &s_two

The first comparison works fine, because the function types are
the same; the second comparison gives a diagnostic, because the
two types are different from each other.

Sorry to be such a nit on this; I've had this point about
structs and types drilled into me by Chris Torek. :)
 
K

Keith Thompson

Tim Rentsch said:
I'm not sure what you're meaning to say here. A struct declaration
does define a new type, but a function declaration (or definition)
does not.

I meant to say exactly what I said. The fact that I was wrong is
beside the point. :cool:}

[...]
Sorry to be such a nit on this; I've had this point about
structs and types drilled into me by Chris Torek. :)

No need to apologize. Thanks for the correction.
 

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

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,143
Latest member
SterlingLa
Top