#if constant expression

K

kerravon

According to 6.8 of C90, #if takes a constant expression.

According to 6.4 of C90, the sizeof operator is part of a constant
expression.

Why then do most of my compilers barf on this?

#include <stdio.h>

#if sizeof(int) >= 4
#define XXX "big"
#else
#define XXX "small"
#endif

int main(void)
{
printf("hello %s\n", XXX);
return (0);
}

They barf on the "#if sizeof ..." line.

They explicitly say that I can't use sizeof in a #if

So which bit of the standard did I miss?

BFN. Paul.
 
V

vicks

#include said:
#if sizeof(int) >= 4
#define XXX "big"
#else
#define XXX "small"
#endif

int main(void)
{
printf("hello %s\n", XXX);
return (0);

}
[code snnipet...]
So which bit of the standard did I miss?


Well I think that #if can be used only with the Macros(who gets
replaced with contant expressions at compile time) since sizeof gets
resolved at run time I dont think it's good idea to use sizeof with
#if!!

Regards
Vikas Gupta
 
J

James Kuyper

kerravon said:
According to 6.8 of C90, #if takes a constant expression.

According to 6.4 of C90, the sizeof operator is part of a constant
expression.

Why then do most of my compilers barf on this?

#include <stdio.h>

#if sizeof(int) >= 4
#define XXX "big"
#else
#define XXX "small"
#endif

int main(void)
{
printf("hello %s\n", XXX);
return (0);
}

They barf on the "#if sizeof ..." line.

They explicitly say that I can't use sizeof in a #if

So which bit of the standard did I miss?

BFN. Paul.

I don't have a copy of C90; but I suspect that this is not an area where
the differences between C90 and C99 matter. Section 6.10.1p4 of
n1256.pdf says

"After all replacements due to macro expansion and the *defined* unary
operator have been performed, all remaining identifiers (including those
lexically identical to keywords) are replaced with the pp-number 0, "

I believe that this applies to both 'sizeof' and 'int' in your example.
As a result, it becomes:

#if 0(0) >= 4

which explains why it fails.
 
T

Tomás Ó hÉilidhe

Well I think that #if can be used only with the Macros(who gets
replaced with contant expressions at compile time) since sizeof gets
resolved at run time I dont think it's good idea to use sizeof with
#if!!


sizeof yields a compile-time constant, and is very much _not_ evaluated at
runtime.
 
P

pete

kerravon said:
According to 6.8 of C90, #if takes a constant expression.

According to 6.4 of C90, the sizeof operator is part of a constant
expression.

The preprocessor can't read keywords.


ISO/IEC 9899: 1990
6.8.1 Conditional inclusion
Constraints

identifiers (including those lexically identical to keywords)
are interpreted as described below;83

83 Because the controlling constant expression
is evaluated during translation phase 4,
all identifiers either are or are not macro names
— there simply are no keywords, enumeration constants, etc.
 
Q

quarkLore

The preprocessor can't read keywords.

ISO/IEC 9899: 1990
6.8.1 Conditional inclusion
Constraints

identifiers (including those lexically identical to keywords)
are interpreted as described below;83

83 Because the controlling constant expression
is evaluated during translation phase 4,
all identifiers either are or are not macro names
-- there simply are no keywords, enumeration constants, etc.

#if is for preprocessor, sizeof is a compile time operator but not
handled at preprocessing stage. If you have gcc put sizeof in your
code and run gcc -E <soure filename> it should give you the
preprocessor output and sizeof would remain as it is.
 
F

Fancois Grieu

kerravon said:
Why then do most of my compilers barf on this?

#include <stdio.h>
#if sizeof(int) >= 4
#define XXX "big"
#else
#define XXX "small"
#endif
int main(void)
{
printf("hello %s\n", XXX);
return (0);
}

One way to see this is that sizeof is not usable in the proprocessor, which has no
knowledge of types. There is a solution, though

#include <stdio.h>
#define XXX (sizeof(int) >= 4 ? "big" : "small")
int main(void)
{
printf("hello %s\n", XXX);
return (0);
}



If you want to check at compile time that int is big:


/* cause a compile-time error if x is 0 */
#define CompileAssert(x) do{typedef struct{char f[(x)?1:-1];}assertion_failure;}while(0) /* compile time assertion failure */

#include <stdio.h>
int main(void)
{
CompileAssert(sizeof(int) >= 4);
puts("hello big");
return (0);
}


Francois Grieu
 
K

Keith Thompson

pete said:
The preprocessor can't read keywords.


ISO/IEC 9899: 1990
6.8.1 Conditional inclusion
Constraints

identifiers (including those lexically identical to keywords)
are interpreted as described below;83

83 Because the controlling constant expression
is evaluated during translation phase 4,
all identifiers either are or are not macro names
-- there simply are no keywords, enumeration constants, etc.

That quotation is from the C99 standard, not the C90 standard.

In both C90 and C99, handling of identifiers in a #if directive is
described as (C90 6.8.1, C99 6.10.1p3):

After all replacements due to macro expansion and the defined
unary operator have been performed, all remaining identifiers are
replaced with the pp-number 0, and then each preprocessing token
is converted into a token.

Technical Corrigendum 3 (incorporated into n1256) changes this to:

After all replacements due to macro expansion and the defined
unary operator have been performed, all remaining identifiers

(including those lexically identical to keywords)

are replaced with the pp-number 0, and then each preprocessing
token is converted into a token.

I've marked the added text by putting it on a separate line.

This is a clarification, not a change, since keywords are lexically
identifiers. See DR #305,
<http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_305.htm>.
(It would be nice if the TC documents referred back to the DRs.)
 
P

pete

Keith said:
That quotation is from the C99 standard, not the C90 standard.

That quotation is from the C90 standard.
I think you must be using a public draft instead.


This quotation is from the C99 standard:

ISO/IEC 9899:1999(E)
6.10.1 Conditional inclusion
Constraints

identifiers (including those lexically identical to keywords)
are interpreted as described below;140)

140) Because the controlling constant expression
is evaluated during translation phase 4,
all identifiers either are or are not macro names
— there simply are no keywords, enumeration constants, etc.
 
K

Keith Thompson

pete said:
That quotation is from the C90 standard.
I think you must be using a public draft instead.

No, I'm using a copy of the actual C90 standard, but you're right, the
quotation is from the C90 standard. I don't know how I missed that.
Apologies.

[...]
 
K

Keith Thompson

pete said:
That quotation is from the C90 standard.
I think you must be using a public draft instead.

No, I'm using a copy of the actual C90 standard, but you're right, the
quotation is from the C90 standard. I don't know how I missed that.
Apologies.

[...]
 
S

SM Ryan

# According to 6.8 of C90, #if takes a constant expression.
#
# According to 6.4 of C90, the sizeof operator is part of a constant
# expression.

You conceptual have the stages
(1) preprocessor
(2) parser
(3) code generator

sizeof is a constant in third stage (code generator) which
comes after the preprocessor. You should not expect this kind
of backwards information flow from code generator to the
preprocessor.

One work around is write a small program that does the sizeof
and then writes an include file with appropriate defines.

# #if sizeof(int) >= 4
# #define XXX "big"
# #else
# #define XXX "small"
# #endif

For example, with make you can have something like

defineXXX.c :
#include <stdio.h>
int main(int N,char **P) {
if (sizeof(int)>=4)) puts("#define XXX \"big\"");
else puts("#define XXX \"small\"");
return 0;
}

main.c:
#include <stdio.h>
#include "XXX.h"

int main(void)
{
printf("hello %s\n", XXX);
return (0);
}

makefile:
main: main.c XXX.h
cc -o main main.c
XXX.h: defineXXX
defineXXX > XXX.h
defineXXX: defineXXX.c
cc -o defineXXX defineXXX.c
 
K

Keith Thompson

SM Ryan said:
You conceptual have the stages
(1) preprocessor
(2) parser
(3) code generator

sizeof is a constant in third stage (code generator) which
comes after the preprocessor. You should not expect this kind
of backwards information flow from code generator to the
preprocessor.

One work around is write a small program that does the sizeof
and then writes an include file with appropriate defines.


For example, with make you can have something like

defineXXX.c :
#include <stdio.h>
int main(int N,char **P) {
if (sizeof(int)>=4)) puts("#define XXX \"big\"");
else puts("#define XXX \"small\"");
return 0;
}

main.c:
#include <stdio.h>
#include "XXX.h"

int main(void)
{
printf("hello %s\n", XXX);
return (0);
}

makefile:
main: main.c XXX.h
cc -o main main.c
XXX.h: defineXXX
defineXXX > XXX.h
defineXXX: defineXXX.c
cc -o defineXXX defineXXX.c

Taking the system-specific makefile syntax as an *example* of the
general approach, I'll point out that this works only when the
software is being compiled on the same system that it's being compiled
for. For cross-compilation, you'd need to arrange for the "defineXXX"
program to be executed on the target, and the output copied back to
the host system.

<OT>And you'd want "./defineXXX", not "defineXXX".</OT>
 

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

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,054
Latest member
LucyCarper

Latest Threads

Top