Syntax error?

J

Jeremy Yallop

Looking over some code I came across a line like this

if isalnum((unsigned char)c) {

which was accepted by the compiler without complaint. Should the
compiler have issued a diagnostic in this case? (I think it's not
required to, but I'd like confirmation).

Jeremy.
 
D

Dave Vandervies

Looking over some code I came across a line like this

if isalnum((unsigned char)c) {

which was accepted by the compiler without complaint. Should the
compiler have issued a diagnostic in this case? (I think it's not
required to, but I'd like confirmation).

isalnum probably expands to something that's wrapped with parens.
F'rexample, on a random system readily accessible to me:
--------
dave@hct-cvs:~/clc (0) $ cat jy-for-syntax-expand-isalnum.c
#include <ctype.h>
#include <stdio.h>

#define STR(x) STR_(x)
#define STR_(x) #x

int main(void)
{
printf("isalnum(x) expands to %s\n",STR(isalnum(x)));

return 0;
}
dave@hct-cvs:~/clc (0) $ gcc -W -Wall -ansi -pedantic -O -c jy-for-syntax-expand-isalnum.c
dave@hct-cvs:~/clc (0) $ ./a.out
isalnum(x) expands to (__ctype_b[(int) ((x))] & (unsigned short int) _ISalnum)
dave@hct-cvs:~/clc (0) $
--------
so "if isalnum(foo)" would be expanded to
"if (expansion_of_isalnum_with_parens)", which is valid.

If this weren't the case it would be, if I'm not mistaken, a syntax
error that requires a diagnostic. GCC appears to agree with me:
--------
dave@hct-cvs:~/clc (0) $ cat jy-for-syntax-broken-if.c
int bogus_function(int);

#include <stdio.h>

int main(void)
{
if bogus_function(42)
{
puts("bogus_function() returned nonzero");
}

return 0;
}
dave@hct-cvs:~/clc (0) $ gcc -W -Wall -ansi -pedantic -O -c jy-for-syntax-broken-if.c
jy-for-syntax-broken-if.c: In function `main':
jy-for-syntax-broken-if.c:7: parse error before `bogus_function'
jy-for-syntax-broken-if.c:10: warning: control reaches end of non-void function
dave@hct-cvs:~/clc (1) $
 
K

Kevin Goodsell

Jeremy said:
Looking over some code I came across a line like this

if isalnum((unsigned char)c) {

which was accepted by the compiler without complaint. Should the
compiler have issued a diagnostic in this case? (I think it's not
required to, but I'd like confirmation).

Presumably this is accepted because 'isalnum' is a macro that happens to
have a form that makes the syntax valid. You probably knew that already,
but some people reading might not.

I don't know for sure, but I don't think the standard mandates anything
particular about the form of the 'is*' and 'to*' macros (if they even
exist), other than the requirement that they evaluate their argument
exactly once.

-Kevin
 
E

Eric Sosman

Jeremy said:
Looking over some code I came across a line like this

if isalnum((unsigned char)c) {

which was accepted by the compiler without complaint. Should the
compiler have issued a diagnostic in this case? (I think it's not
required to, but I'd like confirmation).

It's bad code, but not necessarily incorrect code.
For example, here's one of the several definitions of
isalnum() on the system I happen to be using at the
moment (exactly which definition you get depends on a
lot of environmental things):

#define isalnum(c) (__ctype_mask[c] & _ISALNUM)

Note the parentheses surrounding the replacement. Once
the macro is expanded in the context you've shown, you'll
have

if (__ctype_mask((unsigned char)c) & _ISALNUM) {

.... which is syntactically correct (as far as it goes).

Of course, relying on this would be a mistake.
 
C

CBFalconer

Jeremy said:
Looking over some code I came across a line like this

if isalnum((unsigned char)c) {

which was accepted by the compiler without complaint. Should the
compiler have issued a diagnostic in this case? (I think it's not
required to, but I'd like confirmation).

It is necessary and absolutely correct, apart from the missing set
of parenthesis. isalnum() is a standard function, prototyped in
ctype.h. The standard (N869) says:

7.4 Character handling <ctype.h>

[#1] The header <ctype.h> declares several functions useful
for testing and mapping characters.155) In all cases the
argument is an int, the value of which shall be
representable as an unsigned char or shall equal the value
of the macro EOF. If the argument has any other value, the
behavior is undefined.

Without the cast the result would be undefined on any system where
char is signed.
 
P

Peter Nilsson

Jeremy Yallop said:
Looking over some code I came across a line like this

if isalnum((unsigned char)c) {

which was accepted by the compiler without complaint. Should the
compiler have issued a diagnostic in this case? (I think it's not
required to, but I'd like confirmation).

Jeremy.

The macro issue aside...

5.1.1.3 Diagnostics

1 A conforming implementation shall produce at least one diagnostic message
(identified in an implementation-defined manner) if a preprocessing
translation unit or translation unit contains a violation of any syntax
rule or constraint,...
 
J

Jeremy Yallop

Eric said:
It's bad code, but not necessarily incorrect code.

Thanks for the responses, everyone. They answered the question I
/meant/ to ask, although my post was a bit elliptic. For the record,
what I wanted to ask regarding the line of code above was something
like:

"I know that a syntax error requires a diagnostic. Clearly the
code above contains a syntax error if "isalnum" is a normal
function. Ony my system, isalnum is (also) defined as a macro
which expands to an expression enclosed in parentheses. As this
makes the above syntactically valid, no warning is issued. Is
this allowed? i.e. can the macro alternative to a standard
function expand into code that stops the issuance of a diagnostic
that would otherwise be required?"
Of course, relying on this would be a mistake.

Understood :).

Jeremy.
 
D

Dan Pop

In said:
Looking over some code I came across a line like this

if isalnum((unsigned char)c) {

which was accepted by the compiler without complaint. Should the
compiler have issued a diagnostic in this case? (I think it's not
required to, but I'd like confirmation).

It entirely depends on what the compiler is seeing in translation phase 7,
when the syntactical analysis of this statement takes place. If there is
an "#undef isalnum" in effect anywhere between the inclusion of <ctype.h>
and this statement, the diagnostic is required, of course.

Your example is no different from

if FOO {

Dan
 

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,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top