cpreprocessor

In the C preprocessor does #define incorporate previous #defines?


With these #defines without arguments

#define r 31
#define UMASK (0xffffffffUL<<r)
#define LMASK (0xffffffffUL ^ UMASK)

will UMASK be identical to (0xffffffffUL<<31) and LMASK be identical to (0xffffffffUL ^ (0xffffffffUL<<31)) in the actual code? Which is

uint32_t x = (state_array[k] & UMASK) | (state_array[j] & LMASK);

I want the compiler to see it as

uint32_t x = (state_array[k] & 0x80000000UL) | (state_array[j] & 0x7fffffffUL);

I just cannot decode the standard enough to spell it out.


Solution

  • will UMASK be identical to (0xffffffffUL<<31)

    Yes.

    and LMASK be identical to (0xffffffffUL ^ (0xffffffffUL<<31))

    Yes.

    As the macro replacement text for UMASK is scanned, the token r will be recognized as a macro and 31 will be copied, so the UMASK result follows.

    As the macro replacement text for LMASK is scanned, the token UMASK will be recognized as a macro and expanded as before, so the LMASK result follows.

    The C11 standard §6.10.3 Macro replacement ¶9 specifies the expansion of object-like macros:

    A preprocessing directive of the form

    # define identifier replacement-list new-line
    

    defines an object-like macro that causes each subsequent instance of the macro name171) to be replaced by the replacement list of preprocessing tokens that constitute the remainder of the directive. The replacement list is then rescanned for more macro names as specified below.

    Footnote 171 isn't germane to this discussion.

    §6.10.3.4 Rescanning and further replacement details the scanning that occurs while processing the replacement text.

    After all parameters in the replacement list have been substituted and # and ## processing has taken place, all placemarker preprocessing tokens are removed. The resulting preprocessing token sequence is then rescanned, along with all subsequent preprocessing tokens of the source file, for more macro names to replace.

    If the name of the macro being replaced is found during this scan of the replacement list (not including the rest of the source file's preprocessing tokens), it is not replaced. Furthermore, if any nested replacements encounter the name of the macro being replaced, it is not replaced. These nonreplaced macro name preprocessing tokens are no longer available for further replacement even if they are later (re)examined in contexts in which that macro name preprocessing token would otherwise have been replaced.

    The resulting completely macro-replaced preprocessing token sequence is not processed as a preprocessing directive even if it resembles one, but all pragma unary operator expressions within it are then processed as specified in 6.10.9 below.