Standard Behavior Of Function-Like Macro With Empty Argument Next To ## Operator?












5















Take the following example:



#define FOO(x) bar x ## baz
FOO( )


What is the expected output of the above code, according to the ANSI C and C99 standards, after the preprocessing phase?



I ran the above through gcc -E and clang -E, and both produced output equivalent to the following:



bar baz




Also, if the above preprocessed output is considered to conform to the standards, then what about this?



#define FOO(x) x ## baz
FOO( )


With the above modification GCC and clang still produce output equivalent to the following, without emitting any warning or error (even with the -Wall -Werror flags):



baz




The reason I am suspicious that the above output is not conformant to the standards is that the ANSI C 9899:1990 standard states:




6.8.3.3 The ## operator



A ## preprocessing token shall not occur at the beginning or at the end of a replacement list for either form of macro definition.



If, in the replacement list, a parameter is immediately preceded or followed by a ## preprocessing token, the parameter is replaced by the corresponding argument's preprocessing token sequence.




Okay, so technically the ## operator is NOT at the beginning of the replacement list in both of the above two examples, but x does expand to... a single space? nothing? ...so the ## operator (at least, as I understand it) is concatenating a space pp-token (or nothing) to baz.





Furthermore, the standard states:




For both object-like and function-like macro invocations, before the replacement list is reexamined for more macro names to replace, each instance of a ## preprocessing token in the replacement list (not from an argument) is deleted and the preceding preprocessing token is concatenated with the following preprocessing token.




So, considering the first example I gave above, why shouldn't the correct output be, say, this?



barbaz





UPDATE



As a sidenote, I did manage to get GCC to emit an error for the first example I gave above when preprocessing the code as follows:



gcc -ansi -pedantic -Wall -Werror -E ex1.c -o -


The output (with error) is:



foo.c:2:6: error: invoking macro FOO argument 1: empty macro arguments are undefined in ISO C90 [-Werror=pedantic]
FOO( )
^
# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "foo.c"

bar baz
cc1: all warnings being treated as errors


The error, however, is not related to the behavior of the ## operator, which is what this question was all about. It's still interesting nonetheless.



Also interesting to note is that no error is emitted by clang when preprocessing the file, using the same flags.










share|improve this question

























  • If you want to achieve barbaz you need two token-pasting operators: #define FOO(x) bar ## x ## baz. This works with FOO(X) as well as with FOO(). (I just tried with echo -e '#define FOO(x) bar ## x ## baznFOO(x)nFOO()n' | gcc -std=c99 -E -, although I was actually sure about this.) ;-)

    – Scheff
    Nov 20 '18 at 6:33













  • @4386427 Sorry, that's a typo in my question. I meant to write baz. Fixing that now.

    – jinscoe123
    Nov 20 '18 at 6:36











  • @Scheff Thanks, but I'm not trying to achieve anything in particular with the above code. I'm writing a C preprocessor, and I'd like to know what is the standard behavior of the above code snippets, so that I know what is the proper way to handle these corner cases.

    – jinscoe123
    Nov 20 '18 at 6:39











  • OK. As I understand token-pasting, with #define FOO(x) bar x ## baz and FOO(X) the expected is bar Xbaz, and for FOO() the expected is bar baz. The token-pasting connects left and right, even if left or right is a macro argument which is left empty. And, this is what you described in your question. Standard texts are somehow hard to understand sometimes (at least for me). But the token-pasting itself is rather simple (for me). ;-)

    – Scheff
    Nov 20 '18 at 6:42













  • I once wrote a pre-processor, but I didn't make it perfect. To keep it simple, it reads and writes an ASCII stream (not a token stream). Additionally, I didn't implement blue-painting - it just processes stream from begin to end (no repeating). For what I wanted to use it, this was sufficient but things like this C Preprocessor tricks, tips, and idioms will surely not work. (I even didn't try.) ;-)

    – Scheff
    Nov 20 '18 at 6:50


















5















Take the following example:



#define FOO(x) bar x ## baz
FOO( )


What is the expected output of the above code, according to the ANSI C and C99 standards, after the preprocessing phase?



I ran the above through gcc -E and clang -E, and both produced output equivalent to the following:



bar baz




Also, if the above preprocessed output is considered to conform to the standards, then what about this?



#define FOO(x) x ## baz
FOO( )


With the above modification GCC and clang still produce output equivalent to the following, without emitting any warning or error (even with the -Wall -Werror flags):



baz




The reason I am suspicious that the above output is not conformant to the standards is that the ANSI C 9899:1990 standard states:




6.8.3.3 The ## operator



A ## preprocessing token shall not occur at the beginning or at the end of a replacement list for either form of macro definition.



If, in the replacement list, a parameter is immediately preceded or followed by a ## preprocessing token, the parameter is replaced by the corresponding argument's preprocessing token sequence.




Okay, so technically the ## operator is NOT at the beginning of the replacement list in both of the above two examples, but x does expand to... a single space? nothing? ...so the ## operator (at least, as I understand it) is concatenating a space pp-token (or nothing) to baz.





Furthermore, the standard states:




For both object-like and function-like macro invocations, before the replacement list is reexamined for more macro names to replace, each instance of a ## preprocessing token in the replacement list (not from an argument) is deleted and the preceding preprocessing token is concatenated with the following preprocessing token.




So, considering the first example I gave above, why shouldn't the correct output be, say, this?



barbaz





UPDATE



As a sidenote, I did manage to get GCC to emit an error for the first example I gave above when preprocessing the code as follows:



gcc -ansi -pedantic -Wall -Werror -E ex1.c -o -


The output (with error) is:



foo.c:2:6: error: invoking macro FOO argument 1: empty macro arguments are undefined in ISO C90 [-Werror=pedantic]
FOO( )
^
# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "foo.c"

bar baz
cc1: all warnings being treated as errors


The error, however, is not related to the behavior of the ## operator, which is what this question was all about. It's still interesting nonetheless.



Also interesting to note is that no error is emitted by clang when preprocessing the file, using the same flags.










share|improve this question

























  • If you want to achieve barbaz you need two token-pasting operators: #define FOO(x) bar ## x ## baz. This works with FOO(X) as well as with FOO(). (I just tried with echo -e '#define FOO(x) bar ## x ## baznFOO(x)nFOO()n' | gcc -std=c99 -E -, although I was actually sure about this.) ;-)

    – Scheff
    Nov 20 '18 at 6:33













  • @4386427 Sorry, that's a typo in my question. I meant to write baz. Fixing that now.

    – jinscoe123
    Nov 20 '18 at 6:36











  • @Scheff Thanks, but I'm not trying to achieve anything in particular with the above code. I'm writing a C preprocessor, and I'd like to know what is the standard behavior of the above code snippets, so that I know what is the proper way to handle these corner cases.

    – jinscoe123
    Nov 20 '18 at 6:39











  • OK. As I understand token-pasting, with #define FOO(x) bar x ## baz and FOO(X) the expected is bar Xbaz, and for FOO() the expected is bar baz. The token-pasting connects left and right, even if left or right is a macro argument which is left empty. And, this is what you described in your question. Standard texts are somehow hard to understand sometimes (at least for me). But the token-pasting itself is rather simple (for me). ;-)

    – Scheff
    Nov 20 '18 at 6:42













  • I once wrote a pre-processor, but I didn't make it perfect. To keep it simple, it reads and writes an ASCII stream (not a token stream). Additionally, I didn't implement blue-painting - it just processes stream from begin to end (no repeating). For what I wanted to use it, this was sufficient but things like this C Preprocessor tricks, tips, and idioms will surely not work. (I even didn't try.) ;-)

    – Scheff
    Nov 20 '18 at 6:50
















5












5








5








Take the following example:



#define FOO(x) bar x ## baz
FOO( )


What is the expected output of the above code, according to the ANSI C and C99 standards, after the preprocessing phase?



I ran the above through gcc -E and clang -E, and both produced output equivalent to the following:



bar baz




Also, if the above preprocessed output is considered to conform to the standards, then what about this?



#define FOO(x) x ## baz
FOO( )


With the above modification GCC and clang still produce output equivalent to the following, without emitting any warning or error (even with the -Wall -Werror flags):



baz




The reason I am suspicious that the above output is not conformant to the standards is that the ANSI C 9899:1990 standard states:




6.8.3.3 The ## operator



A ## preprocessing token shall not occur at the beginning or at the end of a replacement list for either form of macro definition.



If, in the replacement list, a parameter is immediately preceded or followed by a ## preprocessing token, the parameter is replaced by the corresponding argument's preprocessing token sequence.




Okay, so technically the ## operator is NOT at the beginning of the replacement list in both of the above two examples, but x does expand to... a single space? nothing? ...so the ## operator (at least, as I understand it) is concatenating a space pp-token (or nothing) to baz.





Furthermore, the standard states:




For both object-like and function-like macro invocations, before the replacement list is reexamined for more macro names to replace, each instance of a ## preprocessing token in the replacement list (not from an argument) is deleted and the preceding preprocessing token is concatenated with the following preprocessing token.




So, considering the first example I gave above, why shouldn't the correct output be, say, this?



barbaz





UPDATE



As a sidenote, I did manage to get GCC to emit an error for the first example I gave above when preprocessing the code as follows:



gcc -ansi -pedantic -Wall -Werror -E ex1.c -o -


The output (with error) is:



foo.c:2:6: error: invoking macro FOO argument 1: empty macro arguments are undefined in ISO C90 [-Werror=pedantic]
FOO( )
^
# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "foo.c"

bar baz
cc1: all warnings being treated as errors


The error, however, is not related to the behavior of the ## operator, which is what this question was all about. It's still interesting nonetheless.



Also interesting to note is that no error is emitted by clang when preprocessing the file, using the same flags.










share|improve this question
















Take the following example:



#define FOO(x) bar x ## baz
FOO( )


What is the expected output of the above code, according to the ANSI C and C99 standards, after the preprocessing phase?



I ran the above through gcc -E and clang -E, and both produced output equivalent to the following:



bar baz




Also, if the above preprocessed output is considered to conform to the standards, then what about this?



#define FOO(x) x ## baz
FOO( )


With the above modification GCC and clang still produce output equivalent to the following, without emitting any warning or error (even with the -Wall -Werror flags):



baz




The reason I am suspicious that the above output is not conformant to the standards is that the ANSI C 9899:1990 standard states:




6.8.3.3 The ## operator



A ## preprocessing token shall not occur at the beginning or at the end of a replacement list for either form of macro definition.



If, in the replacement list, a parameter is immediately preceded or followed by a ## preprocessing token, the parameter is replaced by the corresponding argument's preprocessing token sequence.




Okay, so technically the ## operator is NOT at the beginning of the replacement list in both of the above two examples, but x does expand to... a single space? nothing? ...so the ## operator (at least, as I understand it) is concatenating a space pp-token (or nothing) to baz.





Furthermore, the standard states:




For both object-like and function-like macro invocations, before the replacement list is reexamined for more macro names to replace, each instance of a ## preprocessing token in the replacement list (not from an argument) is deleted and the preceding preprocessing token is concatenated with the following preprocessing token.




So, considering the first example I gave above, why shouldn't the correct output be, say, this?



barbaz





UPDATE



As a sidenote, I did manage to get GCC to emit an error for the first example I gave above when preprocessing the code as follows:



gcc -ansi -pedantic -Wall -Werror -E ex1.c -o -


The output (with error) is:



foo.c:2:6: error: invoking macro FOO argument 1: empty macro arguments are undefined in ISO C90 [-Werror=pedantic]
FOO( )
^
# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "foo.c"

bar baz
cc1: all warnings being treated as errors


The error, however, is not related to the behavior of the ## operator, which is what this question was all about. It's still interesting nonetheless.



Also interesting to note is that no error is emitted by clang when preprocessing the file, using the same flags.







c c-preprocessor preprocessor






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 20 '18 at 8:02







jinscoe123

















asked Nov 20 '18 at 6:17









jinscoe123jinscoe123

214212




214212













  • If you want to achieve barbaz you need two token-pasting operators: #define FOO(x) bar ## x ## baz. This works with FOO(X) as well as with FOO(). (I just tried with echo -e '#define FOO(x) bar ## x ## baznFOO(x)nFOO()n' | gcc -std=c99 -E -, although I was actually sure about this.) ;-)

    – Scheff
    Nov 20 '18 at 6:33













  • @4386427 Sorry, that's a typo in my question. I meant to write baz. Fixing that now.

    – jinscoe123
    Nov 20 '18 at 6:36











  • @Scheff Thanks, but I'm not trying to achieve anything in particular with the above code. I'm writing a C preprocessor, and I'd like to know what is the standard behavior of the above code snippets, so that I know what is the proper way to handle these corner cases.

    – jinscoe123
    Nov 20 '18 at 6:39











  • OK. As I understand token-pasting, with #define FOO(x) bar x ## baz and FOO(X) the expected is bar Xbaz, and for FOO() the expected is bar baz. The token-pasting connects left and right, even if left or right is a macro argument which is left empty. And, this is what you described in your question. Standard texts are somehow hard to understand sometimes (at least for me). But the token-pasting itself is rather simple (for me). ;-)

    – Scheff
    Nov 20 '18 at 6:42













  • I once wrote a pre-processor, but I didn't make it perfect. To keep it simple, it reads and writes an ASCII stream (not a token stream). Additionally, I didn't implement blue-painting - it just processes stream from begin to end (no repeating). For what I wanted to use it, this was sufficient but things like this C Preprocessor tricks, tips, and idioms will surely not work. (I even didn't try.) ;-)

    – Scheff
    Nov 20 '18 at 6:50





















  • If you want to achieve barbaz you need two token-pasting operators: #define FOO(x) bar ## x ## baz. This works with FOO(X) as well as with FOO(). (I just tried with echo -e '#define FOO(x) bar ## x ## baznFOO(x)nFOO()n' | gcc -std=c99 -E -, although I was actually sure about this.) ;-)

    – Scheff
    Nov 20 '18 at 6:33













  • @4386427 Sorry, that's a typo in my question. I meant to write baz. Fixing that now.

    – jinscoe123
    Nov 20 '18 at 6:36











  • @Scheff Thanks, but I'm not trying to achieve anything in particular with the above code. I'm writing a C preprocessor, and I'd like to know what is the standard behavior of the above code snippets, so that I know what is the proper way to handle these corner cases.

    – jinscoe123
    Nov 20 '18 at 6:39











  • OK. As I understand token-pasting, with #define FOO(x) bar x ## baz and FOO(X) the expected is bar Xbaz, and for FOO() the expected is bar baz. The token-pasting connects left and right, even if left or right is a macro argument which is left empty. And, this is what you described in your question. Standard texts are somehow hard to understand sometimes (at least for me). But the token-pasting itself is rather simple (for me). ;-)

    – Scheff
    Nov 20 '18 at 6:42













  • I once wrote a pre-processor, but I didn't make it perfect. To keep it simple, it reads and writes an ASCII stream (not a token stream). Additionally, I didn't implement blue-painting - it just processes stream from begin to end (no repeating). For what I wanted to use it, this was sufficient but things like this C Preprocessor tricks, tips, and idioms will surely not work. (I even didn't try.) ;-)

    – Scheff
    Nov 20 '18 at 6:50



















If you want to achieve barbaz you need two token-pasting operators: #define FOO(x) bar ## x ## baz. This works with FOO(X) as well as with FOO(). (I just tried with echo -e '#define FOO(x) bar ## x ## baznFOO(x)nFOO()n' | gcc -std=c99 -E -, although I was actually sure about this.) ;-)

– Scheff
Nov 20 '18 at 6:33







If you want to achieve barbaz you need two token-pasting operators: #define FOO(x) bar ## x ## baz. This works with FOO(X) as well as with FOO(). (I just tried with echo -e '#define FOO(x) bar ## x ## baznFOO(x)nFOO()n' | gcc -std=c99 -E -, although I was actually sure about this.) ;-)

– Scheff
Nov 20 '18 at 6:33















@4386427 Sorry, that's a typo in my question. I meant to write baz. Fixing that now.

– jinscoe123
Nov 20 '18 at 6:36





@4386427 Sorry, that's a typo in my question. I meant to write baz. Fixing that now.

– jinscoe123
Nov 20 '18 at 6:36













@Scheff Thanks, but I'm not trying to achieve anything in particular with the above code. I'm writing a C preprocessor, and I'd like to know what is the standard behavior of the above code snippets, so that I know what is the proper way to handle these corner cases.

– jinscoe123
Nov 20 '18 at 6:39





@Scheff Thanks, but I'm not trying to achieve anything in particular with the above code. I'm writing a C preprocessor, and I'd like to know what is the standard behavior of the above code snippets, so that I know what is the proper way to handle these corner cases.

– jinscoe123
Nov 20 '18 at 6:39













OK. As I understand token-pasting, with #define FOO(x) bar x ## baz and FOO(X) the expected is bar Xbaz, and for FOO() the expected is bar baz. The token-pasting connects left and right, even if left or right is a macro argument which is left empty. And, this is what you described in your question. Standard texts are somehow hard to understand sometimes (at least for me). But the token-pasting itself is rather simple (for me). ;-)

– Scheff
Nov 20 '18 at 6:42







OK. As I understand token-pasting, with #define FOO(x) bar x ## baz and FOO(X) the expected is bar Xbaz, and for FOO() the expected is bar baz. The token-pasting connects left and right, even if left or right is a macro argument which is left empty. And, this is what you described in your question. Standard texts are somehow hard to understand sometimes (at least for me). But the token-pasting itself is rather simple (for me). ;-)

– Scheff
Nov 20 '18 at 6:42















I once wrote a pre-processor, but I didn't make it perfect. To keep it simple, it reads and writes an ASCII stream (not a token stream). Additionally, I didn't implement blue-painting - it just processes stream from begin to end (no repeating). For what I wanted to use it, this was sufficient but things like this C Preprocessor tricks, tips, and idioms will surely not work. (I even didn't try.) ;-)

– Scheff
Nov 20 '18 at 6:50







I once wrote a pre-processor, but I didn't make it perfect. To keep it simple, it reads and writes an ASCII stream (not a token stream). Additionally, I didn't implement blue-painting - it just processes stream from begin to end (no repeating). For what I wanted to use it, this was sufficient but things like this C Preprocessor tricks, tips, and idioms will surely not work. (I even didn't try.) ;-)

– Scheff
Nov 20 '18 at 6:50














2 Answers
2






active

oldest

votes


















5














Okay, so technically the ## operator is NOT at the beginning of the replacement list in both of the above two examples,


The word "technically" here is redundant. The replacement list of both of your macros has x before the ##, so that rule doesn't apply.



but x does expand to... a single space? nothing?


6.4 lists what's considered preprocessing tokens: header-name, identifier, pp-number, character-constant, string-literal, punctuator, and "each non-whitespace character that cannot be one of the above". Note what is conspicuously absent from this list... whitespace in and of itself.



So your whitespace in your argument to FOO is not significant; your argument is a sequence of 0 preprocessing tokens (that is, 0 of the things in that list above). That means that this applies:



6.10.3.3 p2:



however, if an argument consists of no preprocessing tokens, the parameter is replaced by a placemarker preprocessing token instead.


The next paragraph, 3, applies to the result here:



concatenation of a placemarker with a non-placemarker preprocessing token results in the non-placemarker preprocessing token.


So, placemarker pasted onto baz produces baz.






share|improve this answer































    0














    If you have this:



    #define FOO(x) bar x ## baz                
    FOO();


    You get bar baz. So the space in the FOO call is not relevant.



    If you have this:



    #define FOO(x) bar ## x ## baz                 
    FOO();


    you get barbaz because you ask to get all those pasted together.



    But you write:



    #define FOO(x) bar x ## baz                 
    FOO();


    You get bar baz because you ask for bar and the paste of x and baz. Which is similar to #define FOO(x) bar,x ## baz that gives you bar,baz.






    share|improve this answer























      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53387287%2fstandard-behavior-of-function-like-macro-with-empty-argument-next-to-operator%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      5














      Okay, so technically the ## operator is NOT at the beginning of the replacement list in both of the above two examples,


      The word "technically" here is redundant. The replacement list of both of your macros has x before the ##, so that rule doesn't apply.



      but x does expand to... a single space? nothing?


      6.4 lists what's considered preprocessing tokens: header-name, identifier, pp-number, character-constant, string-literal, punctuator, and "each non-whitespace character that cannot be one of the above". Note what is conspicuously absent from this list... whitespace in and of itself.



      So your whitespace in your argument to FOO is not significant; your argument is a sequence of 0 preprocessing tokens (that is, 0 of the things in that list above). That means that this applies:



      6.10.3.3 p2:



      however, if an argument consists of no preprocessing tokens, the parameter is replaced by a placemarker preprocessing token instead.


      The next paragraph, 3, applies to the result here:



      concatenation of a placemarker with a non-placemarker preprocessing token results in the non-placemarker preprocessing token.


      So, placemarker pasted onto baz produces baz.






      share|improve this answer




























        5














        Okay, so technically the ## operator is NOT at the beginning of the replacement list in both of the above two examples,


        The word "technically" here is redundant. The replacement list of both of your macros has x before the ##, so that rule doesn't apply.



        but x does expand to... a single space? nothing?


        6.4 lists what's considered preprocessing tokens: header-name, identifier, pp-number, character-constant, string-literal, punctuator, and "each non-whitespace character that cannot be one of the above". Note what is conspicuously absent from this list... whitespace in and of itself.



        So your whitespace in your argument to FOO is not significant; your argument is a sequence of 0 preprocessing tokens (that is, 0 of the things in that list above). That means that this applies:



        6.10.3.3 p2:



        however, if an argument consists of no preprocessing tokens, the parameter is replaced by a placemarker preprocessing token instead.


        The next paragraph, 3, applies to the result here:



        concatenation of a placemarker with a non-placemarker preprocessing token results in the non-placemarker preprocessing token.


        So, placemarker pasted onto baz produces baz.






        share|improve this answer


























          5












          5








          5







          Okay, so technically the ## operator is NOT at the beginning of the replacement list in both of the above two examples,


          The word "technically" here is redundant. The replacement list of both of your macros has x before the ##, so that rule doesn't apply.



          but x does expand to... a single space? nothing?


          6.4 lists what's considered preprocessing tokens: header-name, identifier, pp-number, character-constant, string-literal, punctuator, and "each non-whitespace character that cannot be one of the above". Note what is conspicuously absent from this list... whitespace in and of itself.



          So your whitespace in your argument to FOO is not significant; your argument is a sequence of 0 preprocessing tokens (that is, 0 of the things in that list above). That means that this applies:



          6.10.3.3 p2:



          however, if an argument consists of no preprocessing tokens, the parameter is replaced by a placemarker preprocessing token instead.


          The next paragraph, 3, applies to the result here:



          concatenation of a placemarker with a non-placemarker preprocessing token results in the non-placemarker preprocessing token.


          So, placemarker pasted onto baz produces baz.






          share|improve this answer













          Okay, so technically the ## operator is NOT at the beginning of the replacement list in both of the above two examples,


          The word "technically" here is redundant. The replacement list of both of your macros has x before the ##, so that rule doesn't apply.



          but x does expand to... a single space? nothing?


          6.4 lists what's considered preprocessing tokens: header-name, identifier, pp-number, character-constant, string-literal, punctuator, and "each non-whitespace character that cannot be one of the above". Note what is conspicuously absent from this list... whitespace in and of itself.



          So your whitespace in your argument to FOO is not significant; your argument is a sequence of 0 preprocessing tokens (that is, 0 of the things in that list above). That means that this applies:



          6.10.3.3 p2:



          however, if an argument consists of no preprocessing tokens, the parameter is replaced by a placemarker preprocessing token instead.


          The next paragraph, 3, applies to the result here:



          concatenation of a placemarker with a non-placemarker preprocessing token results in the non-placemarker preprocessing token.


          So, placemarker pasted onto baz produces baz.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 20 '18 at 7:15









          H WaltersH Walters

          1,671159




          1,671159

























              0














              If you have this:



              #define FOO(x) bar x ## baz                
              FOO();


              You get bar baz. So the space in the FOO call is not relevant.



              If you have this:



              #define FOO(x) bar ## x ## baz                 
              FOO();


              you get barbaz because you ask to get all those pasted together.



              But you write:



              #define FOO(x) bar x ## baz                 
              FOO();


              You get bar baz because you ask for bar and the paste of x and baz. Which is similar to #define FOO(x) bar,x ## baz that gives you bar,baz.






              share|improve this answer




























                0














                If you have this:



                #define FOO(x) bar x ## baz                
                FOO();


                You get bar baz. So the space in the FOO call is not relevant.



                If you have this:



                #define FOO(x) bar ## x ## baz                 
                FOO();


                you get barbaz because you ask to get all those pasted together.



                But you write:



                #define FOO(x) bar x ## baz                 
                FOO();


                You get bar baz because you ask for bar and the paste of x and baz. Which is similar to #define FOO(x) bar,x ## baz that gives you bar,baz.






                share|improve this answer


























                  0












                  0








                  0







                  If you have this:



                  #define FOO(x) bar x ## baz                
                  FOO();


                  You get bar baz. So the space in the FOO call is not relevant.



                  If you have this:



                  #define FOO(x) bar ## x ## baz                 
                  FOO();


                  you get barbaz because you ask to get all those pasted together.



                  But you write:



                  #define FOO(x) bar x ## baz                 
                  FOO();


                  You get bar baz because you ask for bar and the paste of x and baz. Which is similar to #define FOO(x) bar,x ## baz that gives you bar,baz.






                  share|improve this answer













                  If you have this:



                  #define FOO(x) bar x ## baz                
                  FOO();


                  You get bar baz. So the space in the FOO call is not relevant.



                  If you have this:



                  #define FOO(x) bar ## x ## baz                 
                  FOO();


                  you get barbaz because you ask to get all those pasted together.



                  But you write:



                  #define FOO(x) bar x ## baz                 
                  FOO();


                  You get bar baz because you ask for bar and the paste of x and baz. Which is similar to #define FOO(x) bar,x ## baz that gives you bar,baz.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 20 '18 at 7:00









                  perrealperreal

                  72.4k9111138




                  72.4k9111138






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53387287%2fstandard-behavior-of-function-like-macro-with-empty-argument-next-to-operator%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      這個網誌中的熱門文章

                      Tangent Lines Diagram Along Smooth Curve

                      Yusuf al-Mu'taman ibn Hud

                      Zucchini