standard functions as macros

V

vippstar

This question might be OT I apologise if it is.

All functions are allowed to be macros.
In a hypothetical implementation a tolower might be written as:

#define tolower(x) \
(x) == 'A' ? 'a' : \
(x) == 'B' ? 'b' : \
/* etc */
(x) == 'Z' ? 'z' : (x)

Ofcourse this has other problems (example if you pass i++ to it) but
we don't care about that now.

What I care about is 2 things:

o How does the compiler warn about incorrect arguments passed/etc?
Normally the preprocessor will change the source code, for example:

int add_one(int x);
#define add_one(x) ((x)+1)
/* ... */
char foo[2];
char * p = foo;
char * s = add_one(p); /* at this point, the compiler won't see a
'call to add_one since it would be replaced by the pp. */

o How does the macro work if I don't pass any arguments?
example:
int foo(unsigned x);
#define foo(x) (~(x))
/* ... */
int (*ptr)(void) = foo; /* how does that work? */

My tolower() macro example would not work in both cases.


thank you for your answers
 
V

vippstar

o How does the macro work if I don't pass any arguments?
example:
int foo(unsigned x);
#define foo(x) (~(x))
/* ... */
int (*ptr)(void) = foo; /* how does that work? */
What I ment here is int (*ptr)(int), I changed the function while I
was posting but I forgot to change ptr.
 
R

Richard Bos

All functions are allowed to be macros.

With caveats.
In a hypothetical implementation a tolower might be written as:

#define tolower(x) \
(x) == 'A' ? 'a' : \
(x) == 'B' ? 'b' : \
/* etc */
(x) == 'Z' ? 'z' : (x)

Ofcourse this has other problems (example if you pass i++ to it) but
we don't care about that now.

What I care about is 2 things:

o How does the compiler warn about incorrect arguments passed/etc?

Depends on the implementation
Normally the preprocessor will change the source code, for example:

int add_one(int x);
#define add_one(x) ((x)+1)
/* ... */
char foo[2];
char * p = foo;
char * s = add_one(p); /* at this point, the compiler won't see a
'call to add_one since it would be replaced by the pp. */

Some implementations will remember this, and use the proper name to
complain. Some will not.
o How does the macro work if I don't pass any arguments?
example:
int foo(unsigned x);
#define foo(x) (~(x))
/* ... */
int (*ptr)(void) = foo; /* how does that work? */

This, at least, works: the macro foo is not the same macro as foo().

Richard
 
V

vippstar

This, at least, works: the macro foo is not the same macro as foo().
Ah, this is what I had in mind too, therefore the implementation must
provide a function pointer 'x' that does the equivalent of the macro
'x()'.
Thanks for clearing this Richard.
 
J

James Kuyper

Ah, this is what I had in mind too, therefore the implementation must
provide a function pointer 'x' that does the equivalent of the macro
'x()'.

This is explicitly required by the standard for any standard library
function implemented as a function-like macro. Note, however, that some
standard library features are explicitly described as function-like
macros, such as in <stdarg.h>. In those cases, there is no underlying
function that can be called.
 
A

Army1987

vippstar said:
This question might be OT I apologise if it is.

All functions are allowed to be macros.
In a hypothetical implementation a tolower might be written as:

#define tolower(x) \
(x) == 'A' ? 'a' : \
(x) == 'B' ? 'b' : \
/* etc */
(x) == 'Z' ? 'z' : (x)

Ofcourse this has other problems (example if you pass i++ to it) but
we don't care about that now.
No. Macro implementations are required to evaluate each argument exactly
once, and to have enough parentheses.
What I care about is 2 things:

o How does the compiler warn about incorrect arguments passed/etc?
Normally the preprocessor will change the source code, for example:

int add_one(int x);
#define add_one(x) ((x)+1)
/* ... */
char foo[2];
char * p = foo;
char * s = add_one(p); /* at this point, the compiler won't see a
'call to add_one since it would be replaced by the pp. */

So what? Of course, the macro implementation of a standard library
function must have the right type, so it'd be ((int)(x)+1). So the
compiler *can* see that there's something wrong.
o How does the macro work if I don't pass any arguments?
example:
int foo(unsigned x);
#define foo(x) (~(x))
/* ... */
int (*ptr)(void) = foo; /* how does that work? */
The identifier foo gets replaced by the preprocessor only if immediately
followed by a ( token. ("Immediately" here includes the case in which
there is whitespace/comments between them.)
 
P

pete

Army1987 said:
No. Macro implementations are required to
evaluate each argument exactly once,
and to have enough parentheses.

putc and getc macros
may evaluate their stream argument more than once.
 
H

Harald van Dijk

putc and getc macros
may evaluate their stream argument more than once.

assert is a macro and may not evaluate its argument at all, depending on
NDEBUG.

But that's because special permissions or requirements are explicitly
stated. Since no such special permissions or requirements apply to
tolower, the general requirements apply, which do state each argument
must be evaluated exactly once.
 

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

Latest Threads

Top