C / PREPROCESSOR
Predefined macros like __FILE__ and __LINE__
Use __FILE__, __LINE__ and friends to stamp source coordinates onto logs and checks, and know why they report the call site rather than the macro's own line.
What you will learn
- Capture __FILE__ and __LINE__ in a macro so a logging function learns the caller's position
- Convert __LINE__ to text with a two-step stringify, since # never expands its operand
- Tell __func__ apart from real macros: it is a per-function const char array, not text
- Predict which line __LINE__ reports: the expansion point, not the #define line
Understanding Predefined macros like __FILE__ and __LINE__
Every translation unit carries bookkeeping the compiler already needs for its own diagnostics: the presumed name of the file being read and the presumed number of the line being read. __FILE__ hands you the first as a string literal, __LINE__ hands you the second as an integer constant, and both are substituted before the compiler proper runs, so printf("%s:%d", __FILE__, __LINE__) costs nothing at runtime because the compiler only ever sees a literal and a number. The same table supplies __DATE__ and __TIME__ as strings frozen when the file was compiled, __STDC__, and __STDC_VERSION__, which is 201112L for C11 and 201710L for C17.
What makes these useful is the expansion-point rule. A #define stores its replacement list as an unexpanded sequence of tokens, and __FILE__ or __LINE__ sitting in that list are substituted afresh at each invocation, using the position of that invocation. A macro that forwards them therefore describes its caller, while a function that reads them can only ever describe the single line inside its own body. That asymmetry is the reason assert is a macro, and the reason serious logging code puts a thin macro in front of the function that does the work.
The two are not interchangeable in type, and that is where beginners get stuck. __FILE__ is a string literal, so it sits next to other literals and the compiler joins them into one string. __LINE__ is an integer constant, so producing text from it needs two macro levels: # does not expand its operand, so STR(__LINE__) gives "__LINE__" and only XSTR(__LINE__), which expands one level before stringifying, gives "42". __func__ looks like a member of the family but is not a macro at all; it is an identifier the compiler declares as a static const char array at the top of each function body, invisible to #ifdef and unusable in literal concatenation.
/* saved as main.c, built with: cc main.c -o demo */
<stdio.h>
LOG(msg)
static void log_call(const char *msg)
{
printf("[%s:%d %s] %s\n", __FILE__, __LINE__, __func__, msg);
}
int main(void)
{
LOG("macro reports the caller");
log_call("function reports itself");
LOG("second call, new line");
return 0;
}
__FILE__ and __LINE__ are replaced wherever they are expanded, so a macro carries the caller's coordinates while a function only ever knows its own line.
Worked examples
Building a location string at compile time
Shows that __FILE__ concatenates like any literal while __LINE__ needs a two-level stringify.
/* saved as loc.c, built with: cc loc.c */
<stdio.h>
STR(x)
XSTR(x)
HERE
int main(void)
{
puts(HERE);
puts(STR(__LINE__));
return 0;
}
Example explained
Line 1HERE expands to three adjacent string literals, which the compiler joins after preprocessing, so there is no runtime formatting at all.
Line 2XSTR expands its argument first, so STR then receives the token 10 and stringifies that.
Line 3puts(STR(__LINE__)) prints __LINE__ verbatim because # suppresses expansion of its own operand.
Line 4The number is 10 because that is the line where HERE is used, not line 6 where it was defined.
Both values are only presumed
Demonstrates #line overriding __FILE__ and __LINE__, the mechanism code generators use to point errors back at their input.
/* saved as presumed.c, built with: cc presumed.c */
<stdio.h>
int main(void)
{
printf("real: %s:%d\n", __FILE__, __LINE__);
printf("faked: %s:%d\n", __FILE__, __LINE__);
printf("back: %s:%d\n", __FILE__, __LINE__);
return 0;
}
Example explained
Line 1#line sets the position of the following line, so the printf under the directive reports 100, not 101.
Line 2The second argument of #line replaces __FILE__ with any name you like, even a file that was never compiled.
Line 3Compiler warnings after that directive also move to generated.y, because __FILE__ and __LINE__ read the same counters the diagnostics use.
Line 4The final #line 10 resynchronises the counters with the real file so later messages are truthful again.
Important notes
__FILE__ is the path as it was written on the command line or in the #include, not a bare basename, so building src/main.c stamps src/main.c into every message and into the binary.
When a macro invocation is split across several lines, the standard does not pin down which of those lines __LINE__ reports, so keep the call on one line whenever the number matters.
Common mistakes
Moving the printf into a helper function and reading __LINE__ there: every message then reports the same line inside the logger, and the position of the actual event is lost forever.
Treating __LINE__ as text: "line " __LINE__ does not compile because an integer constant cannot be concatenated with a string literal, and puts(__LINE__) passes an int where a pointer is expected, which crashes at runtime if your compiler only warns.
Assuming __func__ is a macro: #ifdef __func__ is always false and "in " __func__ fails to compile, because __func__ is a variable the compiler declares inside the function, not preprocessor text.
Try it yourself
Change, predict, then run
Write a CHECK(cond) macro that prints the file, the line and the failed condition text (via #cond) when cond is false, then call it twice on different lines, once with a true condition and once with a false one, and confirm only the failing line appears.
Open the C workspaceCheck your understanding
util.h defines LOG on line 5 as #define LOG(m) log_at(__FILE__, __LINE__, (m)). main.c includes it and calls LOG("hi") on line 42. What reaches log_at?
- "main.c" and 42, because both macros are replaced when LOG is expanded at the call site
- "util.h" and 5, because __FILE__ and __LINE__ were resolved when the #define was processed
- "util.h" and 42, because __FILE__ tracks where the macro was written and __LINE__ where it was used
- "main.c" and the line of log_at's definition, since the arguments are only read inside the function
Show answer
#define stores its replacement list as raw tokens and expands nothing, so __FILE__ and __LINE__ are substituted during the expansion on line 42, at which point the preprocessor is reading main.c. Option 2 is the tempting one if you imagine the definition being evaluated at #define time, but nothing in a replacement list is expanded there, and the current file during expansion is main.c, which also rules out the util.h answers.