Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 为什么';函数printk()是否使用逗号分隔参数?_C_Linux_Linux Kernel - Fatal编程技术网

C 为什么';函数printk()是否使用逗号分隔参数?

C 为什么';函数printk()是否使用逗号分隔参数?,c,linux,linux-kernel,C,Linux,Linux Kernel,示例printk调用: printk(KERN_INFO "Log message.\n"); 也许这个问题更多的是关于C语言的,因为我以前在C语言中从来没有见过一个函数不使用逗号分隔参数 这是怎么回事?编译器如何处理这些信息?由于日志级别是整数,而消息是指向字符数组的指针,因此必须单独传递它们。日志级别不是整数,而是字符串文字。相邻的字符串文字在编译时被连接成单个字符串文字。因为如果搜索头文件,您将看到例如是一个扩展为字符串文字的宏(实际上是多个字符串文字,请参见链接交叉引用),两个相邻的字

示例
printk
调用:

printk(KERN_INFO "Log message.\n");
也许这个问题更多的是关于C语言的,因为我以前在C语言中从来没有见过一个函数不使用逗号分隔参数


这是怎么回事?编译器如何处理这些信息?由于日志级别是整数,而消息是指向字符数组的指针,因此必须单独传递它们。

日志级别不是整数,而是字符串文字。相邻的字符串文字在编译时被连接成单个字符串文字。

因为如果搜索头文件,您将看到例如是一个扩展为字符串文字的宏(实际上是多个字符串文字,请参见链接交叉引用),两个相邻的字符串文本将由编译器连接成一个字符串文本

所以电话

printk(KERN_INFO "Log message.\n");
不是具有多个参数的函数调用,而是具有单个字符串文字参数的函数调用。

函数只接受一个
const char*
参数。
KERN\u INFO
宏扩展到
“\001”“6”
,产生:

printk("\001" "6" "Log message.\n");
C lexer连接相邻的字符串文字标记,这意味着 以上内容转换为:

printk("\0016Log message.\n");

编译器支持的字符串文字连接。查看
KERN\u INFO
的定义。我不做内核,但我打赌它是一个字符串文本
#define
@WhozCraig:string-literal串联不仅仅是编译器支持的。它是由语言定义的,自1989年以来一直存在。请注意,多个参数用逗号分隔:
printfk(KERN_INFO“n=%d\n”,n)。格式字符串
KERN_INFO“n=%d\n”
是第一个参数,
n
是第二个参数。
printk
类似于
printf
,它采用格式字符串和零个或多个以下参数。而且可能(这纯粹是猜测)早期版本的Linux不支持不同的日志级别;通过向格式中添加字符串来添加它们不会破坏现有代码。
为什么不将它们作为单独的参数传递?
效率。为什么要分别
推送
一个额外的参数,然后让printk将其预先挂起到字符串中?在通过寄存器中前几个参数的ABI中,这实际上浪费了一个通过参数的寄存器。还有一个代码大小的优势。推入一个立即数整数的机器指令总是比直接将数据前置到字符串中的指令要大。传递一个指针而不是实际要挂起的字节更糟糕,因为这样字节需要存储在某个地方,代码中需要一个32位的指针。谢谢。我看到头中的日志级别是数字,但没有看到它们是字符串文本。我还必须复习一下C如何连接由空格分隔的字符串文字。@PSkocik,但是为什么宏
KERN\u INFO
“\001”“6”
?我只理解开头的空字符,但它是八进制的01?(如前所述,
0
?-因此在串联后的八进制中是
016
?在ascii中是016(
14
十进制,
0E
十六进制,
so-shift out
),因此要确保下一个
6
不会是
^
)然后-我试图在
/usr/include/linux/kernel.h
中查找宏,但没有找到它。它是在该目录中还是在其他地方?@raskman转义序列的语法是在。也就是说,对于八进制,它是'\'+1–3个八进制数字(包括起始的0)。因此“\0016”(或等效的“\001”“6”)被解析为“{001}6”,即字节1后跟数字6(十进制ASCII中的字节36)。我想,3个八进制数字的限制就是为什么使用八进制转义而不是十六进制转义的原因。十六进制转义没有数字限制,所以
“\X111111aaaabbbcccddeeffgreetings,world”
会将g之前的所有内容解释为转义。