Function syntax

B

BartC

Consider this typedef that defines a struct type T (probably the type can be
simpler than this but this is how the problem manifested itself):

typedef struct _T T;
typedef struct _T {
T *left;
T *right;
int data;
} T;

And a function that returns a pointer to T:

T *newT (int,int,int);

These work fine. However if extra parentheses are added to pointer
declarations:

typedef struct _T T;
typedef struct _T {
T (*left);
T (*right);
int data;
} T;

T (*newT) (int,int,int);

then, while the 'left' and 'right' declarations are unaffected by the extra
parentheses, the compiler doesn't like the new function declaration.

Is there any reason why superfluous parentheses can't be added to functions
like this, but they can elsewhere?

(I'm generating C code automatically and it's easier to have them in. I
don't care what the code looks like.)
 
M

Malcolm McLean

Consider this typedef that defines a struct type T (probably the type can be

simpler than this but this is how the problem manifested itself):



typedef struct _T T;

typedef struct _T {

T *left;

T *right;

int data;

} T;



And a function that returns a pointer to T:



T *newT (int,int,int);



These work fine. However if extra parentheses are added to pointer

declarations:



typedef struct _T T;

typedef struct _T {

T (*left);

T (*right);

int data;

} T;



T (*newT) (int,int,int);



then, while the 'left' and 'right' declarations are unaffected by the extra

parentheses, the compiler doesn't like the new function declaration.



Is there any reason why superfluous parentheses can't be added to functions

like this, but they can elsewhere?



(I'm generating C code automatically and it's easier to have them in. I

don't care what the code looks like.)

T (*left)(int x); declares a function pointer that return a T and take an integer. However the last pair of parentheses may not be omitted. They
can of course take void or be empty.
 
M

Massimo Ortolano

And a function that returns a pointer to T:

T *newT (int,int,int);
Yes.

T (*newT) (int,int,int);

This is not the same as the declaration above: newT is here declared as
a pointer to a function.
Is there any reason why superfluous parentheses can't be added to functions
like this

Because those parentheses aren't superfluous at all.
 
S

Scott Fluhrer

BartC said:
Consider this typedef that defines a struct type T (probably the type can
be
simpler than this but this is how the problem manifested itself):

typedef struct _T T;
typedef struct _T {
T *left;
T *right;
int data;
} T;

And a function that returns a pointer to T:

T *newT (int,int,int);

These work fine. However if extra parentheses are added to pointer
declarations:

typedef struct _T T;
typedef struct _T {
T (*left);
T (*right);
int data;
} T;

T (*newT) (int,int,int);

then, while the 'left' and 'right' declarations are unaffected by the
extra
parentheses, the compiler doesn't like the new function declaration.

Well, that's because it's no longer a function declaration. Instead of
declaring newT as a function that returns a pointer to a T, you're declaring
newT as a pointer to a function that returns a T.
Is there any reason why superfluous parentheses can't be added to
functions
like this, but they can elsewhere?

Because it changes the meaning, much as 3 + 4 * 5 and (3 + 4) * 5 have
different meanings.
(I'm generating C code automatically and it's easier to have them in. I
don't care what the code looks like.)

Would:

T (*newT(int, int, int));

work for you?
 
J

James Kuyper

Consider this typedef that defines a struct type T (probably the type can be
simpler than this but this is how the problem manifested itself):

typedef struct _T T;
typedef struct _T {
T *left;
T *right;
int data;
} T;

Other people have addressed the question you asked, so I'll just address
an issue that you didn't ask about.

The identifier _T is "always reserved for any use." 7.1.3p1
Therefore, any program containing a declaration or definition of _T has
undefined behavior. 7.1.3p3. The purpose of the reservations is to allow
the implementation to use reserved names for it's own purposes without
interfering with user code that respects the reservations. Imagine what
would happen to your code if, for instance, a previously #included
standard header had #defined _T.
 
B

BartC

Well, that's because it's no longer a function declaration. Instead of
declaring newT as a function that returns a pointer to a T, you're
declaring newT as a pointer to a function that returns a T.

OK, so I can't generate the first part of a function spec (return type and
name) separately from the (...) part containing the parameters.
Would:

T (*newT(int, int, int));

work for you?

Yes, it looks like I will have to make the generating code more elaborate!
 
K

Kenny McCormack

James Kuyper said:
Other people have already addressed the question you asked, so I'll just
blather on about something stupid, like I usually do.

The identifier _T is "always reserved for any use." 7.1.3p1
Therefore, any program containing a declaration or definition of _T has
undefined behavior. 7.1.3p3. The purpose of the reservations is to allow
the implementation to use reserved names for it's own purposes without
interfering with user code that respects the reservations. Imagine what
would happen to your code if, for instance, a previously #included
standard header had #defined _T.

Should we add "bitching about people using identifiers that start with _"
to the list (see below):
1) Prototyping main()
2) (not) Casting the return value of malloc()
3) Not emitting a final newline after the last bit of output of a program.

--
(The Republican mind, in a nutshell)
You believe things that are incomprehensible, inconsistent, impossible
because we have commanded you to believe them; go then and do what is
unjust because we command it. Such people show admirable reasoning. Truly,
whoever is able to make you absurd is able to make you unjust. If the
God-given understanding of your mind does not resist a demand to believe
what is impossible, then you will not resist a demand to do wrong to that
God-given sense of justice in your heart. As soon as one faculty of your
soul has been dominated, other faculties will follow as well. And from this
derives all those crimes of religion which have overrun the world.

(Alternative condensed translation)
"Those who can make you believe absurdities, can make you commit atrocities".
 
K

Keith Thompson

You have two typedefs with the same name. That's a constraint violation
in C99; C11 allows it (and gcc seems to allow it by default).
Other people have addressed the question you asked, so I'll just address
an issue that you didn't ask about.

The identifier _T is "always reserved for any use." 7.1.3p1
Therefore, any program containing a declaration or definition of _T has
undefined behavior. 7.1.3p3. The purpose of the reservations is to allow
the implementation to use reserved names for it's own purposes without
interfering with user code that respects the reservations. Imagine what
would happen to your code if, for instance, a previously #included
standard header had #defined _T.

Furthermore, there's no real need for a typedef and tag for the
same struct to be distinct identifiers. This:

typedef struct T T;
struct T {
T *left;
T *right;
int data;
};

is perfectly legal, and lets you refer to the type either as "struct T"
or as "T"

If you want to use distinct identifiers (say, to discourage accidental
use of the tag name), you can always append an underscore, which doesn't
infringe on the implementation's namespace:

typedef struct T_ T;
struct T_ {
T *left;
T *right;
int data;
};

Or you can omit the typedef altogether:

struct T {
struct T *left;
struct T *right;
int data;
};

and refer to the type as "struct T".
 
B

BartC

Furthermore, there's no real need for a typedef and tag for the
same struct to be distinct identifiers. This:

typedef struct T T;
struct T {
T *left;
T *right;
int data;
};

is perfectly legal, and lets you refer to the type either as "struct T"
or as "T"

Thanks, I'll use that pattern then.
 
B

BartC

BartC said:
Yes, it looks like I will have to make the generating code more elaborate!

It seems I've already come across the same problem - and solved it - about a
year ago! I thought it seemed familiar, but I couldn't find any posts here
about it.

Anyway the solution turned out to be simple: whatever the parameters of the
function are, they are simply concatenated (as a string) to the end of the
function name, before passing the result to the routine that produces a C
type-spec (which involves wrapping the type-spec around any associated
name).
 
T

Tim Rentsch

[...]
Furthermore, there's no real need for a typedef and tag for the
same struct to be distinct identifiers. [snip elaboration]

What I think you mean is that, as far as the language definition
is concerned, having a struct tag be the same as a typedef name
does not produce any conflicts. There may be a reason to want
the typedef name for a struct to be different from its tag, but
the rules of the language don't forbid it.
 
K

Keith Thompson

Tim Rentsch said:
[...]
Furthermore, there's no real need for a typedef and tag for the
same struct to be distinct identifiers. [snip elaboration]

What I think you mean is that, as far as the language definition
is concerned, having a struct tag be the same as a typedef name
does not produce any conflicts. There may be a reason to want
the typedef name for a struct to be different from its tag, but
the rules of the language don't forbid it.

What I mean is that there's no real need. You're right that there
may be valid reasons to make them distinct (in which case you should
probably have a consistent convention, like appending an underscore
to the tag name), but I know of no reasons that I consider to be
a *need*. (Yeah, you could have a coding standard that you're
required to follow.)
 
T

Tim Rentsch

Keith Thompson said:
Tim Rentsch said:
[...]
Furthermore, there's no real need for a typedef and tag for the
same struct to be distinct identifiers. [snip elaboration]

What I think you mean is that, as far as the language definition
is concerned, having a struct tag be the same as a typedef name
does not produce any conflicts. There may be a reason to want
the typedef name for a struct to be different from its tag, but
the rules of the language don't forbid it.

What I mean is that there's no real need. You're right that there
may be valid reasons to make them distinct (in which case you should
probably have a consistent convention, like appending an underscore
to the tag name), but I know of no reasons that I consider to be
a *need*. (Yeah, you could have a coding standard that you're
required to follow.)

My intention was to differentiate an objective statement and a
subjective statement. Saying the language definition doesn't
cause any conflicts is an objective statement. Saying there
is no real need is a subjective statement, depending on one's
perception of what constitutes a need - other people may have
a different notion of 'need' than you have.
 
M

Malcolm McLean

My intention was to differentiate an objective statement and a
subjective statement. Saying the language definition doesn't
cause any conflicts is an objective statement. Saying there
is no real need is a subjective statement, depending on one's
perception of what constitutes a need - other people may have
a different notion of 'need' than you have.

I tend to use
typedef struct mywonderfulobject_tag
{
struct mywonderfulobject_tag *next;
int data;
} MYWONDERFULOBJECT;

using the _tag to make clear that the only purpose is to get round the annoying
typedef deficiency, and that everyone should use MYWONDERFULOBJECT *s to
interface to the code.
 

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,982
Messages
2,570,186
Members
46,744
Latest member
CortneyMcK

Latest Threads

Top