using macros ...

M

Mark McIntyre

True, true... (pun not intended), but like I said in my previous reply,
why would anyone *want* to name their function "TRUE"?

Well, DS9K's compiler has a language extension function
int TRUE(void)
{
return cmos.status.power_is_switched_on;
}
 
E

Eric Sosman

Richard said:
So, erm... please explain how, exactly,

enum predefined_values {no, yes};

is any less namespace-polluting than

#define NO 0
#define YES 1

Slight thread drift, but true horror story: I once
tracked down a bug in code written by someone who believed
firmly that enum's were superior to macros as a way to
introduce manifest integer constants. He had all sorts of
high-falutin' theoretical grounds for his preference, but
the bug he'd committed cast doubt on just how much weight
his opinions deserved:

typedef enum { TRUE, FALSE } Boolean;
 
D

Dan Pop

In said:
Slight thread drift, but true horror story: I once
tracked down a bug in code written by someone who believed
firmly that enum's were superior to macros as a way to
introduce manifest integer constants. He had all sorts of
high-falutin' theoretical grounds for his preference, but
the bug he'd committed cast doubt on just how much weight
his opinions deserved:

typedef enum { TRUE, FALSE } Boolean;

An excellent device for code obfuscation purposes!

Dan
 
J

Joona I Palaste

An excellent device for code obfuscation purposes!

Other such devices include:
typedef struct { /* ... */ } ínt;
but that would not be portable across systems with different charsets.
 
D

Dan Pop

In said:
Other such devices include:
typedef struct { /* ... */ } ínt;
but that would not be portable across systems with different charsets.

Much simpler and perfectly portable:

#define int double

*after* including all the headers. Use "signed" when you really mean
"int". Yup, the standard allows it!

Dan
 
E

E. Robert Tisdale

Richard said:
So, erm... please explain how, exactly,

enum predefined_values {no, yes};

is any less namespace-polluting than

#define NO 0
#define YES 1
> cat main.c
#include<stdio.h>
#define NO 0
#define YES 1

int main(int argc, char* argv[]) {
int YES = 1;
return 0;
}
> gcc -Wall -std=c99 -pedantic -O2 -o main main.c
main.c: In function `main':
main.c:7: parse error before numeric constant
> cat main.c
#include<stdio.h>
typedef enum answer { NO, YES } answer;

int main(int argc, char* argv[]) {
int YES = 1;
return 0;
}
> gcc -Wall -std=c99 -pedantic -O2 -o main main.c
main.c: In function `main':
main.c:7: warning: unused variable `YES'
 
B

Ben Pfaff

Much simpler and perfectly portable:

#define int double

*after* including all the headers. Use "signed" when you really mean
"int". Yup, the standard allows it!

Really? Then the following should also be allowed, but GCC
chokes on it:

#include <stddef.h>

#define void

int main(void) {
int *p = NULL;
return 0;
}
 
C

Christopher Benson-Manica

C preprocessor macros are dangerous -- in the wrong
hands, as are all C constructs. The error in the example
above suggests that ERT's hands may not be the right ones,
and may go some ways toward explaining why he finds macros
dangerous. Programmers who deploy a little more skill and
a little more care will find macros both safe and helpful.

For my info, what *is* the error in the above code? </stupid question>
 
M

Mark Gordon

Really? Then the following should also be allowed, but GCC
chokes on it:

#include <stddef.h>

#define void

int main(void) {
int *p = NULL;
return 0;
}

Depending on how NULL is defined that could expand to

int main() {
int *p = (*)0;
return 0;
}

which I would not expect to be valid.
 
B

Ben Pfaff

Mark Gordon said:
Depending on how NULL is defined that could expand to

int main() {
int *p = (*)0;
return 0;
}

which I would not expect to be valid.

Follow along, please: that's the point. Dan claimed that
#define'ing a keyword is portable as long as it is done after
header inclusion. I said it's not and showed an example.
 
B

Ben Pfaff

Christopher Benson-Manica said:
For my info, what *is* the error in the above code? </stupid question>

1. it doesn't define SUCCESS but it does reference it.
2. The TRUE as !FALSE "trick" is pointless, since !0 == 1.
3. I haven't ever run into any C code that TRUE and FALSE really
clarified.
4. Shouldn't moduleName_OK have some moduleName_NOTOK
counterpart?

A 20-line signature is clearly too long.
 
A

Arthur J. O'Dwyer

Mark Gordon said:
Ben Pfaff said:
(e-mail address removed) (Dan Pop) writes:
Much simpler and perfectly portable:

#define int double

*after* including all the headers. Use "signed" when you really
mean "int". Yup, the standard allows it!

#include <stddef.h>
#define void
int main(void) {
int *p = NULL;
return 0;
}
[expands to:]
int *p = (*)0;
Follow along, please: that's the point. Dan claimed that
#define'ing a keyword is portable as long as it is done after
header inclusion. I said it's not and showed an example.

Well, really Dan only said that

#define int double

was portable (as long as, etc). So you could have given a
counterexample to *that* statement, instead of the general
case (which I'm sure Dan considered). Can constant expressions
contain casts? In that case,

#define NULL ((void*)((int)1-1))

could break Dan's *actual* suggestion, as well. Or even

#define NULL ((void *)(sizeof(int)-sizeof(int)))

which I *know* is a correct definition of NULL (don't I?).

-Arthur
 
C

Christopher Benson-Manica

Ben Pfaff said:
A 20-line signature is clearly too long.

My apologies - my newsreader complains when I have more quoted text than new
text, and I felt that more than one line of context was appropriate...
 
D

Dave Vandervies

Well, really Dan only said that

#define int double

was portable (as long as, etc). So you could have given a
counterexample to *that* statement, instead of the general
case (which I'm sure Dan considered). Can constant expressions
contain casts? In that case,

#define NULL ((void*)((int)1-1))

could break Dan's *actual* suggestion, as well. Or even

#define NULL ((void *)(sizeof(int)-sizeof(int)))

which I *know* is a correct definition of NULL (don't I?).

I don't see the #define that Dan suggested breaking this. After expanding
the "int" macro, it would become:
#define NULL ((void *)(sizeof(double)-sizeof(double)))
sizeof(double) will have the same value (of type size_t) both places it
occurs, so this is still casting an integer constant expression with
value 0 to void *, and is no less a valid definition of NULL if "int"
means double than if "int" means int.

Can an implementation legally define macros that rely on int really
meaning int? I think your first example is valid, and in this case
Dan's #define will break code that uses it.

Alternately, either the programmer isn't allowed to define preprocessor
macros with the same names as type names (perhaps all keywords?), or the
implementation really should do something like "typedef void *__voidptr"
and use a cast to __voidptr in NULL (and do something similar for other
type names it uses in macros) instead of using type names that the
programmer is allowed to mangle.


dave
 
R

Richard Bos

E. Robert Tisdale said:
Richard said:
So, erm... please explain how, exactly,

enum predefined_values {no, yes};

is any less namespace-polluting than

#define NO 0
#define YES 1
cat main.c
#include<stdio.h>
#define NO 0
#define YES 1

int main(int argc, char* argv[]) {
int YES = 1;

This is a stupid idea...
return 0;
}

main.c: In function `main':
main.c:7: parse error before numeric constant

....for which you get an error. Not a very cryptic error, either.
cat main.c
#include<stdio.h>
typedef enum answer { NO, YES } answer;

int main(int argc, char* argv[]) {
int YES = 1;

This is an equally stupid idea...
return 0;
}

main.c: In function `main':
main.c:7: warning: unused variable `YES'

....for which you don't even get an error.

Richard
 
D

Dan Pop

In said:

Really! Try to find a chapter and verse prohibiting it! The only such
prohibition is explicitly related to standard header inclusion:

7.1.2 Standard headers
....
4 ... The program shall not have any macros with names lexically
identical to keywords currently defined prior to the inclusion.
^^^^^^^^^^^^^^^^^^^^^^
Such a specification would be completely superfluous in the library
clause if the language prohibited the definition of such macros. Instead,
the standard explicitly says:

6.4.1 Keywords
....
2 The above tokens (case sensitive) are reserved (in translation
^^^^^^^^^^^^^^
phases 7 and 8) for use as keywords, and shall not be used
^^^^^^^^^^^^^^
otherwise.
Then the following should also be allowed, but GCC
chokes on it:

#include <stddef.h>

#define void

int main(void) {
int *p = NULL;
return 0;
}

You can't prove anything about the C standard by invoking the behaviour
of one implementation.

This is a known problem with the C standard and it poses a problem
to implementors who want to get it right: they can't use *any*
keywords in their macro definitions, they have to replace them by
reserved identifiers. A *correct* <stddef.h> would have to contain
code like this:

#ifndef __VOID
typedef void __void;
#define __VOID
#endif

#ifndef NULL
#define NULL ((__void *)0)
#endif

The typedef is safe, because void can't be a macro at the time a standard
header is included and __void is an unconditionally reserved identifier.

In this particular case, it's much easier to define NULL as a plain 0 and
get rid of all the complications, but there are other standard macros
that must be carefully defined to survive this kind of abuse.

Dan
 
J

Jun Woong

Dave Vandervies said:
Alternately, either the programmer isn't allowed to define preprocessor
macros with the same names as type names (perhaps all keywords?), or the
implementation really should do something like "typedef void *__voidptr"
and use a cast to __voidptr in NULL (and do something similar for other
type names it uses in macros) instead of using type names that the
programmer is allowed to mangle.

The latter, which makes it very tricky to implement the standard
library corretly. One of the problems is that it's possible for
"sizeof" to be masked with macros in which case typedef doesn't work.
 
D

Dan Pop

The latter, which makes it very tricky to implement the standard
library corretly.

Well, the implementor can "shadow" each keyword by an alias with the same
name, but prefixed by a double underscore and use the aliases in the
standard headers.

The things get hairy only for people trying to provide "portable"
implementations of the standard library, because they can't afford this
luxury. The standard types can be easily typedef'ed to reserved
identifiers, but there is no similar workaround for the other keywords.

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top