2

This is probably a very simple and core component of C programming but it's extremely hard to search for

printk in the kernel can take a number of log level consts and the function itself uses varargs, however I can't figure out why it works. Here's an example call for those not familiar

printk(KERN_DEBUG "this is my message which can be %s as normal", "formatted");

The source code is below and it uses varargs but what mechanism allows to pass multiple strings that are space-separated to one parameter?

asmlinkage __visible int printk(const char *fmt, ...)
{
        va_list args;
        int r;

        va_start(args, fmt);
        r = vprintk_func(fmt, args);
        va_end(args);

        return r;
}

This isn't particular to printk, I've seen it used in drivers in the kernel when creating a device

device_create(drv_class, 
                      NULL,    
                      dev, 
                      NULL,      
                      MY_DEVICE_NAME "%d", i); 

Can anyone tell me what allows this? Is it compiler specific or a core part of the language?

LiamRyan
  • 1,892
  • 4
  • 32
  • 61

2 Answers2

3
printf("hello World\n");
// or equivalent
printf("h" "e" "l" "l" "o" " " "W" "o" "r" "l" "d" "\n");
// or equivalent
#define char_h "h"
printf(char_h "ello World\n");

String literals are concatenated together. That means, that "ab" and "a" "b" is the same. The null termination character is added on the end only.

The preprocessor substitutes only. So #define KERN_DEBUG "<7>" just makes preprocessor substitute KERN_DEBUG for "<7>".

Then after preprocessor two string literals are concatened. So for example printf(KERN_DEBUG "..."); becomes printf("<7>" "..."); and then string literals are concatenated into printf("<7>...");.

Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
1

This is just a C language feature that concatenates string literals at compile time. "foo" "bar" is equivalent to "foobar". It's very convenient for putting long strings in code but can also be used together with macro expansion. Consider:

#define FOO "foo"
int i;
printf(FOO "%d", i);

This is just passing "FOO" "%d" to printf, which is equivalent to "FOO%d" as a result of macro expansion and the C language rules for string constants.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • Am I missing something with the first example or did you miss the KERN_DEBUG? I thought they were exactly the same mechanism. I was just showing that it otherwise works per printf using the varargs with the % – LiamRyan Mar 09 '19 at 19:49
  • Oh, I missed that! Thanks, that makes my answer *much* simpler. – David Schwartz Mar 09 '19 at 19:51