stringification of __LINE__: why two passes?

  • Thread starter Generic Usenet Account
  • Start date
G

Generic Usenet Account

Can someone kindly explain why stringification of the compiler
preprocessor macro __LINE__ requires two steps, instead of one? I
wanted to pass the error location of a system call to perror() and I
found that I had to use a kludgy way to stick in the line number.

Thanks,
Song

///// Code Snippet /////
#include <stdio.h>
#include <errno.h>
#include <string>

using namespace std;

#define mkstr1(X) #X
#define mkstr2(X) mkstr1(X)

#define INVALID_FD 0x10000000

main()
{
int rc;
if((rc=read(INVALID_FD, NULL, 0)) < 0)
{
string errLoc = string(__FILE__) + string(", ") +
string(mkstr2(__LINE__));
perror(errLoc.c_str());
}
}
 
V

Victor Bazarov

Generic said:
Can someone kindly explain why stringification of the compiler
preprocessor macro __LINE__ requires two steps, instead of one? I
wanted to pass the error location of a system call to perror() and I
found that I had to use a kludgy way to stick in the line number.

Macros are not recursively expanded if the expansion contains # or ##.
That's IIRC, of course.

V
 
A

Andrey Tarasevich

Generic said:
...
Can someone kindly explain why stringification of the compiler
preprocessor macro __LINE__ requires two steps, instead of one? I
wanted to pass the error location of a system call to perror() and I
found that I had to use a kludgy way to stick in the line number.
...

When you use #/## operators in macro definition, macro parameters adjacent to
#/## are substituted with actual argument tokens, but no further recursive macro
replacement takes place. This means that if you use another macro as the actual
argument, this macro will not be recursively replaced.

For example, in your case, if you use 'mkstr1(__LINE__)' what you'll get is
string literal "__LINE__", which normally is not the desired result. But if you
use 'mkstr2(__LINE__)' the recursive replacement of '__LINE__' with the actual
line number will take place early (at the "first pass") and by the time it gets
to # it will already be converted to a number.
 
C

CBFalconer

Generic said:
Can someone kindly explain why stringification of the compiler
preprocessor macro __LINE__ requires two steps, instead of one? I
wanted to pass the error location of a system call to perror() and I
found that I had to use a kludgy way to stick in the line number.

///// Code Snippet /////
#include <stdio.h>
#include <errno.h>
#include <string>

using namespace std;

This is a syntax error in C. You probably want comp.lang.c++.
 
T

Thad Smith

Generic said:
Can someone kindly explain why stringification of the compiler
preprocessor macro __LINE__ requires two steps, instead of one? I
wanted to pass the error location of a system call to perror() and I
found that I had to use a kludgy way to stick in the line number.

///// Code Snippet /////
#include <stdio.h>
#include <errno.h>
#include <string>

using namespace std;

#define mkstr1(X) #X
#define mkstr2(X) mkstr1(X) ....
string errLoc = string(__FILE__) + string(", ") +
string(mkstr2(__LINE__));

This is so that it is possible to convert the argument without macro
substitution. For example:

#include <assert.h>
#define IN_RANGE(x) ((x) > 5 && (x) < 10))
....
assert (IN_RANGE(x));

The assert macro can use the # operator to convert the argument
IN_RANGE(x) to "IN_RANGE(x)" rather than the macro expanded version.

If you want the macro substitution first, you must invoke another macro
which has the # operator, as you did. The substitution happens as part
of the first macro expansion since it does not have a preceding # or
adjacent ## preprocessor token.
 
B

Bart

CBFalconer said:
This is a syntax error in C. You probably want comp.lang.c++.

Ironically, the implicit int for main also makes this invalid in C++.

Regards,
Bart.
 

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,999
Messages
2,570,243
Members
46,836
Latest member
login dogas

Latest Threads

Top