【问题标题】:Segmentation fault when using fprintf output __LINE__使用 fprintf 输出 __LINE__ 时出现分段错误
【发布时间】:2015-12-14 10:09:30
【问题描述】:

代码如下:

#include <stdio.h>

int main() {

    fprintf(stderr, "%s \n", __LINE__);

    return 0;
}

# gcc b.c
# ./a.out
Segmentation fault (core dumped)

【问题讨论】:

    标签: c printf


    【解决方案1】:

    __LINE__ 扩展为一个整数常量。使用%d 打印:

    fprintf(stderr, "%d \n", __LINE__);
    

    §6.10.8.1 强制宏(C11 草案)

    __LINE__ 当前源行的假定行号(在当前源文件中)(一个整数常量)。


    如果__LINE__ 宏溢出int 是一个问题,那么您可以将其转换为uintmax_t 并打印它。这是最安全的方式,因为uintmax_t 是最大的整数类型。

    #include <stdint.h>
    
    fprintf(stderr, "%ju \n", (uintmax_t)__LINE__);
    

    【讨论】:

    • 如果文件超过 32767 行并且您的平台有 16 位 int,这将是 UB。
    • @Bathsheba 按照这个逻辑,long long 也行不通。通常,int 在大多数平台上是 32 位的,如果您的源文件有 4294967296 (2^32 - 1) 行,那么 __LINE__ 宏是您的问题中最少的:)
    • 虽然这是一个很好的答案(加一个),但令人不安的是,C 在__LINE__ 的类型上如此失误。我仍然认为,总的来说,使用(long)__LINE__ 是最安全的做法。
    【解决方案2】:

    您的程序的行为是未定义,因为您的格式说明符不正确。

    然而,C 标准在__LINE__类型 上令人恼火。它只是声明它是一个整体类型。这意味着它可能是 int,或者,如果 int 不够大(int 的最大大小可能为 32767),那么它将是 long

    所以可以肯定的是,我会使用 %ld 作为格式说明符并编写

    fprintf(stderr, "%ld \n", (long)__LINE__);

    对于真的大文件,我猜它可能是long long 类型;那么你会 需要

    fprintf(stderr, "%lld \n", (long long)__LINE__);

    【讨论】:

    • int 可能是 16 位宽?
    • 确实如此:但为了便携性,您应该考虑到这一点。
    【解决方案3】:

    由于__LINE__ 是一个整数常量,所以不能将其用作字符串。如果需要字符串,则必须告诉预处理器将数字转换为字符串:

    #define STRINGIFY(x) #x
    #define STR(x) STRINGIFY(x)
    
    fprintf(stderr, "%s \n", STR(__LINE__));
    

    【讨论】:

      【解决方案4】:

      __LINE__ 实际上是一个整数常量,通过尝试将其打印为字符串,系统会搜索要打印的内容,直到整数常量没有的终止符,从而导致进程进入内存它不应该。在这种情况下,结果当然是段错误。

      长话短说,使用%d 作为格式说明符来打印。

      【讨论】:

        【解决方案5】:

        __LINE__ 至少需要%d 格式,因为是整数常量。

        一个好的提示:始终使用-Wall 选项进行编译。在您的情况下,您会看到:

        b.c: In function ‘main’:
        b.c:5:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 3 has type ‘int’ [-Wformat=]
             fprintf(stderr, "%s \n", __LINE__);
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-07-19
          • 2020-02-23
          • 1970-01-01
          • 2017-06-06
          • 2017-08-26
          • 2018-06-18
          • 2019-05-10
          • 2018-02-15
          相关资源
          最近更新 更多