Why oh why does this NOT give a compile error?


P

Paul Melis

Can someone explain to me why the following code compiles without
errors on gcc 4.0.2?

void f()
{
}

void t()
{
f(1,2,3);
f("1");
}

I would expect at least some warning, but not even that. Is this a
feature of the newest C dialect or something, that you can provide
arbitrary arguments to a function having no arguments?

Paul

And yes, I'm compiling the right file:

12:58|[email protected]:/tmp> gcc -v
Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --
infodir=/usr/share/info --enable-shared --enable-threads=posix --
enable-checking=release --with-system-zlib --enable-__cxa_atexit --
disable-libunwind-exceptions --enable-libgcj-multifile --enable-
languages=c,c++,objc,java,f95,ada --enable-java-awt=gtk --with-java-
home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre --host=i386-redhat-linux
Thread model: posix
gcc version 4.0.2 20051125 (Red Hat 4.0.2-8)
12:58|[email protected]:/tmp> cat t.c
void f()
{
}

void t()
{
f(1,2,3);
f("1");
}

int
main()
{
t();

return 0;
}
12:58|[email protected]:/tmp> gcc -o t -W -Wall t.c
12:58|[email protected]:/tmp> ls -l t
-rwxrwxr-x 1 paul paul 4659 Nov 5 12:58 t
 
Ad

Advertisements

S

santosh

Can someone explain to me why the following code compiles without
errors on gcc 4.0.2?

void f()
{
}

void t()
{
f(1,2,3);
f("1");
}

I would expect at least some warning, but not even that. Is this a
feature of the newest C dialect or something, that you can provide
arbitrary arguments to a function having no arguments?

It's a feature of "K&R" C, i.e., a pre-Standard dialect of C. For
backwards compatibility it is still legal though not recommended.

An empty parameter list in a function declaration tells the compiler
that the function takes an unspecified number and type of arguments and
turns of parameter cross-checking of invocations against the
declaration.

To specify that a function accepts no arguments put the void keyword
between the parameter list.

void f(void) { /* ... */ }

<snip>
 
J

Joachim Schmitz

santosh said:
It's a feature of "K&R" C, i.e., a pre-Standard dialect of C. For
backwards compatibility it is still legal though not recommended.
And therefore I'd expect at least a warning. And on my compiler I get one

warning(229): too many arguments in function call

Bye, Jojo
 
S

santosh

And therefore I'd expect at least a warning. And on my compiler I get
one

warning(229): too many arguments in function call

gcc needs either '-Wmissing-prototypes' or '-Wold-style-definition'
switches to produce a diagnostic. These are not included even
in '-Wall' and '-W'.
 
J

James Kuyper

Paul said:
Can someone explain to me why the following code compiles without
errors on gcc 4.0.2?

void f()
{
}

void t()
{
f(1,2,3);
f("1");
}

I would expect at least some warning, but not even that. Is this a
feature of the newest C dialect or something, that you can provide
arbitrary arguments to a function having no arguments?

No, it's a feature of the C standard that this code has undefined
behavior, but is neither a syntax error nor a constraint violation, and
therefore does not require a diagnostic message. A good compiler might
provide one. The more fundamental problem is that you should be using
function prototypes, in which case the corresponding code would require
a diagnostic message.

What compiler options are you using? With the right compiler options,
gcc can be a good compiler, though what it produces is a warning about
the more fundamental problem, rather than the one you're actually asking
about:


cc -std=c99 -pedantic -Wall -Wpointer-arith -Wcast-align -Wwrite-strings
-Wstrict-prototypes -Wmissing-prototypes -c -o ft.o ft.c
ft.c:2: warning: function declaration isn’t a prototype
ft.c:6: warning: function declaration isn’t a prototype
 
C

cr88192

santosh said:
It's a feature of "K&R" C, i.e., a pre-Standard dialect of C. For
backwards compatibility it is still legal though not recommended.

An empty parameter list in a function declaration tells the compiler
that the function takes an unspecified number and type of arguments and
turns of parameter cross-checking of invocations against the
declaration.

I guess a lot depends on if the compiler will still accept K&R style code
(mine will not, nor will it accept some aspects of C90 syntax, such as
'implicit int', being tolerant of missing prototypes, ...).

of course, I am not sure whether one can view newer C dialects as infact
proper supersets of the old dialects (say, C99 also implies full support of
C90), or if the view is more that C in itself is actually a moving target
(would seem at least implied), in truth several different languages that
happen to be closly enough related that as a general rule code works between
them without problem.

or such...
 
Ad

Advertisements

J

James Kuyper

cr88192 said:
I guess a lot depends on if the compiler will still accept K&R style code
(mine will not, nor will it accept some aspects of C90 syntax, such as
'implicit int', being tolerant of missing prototypes, ...).

A conforming implementation of C99 is required to accept functions
without prototypes. But then, you've made it clear that conformance to
any particular standard is not a priority for you.
of course, I am not sure whether one can view newer C dialects as infact
proper supersets of the old dialects (say, C99 also implies full support of
C90), or if the view is more that C in itself is actually a moving target
(would seem at least implied), in truth several different languages that
happen to be closly enough related that as a general rule code works between
them without problem.

C99 is almost completely backwards compatible with C90, and I don't
think this program is one of the exceptions to that rule (I can't be
certain, I don't have a copy of the C90 standard).
 
U

ups_genius

No, it's a feature of the C standard that this code has undefined
behavior, but is neither a syntax error nor a constraint violation, and
therefore does not require a diagnostic message. A good compiler might
provide one. The more fundamental problem is that you should be using
function prototypes, in which case the corresponding code would require
a diagnostic message.

What compiler options are you using? With the right compiler options,
gcc can be a good compiler, though what it produces is a warning about
the more fundamental problem, rather than the one you're actually asking
about:

cc -std=c99 -pedantic -Wall -Wpointer-arith -Wcast-align -Wwrite-strings
-Wstrict-prototypes -Wmissing-prototypes -c -o ft.o ft.c
ft.c:2: warning: function declaration isn't a prototype
ft.c:6: warning: function declaration isn't a prototype- Zitierten Text ausblenden -

- Zitierten Text anzeigen -

No, it's a feature of the C standard that this code has undefined
behavior, but is neither a syntax error nor a constraint violation, and
therefore does not require a diagnostic message.

Exactly!
Things that are "correct" in C might still not always be the best
solution.

Think about the following:

(array == i[array]) will return (!0)
array is the same as i[array], and it is perfectly correct in C.
But you still would not want to use it.

Why?
array == *(array+i) == *(i+array) == i[array]

Christian
 
S

Stephen Sprunk

santosh said:
It's a feature of "K&R" C, i.e., a pre-Standard dialect of C. For
backwards compatibility it is still legal though not recommended.

An empty parameter list in a function declaration tells the compiler
that the function takes an unspecified number and type of
arguments and turns of parameter cross-checking of invocations
against the declaration.

That is correct, but he provided a function _definition_, not just a
declaration.
To specify that a function accepts no arguments put the void keyword
between the parameter list.

void f(void) { /* ... */ }

I thought that the "void" in the _definition_ was unnecessary; it's only
necessary in a pure _declaration_. (Note: answer differs from C++)

I would have expected the above behavior if he'd just provided:

void f();

Also, I would have expected GCC to be smart enough to realize that f(1,2,3)
and f("1") were incompatible signatures, since f() wasn't declared as taking
varargs, and give a warning on the second call.

S
 
F

Flash Gordon

Stephen Sprunk wrote, On 05/11/07 15:19:
I thought that the "void" in the _definition_ was unnecessary; it's only
necessary in a pure _declaration_. (Note: answer differs from C++)

This has been argued to death both here and in comp.lang.c. Although
"void(f() {}" defined a function that takes no parameters it does not
provide a prototype so the compiler is not required to diagnose
parameters being passed to it. It is, of course, *allowed* to diagnose it.
I would have expected the above behavior if he'd just provided:

void f();

Also, I would have expected GCC to be smart enough to realize that
f(1,2,3) and f("1") were incompatible signatures, since f() wasn't
declared as taking varargs, and give a warning on the second call.

I would have said it was better for a compiler to diagnose it as well,
but it is not a bug as such as it is not required to.
 
M

Mike Wahler

Paul Melis said:
Can someone explain to me why the following code compiles without
errors on gcc 4.0.2?

void f()
{
}

void t()
{
f(1,2,3);
f("1");
}

I would expect at least some warning, but not even that. Is this a
feature of the newest C dialect or something, that you can provide
arbitrary arguments to a function having no arguments?

The signature:

void f()

does NOT mean 'no arguments',
it means 'unspecified arguments'.

If you want 'no arguments', write:

void t(void)

An empty parameter list means no arguments
in That Other Language, but not in C.

-Mike
 
Ad

Advertisements

C

cr88192

James Kuyper said:
A conforming implementation of C99 is required to accept functions without
prototypes. But then, you've made it clear that conformance to any
particular standard is not a priority for you.

not a priority in a strict sense, but in general, compatibility is a
worthwhile goal.

now, in my case, I don't accept implicit int, and prototypes are generally
required (probably 'odd' for a compiler intended for scripting, but oh
well).

somehow, I had thought C99 did not mandate support for these either (only,
that compilers often retained them because they were valid in C90).

C99 is almost completely backwards compatible with C90, and I don't think
this program is one of the exceptions to that rule (I can't be certain, I
don't have a copy of the C90 standard).

C99 to C90 is not so major, and infact, they should be nearly completely
compatible, but, C99 is very different from K&R...

if future standards continue this pattern, and compilers eventually drop
support for older constructions, then infact, C code from different eras can
be viewed as, effectively, different languages.

similar can be said about English as well, for example, do Shakespeare or
Twain use, strictly, the same language that we use now?... or is it infact
that they are different but closely related languages, so a modern listener
can largely understand both of these writers, but would not speak or write
as they do, and there are cases where confusion arrises.

this is much more emphasized if we consider Beowulf, which was, at the time,
English...

or, what about Cockney vs US English (various) vs Australian English ("blimy
y'all, dose be some fatty mosies, yo...").

yet, in general, we regard English as a singular language.


the only other possibility would be that each is a strict superset of the
previous, and in effect that each newer version formally included all
previously defined constructions and semantics (rather than, most of them).

however, as far as I have understood it, this may not be the case.

or such...
 
J

James Kuyper

cr88192 said:
not a priority in a strict sense, but in general, compatibility is a
worthwhile goal.

now, in my case, I don't accept implicit int, and prototypes are generally
required (probably 'odd' for a compiler intended for scripting, but oh
well).

somehow, I had thought C99 did not mandate support for these either (only,
that compilers often retained them because they were valid in C90).

Implicit int was dropped, but otherwise support for K&R style
declarations is still mandatory. It's hard to notice this fact unless
you know what to look for. The relevant standardese talks about
identifier lists and declaration lists, not "K&R" declarations.

6.7.5.3p5 says that a function declarator may have either a parameter
type list, or a an identifier list. 6.7.5.3p14 describes the meaning of
such a list.

6.9.1p1 describes the syntax of a function definition, including an
optional declaration list between the declarator and the function body.
6.9.1p5 says that "If the declarator includes a parameter type list, ...
No declaration list shall follow." 6.9.1p6 describes the required
relationship between the identifier list in a declarator, and the
declaration list that follows it.
the only other possibility would be that each is a strict superset of the
previous, and in effect that each newer version formally included all
previously defined constructions and semantics (rather than, most of them).

however, as far as I have understood it, this may not be the case.

Correct: C99 is not a strict superset of C90, and I suspect that this is
typical of updates to language standard.
 
Ad

Advertisements

C

cr88192

James Kuyper said:
Implicit int was dropped, but otherwise support for K&R style declarations
is still mandatory. It's hard to notice this fact unless you know what to
look for. The relevant standardese talks about identifier lists and
declaration lists, not "K&R" declarations.

6.7.5.3p5 says that a function declarator may have either a parameter type
list, or a an identifier list. 6.7.5.3p14 describes the meaning of such a
list.

6.9.1p1 describes the syntax of a function definition, including an
optional declaration list between the declarator and the function body.
6.9.1p5 says that "If the declarator includes a parameter type list, ...
No declaration list shall follow." 6.9.1p6 describes the required
relationship between the identifier list in a declarator, and the
declaration list that follows it.

yes, ok, good to know.

of course, this means I am theoretically obligated to support K&R style
function declarations, which at this point I do not (and am not particularly
compelled by this idea...).

Correct: C99 is not a strict superset of C90, and I suspect that this is
typical of updates to language standard.

understood.


well, in any case, I have both a subset and a superset of both...
still C IMO, but not by strict definitions.

it works...
 

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

Top