0
#include <stdio.h>

#define LINE_FILE ("Line %d of file %s", __LINE__, __FILE__)


int main(void) {
    const char* str = LINE_FILE;
    printf("%s\n", str);
    printf("Line %d of file %s\n", __LINE__, __FILE__);
}

First print statement only prints the file name and not the complete line.

raphire
  • 198
  • 9

5 Answers5

2

If you want a string pre-formatted like that, here's how you do it:

#include <stdio.h>

#define STR_IMPL(x) #x
#define STR(x) STR_IMPL(x)
#define LINE_FILE ("Line " STR(__LINE__) " of file " __FILE__)


int main() {
    printf("%s\n", LINE_FILE);
}
Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
2

To actually explain why the code didn't work and how to make it work:

  • As mentioned previously, macros are basically text replacement, so you end up with
    const char* str = ("Line %d of file %s", __LINE__, __FILE__); which turns out to be gibberish.

  • The %d and %s etc format specifiers inside string literals ("these things") actually has no special meaning in C at all. It just happens that the printf family of functions defines a specific meaning for those, since printf family of functions use run-time string parsing of your input internally. And we wanted this to be done at compile-time as well, so sprintf etc is no good.

  • Now as it turns out, this line is actually valid C by accident, but not as you expected. The resulting declaration contains several commas, but here they are neither an initializer list like char str[] = {'A','B','C','\0'}; nor is it a function call. Because you placed the expression inside a parenthesis, it ends up as a subexpression and the compiler understands that as if you want to use the peculiar comma operator ,. What does the comma operator , do?.

    The TL;DR simplification about the comma operator is that it discards everything to the left and only uses the right-most operand as the result. So your expression ended up 100% equivalent to const char* str = __FILE__; Hence the surprising result with only the file name when you try to to print str.

  • Either way, this is not how we do string concatenation in C. It can be done in run-time with allocated strings and functions like strcpy and strcat, but it is also possible to concatenate string literals during compile time.

    The C preprocessor has a few tricks up its sleeve. Preprocessor refers to the first compiler stages executed, when the compiler goes through your code to make sure everything seems to be valid C "at a glance". The preprocessor was the one which replaced LINE_FILE with the macro body and then in turn replaced __LINE__ and __FILE__ with the actual data. But it is also capable of concatenating string literals. In C, this is simply done by writing two string literals with one or more spaces in between, such as "hello" "world", which will then get concatenated as "helloworld".

  • Since __FILE__ is guaranteed to be a string literal we could write "file " __FILE__ and then the preprocessor would turn that into "file test.c" etc. However, this is not the case for __LINE__ which is an integer.

  • Therefore in order to do all the concatenation at compile-time by the preprocessor, we need to convert __LINE__ into a string literal. As long as __LINE__ is a compile-time constant, the preprocessor can do that too. We would use a "stringification macro" Stringification - how does it work?.

    The TL;DR about stringification macros is that the "stringification operator" # is always applied first in the macro where it resides, before all other tokens in that macro are expanded. So if we write a macro #define STR(s) #s and pass STR(__LINE__), we will get a string literal but it will become "__LINE__", not quite what we wanted. In order to fix that, we need to create a helper macro which expands all preprocessor tokens first, before calling a macro containing #. Like this:

    #define STR_(s) #s
    #define STR(s) STR_(s)
    
  • Also we probably shouldn't do const char* str = LINE_FILE; or it will get assigned the line and file at the line where str was declared, not at the line where we chose to print it.

Complete example:

#include <stdio.h>

#define STR_(s) #s
#define STR(s) STR_(s)

#define LINE_FILE "Line " STR(__LINE__) " of file " __FILE__

int main(void) {
    puts(LINE_FILE);
}

Output:

Line 9 of file example.c
Lundin
  • 195,001
  • 40
  • 254
  • 396
1

Remember that a macro is a simple substitution, so your str is effectively

    const char* str = ("Line %d of file %s", __LINE__, __FILE__);

The expression is composed of three sub-expressions, joined using the , operator, which evaluates and ignores its first argument, then evaluates and yields its second. So it's equivalent to

    "Line %d of file %s";
    __LINE__;
    const char* str = __FILE__;

Hopefully, that helps you see why you get the result you do.

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
0

Hard to tell what you actually want here. Remember, macros are essentially just a glorified copy and paste, so this macro is not very useful:

#define LINE_FILE ("Line %d of file %s", __LINE__, __FILE__)

I think what you are looking for is a macro that calls printf with __LINE__ and __FILE__. Something like this should do it:

#define LINE_FILE printf("Line %d of file %s", __LINE__, __FILE__)

Or maybe you want to store it in a buffer for something else with a "function-like macro":

#define LINE_FILE(buf_, n_) \
    snprintf(buf_, n_, "Line %d of file %s", __LINE__, __FILE__)

int main()
{
    char buf[50];
    LINE_FILE(buf, sizeof(buf));
}
Jason
  • 2,493
  • 2
  • 27
  • 27
0

("Line %d of file %s", __LINE__, __FILE__) create the string using printf formats.

You need to:

printf LINE_FILE;

or

#define LL "Line %d of file %s\n", __LINE__, __FILE__
#define LINE_FILE (LL)

#define LINE_FILE1(name) char *name; { size_t len; name = malloc(len = (snprintf(NULL, 0, LL) + 1)); \
                         if(name) snprintf(name, len, LL);}


int main(void) 
{
    printf LINE_FILE;
    printf("Line %d of file %s\n", __LINE__, __FILE__);
    LINE_FILE1(str);
    printf("%s", str);
    free(str);
}

0___________
  • 60,014
  • 4
  • 34
  • 74