Test of a preprocessor symbol defined as nothing vs. zero

K

Keith Thompson

Mark Adler said:
I wasn't worried about the minus, I was worried about the plus. Unary
plus was not always valid in C. K&R and the old Sun C didn't allow it.

Unary + was introduced by ANSI in the C89 standard. If you're using a
compiler so old that it doesn't support it, then it doesn't conform to
*any* standard, and you're likely to have worse problems than that.
 
B

Ben Bacarisse

Mark Adler said:
Oh, wait. Then there's an easy fix:

#if -FOO - -1 == 1

Should do the same thing, where - - -1 is clearly valid. Testing
... and ... it works!

Thank you all for your help. This looks like the most portable
solution.

If you are really trying to get something that works for pre-ANSI C then
you need to remember that K&R C does not say what happens in case A
where FOO is not defined. At least +1 will generate an error message on
such systems. In some K&R C implementations, undefined FOO may be
treated as if FOO were defined to be empty (though, to be honest, I
can't remember any particular behaviour).
 
F

Francois Grieu

Unary + was introduced by ANSI in the C89 standard. If you're using a
compiler so old that it doesn't support it, then it doesn't conform to
*any* standard, and you're likely to have worse problems than that.

Making the preprocessor standards-conformant is an area the compiler vendors tend to neglect. Two examples that hit me in the last 6 months:

1) An admittedly obscure embedded C compiler, claiming C90 conformance with traces of C99, under active maintenance, recognized unary + in the compiler, but not the preprocessor, due to a defect; the vendor fixed it within hours of my report.


2) A non-obscure compiler (if you visualize what I mean) won't compile:

// return the smallest of x y z
#define MIN3(x,y,z) ( (x)>(y) ? (y)>(z) ? (z) : (y) : (x) )

#define ALPHA 5
#define BETA 4
#define GAMMA 6

#if MIN3(ALPHA,BETA,GAMMA) < 2
#error "check ALPHA BETA GAMMA"
#endif

The (representative of the) vendor's comment on that bug: "We were able to reproduce this issue. But Unfortunately we will not fix this issue as it is not a common code and is not a high priority issue.Thanks for playing with our product."

https://connect.microsoft.com/VisualStudio/feedback/details/546053


Francois Grieu
 
M

Mark Adler

Unary + was introduced by ANSI in the C89 standard. If you're using a
compiler so old that it doesn't support it, then it doesn't conform to
*any* standard, and you're likely to have worse problems than that.

Age doesn't necessarily have anything to do with it. I would very much
like to live in a world where compilers (and preprocessors) that
claimed to conform to a standard actually did. A compiler can be new
and still not be compilant with C89. The standard is unfortunately not
reality -- the standard is a wish, often unfulfilled.

Mark
 
P

Peter Nilsson

[email protected] (Alan Curry) said:
|Outside of my source file, someone will do one of these
| four things:
[...]
|B.  #define FOO
|or
|C.  #define FOO 0
[...]
|The problem is that I can't find a test that distinguishes
|cases B and C.

Token-gluing with the ## operator should solve it.

Just hope the pool of crazy definitions doesn't expand to include
-DFOO=yes -DFOO=no

#include <stdio.h>

/*Insert one of A,B,C,D here*/

#define CAT(x,y) CAT2(x,y)
#define CAT2(x,y) x##y

I prefer the other way...

#ifndef CAT
#define CAT(a,b) a ## b
#define CAT2(a,b) CAT(a, b)
#define CAT3(a,b,c) CAT2(CAT2(a, b), c)
#define CAT4(a,b,c,d) CAT2(CAT3(a, b, c), d)
...
#endif

Then I use CAT said:
#ifdef FOO
# if CAT(1,FOO) == 1
#  define FOO_is_undef_or_0 0
# elif FOO
#  define FOO_is_undef_or_0 0
# else
#  define FOO_is_undef_or_0 1
# endif
#else
# define FOO_is_undef_or_0 1
#endif

% type defined.h
#define PREFIX_FOO 1 /* undefined */
#define PREFIX_0 10 /* defined 0 */
#define PREFIX_1 11 /* defined 1 */

#define CAT(a,b) a ## b
#define CAT2(a,b) CAT(a, b)

#define STR(x) #x
#define STR2(x) STR(x)

puts(STR2(CAT2(PREFIX_,FOO)));

#if !defined(FOO) || CAT2(PREFIX_,FOO) == PREFIX_0
puts("A or C");
#else
puts("B or D");
#endif

#if CAT2(PREFIX_,FOO) == PREFIX_FOO
puts("A undefined");
#elif CAT2(PREFIX_,FOO) == 0
puts("B defined blank");
#elif CAT2(PREFIX_,FOO) == PREFIX_0
puts("C defined 0");
#elif CAT2(PREFIX_,FOO) == PREFIX_1
puts("D defined 1");
#else
#error huh
#endif

% type defined.c
#include <stdio.h>

int main(void)
{
puts("#undef FOO");
#undef FOO
#include "defined.h"

puts("\n#define FOO");
#define FOO
#include "defined.h"

puts("\n#define FOO 0");
#undef FOO
#define FOO 0
#include "defined.h"

puts("\n#define FOO 1");
#undef FOO
#define FOO 1
#include "defined.h"

return 0;
}

% acc defined.c -o defined.exe

% defined.exe
#undef FOO
1
A or C
A undefined

#define FOO
PREFIX_
B or D
B defined blank

#define FOO 0
10
A or C
C defined 0

#define FOO 1
11
B or D
D defined 1

%
 
S

Stefan Ram

Ben Bacarisse said:
If you are really trying to get something that works for pre-ANSI C then
you need to remember that K&R C does not say what happens in case A
where FOO is not defined.

I remember that in the 80s, I had some (well, at least
one - I am not sure how many) compilers that only would
accept »#ifdef« or »#ifnder«, but not »#if«.

There also were those »Tiny-C« compilers (maybe with source
code listed in the Byte Magazine?), who implemented subsets
of C.

The C of 1972 did not had a preprocessor.

1972 - 1973 the preprocessor was added

The C of 1974 only had »#define« and »#include«.

Conditional compilation was added not much later, but I
was not able to find a specific date.
 
S

Stefan Ram

Mark Adler said:
Age doesn't necessarily have anything to do with it. I would very much
like to live in a world where compilers (and preprocessors) that
claimed to conform to a standard actually did.

Amazon recently partially refunded a customer 20 percent of
the price

http://www.neogaf.com/forum/showthr...67ea3e7650581cbfa3ec0&p=20573361#post20573361

of a product after the customer has advised Amazon of the EU
directive

http://eur-lex.europa.eu/LexUriServ/LexUriServ.do?uri=CELEX:31999L0044:de:HTML

, which says that a retail-dealer (not the manufacturer) has
to give a two-year warranty that a product sold really has
the features that are advertised for it. The customer had
bought a playstation 3, which was advertised to support
Linux, but now will not support Linux anymore.

According to German law, when a retail dealer sells you a
software said to compile C programs, but it does not compile
C programs, you are possibly entitled to a partial refund or
to a rescission of the purchase or to a remediation of the
defect. But due to the diffulty of the application of such
laws, one can not be sure what really will happen, when a
customer tries to get such a refund in the case of a C
compiler.

(The contents of this post follows a recent news report of
the »Heise Zeitschriften Verlag«.)
 
P

Peter Nilsson

[email protected] (Alan Curry) said:
| By the way, why is CAT2 needed?

Because the preprocessor won't expand a macro parameter and
do the ## operation in a single step, so you have to give it
2 chances. As for why it was designed that way, I have no
idea.

Why disable an option unnecessarily? Sometimes you want the
macros expanded, sometimes you don't. Maybe you don't very
often, but maybe you don't know you don't until it happens,
and then you _really_ don't want it! ;)

I've certainly had cases where I didn't want # to expand
it's argument. Why make ## different?
There would be no harm in allowing #define cat(x,y) x##y to
do the job by itself, since what it does now without the
second expansion pass is never useful.

A related problem is stopping the expansion...

#define CAT(x,y) x ## y
#define CAT2(x,y) CAT(x,y)

#define PLUS '+'
#define MINUS '-'

#define OP_PLUS 0
#define OP_MINUS 1

#ifndef TEST /* default PLUS, but allow -DTEST=MINUS
#define TEST PLUS
#endif

/* neither of these work */
#define OP_TEST CAT(OP_, TEST)
#define OP_TEST CAT2(OP_, TEST)

I want OP_TEST to expand to OP_PLUS, not OP_TEST, and
certainly not error on OP_ ## '+'.

[Of course, the solution is to do something like...

#define CHAR_PLUS '+'
#define CHAR_MINUS '-'

#define OP_PLUS 0
#define OP_MINUS 1

#ifndef TEST /* default PLUS, but allow -DTEST=MINUS
#define TEST PLUS
#endif

#define CHAR_TEST CAT2(CHAR_, TEST)
#define OP_TEST CAT2(OP_, TEST)
]
 
N

Nick

Tim Rentsch said:
Disclaimer: this idea doesn't work if the definition for FOO is
other than a simple numeric value 0 (or blank), and can fail
miserably if it's something more complicated. And, stylistically,
it's a total crock. However, you did say "any suggestions?".

#define CROCKIFY(x) x ## 15
#define C_TEST(x) CROCKIFY(x) == 13

After these macro definitions, the preprocessor test

#if C_TEST(FOO)

will include the following lines if FOO is defined as 0, and not
include the following lines if FOO is defined just as an empty
definition.

It also has the additional benefit of being very likely to generate
compilation errors if FOO is defined as anything other than blank or
a simple number (or identifier). Of course some people might not
think of that as a benefit.

That's positively, err, something.
 
O

Oliver Jackson

That's positively, err, something.

Thank you for contributing, Nick. I have given your post a 5-star
rating in Google Groups. It's posts like yours that make this
newsgroup such a valuable resource, and I think it's important that we
all take a moment to acknowledge that. Bless you, sir!
 
N

Nick

Oliver Jackson said:
Thank you for contributing, Nick. I have given your post a 5-star
rating in Google Groups. It's posts like yours that make this
newsgroup such a valuable resource, and I think it's important that we
all take a moment to acknowledge that. Bless you, sir!

I can't quite work out whether you are sarcastically getting at me for a
silly comment, or agreeing with me!

I felt that Tim's wonderful abuse of octal/decimal was well worth
pulling out of a thread and drawing more attention to. It's not like we
have too much C code posted here.
 
S

Seebs

I felt that Tim's wonderful abuse of octal/decimal was well worth
pulling out of a thread and drawing more attention to. It's not like we
have too much C code posted here.

I'm glad you did, I'd missed it, and it is BRILLIANT.

-s
 
T

Tim Rentsch

Nick said:
I can't quite work out whether you are sarcastically getting at me for a
silly comment, or agreeing with me!

I felt that Tim's wonderful abuse of octal/decimal was well worth
pulling out of a thread and drawing more attention to. It's not like we
have too much C code posted here.

I'm glad you liked it. How often do we get a code example
that so obviously satisfies the 80/20 rule as the use here
of octal/decimal does?
 
F

Francois Grieu

In another thread, on the sad state of standards-conformance in C
(and C++) compilers, and varying degree of willingness to progress
on that in compiler vendors, I wrote:

A non-obscure compiler (if you visualize what I mean) won't compile:

// return the smallest of x y z
#define MIN3(x,y,z) ( (x)>(y) ? (y)>(z) ? (z) : (y) : (x) )

#define ALPHA 5
#define BETA 4
#define GAMMA 6

#if MIN3(ALPHA,BETA,GAMMA) < 2
#error "check ALPHA BETA GAMMA"
#endif

The (representative of the) vendor's comment on that bug: "We were
able to reproduce this issue. But Unfortunately we will not fix this
issue as it is not a common code and is not a high priority issue.
Thanks for playing with our product."

A "Quality Assurance" representative for that compiler added: "Though
the case you reference is more common, since it is wrapped in a macro,
it is fairly trivial to apply the workaround you provided [adding
parenthesis]. Especially given the workaround, we do not view this
issue as one that affects a significant number of customers, and have
chosen to prioritize it below other, more serious, issues.

https://connect.microsoft.com/VisualStudio/feedback/details/546053


The aspiration to make a bug-free program seems gone; even though,
in the case of at least the preprocessor, it seems something a single
person could fulfill in at most a few weeks of work.

Comments and other experiences welcome. Also, feel free to vote at
the above URL on what you think should be done.


Francois Grieu
 
E

Eric Sosman

[...]
The (representative of the) vendor's comment on that bug: "We were
able to reproduce this issue. But Unfortunately we will not fix this
issue as it is not a common code and is not a high priority issue.
Thanks for playing with our product."

The final sentence is telling: It reveals that the vendor
considers the product to be a toy.
 

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
474,434
Messages
2,571,690
Members
48,796
Latest member
Greg L.

Latest Threads

Top