Warning with K&R style function definition

O

Old Wolf

I have some code that has in the header file:

void foo( char bar );

and in the source file:
void foo( bar )
char bar;
{ /* etc. */ }

The compiler (with many warnings enabled) warns that the
prototype doesn't match the definition. (However this code
has worked fine in the past, I only turned the warning level
up recently and the warning appeared).

Given that the prototype is visible in the source file, is
there actually any problem with this code? The compiler
can see the prototype when it is compiling the definition
so must it know to grab a char off the stack (or whatever)
instead of an int?

NB. The definition can't be changed to ANSI-style because
it's automatically generated by a third party precompiler.
 
H

Harald van =?UTF-8?B?RMSzaw==?=

Old said:
I have some code that has in the header file:

void foo( char bar );

and in the source file:
void foo( bar )
char bar;
{ /* etc. */ }

The compiler (with many warnings enabled) warns that the
prototype doesn't match the definition. (However this code
has worked fine in the past, I only turned the warning level
up recently and the warning appeared).

Given that the prototype is visible in the source file, is
there actually any problem with this code? The compiler
can see the prototype when it is compiling the definition
so must it know to grab a char off the stack (or whatever)
instead of an int?

Your declaration says that the caller passes an argument of type char. Your
definition says that the caller passes an argument of type int [*], which
foo() will convert to a char when the function is called. The compiler is
right to complain.
NB. The definition can't be changed to ANSI-style because
it's automatically generated by a third party precompiler.

In your header, you can use

void foo( int bar );

and in your source file, you can either use

void foo( bar )
int bar;
{
char baz = bar;
/* ... */
}

or if your precompiler can handle it, you can change the header as shown
above, but keep the source file as

void foo( bar )
char bar;
{
/* ... */
}



[*] assuming CHAR_MAX <= INT_MAX
 
O

Old Wolf

Old said:
I have some code that has in the header file:
void foo( char bar );
and in the source file:
void foo( bar )
char bar;
{ /* etc. */ }

Your declaration says that the caller passes an argument of type char. Your
definition says that the caller passes an argument of type int [*], which
foo() will convert to a char when the function is called. The compiler is
right to complain.

So the compiler will read the arguments as per K&R,
and not as per the visible prototype?
In your header, you can use

void foo( int bar );

and in your source file, you can either use

void foo( bar )
int bar;
{
char baz = bar;

That was my temporary workaround :)
or if your precompiler can handle it, you can change the header as shown
above, but keep the source file as

void foo( bar )
char bar;
{

I'll give that a go and see if it likes it.
How is the conversion from int to char specified
for these K&R style definitions? Does it read an
int and then convert in the same way as an
ordinary implicit conversion from int to char?
 
A

anson

I have some code that has in the header file:

void foo( char bar );
This is a ANSI C style declare.
.
and in the source file:
void foo( bar )
char bar;
{ /* etc. */ }
but function's definition is just k&r style .
see 'expert C programming' , provide a chapter discuss about this .

solution :
1. change declare to k&r style , void foo();
2. change function define to ANSI c style ,void food(char bar){/
*etc*/};
*** the declare and the define must be matched ***
 
E

Eric Sosman

Old said:
Old said:
I have some code that has in the header file:
void foo( char bar );
and in the source file:
void foo( bar )
char bar;
{ /* etc. */ }
Your declaration says that the caller passes an argument of type char. Your
definition says that the caller passes an argument of type int [*], which
foo() will convert to a char when the function is called. The compiler is
right to complain.

So the compiler will read the arguments as per K&R,
and not as per the visible prototype?

The header's declaration conflicts with the function's
definition (which is also a declaration). If the header said

void floo(double boo);

.... and the definition said

int floo(int goo, char *shoo, const struct glue **moo)
{ ... }

.... would you expect the compiler to reconcile them in
some magical way? Of course not: The declaration and the
definition disagree, and that's that. The compiler must
issue a diagnostic; if it then decides to accept the faulty
program, it "reads arguments" according to its own whim.
 
O

Old Wolf

Eric Sosman said:
The header's declaration conflicts with the function's
definition (which is also a declaration). If the header said

void floo(double boo);

... and the definition said

int floo(int goo, char *shoo, const struct glue **moo)
{ ... }

... would you expect the compiler to reconcile them in
some magical way? Of course not: The declaration and the
definition disagree, and that's that.

If, as suggested by Harald, the header is:
void foo( int bar );

and the definition is:
void foo( bar )
char bar;
{ .... }

then do you know if the code is correct, or is this
still a mismatch? I'm concerned about how the compiler
will turn the int 'bar' into a char.
 
I

Ian Collins

Old said:
If, as suggested by Harald, the header is:
void foo( int bar );

and the definition is:
void foo( bar )
char bar;
{ .... }

then do you know if the code is correct, or is this
still a mismatch? I'm concerned about how the compiler
will turn the int 'bar' into a char.
Wouldn't that be UB? The compiler might use different tricks
(registers?) to pass int and char to functions.
 
O

Old Wolf

Wouldn't that be UB? The compiler might use different tricks
(registers?) to pass int and char to functions.

Well it might be OK if the behaviour of the
definition is to read an int using the int-passing
mechanism, and then convert it to char using an
implicit conversion. That's what Harald suggested.
I don't know whether the compiler will behave this
way or not; I was wondering if Eric could confirm
or deny.
 
I

Ian Collins

Old said:
Well it might be OK if the behaviour of the
definition is to read an int using the int-passing
mechanism, and then convert it to char using an
implicit conversion. That's what Harald suggested.

I'd expect the char you pass to be sign extended to int (assuming char
is signed) and passed by whatever means to the function. How the
parameter value is retrieved would determine whether this would work.
 
H

Harald van =?UTF-8?B?RMSzaw==?=

Old said:
Old said:
I have some code that has in the header file:
void foo( char bar );
and in the source file:
void foo( bar )
char bar;
{ /* etc. */ }

Your declaration says that the caller passes an argument of type char.
Your definition says that the caller passes an argument of type int [*],
which foo() will convert to a char when the function is called. The
compiler is right to complain.

So the compiler will read the arguments as per K&R,
and not as per the visible prototype?
Yes.
In your header, you can use

void foo( int bar );

and in your source file, you can either use

void foo( bar )
int bar;
{
char baz = bar;

That was my temporary workaround :)
or if your precompiler can handle it, you can change the header as shown
above, but keep the source file as

void foo( bar )
char bar;
{

I'll give that a go and see if it likes it.
How is the conversion from int to char specified
for these K&R style definitions? Does it read an
int and then convert in the same way as an
ordinary implicit conversion from int to char?

Right. The function call operator will have converted foo's argument to int,
and that argument is then converted "as if by assignment" to char on entry
of foo.
 
M

Mark McIntyre

I have some code that has in the header file:

void foo( char bar );

and in the source file:
void foo( bar )
char bar;
{ /* etc. */ }

The compiler (with many warnings enabled) warns that the
prototype doesn't match the definition. (However this code
has worked fine in the past, I only turned the warning level
up recently and the warning appeared).

Fixes are either convert the definition to ANSI style, or remove the
prototype (make it a declaration instead).
Given that the prototype is visible in the source file, is
there actually any problem with this code?

Quite possibly. The prototype tells the compiler to expect a char, but
the definition suggests otherwise so the compiler can presumably jump
either way.
--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
 
E

Eric Sosman

Old said:
If, as suggested by Harald, the header is:
void foo( int bar );

and the definition is:
void foo( bar )
char bar;
{ .... }

then do you know if the code is correct, or is this
still a mismatch? I'm concerned about how the compiler
will turn the int 'bar' into a char.

It's implementation-defined whether Harald's rewrite
is correct. On systems where plain `char' promotes to
`int' it's correct. On those few where `char' promotes
to `unsigned int' (INT_MAX < CHAR_MAX <= UINT_MAX), the
declaration and definition disagree. Even on most of the
latter you'll get away with it -- but you'll know in your
heart that it's wrong.

"You've got to ask yourself one question: 'Do I
feel lucky?' Well do ya, punk?" -- Harry Callahan
 
T

Thad Smith

Old said:
Well it might be OK if the behaviour of the
definition is to read an int using the int-passing
mechanism, and then convert it to char using an
implicit conversion. That's what Harald suggested.
I don't know whether the compiler will behave this
way or not; I was wondering if Eric could confirm
or deny.

That depends on the particular compiler. If you are only using a single
compiler, you can verify. If it were me, I would change the code to
make it Standard conforming.
 
C

CryptiqueGuy

I have some code that has in the header file:

void foo( char bar );
Changing this to

#include <limits.h>

#if CHAR_MAX <= INT_MAX
void foo(int);
#else
void foo(unsigned int);
#endif

I think this will solve the problem cited by Eric.
and in the source file:
void foo( bar )
char bar;
{ /* etc. */ }

In K&R style of function definition, the functions definition like the
above are effectively equivalent to:

void foo( buf_bar )
PROMOTED_TYPE buf_bar;/*PROMOTED_TYPE is int if CHAR_MAX <= INT_MAX or
else it is unsigned int*/
{
char bar = buf_bar;
/*Use 'bar' as char in ur code*/
/* etc. */
}

This ratiociantes the error generated by the compiler.
 

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,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top