Unknown function

  • Thread starter Christian Christmann
  • Start date
C

Christian Christmann

Hi,

I was just going through this exercise
http://www.cas.mcmaster.ca/~franek/books/membook-answers/ch4/answers-ch4-3.html
and I'am confused about the answer.

It says: "... the compiler actually does not "know" the signature of
malloc(), hence it assumes by default, that it returns int..."

How can the function call of 'malloc' work at all if it is unknown?
I thought that each function that is unknown to the compiler at a specific
point of the program leads to an 'undefined reference' when tried
to get linked.

Can you shed some light onto it.

Thank you.

Chris
 
M

Michael Mair

Christian said:
Hi,

I was just going through this exercise
http://www.cas.mcmaster.ca/~franek/books/membook-answers/ch4/answers-ch4-3.html
and I'am confused about the answer.

It says: "... the compiler actually does not "know" the signature of
malloc(), hence it assumes by default, that it returns int..."

How can the function call of 'malloc' work at all if it is unknown?
I thought that each function that is unknown to the compiler at a specific
point of the program leads to an 'undefined reference' when tried
to get linked.

Can you shed some light onto it.

The author of this page does either not tell the whole truth (assuming
a certain kind of implementations) or does not know better (if
considered from the standard C point of view).

Without prototype in scope, malloc() indeed is assumed to return int.

The conversion from int to void * or backwards is allowed;
however, it is not guaranteed to be without loss. As char * and void *
essentially have the same size, representation and alignment, we can
treat them the same at the moment.
_If_ it is without loss, i.e. if for all possible integer and pointer
values
p = i; i = p;
and
i = p; p = i;
yield the original i and p, respectively, and sizeof i == sizeof p
then chances are good that everything works automagically.
If the return conventions of pointers and integers are different or
sizeof void * > sizeof i or the conversion is not lossless, then it
may very well go wrong, maybe always, maybe sometimes.

This is not the whole truth either; does this already answer your
question?

Cheers
Michael
 
T

Thomas Lumley

Christian said:
It says: "... the compiler actually does not "know" the signature of
malloc(), hence it assumes by default, that it returns int..."

How can the function call of 'malloc' work at all if it is unknown?
I thought that each function that is unknown to the compiler at a specific
point of the program leads to an 'undefined reference' when tried
to get linked.

No (at least not in C89)

If there is no definition or prototype the compiler assumes (because
the standard tells it to) that malloc() takes int arguments and
returns an int. As you clearly understand, this is going to be a
problem since malloc actually takes size_t and returns void *. Since
20 is a valid value to pass to a function that takes either int or
size_t, the compiler doesn't know that the argument is wrong, but it
does know that the return value is wrong, hence the warning.

It is not unusual for the code to work on a particular implementation,
since size_t is often a typedef for int, and pointers may be
implemented as integers of the same size as int. When it doesn't work,
it can just as easily be because the argument type is wrong as because
the return type is wrong. For example, on 64-bit hardware, void * and
size_t may both be 64-bit types and int a 32-bit type. The reason the
compiler complains [and is required to complain] about the return value
but not the argument is that the return value problem is easily
detectable.

The warning is misleading, since it suggests that adding a cast would
solve the problem. This is not true in general and is very unlikely to
be true in practice. Writing
p = (char *) malloc(20);
is likely to make the warning go away, but if void * return values are
passed differently than ints
or are a different size then the cast is not going to magically
retrieve the lost information. This code doesn't say "malloc returns a
char *", it says "although malloc returns an int, I want the compiler
to pretend that it is a char *". For this to be helpful you need a
strange implementation where void * and int are stored and returned
from functions in the same way but char * is stored differently.

A more helpful compiler message might mention that the return value of
int came from the "implicit int" rule rather than an actual
declaration. Something like: "use of undeclared function malloc() does
not match implicit declaration". However, it could be worse. The
Standard permits the compiler to give even less helpful messages such
as "There might be a problem with line 42".


-thomas
 
J

Jordan Abel

Hi,

I was just going through this exercise
http://www.cas.mcmaster.ca/~franek/books/membook-answers/ch4/answers-ch4-3.html
and I'am confused about the answer.

It says: "... the compiler actually does not "know" the signature of
malloc(), hence it assumes by default, that it returns int..."

How can the function call of 'malloc' work at all if it is unknown?
I thought that each function that is unknown to the compiler at a specific
point of the program leads to an 'undefined reference' when tried
to get linked.

It doesn't know the signature of malloc at phase 7, but it knows of the
existence of a function called 'malloc' at phase 8.
 
K

Keith Thompson

Thomas Lumley said:
It is not unusual for the code to work on a particular implementation,
since size_t is often a typedef for int, and pointers may be
implemented as integers of the same size as int.

Slight quibble: size_t can be a typedef for unsigned int.
 
C

Christian Christmann

Without prototype in scope, malloc() indeed is assumed to return int.
Actually this is my question.
An easy example:

int main()
{
func();
return 0;
}

void func()
{
int a = 10;
}

Of course, the compiler complains that it does not know the function
'func' in the 'mai' function since it's unknown to it at that
point of the compilation process.
So, when the author mentions on his website (I mentioned in my first
message) "the compiler actually dos not "know" the signature of
malloc()", I understand it in the way that malloc is not known to the
compiler at that specific point of program.

Or is it possible for a function to be known to the compiler without
a prototype? If so, could you give me a short example.


The casting you described in your previous message is clear now. Thank
you.

Thank you.
Chris
 
F

Flash Gordon

Christian Christmann wrote:

Please leave in attribution lines, the bits that say who said what. It
makes it easier to follow the thread.
Actually this is my question.
An easy example:

int main()
{
func();
return 0;
}

void func()
{
int a = 10;
}

Of course, the compiler complains that it does not know the function
'func' in the 'mai' function since it's unknown to it at that
point of the compilation process.
So, when the author mentions on his website (I mentioned in my first
message) "the compiler actually dos not "know" the signature of
malloc()", I understand it in the way that malloc is not known to the
compiler at that specific point of program.

Or is it possible for a function to be known to the compiler without
a prototype? If so, could you give me a short example.

There are a couple of different issues here. What the standard mandates
that the compiler must do and what the compiler can do in addition to
what the standard mandates. Also, what the standard mandates is
different in the most commonly implemented version of the standard (C90)
to the current version of the standard (C99). In the following I'm
assuming C90 (the commonly implemented standard). I'm also not going to
go in to the details of all the steps of the compilation.

The compiler first processes all the pre-processor directives, such as
#include. This in effect produces one very long source file with
everything in it which is then passed to the actual C compiler. If a
call to a function occurs in the pre-processed C file before a
definition is encounters the C standard mandates that the compiler treat
it as a function returning an int and taking an unspecified number of
parameters.

Now on to bits compilers are allowed to do but the standard does not
mandate. The standard mandates that under some conditions the compiler
produce a diagnostic (typically reported as a warning or error), such as
reporting a syntax error. However, the standard also allows the compiler
to produce diagnostics for any other reason it chooses. So, although the
compiler is required to assume malloc returns an int if it has not yet
seen a declaration of it, it is also allowed to say, "ah, but I know
malloc actually returns a void* because that is what the standard malloc
function returns, so I'm going to be nice and tell the user that they
have got it wrong." Indeed, some compilers will actually do this even
though it is not required. So in that sense a compiler writer can choose
to make the compiler "know" more than the standard says it has to know
and produce more helpful messages as a result.

So, given the following example of a *bad* program:

int main(void)
{
int i = malloc(5);
return 0;
}

The compiler is not *required* to produce an diagnostics (errors or
warnings), since it is required to assume that malloc returns an int
because it has not seen a diagnostic. However, some compilers will tell
you that this disagrees which what it knows is the standard declaration
of malloc.

A more common example of the same problem is:
int main(void)
{
int *ptr = (int*)malloc(5);
return 0;
}

Again, the compiler is required to assume that malloc returns an int,
which we all know is wrong. The cast then tells the compiler to convert
that expected in in to a pointer. So again, the compiler is *not*
required to complain. However, as before, there are some compilers that
will be helpful and complain.

As a final example, given:
int main(void)
{
int *ptr = malloc(5);
return 0;
}
The compiler is required to assume that malloc returns an int. However,
the standard also requires a diagnostic on attempting to assign an int
directly to a pointer. So due to the lack of the cast and the required
assumed return type of malloc, the compiler is *required* to produce a
diagnostic. Often the diagnostic will be something like, "attempt to
assign integer to pointer without cast" which often leads people who
don't know any better to add in the cast changing it to the previous
example.

Since malloc does not return an int, not of the examples I've given are
required to "work" whether or not the compiler complains and there are
real modern systems (some modern 64 bit systems in certain common modes)
where it will *not* work.
 
C

CBFalconer

Flash said:
.... snip ...

There are a couple of different issues here. What the standard
mandates that the compiler must do and what the compiler can do
in addition to what the standard mandates. Also, what the
standard mandates is different in the most commonly implemented
version of the standard (C90) to the current version of the
standard (C99). In the following I'm assuming C90 (the commonly
implemented standard). I'm also not going to go in to the
details of all the steps of the compilation.

The compiler first processes all the pre-processor directives,
such as #include. This in effect produces one very long source
file with everything in it which is then passed to the actual C
compiler. If a call to a function occurs in the pre-processed C
file before a definition is encounters the C standard mandates
that the compiler treat it as a function returning an int and
taking an unspecified number of parameters.

Correction. This first encountered call effectively defines the
number and type of parameters for the function. Now all other
calls should agree, but will not be checked for agreement, leading
to optimum conditions for black fly breeding.

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
 
B

Barry Schwarz

The author of this page does either not tell the whole truth (assuming
a certain kind of implementations) or does not know better (if
considered from the standard C point of view).

Without prototype in scope, malloc() indeed is assumed to return int.

This is only true in the old standard. The current standard no longer
supports this assumption.
The conversion from int to void * or backwards is allowed;
however, it is not guaranteed to be without loss. As char * and void *

While this is reasonably true, it is irrelevant. Allowing the
compiler to believe the function returns a different type than it
actually does leads to undefined behavior. Think about systems where
a pointer is returned in one type of register and an int in another or
where pointers and ints have different endian-ness.


Remove del for email
 
K

Keith Thompson

Barry Schwarz said:
On Sun, 05 Mar 2006 22:58:33 +0100, Michael Mair


This is only true in the old standard. The current standard no longer
supports this assumption.

But even a C99 compiler is free to do so, as long as it issues a
diagnostic. It's likely to allow it for backwards compatibility.
While this is reasonably true, it is irrelevant. Allowing the
compiler to believe the function returns a different type than it
actually does leads to undefined behavior. Think about systems where
a pointer is returned in one type of register and an int in another or
where pointers and ints have different endian-ness.

Right. A conversion can occur only when the compiler knows the type
of the expression and the type to which it's converted. If you call
malloc() with no visible prototype, the compiler doesn't have enough
information to perform a conversion. At best, it treats the bits of
the void* result *as if* they were an int representation (whereas a
conversion might involve a change of representation); at worst,
arbitrarily bad things can happen.
 

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,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top