【发布时间】: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)
【问题讨论】:
代码如下:
#include <stdio.h>
int main() {
fprintf(stderr, "%s \n", __LINE__);
return 0;
}
# gcc b.c
# ./a.out
Segmentation fault (core dumped)
【问题讨论】:
__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__);
【讨论】:
int,这将是 UB。
long long 也行不通。通常,int 在大多数平台上是 32 位的,如果您的源文件有 4294967296 (2^32 - 1) 行,那么 __LINE__ 宏是您的问题中最少的:)
__LINE__ 的类型上如此失误。我仍然认为,总的来说,使用(long)__LINE__ 是最安全的做法。
您的程序的行为是未定义,因为您的格式说明符不正确。
然而,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 位宽?
由于__LINE__ 是一个整数常量,所以不能将其用作字符串。如果需要字符串,则必须告诉预处理器将数字转换为字符串:
#define STRINGIFY(x) #x
#define STR(x) STRINGIFY(x)
fprintf(stderr, "%s \n", STR(__LINE__));
【讨论】:
__LINE__ 实际上是一个整数常量,通过尝试将其打印为字符串,系统会搜索要打印的内容,直到整数常量没有的终止符,从而导致进程进入内存它不应该。在这种情况下,结果当然是段错误。
长话短说,使用%d 作为格式说明符来打印。
【讨论】:
__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__);
【讨论】: