要打印多种类型off_t,建议使用以下代码:
off_t a;
printf("%llu\n", (unsigned long long)a);
Run Code Online (Sandbox Code Playgroud)
rua*_*akh 16
格式字符串不告诉编译器执行强制转换unsigned long long,它只是告诉printf它将接收到unsigned long long.如果你的东西的传递不是一个unsigned long long(这off_t可能不是),然后printf将简单地曲解它,以令人惊讶的结果.
原因是编译器不必知道有关格式字符串的任何信息.如果你写的话printf("%d", 3.0),一个好的编译器会给你一个警告信息,但是如果你编写的话,编译器可以做什么printf(s, 3.0),并且s是在运行时动态确定的字符串?
编辑添加:正如Keith Thompson在下面的评论中指出的那样,编译器可以在很多地方执行这种隐式转换.printf是一个相当特殊的例子,在一个案例中它不能.但是如果你声明一个函数接受一个unsigned long long,那么编译器将执行转换:
#include <stdio.h>
#include <sys/types.h>
int print_llu(unsigned long long ull)
{
return printf("%llu\n", ull); // O.K.; already converted
}
int main()
{
off_t a;
printf("%llu\n", a); // WRONG! Undefined behavior!
printf("%llu\n", (unsigned long long) a); // O.K.; explicit conversion
print_llu((unsigned long long) a); // O.K.; explicit conversion
print_llu(a); // O.K.; implicit conversion
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这样做的原因printf是声明为int printf(const char *format, ...),其中...是"可变参数"或"变量参数"符号,告诉编译器它可以接受任何数量和类型的参数format.(显然printf不能真正接受任何数量和类型的参数:它只能接受你告诉它使用的数字和类型format.但是编译器对此没有任何了解;它留给程序员来处理它. )
即使有...,编译器确实做了一些隐式转换,如推广char到int和float到double.但是这些转换并不是特定的printf,并且它们不依赖于格式字符串,也不能依赖格式字符串.
问题是您不知道off_t有多大。它可以是64位类型或32位类型(或其他类型)。如果使用%llu,并且不传递(无符号)long long类型,则将得到未定义的行为,实际上,它可能只是打印垃圾。
不知道它有多大,简单的方法是将其转换为系统支持的最大合理类型,例如unsigned long long。这样使用%llu是安全的,因为由于强制转换,printf将收到一个无符号的long long类型。
(例如,在Linux上,默认情况下,在32位计算机上,off_t的大小为32位;如果#define _FILE_OFFSET_BITS=64在包含相关系统标头之前通过启用了大文件支持,则off_t的大小为64位)