C preprocessor function macros with empty aguments

  • Thread starter Sabyasachi Basu
  • Start date
S

Sabyasachi Basu

While trying to port some stuff from Unix to Windows, I encountered a
strange behaviour of function macros with empty arguments. Here is a small
snippet which illustrates the problem:

#include <iostream>
#include <string>
using namespace std;

#define B(X, Y) Y

int main()
{
string mystr (B(, "hello world"));
cout << mystr << std::endl;

return 0;
}

This correctly prints 'hello world' when compiled with g++. However, this
program fails to compile on VC++. On going through the preprocessor output
in VC++, I found that the macro call line is:
string mystr ();
This expansion is incorrect.
g++ does the correct expansion (as documented:
http://gcc.gnu.org/onlinedocs/gcc-3.0.1/cpp_3.html#SEC15 )
and the output for the same statement for the g++ preprocessor is:
string mystr ("hello world");

On fiddling around a little more, I realised that the VC++ preprocessor
shifts to the left the non-empty arguments passed, if any. For instance, on
changing the macro definition to:
#define B(X, Y) X X
the statement string mystr (B(, "hello world")); got incorrectly
expanded on VC++ to
string mystr ("hello world" "hello world");
while g++ correctly expanded it to
string mystr ( );

I am using VC++ 6.0

-- Saby
 
A

Aggro

Sabyasachi said:
This correctly prints 'hello world' when compiled with g++. However, this
program fails to compile on VC++.

So why don't you compile it with g++ then? You can use that in Windows
also to compile windows binaries. You can get mingw from here:

http://www.mingw.org/
 
P

Paul Mensonides

Sabyasachi said:
int main()
{
string mystr (B( , "hello world"));
^^^

Passing nothing as an argument results in undefined behavior, so neither
preprocessor is "correct." In C99, this behavior is well-defined and
more-or-less works like you'd assume an empty argument should work, but this is
not yet a part of C++.

Regards,
Paul Mensonides
 
R

red floyd

Paul said:
Sabyasachi Basu wrote:



^^^

Passing nothing as an argument results in undefined behavior, so neither
preprocessor is "correct." In C99, this behavior is well-defined and
more-or-less works like you'd assume an empty argument should work, but this is
not yet a part of C++.

Regards,
Paul Mensonides

I guess the OP could use:

#define EMPTY

// yada yada yada

string mystr(B(EMPTY, "Hello World"));
 
P

Paul Mensonides

red said:
I guess the OP could use:

#define EMPTY

// yada yada yada

string mystr(B(EMPTY, "Hello World"));

Yes, so long as it only goes through one level of expansion:

#define EMPTY

#define A(x) x

A(EMPTY) // okay

#define X(p) Y(p)
#define Y(p) p

X(EMPTY) // undefined behavior

Regards,
Paul Mensonides
 
S

Sabyasachi Basu

I don't think this behaviour is undefined, going by the GNU documentation,
at least.

Here is what it has to say:
http://gcc.gnu.org/onlinedocs/gcc-3.0.1/cpp_3.html#SEC16
"You can leave macro arguments empty; this is not an error to the
preprocessor (but many macros will then expand to invalid code). You cannot
leave out arguments entirely; if a macro takes two arguments, there must be
exactly one comma at the top level of its argument list. "

Regards,
Saby
 
S

Sabyasachi Basu

I am afraid, the path is not open for me. This is a small contrived snippet
of code that I wrote to illustrate the problem. The actual software that I
need to port, runs into hundreds of thousands of lines and it needs to be
compiled with VC++ on Windows.

Regards,
Sabya
 
P

Peter van Merkerk

I don't think this behaviour is undefined, going by the GNU
documentation,
at least.

Here is what it has to say:
http://gcc.gnu.org/onlinedocs/gcc-3.0.1/cpp_3.html#SEC16
"You can leave macro arguments empty; this is not an error to the
preprocessor (but many macros will then expand to invalid code). You cannot
leave out arguments entirely; if a macro takes two arguments, there must be
exactly one comma at the top level of its argument list. "

It may be defined behaviour for the G++ compiler, however that doesn't
mean it is defined behaviour according to the C++ standard. The G++
compiler supports several features that are not defined in the C++
standard.
 
J

Jack Klein

I don't think this behaviour is undefined, going by the GNU documentation,
at least.

Here is what it has to say:
http://gcc.gnu.org/onlinedocs/gcc-3.0.1/cpp_3.html#SEC16
"You can leave macro arguments empty; this is not an error to the
preprocessor (but many macros will then expand to invalid code). You cannot
leave out arguments entirely; if a macro takes two arguments, there must be
exactly one comma at the top level of its argument list. "

Regards,
Saby

The GNU compiler does not define the language, the ISO standard does.
Omitting arguments from macros is not now, and never has been, legal
in the C++ language. It is possible to write macros with variable
arguments under the latest C standard, but not in this form.

Visual C++, at least through version 6, does not support this in
either C or C++.

If you want portability, write portable code and do not use
non-standard compiler extensions.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
 
S

Sabyasachi Basu

Yes, that would work if there were only level of macro expansion. However,
the following program is closer to what actually exists in my code. The
preprocessor correctly expands EMPTY to blank when expanding the first
level; however, it ends up in the same situation as before when it passes
that blank to the next macro.

#include <iostream>
#include <string>
using namespace std;

#define EMPTY
#define B(X, Y) Y
#define XY(X, Y) \
B(X, Y)

int main()
{
string mystr (XY(EMPTY, "hello world"));
cout << mystr << std::endl;
return 0;
}

Compiling...
testmacro.cpp
C:\Work\testmacro\testmacro.cpp(14) : warning C4003: not enough actual
parameters for macro 'B'
Linking...
testmacro.obj : error LNK2001: unresolved external symbol "class
std::basic_string<char,struct std::char_traits<char>,class
std::allocator<char> > __cdecl mystr(void)"
(?mystr@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@X
Z)
Debug/testmacro.exe : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.

testmacro.exe - 2 error(s), 1 warning(s)
 
J

Jarno A Wuolijoki

The GNU compiler does not define the language, the ISO standard does.
Omitting arguments from macros is not now, and never has been, legal
in the C++ language. It is possible to write macros with variable
arguments under the latest C standard, but not in this form.

Huh?

"Major changes from the previous edition include:
-- empty macro arguments"
 
L

LibraryUser

*** rude topposting fixed ***

Sabyasachi said:
I don't think this behaviour is undefined, going by the GNU
documentation, at least.

Here is what it has to say:
http://gcc.gnu.org/onlinedocs/gcc-3.0.1/cpp_3.html#SEC16
"You can leave macro arguments empty; this is not an error to
the preprocessor (but many macros will then expand to invalid
code). You cannot leave out arguments entirely; if a macro
takes two arguments, there must be exactly one comma at the
top level of its argument list. "

Please do not toppost, and please make up your mind if you are
dealing with C++ or with C. The languages are different.

The GNU documentation has nothing to do with what is portable in
either language. The only appropriate documentation is the
relevant ISO standards, which are available. Suitable gcc
switches can restrict gcc to standard portable code, which is the
only subject of this newsgroup (c.l.c).

For C at least, the C99 standard allows for variable argument
lists to macros, but this is not yet widely implemented. The C90
standard does not allow such. For C++ see a C++ newsgroup (I am
reading in c.l.c).

You might be best off rewriting your macros, and thus the macro
calls, for portability. Remember that macros perform text
replacement, and that the components must be suitable language
components. You could put tests in the actual macros to
eliminate specific arguments, using #if statements. Then the
calls might be something like:

B(NULL, "Hello world");
 
I

Irrwahn Grausewitz

LibraryUser said:
The GNU documentation has nothing to do with what is portable in
either language. The only appropriate documentation is the
relevant ISO standards, which are available. Suitable gcc
switches can restrict gcc to standard portable code, which is the
only subject of this newsgroup (c.l.c).
For C at least, the C99 standard allows for variable argument
lists to macros, but this is not yet widely implemented. The C90
standard does not allow such. For C++ see a C++ newsgroup (I am
reading in c.l.c).

Right. And the whole thread has been cross-posted to:

comp.lang.c, comp.lang.c++, microsoft.public.vc.language

< This reply is posted to c.l.c only :p >
 
P

Paul Mensonides

Sabyasachi said:
I don't think this behaviour is undefined, going by the GNU
documentation, at least.

Here is what it has to say:
http://gcc.gnu.org/onlinedocs/gcc-3.0.1/cpp_3.html#SEC16
"You can leave macro arguments empty; this is not an error to the
preprocessor (but many macros will then expand to invalid code). You
cannot leave out arguments entirely; if a macro takes two arguments,
there must be exactly one comma at the top level of its argument
list. "

C++ Standard - 16.3/10 - ."...If (before argument substitution) any argument
consists of no preprocessing tokens, the behavior is undefined...."

The C99 standard, explicitly allows and defines the semantics for empty
arguments--a.k.a. placemarkers.

Regards,
Paul Mensonides
 
P

Paul Mensonides

Jarno said:
Huh?

"Major changes from the previous edition include:
-- empty macro arguments"

C99 allows both placemarkers (empty arguments) and variadic arguments. Either
or both can be empty, but delineating commas are still necessary. E.g.

#define A(a, b) // ...

A() // illegal
A(,) // okay

#define B(...) // ...

B() // okay
B(,) // okay

Regards,
Paul Mensonides
 
P

Paul Mensonides

Sabyasachi said:
Yes, that would work if there were only level of macro expansion.
However, the following program is closer to what actually exists in
my code. The preprocessor correctly expands EMPTY to blank when
expanding the first level; however, it ends up in the same situation
as before when it passes that blank to the next macro.

#include <iostream>
#include <string>
using namespace std;

#define EMPTY
#define B(X, Y) Y
#define XY(X, Y) \
B(X, Y)

int main()
{
string mystr (XY(EMPTY, "hello world"));
cout << mystr << std::endl;
return 0;
}

Then do something like this:

#include <iostream>
#include <string>
using namespace std;

#define EMPTY()
#define IDENTITY(x) x EMPTY

#define B(x, y) y()
#define XY(x, y) B(x, y)

int main()
{
string mystr (XY(EMPTY, IDENTITY("hello world")));
cout << mystr << std::endl;
return 0;
}

Regards,
Paul Mensonides
 
P

Peter Nilsson

Sabyasachi Basu said:
Yes, that would work if there were only level of macro expansion. However,
the following program is closer to what actually exists in my code. The
preprocessor correctly expands EMPTY to blank when expanding the first
level; however, it ends up in the same situation as before when it passes
that blank to the next macro.

#include <iostream>
#include <string>
using namespace std;

#define EMPTY
#define B(X, Y) Y
#define XY(X, Y) \
B(X, Y)

int main()
{
string mystr (XY(EMPTY, "hello world"));
cout << mystr << std::endl;
return 0;
}

Since B and XY (via B) discard the first parameter, why don't you just use...

#define EMPTY EMPTY
 
J

Jack Klein

C99 allows both placemarkers (empty arguments) and variadic arguments. Either
or both can be empty, but delineating commas are still necessary. E.g.

#define A(a, b) // ...

A() // illegal
A(,) // okay

#define B(...) // ...

B() // okay
B(,) // okay

Regards,
Paul Mensonides

Oops, my mistake. I was aware of the variadic arguments, unaware of
the placeholders, which would make the OP's code usable, perhaps. Of
course the OP never said what version of VC he needed to use. I know
for a fact that 6.0 doesn't.

Any ideas what VC++ 7.1 claims for C99 conformance?

If he "has" to compile it with VC++, and VC++ doesn't support this,
there's always writing a program to fix the source code, perhaps
change each macro invocation into one of several closely related
macros depending on how many arguments are actually present.

Could do this in C, in Perl, in quite a few text editors, even.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
 

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,054
Latest member
TrimKetoBoost

Latest Threads

Top