Can a C #error macro display multiple line message? - c

I tried to use the #error directive with GCC compiler like this:
#error "The charging pins aren't differing! One pin cannot be used for multiple purposes!"
This says, I should use double quotes, so the argument will be a single string constant and I can use an apostrophe inside of it. However, I want this string to be appeared in the source code in mutiple lines, like:
#error "The charging pins aren't differing!
One pin cannot be used for multiple purposes!"
Then, I got some error messages:
warning: missing terminating " character
#error "The charging pins aren't differing! One pin
error: missing terminating " character
cannot be used for multiple purposes!"
If I insert a blackslash at the end of the first line, the diagnostic message conatains all the whitespaceb between the beginning of the second line and the first word (One). If both lines are strings the diagnostic message shows the inner double quotes.
So the question: How can I achieve this output? (or a similar wihtout double quotes, but the apostrophe included)
#error "The charging pins aren't differing! One pin cannot be used for multiple purposes!"

Unfortunately, you can't have it all.
Either you have to get rid of the apostrophe so that the message only contains what's regarded as valid pre-processing tokens.
Or you can write it as a string on a single line.
Or you can write it two string literals and break the line with \. You can't do this in the middle of a string literal, because then it wouldn't be a valid pre-processing token. This will make the output look weird though, like : error: "hello" "world".
Relying on pre-processor concatenation of two string literals won't work, since the error directive only looks until it spots a newline character in the source. And the error directive translates everything you type into strings anyway.
The relevant translation phases are (from C17 5.1.1.2) executed in this order:
2) Each instance of a backslash character () immediately followed by a new-line
character is deleted, splicing physical source lines to form logical source lines.
3) The source file is decomposed into preprocessing tokens and sequences of
white-space characters (including comments).
4) Preprocessing directives are executed, ...
6) Adjacent string literal tokens are concatenated.
#error is executed in step 4, earlier than string literal concatenation in step 6.
I personally think the best solution is to skip the apostrophe:
#error The charging pins are not differing! \
One pin cannot be used for multiple purposes!
Slight fix of English and you get the best compromise between readable source and a readable error message.

As stated here
Neither ‘#error’ nor ‘#warning’ macro-expands its argument.
Internal whitespace sequences are each replaced with a single space. The line must consist of complete tokens. It is wisest to make the argument of these directives be a single string constant; this
avoids problems with apostrophes and the like.
So you can use it in single line only.
#include <stdio.h>
//#define var 10
#ifdef var
#error "The charging pins aren't differing! One pin cannot be used for multiple purposes!"
#endif
int main(void){
printf("in main() \n");
return 0;
}

Use double-quotes and \ to split the string on multiple lines:
#error "These aren't \
working!"
MSVC (v19.14) outputs:
<source>(2): fatal error C1189: #error: "These aren't working!"
GCC (v5.5) outputs:
<source>:1:2: error: #error "These aren't working!"
#error "These aren't \
^

Related

Does C preprocessed file contain source file line number information?

Here is the problem:
I have a C source file main.c and the corresponding preprocessed file main.i. Given a line in main.i, how can I get the corresponding line number in main.c?
The C standard does not specify this. GCC and Clang emit lines starting with # followed by a space, a line number, a file name, and other information.. You can determine the line number in main.c:
Read the preprocessed file, main.i. After any line with # followed by a space, a number, and a file name that is not “main.c”, read and ignore further lines until there is a # followed by a space, a number, and “main.c”. Remember that number as the current line number.
Subsequent lines until another # line in this form are lines from main.c (after preprocessing) with consecutive line numbers continuing from the line number remembered above.
When used as a separate phase to produce a text file, the C preprocessor usually inserts #line directives, sometimes appearing as bare # directives providing the original line number, file name and other contextual information. #line directives have this form:
# line pp-tokens new-line
which after macro substitution should become:
# line digit-sequence new-line
or
# line digit-sequence " s-char-sequenceopt " new-line
Where digit-sequence is the line number of the next list in the source stream and the s-char-sequenceopt is the name of the file to use for diagnostics and as a replacement for the __FILE__ macro. Subsequent newlines increment the line number thus defined.
#line directives are produced by external programs that generate C code files to make compiler diagnostics point to the original source file.
C Compilers such as gcc and clang produce similar information in their preprocessing output in the form:
# number filename other-information new-line
This syntax is not defined by the C Standard but very common in preprocessing output produced by C compilers. The C standard does not define this output, used mostly for debugging purposes.

C preprocessor: building a path string

Given a macro that has been defined previously:
#define FILENAME somefile.h
I want to concatenate this with another macro-string that defines the (relative) path of this file. My current approach is to do this like so:
#define DIRECTORY ../somedir/
#define STRINGIFY_(x) #x
#define FILE2_(dir, file) STRINGIFY_(dir ## file)
#define FILE_(dir, file) FILE2_(dir, file)
#include FILE_(DIRECTORY, FILENAME)
This however results in an error (GCC4.9):
error: pasting "/" and "file" does not give a valid preprocessing token
Removing the final forward slash from the DIRECTORY definition removes this error, but obviously does not yield the desired result. Similar errors appear when I try to smuggle the / in otherwise. For example:
#define FILE2_(dir, file) STRINGIFY_(dir ## / ## file)
does not work for the same reason.
I would like to know what is going wrong here and, obviously, how to circumvent this.
EDIT: Changed double underscores to singles on Columbo's advice. Apparently, identifiers containing double underscores are reserved to the implementation, regardless of where they appear (I was under the impression that this only held true for double underscores at the beginning of an ID).
[cpp.include]/4:
A preprocessing directive of the form
# include pp-tokens new-line
(that does not match one of the two previous forms) is permitted. The
preprocessing tokens after include in the directive are processed
just as in normal text (i.e., each identifier currently defined as a
macro name is replaced by its replacement list of preprocessing
tokens). If the directive resulting after all replacements does not
match one of the two previous forms, the behavior is
undefined.152
152 Note that adjacent string literals are not
concatenated into a single string literal (see the translation phases
in 2.2); thus, an expansion that results in two string literals is an
invalid directive.
So though #include MACRO is valid, MACRO must directly expand to an otherwise valid argument to #include. The concatenation of string literals happens two translation phases after preprocessing.
Also, in the definition of the ## operator, [cpp.concat]/3:
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.
[..] If the result is not a valid preprocessing token, the behavior is undefined.
Hence the result of A##B must be one valid preprocessing token. / is an own preprocessing token, and so are the names of the directories and files.
You can't concatenate "abc and /xyz", since abc/ is not a valid preprocessing token - "abc is not one preprocessing token, but two, though "abc" is one.
On the other hand, if you concatenate <abc/ and xyz>, then / and xyz are concatenated, examined, and we have a problem again.
Thus it appears to be impossible to concat the paths using ##. Your approach looks quite impossible to me, too.
With GCC, this is fine though:
#define PATH <foo/bar/
#define FILE boo>
#define ARG PATH FILE
#include ARG
It works because GCCs preprocessor removes the white space (for some reason). Does not work on VC++ or Clang and isn't covered by standard anyway, so definitely not recommended.

C compiler warning Unknown escape sequence '\.' using regex for c program

I am using regex to determine a command line argument has the .dat extension. I am trying the following regex:
#define to_find "^.*\.(dat)?"
For some reason I am getting the warning I stated in the title of this question. First, is this expression correct? I believe it is. Second, if it is correct, how can i get rid of this warning?
I am coding a c program in Xcode and the above #define is in my .h file.
Thanks!
The warning is coming from the C compiler. It is telling you that \. is not a known escape sequence in C. Since this string is going to a regex engine, you need to double-escape the slash, like this:
#define to_find "^.*\\.(dat)?"
This regex would match a string with an optional .dat extension, with dat being optional. However, the dot . is required. If you want the dot to be optional as well, put it inside the parentheses, like this: ^.*(\\.dat)?.
Note that you can avoid escaping the individual metacharacters by enclosing them in square brackets, like this:
#define to_find "^.*([.]dat)?"
You need
#define to_find "^.*\\.(dat)?"
Should do the trick as the \ needs to be escaped for C and not the benefit for regex at this stage

What kind of statements,keywords,arguments etc can span multiple lines,and what need "\" for this?

How to know what kind of "things" can span multiple lines in C code without needing a \ character at the end of the line?And what kind of "things" need the \?How to know that?For example, in the following code, if and printf() work fine if I split them up in multiple lines.
if
(2<5)
printf
("Hi");
But in the following code,printf() needs a \ ,else shows error:
printf("Hi \
");
Similarly,the following shows error without a \
char name[]="Alexander the \
great of Greece";
So please tell me how to know when to use the \ while spanning multiple lines in C code, and when we can do without it?I mean, like if works both with and without the \.
This is about a concept called 'tokens'. A token is source-program text that the compiler does not break down into component elements. Literals (42, "text"), variable names, keywords are tokens.
Endline escaping is important for string constants only because it breaks apart a token. In your first example line breaks don't split tokens. All whitespace symbols between tokens are ignored.
The exception is macro definitions. A macro definition is ended with line break, so you need to escape it. But macros are not C code.
If you want to break a string across lines, you can either use the \ as you have...
printf("Hello \
World");
Or, alternatively, you can terminate the string with a " and then start a new string on the next line with no punctuation...
printf("Hello "
"World");
To the best of my knowledge, the issue with lines applies in only two places... within a string and within a define..
#define MY_DEFINE(fp) \
fprintf( fp, "Hello "\
"World" );
In short, the \ character is telling the compiler this statement continues on the next line. However, C/C++ is not white-space dependent, so really the only place this would come up is on a statement that is expected to be on a single line... which would be a string or a define.
C does not depend on line feeds.
You could use line feeds anywhere you like, as well as just not using them at all.
This implies seeing string literals as one token.
But, as in real life: Too much or to few, both does make life difficult. Happyness is matter of balance ... :-)
Please note that lines starting with a # are not C code, but pre-processor instructions.

How can I insert a #defined string into a system() command? (win32)

Here is an overly simplified version of what I am trying to do:
#define LOGDIRECTORY C:\\logs\\
system("mkdir LOGDIRECTORY");
However the preprocessor, instead of swapping out the defined name is not. Instead the system command actually thinks LOGDIRECTORY is the name, and thus is shooting me errors when starting the program.
I know it's wrong and there must be something I can do with the " marks or other characters to specify what I want, but I can't figure it out. I don't want to hardcode the directory and file names because someone may want to change them in the future and it would be much easier to change a define than the whole function etc.
PS, I am coding this in plain C.
#define LOGDIRECTORY C:\\logs\\
#define DEF2STR(x) #x
system("mkdir " DEF2STR(LOGDIRECTORY));
#define LOGDIRECTORY_WITH_QUOTES "C:\\logs\\"
system("mkdir " LOGDIRECTORY_WITH_QUOTES);
In C, you can do simple string concatenation by writing two string literals with no operator in between. "A" "B" will be converted to "AB" at compile time. You can also use this for splitting a long string to multiple lines.
printf("a very long "
"string indeed");
To convert the define to a proper string, use the pound sign (#) in a macro or skip the whole thing and include the quotes in the define itself.
If you were compiling with GCC, you would have no choice but to wrap the define with quotes since the final trailing backslash would be interpreted as a line continuation character, and if that does not cause an error on its own, the penultimate backslash would likely raise a error. However, if you chose to just get rid of the trailing backslash, you'd still need to use two levels of stringification macros, or your syscal would be "mkdir LOGDIRECTORY". See http://gcc.gnu.org/onlinedocs/cpp/Stringification.html
So the above example would become:
#define LOGDIRECTORY C:\\logs
#define DEF2STR(x) #x
#define STR(x) DEF2STR(x)
system("mkdir " STR(LOGDIRECTORY));

Resources