Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > invoke function without declaration

Reply
Thread Tools

invoke function without declaration

 
 
Stanley Rice
Guest
Posts: n/a
 
      11-15-2011
Dear all

Once again I come across some question about linking. In f1.c, I have
the following function definition.
----------------f1.c------------
#include <stdio.h>
void my_print(float a, int b)
{
printf("%f\t%d\n", a, b);
}

int add(int a, int b)
{
return a + b;
}

In main.c, I call the two function without declaration.
----------------main.c-------------
int main(void)
{
int a = add(1, 2);
printf("%d\n", a);
my_print(2.0, a);

return 0;
}

Notice here, in file main.c, I don't include any headers, say, 'f1.h',
'stdio.h', and don't declare anything deliberately, trying to get what
the result would like to be.

In my machine, with compiler gcc on ubuntu, I got some warnings while
compiling the code, and the binary file runs happily, printing the
following lines:
3
0.000000 1073741824

From the result, I got that
1. the function 'add' and the standard library function 'printf'
performs well, because the first line printed is 3.
2. the function 'my_print' doesn't work, the printed line obviously
shows.

All three function are defined external without declaration in file
main.c. But why the first two works well, but the last one fails? Is
it undefined in ISO C?

Thanks in advance.
 
Reply With Quote
 
 
 
 
bartek szurgot
Guest
Posts: n/a
 
      11-15-2011
On 11/15/2011 10:20 AM, Stanley Rice wrote:
> Dear all
>
> Once again I come across some question about linking. In f1.c, I have
> the following function definition.
> ----------------f1.c------------
> #include <stdio.h>
> void my_print(float a, int b)
> {
> printf("%f\t%d\n", a, b);
> }
>
> int add(int a, int b)
> {
> return a + b;
> }
>
> In main.c, I call the two function without declaration.
> ----------------main.c-------------
> int main(void)
> {
> int a = add(1, 2);
> printf("%d\n", a);
> my_print(2.0, a);
>
> return 0;
> }
>
> Notice here, in file main.c, I don't include any headers, say, 'f1.h',
> 'stdio.h', and don't declare anything deliberately, trying to get what
> the result would like to be.
>
> In my machine, with compiler gcc on ubuntu, I got some warnings while
> compiling the code, and the binary file runs happily, printing the
> following lines:
> 3
> 0.000000 1073741824
>
> From the result, I got that
> 1. the function 'add' and the standard library function 'printf'
> performs well, because the first line printed is 3.
> 2. the function 'my_print' doesn't work, the printed line obviously
> shows.
>
> All three function are defined external without declaration in file
> main.c. But why the first two works well, but the last one fails? Is
> it undefined in ISO C?
>
> Thanks in advance.


when C does not know the exact type of arguments/return values it
assumes 'int'. as long as arguments are in fact ints, it works. by when
they differ, problems arise, since compiler put different types on
stack, and tries to take different inside the function.

it gets even funnier when architecture changes. your code gives
different results on ia32 and amd64.

real life situation - about a week ago a friend of mine found similar
bug in code he develops. for some reason it crashed on amd64, while
working stable on ia32. some debugging shown that stdlib.h was not
included, thus malloc was not defined, thus compiler assumed it returns
'int' instead of 'void*'. it worked well on ia32, since there, on GCC
sizeof(int)==sizeof(void*). on the amd64 however
sizeof(int)<sizeof(void*) and program used some random memory space,
instead of newly allocated block.

notice that similar problems may arise if you do not include some header
(say: aaa.h), that you use calls from, but other header you do include
(say bbb.h) does that (i.e. bbb.h includes aaa.h). it will work on your
machine, but when moved to different implementation of library with
bbb.h file, this implicit include may not take place (i.e. bbb.h may
DON'T include aaa.h), users of that system will have, possibly
nontrivial, problems with your code...

summary is short. do NOT never, ever use functions that were not
declared. also always include headers of the functions that you use,
even if you "know" they are already included by some other header.

--
pozdrawiam serdecznie / best regards,
Bartek 'BaSz' Szurgot

http://www.baszerr.org
 
Reply With Quote
 
 
 
 
Stanley Rice
Guest
Posts: n/a
 
      11-15-2011
On Nov 15, 6:10*pm, bartek szurgot <(E-Mail Removed)> wrote:
> On 11/15/2011 10:20 AM, Stanley Rice wrote:
>
>
>
>
>
>
>
>
>
> > Dear all

>
> > Once again I come across some question about linking. In f1.c, I have
> > the following function definition.
> > ----------------f1.c------------
> > #include <stdio.h>
> > void my_print(float a, int b)
> > {
> > * * printf("%f\t%d\n", a, b);
> > }

>
> > int add(int a, int b)
> > {
> > * * return a + b;
> > }

>
> > In main.c, I call the two function without declaration.
> > ----------------main.c-------------
> > int main(void)
> > {
> > * * int a = add(1, 2);
> > * * printf("%d\n", a);
> > * * my_print(2.0, a);

>
> > * * return 0;
> > }

>
> > Notice here, in file main.c, I don't include any headers, say, 'f1.h',
> > 'stdio.h', and don't declare anything deliberately, trying to get what
> > the result would like to be.

>
> > In my machine, with compiler gcc on ubuntu, I got some warnings while
> > compiling the code, and the binary file runs happily, printing the
> > following lines:
> > 3
> > 0.000000 * *1073741824

>
> > From the result, I got that
> > 1. the function 'add' and the standard library function 'printf'
> > performs well, because the first line printed is 3.
> > 2. the function 'my_print' doesn't work, the printed line obviously
> > shows.

>
> > All three function are defined external without declaration in file
> > main.c. But why the first two works well, but the last one fails? Is
> > it undefined in ISO C?

>
> > Thanks in advance.

>
> when C does not know the exact type of arguments/return values it
> assumes 'int'. as long as arguments are in fact ints, it works. by when
> they differ, problems arise, since compiler put different types on
> stack, and tries to take different inside the function.
>
> it gets even funnier when architecture changes. your code gives
> different results on ia32 and amd64.
>
> real life situation - about a week ago a friend of mine found similar
> bug in code he develops. for some reason it crashed on amd64, while
> working stable on ia32. some debugging shown that stdlib.h was not
> included, thus malloc was not defined, thus compiler assumed it returns
> 'int' instead of 'void*'. it worked well on ia32, since there, on GCC
> sizeof(int)==sizeof(void*). on the amd64 however
> sizeof(int)<sizeof(void*) and program used some random memory space,
> instead of newly allocated block.
>
> notice that similar problems may arise if you do not include some header
> (say: aaa.h), that you use calls from, but other header you do include
> (say bbb.h) does that (i.e. bbb.h includes aaa.h). it will work on your
> machine, but when moved to different implementation of library with
> bbb.h file, this implicit include may not take place (i.e. bbb.h may
> DON'T include aaa.h), users of that system will have, possibly
> nontrivial, problems with your code...
>
> summary is short. do NOT never, ever use functions that were not
> declared. also always include headers of the functions that you use,
> even if you "know" they are already included by some other header.
>
> --
> pozdrawiam serdecznie / best regards,
> Bartek 'BaSz' Szurgot
>
> http://www.baszerr.org


I found a similar question in comp.lang.c FAQ list.Qustion 1.25

Functions which are called without a declaration in scope, perhaps
because the first call precedes the function's definition, are assumed
to be declared as if by:

extern int f();
That is, an undeclared function is assumed to return int, and to
accept an unspecified number of arguments (though there must be a
fixed number of them and none may be ``narrow'').

The statement above is not consistant with what you said,
'when C does not know the exact type of arguments/return values it
assumes 'int'. as long as arguments are in fact ints, '

The points is that what on earth the type of argument in the function
which is not declared is, int or not specified at all?
As you can see that even I pass an int variable to the function
that requires an int type, the result is confusing.
Does the standard say something about this, I got a draft, but
don't know where to get the point.
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      11-15-2011
Stanley Rice <(E-Mail Removed)> writes:
<snip>
>> On 11/15/2011 10:20 AM, Stanley Rice wrote:

<snip>
>> > ----------------f1.c------------
>> > #include <stdio.h>
>> > void my_print(float a, int b)
>> > {
>> > ¬* ¬* printf("%f\t%d\n", a, b);
>> > }

>>
>> > int add(int a, int b)
>> > {
>> > ¬* ¬* return a + b;
>> > }

>>
>> > In main.c, I call the two function without declaration.
>> > ----------------main.c-------------
>> > int main(void)
>> > {
>> > ¬* ¬* int a = add(1, 2);
>> > ¬* ¬* printf("%d\n", a);
>> > ¬* ¬* my_print(2.0, a);

>>
>> > ¬* ¬* return 0;
>> > }

<snip>
> I found a similar question in comp.lang.c FAQ list.Qustion 1.25
>
> Functions which are called without a declaration in scope, perhaps
> because the first call precedes the function's definition, are assumed
> to be declared as if by:
>
> extern int f();
> That is, an undeclared function is assumed to return int, and to
> accept an unspecified number of arguments (though there must be a
> fixed number of them and none may be ``narrow'').

<snip>
> Does the standard say something about this, I got a draft, but
> don't know where to get the point.


Most of what you want is in 6.5.2.2 paragraph 6.

I don't think it's productive to try to find out about these sorts of
rules by trying things out. It's very easy to think that, because
something works, it's valid C. For example, if you'd left out my_print
you might have concluded that the program is correct when, in fact,
calling a variadic function (like printf) without a prototype in scope
is undefined.

--
Ben.
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      11-15-2011
Stanley Rice <(E-Mail Removed)> writes:
[...]
> I found a similar question in comp.lang.c FAQ list.Qustion 1.25
>
> Functions which are called without a declaration in scope, perhaps
> because the first call precedes the function's definition, are assumed
> to be declared as if by:
>
> extern int f();
> That is, an undeclared function is assumed to return int, and to
> accept an unspecified number of arguments (though there must be a
> fixed number of them and none may be ``narrow'').

[...]

That's no longer the case in C99. In C99, a call to an undeclared
function is a constraint violation. (It's a bad idea in either version
of the language.)

--
Keith Thompson (The_Other_Keith) http://www.velocityreviews.com/forums/(E-Mail Removed) <http://www.ghoti.net/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      11-15-2011
Ben Bacarisse <(E-Mail Removed)> writes:
<snip>
> Most of what you want is in 6.5.2.2 paragraph 6.


And, I have been reminded, paragraph 1 as well.

<snip>
--
Ben.
 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      11-15-2011
On 11/15/2011 04:20 AM, Stanley Rice wrote:
> Dear all
>
> Once again I come across some question about linking. In f1.c, I have
> the following function definition.
> ----------------f1.c------------
> #include <stdio.h>
> void my_print(float a, int b)
> {
> printf("%f\t%d\n", a, b);
> }
>
> int add(int a, int b)
> {
> return a + b;
> }
>
> In main.c, I call the two function without declaration.
> ----------------main.c-------------
> int main(void)
> {
> int a = add(1, 2);
> printf("%d\n", a);
> my_print(2.0, a);
>
> return 0;
> }
>
> Notice here, in file main.c, I don't include any headers, say, 'f1.h',
> 'stdio.h', and don't declare anything deliberately, trying to get what
> the result would like to be.


main.c relies upon the implicit int rules from C90. They cause add() to,
in effect, be implicitly declared as taking two arguments of type 'int'
and returning an int. They cause printf() in main.c to be treated as if
took a char* and an int as arguments, and returns an int. They cause
my_print() to be treated as if it took a double and an int as arguments,
and returns an int.

These implicit declarations are correct for add(), but not for printf()
or my_print(). As a result, the behavior of your program is undefined.
The implementation is not required to issue a diagnostic for such code.

Since the problem occurs due to a mismatch between the implicit
declaration in one translation unit, and the actual definition in
another translation unit, the compiler cannot detect this mismatch. The
linker could have enough information to detect it, but it doesn't need
that information in order to do it's job, and therefore doesn't
necessarily have access to such information.

> In my machine, with compiler gcc on ubuntu, I got some warnings while
> compiling the code,


Good. However, it would have been better to compile in C99 mode, where
the implicit int rule has been dropped. Your program provides a prime
example of why it was dropped. At least one diagnostic message for this
code due to missing declarations is mandatory in C99, and gcc would
almost certainly refuse to continue after issuing that message.

and the binary file runs happily, printing the
> following lines:
> 3
> 0.000000 1073741824
>
> From the result, I got that
> 1. the function 'add' and the standard library function 'printf'
> performs well, because the first line printed is 3.


The printf() call in main() has undefined behavior; that it appeared to
work is a coincidence; it didn't have to work. And even though it
appeared to work, it might have malfunctioned in some way that caused
something else to go wrong.

> 2. the function 'my_print' doesn't work, the printed line obviously
> shows.


It may seem obvious, but it's wrong. The function my_print() should work
perfectly, if called correctly, and if stdout is writeable; it's the
call to my_print() inside main() which is defective, not my_print() itself.

> All three function are defined external without declaration in file
> main.c. But why the first two works well, but the last one fails? Is
> it undefined in ISO C?


Yes.
--
James Kuyper
 
Reply With Quote
 
André Gillibert
Guest
Posts: n/a
 
      11-15-2011
Stanley Rice <(E-Mail Removed)> wrote:
> Dear all
>
> Once again I come across some question about linking. In f1.c, I have
> the following function definition.
> ----------------f1.c------------
> #include <stdio.h>
> void my_print(float a, int b)
> {
> printf("%f\t%d\n", a, b);
> }
>
> int add(int a, int b)
> {
> return a + b;
> }
>
> In main.c, I call the two function without declaration.
> ----------------main.c-------------
> int main(void)
> {
> int a = add(1, 2);
> printf("%d\n", a);
> my_print(2.0, a);
>
> return 0;
> }
>


Implicit declarations are a constraint violation in C99 but valid
in C90.
In C90, my_print(2.0, a) implicitly returns int, and has to take two
arguments: The first is of type double (float is promoted to
double) while the second is of type int. Since the prototype of
my_print doesn't match, the behavior is undefined, even in C90.

--
André Gillibert
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      11-15-2011
James Kuyper <(E-Mail Removed)> writes:
[...]
> Good. However, it would have been better to compile in C99 mode, where
> the implicit int rule has been dropped. Your program provides a prime
> example of why it was dropped. At least one diagnostic message for this
> code due to missing declarations is mandatory in C99, and gcc would
> almost certainly refuse to continue after issuing that message.


Almost, but not quite. gcc's diagnostic for a call to an undeclared
function, even with "-std=c99 -pedantic", is merely a warning; after
printing the warning, it proceeds under C90 rules. You can make it a
fatal error by specifying "-pedantic-errors".

This is conforming, of course; the standard doesn't distinguish between
fatal errors and non-fatal warnings; it only requires diagnostics.

[...]

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      11-15-2011
Acid Washed China Blue Jeans <(E-Mail Removed)> writes:
> In article <(E-Mail Removed)>,
> Stanley Rice <(E-Mail Removed)> wrote:
>
>> #include <stdio.h>
>> void my_print(float a, int b)
>> {
>> printf("%f\t%d\n", a, b);
>> }

>
>> All three function are defined external without declaration in file
>> main.c. But why the first two works well, but the last one fails? Is
>> it undefined in ISO C?

>
> If you don't declare a function f, it is assumed to be
> int f()
> which passes all arguments with var-args rules.


Not exactly, if by "var-args rules" you mean as if calling a variadic
function (one with ", ..." in its declaration).

Under C90 rules, the implicit declaration is for a function that returns
int with a fixed number of parameters corresponding to the promoted
types of the actual arguments in the call. So for

my_print(2.0, a);

the implicit declaration is

int my_print(double, int);

*not*

int my_print(...);

(which isn't even a valid declaration; variadic functions must have at
least one non-variadic parameter).

> So every float argument is promoted to double. However your function expects a
> float which on most machines is passed in different manner and binary format.
> Much confusion will occur.


Right.

--
Keith Thompson (The_Other_Keith) (E-Mail Removed) <http://www.ghoti.net/~kst>
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
type declaration in declaration of a parameter or return type of a function Luca Forlizzi C Programming 4 11-14-2010 09:30 PM
Can a static function declaration conflict with a non-static declaration? nospam_timur@tabi.org C Programming 4 12-12-2006 10:26 PM
maxplusII error: a deferred constant declaration without a full declaration is not supported Noah VHDL 5 04-07-2006 02:34 PM
Variable declaration taken as a function pointer declaration Bolin C++ 4 12-02-2005 05:28 PM
Function declaration in class declaration Ovidesvideo C++ 4 12-10-2004 06:36 PM



Advertisments