2

I'm using stringizing operator to convert parameter which may contains comma passed to a macro into string. As I know, some characters cannot be stringified – notably, the comma(,) because it is used to delimit parameters and the right parenthesis()) because it marks the end of the parameter. So I use a variadic macro to pass commas to the stringizing operator like this:

#include <stdio.h>

#define TEST 10, 20

#define MAKE_STRING(...)  #__VA_ARGS__
#define STRING(x)       MAKE_STRING(x)

int main()
{
    printf("%s\n", STRING(TEST) );
    return 0;
}

it works fine. But it occurs to me what would happen without variadic macro, so I modify the macro: #define MAKE_STRING(x) #x. It compiles fine unexpectedly in visual c++ 2008/2010, and output 10, 20 while gcc/clang give the compilation error as expected:

macro "MAKE_STRING" passed 2 arguments, but takes just 1

So my question: is the Visual c++ doing additional work or the behavior is undefined?

jfly
  • 7,715
  • 3
  • 35
  • 65
  • @AlecTeal maybe he mean stringification – WileTheCoyot Mar 24 '14 at 11:43
  • @WileTheCoyot you can't do that with __VA_ARGS__ -GCC has a special case - hold. – Alec Teal Mar 24 '14 at 11:44
  • 1
    @WileTheCoyot don't delete your answer! You had good stuff in it! What you said is right! The OP wants nonsense! – Alec Teal Mar 24 '14 at 11:47
  • @AlecTeal now i have undeleted it, i have deleted because it does not answered the question – WileTheCoyot Mar 24 '14 at 11:49
  • 1
    All these macro replacement rules are quite complicated and have too many fine points - but I can see nothing in the Macro Replacement section of the C99 standard which might justify what VC++ does. But after all, VC++ is not C99 compliant. – ach Mar 24 '14 at 11:50
  • OP has changed the question, see argument prescan which can be found by http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html#Variadic-Macros that page. You really ... the pre-processor is thick, it can't recurse and comes from the days before we had enough ram for a compiler to think about inlining, it didn't even have enough to think about variables being in a register rather than on the stack, hence `register`, then when we had a smidgen more ram, we had the inline keyword, then we had more ram, so could do smarter things, and the compiler ignores us now, it knows best. – Alec Teal Mar 24 '14 at 12:10
  • The pre-processor is for those inline things, constants we don't want to put in a symbol table (and thus loose performance) and conditionally "allowing" swaths of code (`#ifdef`) and for allowing us to add chunks of boilerplate code to our code without find-and-replace (see my `REGISTER_THING` example). – Alec Teal Mar 24 '14 at 12:11

3 Answers3

1

VS in general allows extra parameters in macros and then just drops them silently: STRING(10, 20, 30) - still works and prints 10. This is not the case here, but it pretty much means VS don't even have the error gcc threw at you.

It's not any additional work but "merely" a difference in substitution order.

Agent_L
  • 4,960
  • 28
  • 30
-1

I am not sure if this will answer your question but i hope this will help you solving your problem. When defining a string constant in C, you should include it in double quotes (for spaces). Also, the # macro wrap the variable name inside double quotes so, for example, #a become "a".

#include <stdio.h>

#define TEST "hello, world"
#define MAKE_STRING(x) #x

int main()
{
    int a;
    printf("%s\n", TEST);
    printf("%s\n", MAKE_STRING(a));
    return 0;
}

I compiled this code using gcc 4.7.1 and the output is:

hello, world
a
WileTheCoyot
  • 513
  • 1
  • 5
  • 20
  • Rep is pretty arbitrary, so if you have a post that demonstrates something that ANYONE from the future may appreciate reading; leave it up. Like once someone was asking about a GUI with buttons in C++, they added after that it had to be the windows API, so I added a paragraph of sympathy and left my answer about wxWidgets providing a lovely API up :P This is useful, this is what `#` is for, the OP wants nonsense! – Alec Teal Mar 24 '14 at 11:52
  • I don't need a constant string, it's just a test. – jfly Mar 24 '14 at 12:19
  • An example btw, http://stackoverflow.com/questions/18453261/salted-password-validation-in-php/18453449#18453449 there's useful stuff in that answer about surjective (onto) functions, it gets a new downvote every 2 months though. The -8 points or whatever is worth it if someone understands how hashes are secure because of it. (Got a fresh downvote, reminded of you) – Alec Teal Mar 24 '14 at 12:27
  • @AlecTeal tnaks for the tip. I can't downvote because i don't have 125 rep :) – WileTheCoyot Mar 24 '14 at 12:54
  • I hope you mean this question, I can see the humour of downvoting someone who has told you not to care about downvoting, but you should upvote good info. Provided it is (vaguely) related. An answer that read "Never buy the extended warranty on anything!" is the most sound advice one person can give to another, and they should live their lives by it, anyway such an answer should not be upvoted :P Also never downvote competing answers if it is right but less descriptive than yours, downvote it if it is wrong or totally misleading (eg: "PHP is great") – Alec Teal Mar 24 '14 at 13:03
  • usually i only upvote answers that helps to solve the problem or that explain why the issue occurr (i have nerver downvote), but when you do your best to help who ask the question and you get downvotes, for me is not a good think – WileTheCoyot Mar 24 '14 at 13:09
-2

I dunno why this has upvotes, or an answer got downvoted (so the poster deleted it) but I don't know what you expect!

#__VA_ARGS__ makes no sense, suppose I have MACRO(a,b,c) do you want "a,b,c" as the string?

http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html#Variadic-Macros

Read, that became standard behaviour, variable length arguments in macros allow what they do in variable length arguments to functions. The pre-processor operates on text!

The only special case involving # is ##, which deletes a comma before the ## if there are no extra arguments (thus preventing a syntax error)

NOTE:

It is really important you read the MACRO(a,b,c) part and what do you expect, a string "a,b,c"? or "a, b, c" if you want the string "a, b, c" WRITE THE STRING "a, b, c"

Using the # operator is great for stuff like

#define REGISTER_THING(THING) core_of_program.register_thing(THING); printf("%s registered\n",#THING);
Alec Teal
  • 5,770
  • 3
  • 23
  • 50
  • 2
    `#__VA_ARGS__` is legitimate. 6.10.3.1/2: "An identifier `__VA_ARGS__` that occurs in the replacement list shall be treated as if it were a parameter…" 6.10.3.2/1: "Each `#` preprocessing token in the replacement list for a function-like macro shall be followed by a parameter as the next preprocessing token in the replacement list." Both requirements are met here. – ach Mar 24 '14 at 11:54
  • I've know what you say above, the question is why the code works without variadic macro in vc++. – jfly Mar 24 '14 at 12:00
  • Not sure I agree @AndreyChernyakhovskiy - `__VA_ARGS__` is not just the text occurring after a bracket or comma before another bracket, it may SOMETIMES behave like it, but it is not. http://gcc.gnu.org/onlinedocs/cpp/Stringification.html#Stringification and other pages are the source of my info, I tend to stick to GNU extensions and stuff like that and fall back onto the standard, as it usually goes above and beyond with useful and functional (as in "good for getting work done" not programming style) additions. – Alec Teal Mar 24 '14 at 12:01
  • @jfly oh ... There are many questions about Microsoft and Microsoft related things that are best unanswered, like "who thought the registry was a smart idea?" (I'd get it if UNIX stuff didn't come like 20-30 years before) or "I know! Drive letters!" or "Lets remove all the colour from VS icons and make the menu bar the same, but all in caps" (I read an article about that) or "the entire of internet explorer" with its non-standard events that libraries exist solely to bridge. Or the Xbone (Xbox one), or that silly two-OSs-in-one that looks the same across platforms, but has 3 separate APIs. – Alec Teal Mar 24 '14 at 12:04
  • @AlecTeal: One use for the registry: to remove the upper case menu items in visual studio. I love the irony. – Bathsheba Mar 24 '14 at 12:17
  • @Bathsheba I was speechless until I decided I could only reply with that I am speechless. I don't know what to say to that. – Alec Teal Mar 24 '14 at 12:21