Why do c preprocessor directives ignore the \ newline rule when it is followed directly after a #? - c-preprocessor

Normally, via the standards, any \ followed directly by a newline is converted into the code without the newline and backslash. For example:
int yams\
yams;
turns into
int yamsyams;
and
int cheese // blerg \
more blerg
turns into
int cheese // blerg more blerg
This behavior can be nice with very long single line code.
However, it seems that
#\
This code not part of the macro
While
#a\
This code is part of the macro.
And even
# \
This code is not part of the macro
While
# a\
This code is part of the macro
Why is this the one exception to the "\ newline" being removed rule?

As described in [lex.phases], replacing the backslash-newline is done by the preprocessor, and should happen very early, in phase 2, which is before splitting the source into preprocessor tokens (phase 3) and before handling preprocessor directives such as #define or #include (phase 4).
So in all your examples you should see the backslash-newline removed.

Related

Can comments be created in macro definition by "/##/"?

Assuming that the IDE defines macro NDEBUG in Release build. Is it possible to use the following preprocessor instructions to print debug information in Debug build but not in Release build by using the marco PRINT?
#ifdef NDEBUG
#define PRINT /##/
#else
#define PRINT printf
#endif
No, because replacement of comments with spaces occurs before macro replacement in C’s translation phases.
C 2018 5.1.1.2 1 specifies the precedence of syntax rules in translation. Phase 3 is:
The source file is decomposed into preprocessing tokens and sequences of white-space characters (including comments). A source file shall not end in a partial preprocessing token or in a partial comment. Each comment is replaced by one space character…
Phase 4 is:
Preprocessing directives are executed, macro invocations are expanded…
Interestingly, earlier phases can be invoked by later phases, but this only occurs for processing #include directives; the specification for phase 4 continues:
… A #include preprocessing directive causes the named header or source file to be processed from phase 1 through phase 4, recursively…
Further, pasting / with / to produce // has undefined behavior, because // is not a preprocessing token and C 2018 6.10.3 3 says, of pasting with the ## operator:
… If the result is not a valid preprocessing token, the behavior is undefined…
(Preprocessing tokens are specified in C 2018 6.4 1, and the relevant category there would be punctuator, which includes characters and character combinations such as [, ], +, ++, /, +=, /=, >>=, and so on but does not include //.)
A typical means of accomplishing the goal of printing in a debug build but not a non-debug build is to define a function-like macro that is replaced by nothing in non-debug builds:
#if defined NDEBUG
#define PRINT(...)
#else
#define PRINT(...) printf(__VA_ARGS__)
#endif

backslash meaning in the C context

I am reading the C code related to the hardware. I didn't understand the backslash() in the context. what the relationship between the functions?
#define timer_wait_us(timerNum, time) \
timer_set_us(timerNum, time, 0); \
timer_start(timerNum); \
timer_wait(timerNum)
A #define directive exists by default on a single line. The backslashes are escaping the newline character at the end of the line so that the following line is included as part of the #define.
So if you have this in your code:
timer_wait_us(timerNum, time)
It is replaced with:
timer_set_us(timerNum, time, 0);
timer_start(timerNum);
timer_wait(timerNum)

Concatenate character to __VA_ARGS__ in a macro redefining printf

I'm developing an embedded application that uses a library for interfacing with a SPI NAND memory chip. The library provided uses a print function in which I, as the applications developer, must override for my specific platform.
For instance, they use the function printf_ extensively in their code.
I redefine it as such, to get the print function to print over the serial interface
#define printf_(...) serial.printf(__VA_ARGS__)
It works fine, except that on this platform, you need to supply a carriage return ("\r") for a newline. So right now, when the library is called, the formatting is horrible.
I'd like to append a "\r" to the end of whatever is supplied to the print function. Like
#define printf_(...) serial.printf(__VA_ARGS__##"\r")
Obviously that doesn't work.
I'm really not familiar with, and have sort of a hard time understanding variadic functions in C, so this would provide me with a little learning opportunity if I could figure this out, or at least I would learn if this is not possible.
I also can't just wrap the function using va_lists and vsprintfs because my platform does not support this (and I'd rather redefine it in a macro, as a performance/stylistic choice, personally).
Is there a way to do this?
Perhaps you could just output '\r' after the call to serial.printf ?
#define printf_(...) do { serial.printf(__VA_ARGS__); serial.printf("\r"); } while(0)
I agree with other users that your requirement of CR coming after LF is quite strange, and I have a strong suspicion you mean for it to be CRLF, not LFCR. Regardless, I will help you with your original requirement of appending CR to the string.
It is going to be incredibly difficult to perform this operation in a one-liner macro. Alternatively, you could use a nasty-looking multi-line macro:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define printf_(format, args...) \
do { \
int _len_orig = strlen(format); \
/* strlen doesn't consider newline. Check for that. */ \
if ( format[_len_orig] == '\n' ) \
_len_orig++; \
\
/* len_orig + 2 to make space for null terminator and '\r' */ \
unsigned _new_size = _len_orig + 2; \
char* _new_str = calloc(_new_size, 1); \
strncpy( _new_str, format, _len_orig ); \
_new_str[_new_size-2] = '\r'; \
\
/* Print out the raw hex of the string to prove it worked */ \
int _i; \
for( _i = 0; _i < _new_size; _i++) \
printf("%02x ", _new_str[_i]); \
printf("\n"); \
free(_new_str); \
} while(0)
int main(){
char* str = "####\n";
printf_( str );
return 0;
}
In my macro, I have not used your serial.printf function but rather made some short code that prints out the hexidecimal values of the concatenated string for proof that the logic works.
Explanation
Macros are required to appear as a single line to the C Preprocessor. The additions of \ at the end of each macro line escape the newline character.
gcc allows for named arguments in your macro. Here, format describes the format string you would normally pass to printf, and args... is the variable argument name for "everything else" you would pass into printf. I do not reference args in this example, but you will certainly want to modify my example in your final code to include it. Your call to printf would look something like serial.printf( _new_str, args);
Multi-line macros are kind of nasty in that you need to do some trickery to get them to appear as normal functions to the human programmer. The need for enclosing the macro in a do-while is nicely discussed here. The linked page is meant for C++, but it applies to C as well.
If you copy my code, compile, and run it, this is the output:
[clipp#h2ologin3:~]$ ./a.out
40 40 40 40 0a 0d 00
Here, this ASCII dump is showing us that 4 # symbols were copied, followed by \n, \r, and finally \0.
There is also a strong case for instead writing this as an inline C function. You say that your system doesn't support va_list etc. so if that is true, then a macro may be the only choice.
QED.

C: How to Shield Commas in Macro Arguments?

Is there a general method to shield comments in macro arguments in C? I know that parentheses can be used for this purpose, but that will not work in cases where added parentheses result in syntax errors in the macro output. I've heard that ({ }) works to shield commas in GCC, but I need this code to also work in VC++ (one of the recent versions which does conform to the C standard with regard to commas in macros). I also cannot use variadic macros in my case.
The specific case I'm trying to do is this (lengthof is a macro defined elsewhere). I'm trying to write a single macro for the entire thing because this will be used many times, and having a multi-macro solution would add a large amount of additional testing code.
#define TEST_UNFUNC(func, res_type, res_set, op_type, op_set) \
{ \
static const res_type res[] = res_set; \
static const op_type op[] = op_set; \
int i; \
for (i = 0; i < MIN(lengthof(res), lengthof(op)); i++) \
assert(func(op[i]) == res[i]); \
}
If possible I would like a general answer and not merely a workaround specific to this particular macro.
Use parentheses to shield the comma, and then pass them through a special unparen macro, defined in the example below:
#include <stdio.h>
#define really_unparen(...) __VA_ARGS__
#define invoke(expr) expr
#define unparen(args) invoke(really_unparen args)
#define fancy_macro(a) printf("%s %s\n", unparen(a))
int main()
{
fancy_macro(("Hello", "World"));
}
The trick here is that the invoke macro forces an extra expansion, allowing really_unparen to be called even though it's not followed by parentheses in the source.
Edit: per comment below, this appears to not be necessary in this case. Though I'm sure I've hit a case where I needed it sometime ... and it doesn't hurt.

C: Why is macro expansion not happening recursively?

I have a test program like below.
#define TEST(A,B) A
#define TEST2(A,B) (A,B)
#define TEST3(A,B) TEST TEST2(A,B)
int main()
{
TEST3(Hello,World) //This will expand to TEST (Hello,World)
TEST (hello, World) // This will expand to hello
}
The TEST3 will expand to "TEST (Hello,World)", but it won't be expanded further using TEST definition. I initially thought it must be due to a space between TEST and TEST2(hello, world) in the TEST3 definition. But the plain invocation of TEST (hello, world) expands properly. Can someone explain what is happening here?
The word TEST in #define TEST3(A,B) TEST TEST2(A,B) is not a function-like macro invocation because it is not followed by an open parenthesis. When the pre-processor is expanding TEST3(Hello, World), it encounters TEST, finds it is not an invocation of a function-like macro, and outputs it as text; then it processes TEST2(A, B) and that is a macro invocation, so it outputs the corresponding text, which is (Hello,World), and it continues the processing with the open parenthesis. The TEST is gone, never to be preprocessed again.
See C preprocessor and concatenation for a full discussion of macro expansion with quotes from the standard. You might find How to make a char string from a C macro's value of some help, too.

Resources