【问题标题】:Why doesn't the function printk() use a comma to separate parameters?为什么函数 printk() 不使用逗号分隔参数?
【发布时间】:2016-07-20 22:41:47
【问题描述】:

printk 调用示例:

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

也许这个问题更多地是关于 C 的,因为在没有逗号分隔参数之前我从未见过 C 中的函数。

这是如何工作的?编译器如何处理这些信息?由于日志级别是整数,而消息是指向char数组的指针,所以必须分别传递。

【问题讨论】:

  • 编译器支持的字符串文字连接。看KERN_INFO的定义。我不做内核,但我敢打赌这是一个字符串文字#define
  • @WhozCraig:字符串文字连接不仅仅是编译器支持的。它由语言定义,自 1989 年以来一直如此。
  • 请注意,多个参数用逗号分隔:printfk(KERN_INFO "n = %d\n", n);。格式字符串KERN_INFO "n = %d\n" 是第一个参数,n 是第二个参数。
  • printk 类似于printf,它采用格式字符串和零个或多个以下参数。并且有可能(这纯粹是推测)Linux 的早期版本不支持不同的日志级别。通过将字符串添加到格式中来添加它们不会破坏现有代码。
  • Why not pass these as separate arguments? 效率。为什么要单独给 push 一个额外的参数,然后让 printk 将它预先附加到字符串中?在传递寄存器中前几个参数的 ABI 中,这实际上浪费了传递参数的寄存器。还有一个代码大小的优势。推送一个立即整数的机器指令总是比将数据直接添加到字符串中要大。传递一个指针而不是实际的字节会更糟,因为这样字节需要存储在某个地方,并且代码中需要一个 32 位指针。

标签: c linux linux-kernel


【解决方案1】:

printk() 函数只接受一个const char* 参数。 KERN_INFO 宏扩展为 "\001" "6",产生:

printk("\001" "6" "Log message.\n");

C 词法分析器连接相邻的字符串文字标记,这意味着 以上转换为:

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

【讨论】:

  • 谢谢。我看到标题中的日志级别是数字,而忽略了它们是字符串文字。我还需要复习一下 C 如何连接由空格分隔的字符串文字。
  • @PSkocik,但为什么是宏KERN_INFO"\001" "6"?我只理解开头的空字符,但它是八进制的 01 ? (如前面的0? - 所以它是连接后八进制的016?在ascii中是016(十进制的14,十六进制的0ESO - shift out,所以要确定下一个@987654335 @ 不会是 ^?) 然后 - 我试图在 /usr/include/linux/kernel.h 中查找宏,但没有找到它。是在那个目录中还是在其他地方?
  • @Herdsman 转义序列的语法在port70.net/~nsz/c/c11/n1570.html#6.4.4.4 中。即对于八进制,它是 '\' + 1-3 个八进制数字(包括开头的 0)。因此“\0016”(或等效的“\001”“6”)被解析为“{001}6”,即字节 1 后跟数字 6(十进制 ASCII 中的字节 36)。 3 个八进制数字的限制是为什么,我猜,使用八进制转义而不是十六进制转义。十六进制转义没有数字限制,因此"\x111111111aaaabbbcccdddeeefffgreetings, world" 会将直到 g 的所有内容都解释为转义。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    因为如果您搜索头文件,您会看到例如KERN_INFO 是一个扩展为 字符串文字 的宏(实际上是多个字符串文字,参见例如链接的交叉引用),并且彼此相邻的两个字符串文字将被连接成一个编译器的字符串字面量。

    所以打电话

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

    不是带有多个参数的函数调用,而是带有单个字符串字面量参数的函数调用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-12-22
      • 1970-01-01
      • 2013-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多