Implicit Declaration

P

prasoonthegreat

In the following code....
int putchar(int c);

static void printf(char * str)
{
putchar('H');
putchar('e');
putchar('l');
putchar('l');
putchar('o');
putchar('\n');
}


int main(void)
{
printf("Hi");
return 0;

}

Does removing the declaration int putchar(int c); from the program
invoke Undefined Behaviour????

If yes, why????
 
J

James Kuyper

In the following code....
int putchar(int c);

static void printf(char * str)
{
putchar('H');
putchar('e');
putchar('l');
putchar('l');
putchar('o');
putchar('\n');
}


int main(void)
{
printf("Hi");
return 0;

}

Does removing the declaration int putchar(int c); from the program
invoke Undefined Behaviour????

If yes, why????

In C99, it is a syntax error: "An identifier is a primary expression,
provided it has been declared as designating an object (in which case it
is an lvalue) or a function (in which case it is a function designator)."

Since there is no declaration for putchar in scope at this point,
'putchar' does not qualify as an identifier, as it would have to in
order to be parsed as a function call expression. It doesn't qualify as
anything else that could legally occur at that location, either.

In general, an implementation is allowed to accept programs that contain
syntax errors, but since the standard only describes the behavior of
programs that don't have syntax errors, the behavior is undefined by
reason of the lack of a definition.

In C90, there was a misfeature called 'implicit int'. An identifier used
in this fashion was implicitly declared as a function taking an
unspecified number of arguments and returning an 'int'. since putchar()
happens to return an 'int', this works. This "feature" was removed in
C99, because experience showed that it was highly error prone - few
mourned it's passing.
 
B

Ben Bacarisse

James Kuyper said:
In C99, it is a syntax error: "An identifier is a primary expression,
provided it has been declared as designating an object (in which case
it is an lvalue) or a function (in which case it is a function
designator)."

Note that this text is under the heading "Sematics" not under
the earlier "Syntax" heading.
Since there is no declaration for putchar in scope at this point,
putchar' does not qualify as an identifier, as it would have to in
order to be parsed as a function call expression. It doesn't qualify
as anything else that could legally occur at that location, either.

That, to me, is an odd way of putting it. To me (and I think to the C
standard as well) an identifier is simply a sequence of suitable
characters. I know there is one exception to this simple lexical view
(whether an identifier is a typedef'd name or not) but it does crop up
in this situation.
 
K

Keith Thompson

James Kuyper said:
In C99, it is a syntax error: "An identifier is a primary expression,
provided it has been declared as designating an object (in which case
it is an lvalue) or a function (in which case it is a function
designator)."

Since there is no declaration for putchar in scope at this point,
'putchar' does not qualify as an identifier, as it would have to in
order to be parsed as a function call expression. It doesn't qualify
as anything else that could legally occur at that location, either.

Correction: It does qualify as an identifier, but it doesn't qualify
as a primary expression.

The fact that a syntax rule is given in the "Semantics" section is
less than ideal, but this is a rule that can't be described directly
as a grammar production. A footnote says "Thus, an undeclared
identifier is a violation of the syntax.", so the intent is clear. I
suppose this could have been written as a constraint rather than as a
syntax rule, but there are other cases where that wouldn't work (I'm
thinking of typedefs).

[...]
 
J

jameskuyper

Ben said:
Note that this text is under the heading "Sematics" not under
the earlier "Syntax" heading.

True, but it's a syntax error because the production for a function
call requires that the thing to the left of the '(' be a postfix-
expression, and the only kind of postfix-expression that putchar
could be is a primary-expression. The clause I've cited, even though
it's in a semantics section, indicates that putchar does not qualify
as a primary-expression if it has not been declared as designating a
an object or function. Therefore, the syntax required for a function
call has not been met.
That, to me, is an odd way of putting it. To me (and I think to the C
standard as well) an identifier is simply a sequence of suitable
characters.

You're right - I should have said that it doesn't qualify as a primary-
expression. I was in a hurry - sorry!
 
B

Ben Bacarisse

jameskuyper said:
True, but it's a syntax error because the production for a function
call requires that the thing to the left of the '(' be a postfix-
expression, and the only kind of postfix-expression that putchar
could be is a primary-expression. The clause I've cited, even though
it's in a semantics section, indicates that putchar does not qualify
as a primary-expression if it has not been declared as designating a
an object or function. Therefore, the syntax required for a function
call has not been met.

I agree that is the intent, but I think it is a darned odd way of
expressing it. This is syntax that can't be expressed in the grammar
and is not documented in the sections labelled "syntax"!

<snip>
 
D

Dik T. Winter

>
> True, but it's a syntax error because the production for a function
> call requires that the thing to the left of the '(' be a postfix-
> expression, and the only kind of postfix-expression that putchar
> could be is a primary-expression.

It is strange that something that is stated in the semantics section can be
called a syntax error. In my opinion a syntax error can be a syntax error
only if it violates a production rule of the syntax. Note moreover that it
is a (non-normative) footnote where it is called a syntax error!
The only language I know where an undeclared identifier is really a syntax
error is Algol 68 (and also the use of an identifier in a context which is
not allowed for its type is a syntax). But that is only because the syntax
meta-rules carry information about type and place of declaration of
identifiers, and so a program containing an undeclared identifier can not
be produced by the syntax.
 
C

CBFalconer

In the following code....
int putchar(int c);

static void printf(char * str) { .... snip ...
putchar('\n');
}

int main(void) {
printf("Hi");
return 0;
}

Does removing the declaration int putchar(int c); from the program
invoke Undefined Behaviour????

If yes, why????

Yes, because (in c99) you need a declaration. The simplest way is
#include <stdio.h>
which will access the standard library for you. Then you don't
need your own declaration. You should not use the name "printf".
It is defined differently in the standard library.

I have indented your code. Maybe you used tab chars. Don't do
that.

Some useful references about C:
<http://www.ungerhu.com/jxh/clc.welcome.txt>
<http://c-faq.com/> (C-faq)
<http://benpfaff.org/writings/clc/off-topic.html>
<http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf> (C99)
<http://cbfalconer.home.att.net/download/n869_txt.bz2> (pre-C99)
<http://www.dinkumware.com/c99.aspx> (C-library}
<http://gcc.gnu.org/onlinedocs/> (GNU docs)
<http://clc-wiki.net/wiki/C_community:comp.lang.c:Introduction>
<http://clc-wiki.net/wiki/Introduction_to_comp.lang.c>

n869_txt.bz2 is a bzipped version of n869.txt, which was the last
draft standard available in text format, and is very handy for
searching etc. with grep and similar software.
 
K

Keith Thompson

CBFalconer said:
Yes, because (in c99) you need a declaration. The simplest way is
#include <stdio.h>
which will access the standard library for you. Then you don't
need your own declaration. You should not use the name "printf".
It is defined differently in the standard library.
[...]

Others have already answered the question, with reference to both C90
(in which the answer is no; the code remainds valid but stylistically
horrid) and C99 (in which it's a constraint violation, which means the
behavior is undefined if the compiler accepts it at all).

The declaration of "printf" is legal; the "static" keyword means it
doesn't conflict with the library function of the same name, as long
as there's no "#include <stdio.h>". Again, this is horribly bad
style, but the question was theoretical, not practical. The OP had
asked about a static declaration of printf in another thread.
 
J

James Kuyper

Dik said:
It is strange that something that is stated in the semantics section can be
called a syntax error. In my opinion a syntax error can be a syntax error
only if it violates a production rule of the syntax.

It does. It violates the production rule for a function call, because
without a prior declaration, putchar doesn't qualify as a
primary-expression.
 
J

James Kuyper

Eric Sosman wrote:
....
Under C99 rules, "No, sort of." Using an undeclared identifier
is a constraint violation

Citation, please - which constraint does it violate? I went looking for
such a constraint, but couldn't find it. The closest thing I could find
in the standard was a footnote saying that it's a syntax violation,
referring to a paragraph in a section titled "Semantics".
 
D

Dik T. Winter

> Dik T. Winter wrote: ....
>
> It does. It violates the production rule for a function call, because
> without a prior declaration, putchar doesn't qualify as a
> primary-expression.

What syntax rule does it violate? I see nothing in the *syntax* stating
something about prior declaration.
 
K

Keith Thompson

Dik T. Winter said:
It is strange that something that is stated in the semantics section can be
called a syntax error. In my opinion a syntax error can be a syntax error
only if it violates a production rule of the syntax.

I'm afraid the standard's opinion differs with yours.

Yes, I agree that it's strange. The standard *could* have said that
an undeclared identifier can be a primary-expression, but that use it
as one is a constraint violation. I'm not entirely sure why it didn't
do so.
Note moreover that it
is a (non-normative) footnote where it is called a syntax error!

Yes, but the footnote confirms what the normative text says.
Normatively, an undeclared identifier is not a primary-expression; the
fact that the use of an undeclared identifier is a syntax error is a
consequence of this.

[...]

I suspect that part of the reason it was done this way was because of
typedefs. A typedef declaration actually changes the syntax in ways
that aren't described by the grammar. Look at the grammar for
type-specifier in C99 6.7.2p1:

type-specifier:
void
char
short
...
struct-or-union-specifier
enum-specifier
typedef-name

So this:
foo obj1;
is a syntax error, because "foo" is an identifier, but this:
typedef int foo;
foo obj2;
is not, because now "foo" is a typedef-name. In effect, a typedef
name is a kind of scope-dependent keyword. (I suspect some of my many
gray hairs are the result of having to deal with this while working on
a C parser.)
 
J

James Kuyper

Dik said:
What syntax rule does it violate? I see nothing in the *syntax* stating
something about prior declaration.

The production rule for a function call requires a primary-expression.
Without a prior declaration, 'putchar' isn't a primary-expression. The
rule that says so is in a section titled semantics, but the absence of a
primary-expression from what was intended to be a function call is, in
itself, still a syntax error, regardless of whether that absence is a
due to the grammar or the semantics.
 
E

Eric Sosman

James said:
Eric Sosman wrote:
...

Citation, please - which constraint does it violate? I went looking for
such a constraint, but couldn't find it. The closest thing I could find
in the standard was a footnote saying that it's a syntax violation,
referring to a paragraph in a section titled "Semantics".

A syntax violation *is* a constraint violation (3.8p1).
 
B

Ben Bacarisse

Keith Thompson said:
I'm afraid the standard's opinion differs with yours.

Yes, I agree that it's strange. The standard *could* have said that
an undeclared identifier can be a primary-expression, but that use it
as one is a constraint violation. I'm not entirely sure why it didn't
do so.

I too think it strange, but I accept that the intent was to make
undeclared identifiers a syntax error. The intent would, in my
opinion, have been better served by some annotation to the syntax
rather than some text in a paragraph labelled "semantics". The
standard suggests that syntax and semantics are different things (as
they are in common usage) because in the introduction we learn that
clause 6 describes: "the language syntax, constraints, and semantics"
as if these were distinct things.
Note moreover that it
is a (non-normative) footnote where it is called a syntax error!

Yes, but the footnote confirms what the normative text says.
Normatively, an undeclared identifier is not a primary-expression; the
fact that the use of an undeclared identifier is a syntax error is a
consequence of this.

[...]

I suspect that part of the reason it was done this way was because of
typedefs. A typedef declaration actually changes the syntax in ways
that aren't described by the grammar. Look at the grammar for
type-specifier in C99 6.7.2p1:

type-specifier:
void
char
short
...
struct-or-union-specifier
enum-specifier
typedef-name

So this:
foo obj1;
is a syntax error, because "foo" is an identifier, but this:
typedef int foo;
foo obj2;
is not, because now "foo" is a typedef-name. In effect, a typedef
name is a kind of scope-dependent keyword. (I suspect some of my many
gray hairs are the result of having to deal with this while working on
a C parser.)

A more dramatic example is:

(x)(y)

as part of a (possibly larger) expression. It shows why 6.5.1 is so
precise about the kind of declaration that makes the identifier x (and
hence (x)) a primary expression. If x is a typedef-name, neither x
nor (x) is a primary expression. The result is not a syntax error
because (x) is then a cast operator and the whole thing is a cast
expression. If x is declared an object or a function, then x and (x)
are primary expressions and the whole thing is a function call.
 
S

Stefan Ram

Ben Bacarisse said:
standard suggests that syntax and semantics are different things (as
they are in common usage)

Indeed. I deem the »syntax« of C to be the set of all C programs,
the »semantics« maps each of those programs to a behavior.

(This paragraph is simplified and still vague - it is only
intended to give the general idea.)
 
J

James Kuyper

Eric said:
A syntax violation *is* a constraint violation (3.8p1).

"constraint
restriction, either syntactic or semantic, by which the exposition of
language elements is to be interpreted"

I've never understood what it is that the part of that definition after
the second comma was intended to convey. However, I've assumed that,
whatever it is that it means, there must be at least some violations of
syntax rules that do not qualifying as "restrictions ... by which the
exposition of language elements is to be interpreted". Otherwise, the
following portion of 5.1.1.3 contains a redundancy: "... if a
preprocessing translation unit or translation unit contains a violation
of any syntax rule or constraint ...". If you're right, they could have
simply left out the phrase "syntax rule or", without causing any change
in the meaning.

Any section titled "Constraints" clearly conveys constraints; I don't
think the definition provided in 3.8p1 is sufficiently clear to allow
unambiguous application of that term to any rule specified outside of a
"Constraints" section.
 
K

Keith Thompson

Indeed. I deem the »syntax« of C to be the set of all C programs,
the »semantics« maps each of those programs to a behavior.

(This paragraph is simplified and still vague - it is only
intended to give the general idea.)

I think you still need to consider constraints. For example, this:

int main(void) {
char *p = 1.0;
}

satisfies the syntax of a C program, but because of the constraint
violation it has no defined semantics.
 
J

jameskuyper

Eric said:
James Kuyper wrote: ....

Tempests in teapots anyhow, I think. As far as I can see, either a
constraint violation or a syntax violation (if the two are different)
elicits exactly the same response, to wit, "at least one diagnostic
message." If there's any place in the Standard where CV and SV are
given different treatment, I'm unaware of it (but would appreciate
someone pointing it out to me if it's there).

The standard certainly treats them differently, putting syntax rules
in sections named "Syntax", and summarizing them in Annex A, while it
places constraints in sections named "Constraints". Again, that would
appear to be redundant if all syntax rules also constitute
constraints.

Section 4.2 says 'If a ‘‘shall’’ or ‘‘shall not’’ requirement that
appears outside of a constraint is violated, the
behavior is undefined.'. However, that doesn't help much with making
this distinction, since the word "shall" never occurs in the Syntax
sections.
 

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,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top