Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

As-yet-undefined function type as struct member?

0 views
Skip to first unread message

Dennis Swanson

unread,
Sep 10, 1997, 3:00:00 AM9/10/97
to

Say I have this:

typedef int MY_FUNCT( struct tagMY_STRUCT *myStructPtr );

MY_FUNCT MyFunct;

typedef struct tagMY_STRUCT
{
MY_FUNCT *myFunctPtr;
} MY_STRUCT;

Now, suppose I'd prefer the struct declarations to appear _before_ the
function declarations (I might be confusing "declaration" with "definition"
one or more times here). So specifically what I'm wondering is this: I
can declare a function type that takes as a parameter a pointer to a
structure that has yet to be declared, but can I somehow declare a struct
type that includes as a member a function type that has yet to be declared?
Note that I'm declaring specific function types cuz when called via pointers
I want the compiler to check args for me, so I don't think using generic
function pointers as struct members is a good solution. (I hope I'm not
being an idiot and just missing something obvious here.)

Den

--
Dennis M. Swanson <>< C/Win32 API programmer UNIX hobbyist

Is that what you'd call it?

Kaz Kylheku

unread,
Sep 10, 1997, 3:00:00 AM9/10/97
to

In article <swansondE...@netcom.com>,

Dennis Swanson <swan...@netcom.com> wrote:
>
>Say I have this:
>
> typedef int MY_FUNCT( struct tagMY_STRUCT *myStructPtr );
>
> MY_FUNCT MyFunct;
>
> typedef struct tagMY_STRUCT
> {
> MY_FUNCT *myFunctPtr;
> } MY_STRUCT;

Your declarations have a serious error! In the first line, the structure tag
``tagMY_STRUCT'' was never seen before. The scope of its declaration is only
within the parameter list. The second ``typedef struct tagMY_STRUCT''
introduces a brand new structure type that has nothing to do with the one in
the parameter list.

>Now, suppose I'd prefer the struct declarations to appear _before_ the
>function declarations (I might be confusing "declaration" with "definition"
>one or more times here). So specifically what I'm wondering is this: I
>can declare a function type that takes as a parameter a pointer to a
>structure that has yet to be declared, but can I somehow declare a struct

Yes you can, but not the way you did it above. You have to:

struct tag;
typedef int function(struct tag *);
typedef struct tag {
/*...one or more members...*/
} my_struct_t;

Now, the struct tag inside the paramter list no longer introduces a new
tag with a restricted scope.


>type that includes as a member a function type that has yet to be declared?

What you are, in essence, asking is whether it's possible to have an incomplete
function type the same way you have an incomplete structure type. The answer is
no, there isn't such a thing, so you don't have to worry about it. A
function's definition (body) is not considered part of its type the same way
that a structure's member list is considered part of the type. A structure
without a defined member list is an incomplete structure type, but a function
declaration that is not a definition has a full, complete function type.

You don't have to define a function type in order to use it in a structure. You
just go ahead and use it. Mind you, you can't have a function as a structure
member, merely a pointer to a function. The following examples do the same
thing, except that the former declares an extra typedef that's visible to the rest of the scope:

/* ex. 1 */

typedef int my_funct_t(double, double, char *);

typedef struct my_struct {
my_funct_t *fptr;
} mu_struct_t;


/* ex. 2 */

typedef struct my_struct {
int (* fptr)(double, double, char *);
}

Get it?

>Note that I'm declaring specific function types cuz when called via pointers
>I want the compiler to check args for me, so I don't think using generic
>function pointers as struct members is a good solution. (I hope I'm not
>being an idiot and just missing something obvious here.)

By generic function pointers, I suppose that you mean old-style function
pointers that don't have prototyped types, that is:

struct foo {
int (*generic)();
};

as opposed to

struct foo {
int (*prototyped)(double x, double y);
};

Either way is valid. The latter can only be used to call a function function
that is _defined_ as returning int, and accepting two doubles as arguments. The
former ``generic'' pointer can be used to point at and call any function that
returns int. However, this freedom is next to useless, because the argument
list used in the function call must agree with the argument list accepted by
the pointed-at function (according to old-style argument matching rules). Thus
if you use the ``generic'' pointer to refer to different, incompatible
functions at different times, you will have to have to use some selection logic
to execute a compatible function call that matches the function being called
in the number of arguments and their types.
--
"In My Egotistical Opinion, most people's C programs should be
indented six feet downward and covered with dirt."
-- Blair P. Houghton

Dennis Swanson

unread,
Sep 12, 1997, 3:00:00 AM9/12/97
to

Who would have guessed that on 10 Sep 1997 at 14:29:50 -0700
Kaz Kylheku (k...@helios.crest.nt.com) would say:
~ In article <swansondE...@netcom.com>,
~ Dennis Swanson <swan...@netcom.com> wrote:
~ >
~ >Say I have this:
~ >
~ > typedef int MY_FUNCT( struct tagMY_STRUCT *myStructPtr );
~ >
~ > MY_FUNCT MyFunct;
~ >
~ > typedef struct tagMY_STRUCT
~ > {
~ > MY_FUNCT *myFunctPtr;
~ > } MY_STRUCT;
~
~ Your declarations have a serious error! In the first line, the structure tag
~ ``tagMY_STRUCT'' was never seen before. The scope of its declaration is only
~ within the parameter list. The second ``typedef struct tagMY_STRUCT''

Are you sure about this? (see below for why I'm asking this)

~ introduces a brand new structure type that has nothing to do with the one in
~ the parameter list.

Could this be a case of an error with no consequence? The only reason I'm
questioning you about this is that, as far as I can tell, it "works" the
way I have done it. That is, if I call the function with a pointer to a
different structure type, the compiler properly thumps me on the head. But
if I call it with a pointer to the "brand new structure type", that you
say "has totally nothing to do with the one in the parameter list", the
compiler gives it a pass. And at run-time I've verified that the called
function can access at least one of the function pointer members of the
"different" struct, as it's used it to successfully call back. Maybe it
effectively doesn't matter in this case? (For the sake of discussion I'm
assuming you're interpretation is right, since I'm the one who's asking
for knowledge and you're the one imparting it. :-)

~ >Now, suppose I'd prefer the struct declarations to appear _before_ the
~ >function declarations (I might be confusing "declaration" with "definition"
~ >one or more times here). So specifically what I'm wondering is this: I
~ >can declare a function type that takes as a parameter a pointer to a
~ >structure that has yet to be declared, but can I somehow declare a struct
~
~ Yes you can, but not the way you did it above. You have to:
~
~ struct tag;
~ typedef int function(struct tag *);
~ typedef struct tag {
~ /*...one or more members...*/
~ } my_struct_t;
~
~ Now, the struct tag inside the paramter list no longer introduces a new
~ tag with a restricted scope.

(prescribed method left in as context for the above)

~ >type that includes as a member a function type that has yet to be declared?
~
~ What you are, in essence, asking is whether it's possible to have an incomplete
~ function type the same way you have an incomplete structure type. The answer is
~ no, there isn't such a thing, so you don't have to worry about it. A
~ function's definition (body) is not considered part of its type the same way
~ that a structure's member list is considered part of the type. A structure
~ without a defined member list is an incomplete structure type, but a function
~ declaration that is not a definition has a full, complete function type.

Yes, what I was asking could indeed be distilled as you've written, and now
see that what I was seeking to do (place my structure decl above my function
decls in that header file), simply for stylistic reasons, is not possible,
and why.

~ You don't have to define a function type in order to use it in a structure. You
~ just go ahead and use it. Mind you, you can't have a function as a structure
~ member, merely a pointer to a function. The following examples do the same
~ thing, except that the former declares an extra typedef that's visible to the rest of the scope:
~
~ /* ex. 1 */
~
~ typedef int my_funct_t(double, double, char *);
~
~ typedef struct my_struct {
~ my_funct_t *fptr;
~ } mu_struct_t;
~
~
~ /* ex. 2 */
~
~ typedef struct my_struct {
~ int (* fptr)(double, double, char *);
~ }
~
~ Get it?

Yes, ex. 1 is what I was doing, and ex. 2 is another way of doing it. In
my case I do need to establish identifiers for particular functions types
(so that I can declare as local vars pointers to functions of particular
types, so that when using those pointers to call functions, the compiler
will perform parameter checking for me). And as a matter of personal
preference I think stylistically I'd rather slightly grudgingly have the
struct appear after the functions than have identical pairs of "function
declaration info" (that is, a return type and parm list -- one in the
struct decl, and another in a separate typedef) that I'd have to manually
make sure were always identical. (I hope that made sense.)

~ >Note that I'm declaring specific function types cuz when called via pointers
~ >I want the compiler to check args for me, so I don't think using generic
~ >function pointers as struct members is a good solution. (I hope I'm not
~ >being an idiot and just missing something obvious here.)
~
~ By generic function pointers, I suppose that you mean old-style function
~ pointers that don't have prototyped types, that is:
~
~ struct foo {
~ int (*generic)();
~ };
~
~ as opposed to
~
~ struct foo {
~ int (*prototyped)(double x, double y);
~ };
~
~ Either way is valid. The latter can only be used to call a function function
~ that is _defined_ as returning int, and accepting two doubles as arguments. The
~ former ``generic'' pointer can be used to point at and call any function that
~ returns int. However, this freedom is next to useless, because the argument
~ list used in the function call must agree with the argument list accepted by
~ the pointed-at function (according to old-style argument matching rules). Thus
~ if you use the ``generic'' pointer to refer to different, incompatible
~ functions at different times, you will have to have to use some selection logic
~ to execute a compatible function call that matches the function being called
~ in the number of arguments and their types.

Moreover this freedom is dangerous as there's no (automatic) mechanism for
ensuring that "the function call must agree with the argument list accepted
by the pointed-at function". You're correct about what I meant by "generic
function pointer". Initially I was using these, but after noticing that I
had added a param to the called function's list, yet had forgot to update
the caller to pass this additional one, and yet the function was still
successfully called (meaning the callee would take 4 bytes or whatever of
"garbage" on the stack as that new last param), that's when I decided
generic function pointers weren't for me!

Thank you very much, Kaz, for responding and clueing me in on the nature
of structure definitions versus function definitions. It now makes sense
why I cannot do exactly what I was seeking.

Den

~ --
~ "In My Egotistical Opinion, most people's C programs should be
~ indented six feet downward and covered with dirt."
~ -- Blair P. Houghton

(S/he must have worked where I'm working now! ;-)

--
Dennis M. Swanson <>< C/Win32 API programmer UNIX hobbyist

The "Paper, Rock, Scissors" of Politics:
----------------------------------------
Shredder beats Subpoena

User923005

unread,
Sep 12, 1997, 3:00:00 AM9/12/97
to

[snip]

>Could this be a case of an error with no consequence?
A hidden consequence is still a consequence. Rocks under the water can
rip a hole in the bottom of your canoe. What is worse, you don't see them
until it is too late.

>The only reason I'm
>questioning you about this is that, as far as I can tell, it "works" the
>way I have done it.

I put some sand in my crankcase instead of oil when I was a quart low. I
drove to the market and back. I got where I wanted to (both ways), so
there is no danger. What is wrong with this argument?

[clip]

I'm at home, so I say anything I please.


Kaz Kylheku

unread,
Sep 12, 1997, 3:00:00 AM9/12/97
to

In article <swansondE...@netcom.com>,
Dennis Swanson <swan...@netcom.com> wrote:
>
>Who would have guessed that on 10 Sep 1997 at 14:29:50 -0700
>Kaz Kylheku (k...@helios.crest.nt.com) would say:
>~ In article <swansondE...@netcom.com>,
>~ Dennis Swanson <swan...@netcom.com> wrote:
>~ >
>~ >Say I have this:
>~ >
>~ > typedef int MY_FUNCT( struct tagMY_STRUCT *myStructPtr );
>~ >
>~ > MY_FUNCT MyFunct;
>~ >
>~ > typedef struct tagMY_STRUCT
>~ > {
>~ > MY_FUNCT *myFunctPtr;
>~ > } MY_STRUCT;
>~
>~ Your declarations have a serious error! In the first line, the structure tag
>~ ``tagMY_STRUCT'' was never seen before. The scope of its declaration is only
>~ within the parameter list. The second ``typedef struct tagMY_STRUCT''
>
>Are you sure about this? (see below for why I'm asking this)
>
>~ introduces a brand new structure type that has nothing to do with the one in
>~ the parameter list.
>
>Could this be a case of an error with no consequence? The only reason I'm

It's somewhat of an ``academic'' error, but it's still an error nevertheless.
Incidentally, C allows separately declared structure types to be compatible
if they are in separate translation units, but not if they are in the same one. For example, if you write:

struct foo {
int x;
};

struct bar {
int x;
};

then you have introduced two types that are formally incompatible. But if
the two declarations appeared in separate translation units, then the two
types _are_ compatible, allowing an external struct foo declaration in one
unit to resolve against a struct bar external definition in the other unit.

Within the same translation unit you could have problems if you assume that
two identical structure types are compatible: for example, suppose you had
a function like:

void f(struct foo *a, struct bar *b)
{

}

Since the two types are formally incompatible, and neither type is a pointer to
char, the compiler is allowed to assume that the two pointed-at objects do not
overlap. If they actually do, you have problems.

In your case, you have a slightly different problem. However, your compiler
should be diagnosing a pointer type mismatch error nevertheless! The following
test snippet should elicit a diagnostic message, because it violates a semantic
constraint:

void func(struct foo *x);

struct foo { int x; double y; };


void func(struct foo *x)
{

}

Try it!

The problem is that the *definition* of func has an argument of an incompatible
type with respect to the prior *prototype*. There is no way to reach the
type that was declared in the prototype; the namespace became permanently
closed once the prototype declaration was complete.

Here is what the GNU C compiler gives me, with the -Wall -ansi flags. In
fact it gives me the same thing without *any* options:

test.c:1: warning: `struct foo' declared inside parameter list
test.c:1: warning: its scope is only this definition or declaration,
test.c:1: warning: which is probably not what you want.
test.c:7: conflicting types for `func'
test.c:1: previous declaration of `func'

Which is not to say that the compiler defines the language! I'm just using it
to illustrate something that I already know from the definition.

GCC understands that the two types are formally incompatible, and it
_refuses_ to compile the test.c program. The first three errors are warnings,
but the last three are genuine errors resulting in a failure to translate.

>questioning you about this is that, as far as I can tell, it "works" the
>way I have done it. That is, if I call the function with a pointer to a
>different structure type, the compiler properly thumps me on the head. But
>if I call it with a pointer to the "brand new structure type", that you
>say "has totally nothing to do with the one in the parameter list", the
>compiler gives it a pass.

Without a diagnostic at all? It sounds like your compiler has a slight
non-conformity. A compiler is allowed to translate the program, but it must not
let it pass without at least one diagnostic.

Perhaps the prototype is not visible at the point where your function is
actually defined? In this case, no diagnostic will result (but the behavior
is still formally undefined, even if it happens to work).

>And at run-time I've verified that the called
>function can access at least one of the function pointer members of the
>"different" struct, as it's used it to successfully call back. Maybe it
>effectively doesn't matter in this case? (For the sake of discussion I'm
>assuming you're interpretation is right, since I'm the one who's asking
>for knowledge and you're the one imparting it. :-)

It matters because it's a constraint violation that can readily result in a
failure to emit a translation. If your program won't compile, it's no good! :)

--

"In My Egotistical Opinion, most people's C programs should be

indented six feet downward and covered with dirt."

-- Blair P. Houghton

Dennis Swanson

unread,
Sep 16, 1997, 3:00:00 AM9/16/97
to

Who would have guessed that on 12 Sep 1997 at 09:34:55 -0700

Kaz Kylheku (k...@helios.crest.nt.com) would say:
[...]
~
~ >questioning you about this is that, as far as I can tell, it "works" the
~ >way I have done it. That is, if I call the function with a pointer to a
~ >different structure type, the compiler properly thumps me on the head. But
~ >if I call it with a pointer to the "brand new structure type", that you
~ >say "has totally nothing to do with the one in the parameter list", the
~ >compiler gives it a pass.
~
~ Without a diagnostic at all? It sounds like your compiler has a slight
~ non-conformity. A compiler is allowed to translate the program, but it must not
~ let it pass without at least one diagnostic.
~
[...]

Welcome to the World of Microsoft -- I see you haven't been assimilated yet.
"Slight non-conformity" pegs it pretty dern well. Traipsing thru the docs
for compiler flags I discovered that for Visual C++ (v4.2), ANSI-compliance
is _optional_, and is _off by default_. So what I get are "Microsoft
extensions", one of which is to automagically enter structs first declared
in a function prototype into the global namespace!
But I did like you suggested and put a "forward declaration", so to speak,
of my struct before its use in function prototypes, to be technically
correct. Unfortunately I can't really try it out in "ANSI mode", cuz like
sticking it in Warning Level 4 (the highest), MS's own Windows header files
don't pass. :-(
Thank you for sharing your expertise, Kaz.

Den

--
Dennis M. Swanson <>< C/Win32 API programmer UNIX hobbyist

"When I want your opinion I'll beat it out of you."
-- Elvira, Mistress of the Dark

0 new messages