printf中用于格式化long类型的转换说明符是什么?

608

printf函数需要一个参数类型,例如%d%i用于有符号整数signed int。然而,我没有看到任何适用于long值的选项。


不要使用long,它不具有可移植性。 - MarcH
1
@MarcH - int 也不是可移植的。历史上,int 是一个16位的值;在一些机器上(例如Cray),它也是一个64位的值。即使是“精确宽度类型”如 int64_t,也不是100%可移植的;只有在架构支持这种类型时才定义。int_least64_t 类型是最接近可移植的类型。 - Jonathan Leffler
C11规范是§7.21.6.1fprintf函数§7.21.6.3printf函数 的条目大多重定向到¶7.21.6.1。POSIX规范是printf() - Jonathan Leffler
int在某些情况下可能是最佳选择,但它并不具备可移植性;例如,小型for循环的索引通常不需要可移植性。另一方面,long既不具备可移植性,也从来没有用处,也不是最佳选择。long就是糟糕的。如果您需要保证为32位或64位的东西,则使用uint32_tuint64_t。简单明了。如果在某些奇特的平台上它们不可用,则您的代码将无法编译,这正是您想要的。 - MarcH
关于这个话题:https://faultlore.com/blah/c-isnt-a-language/ - MarcH
7个回答

784

在说明符前直接放置小写字母l

unsigned long n;
long m;

printf("%lu %ld", n, m);

20
printf("%ld", ULONG_MAX) 输出的结果为-1。根据@Blorgbeard所述,应该使用printf("%lu", ULONG_MAX)来输出无符号长整型。 - jammus
2
实际上,你应该将它更改为%ld,以与OP问题更加协调。 - DrBeco
Yep Dr Beco;此外,仅使用%l会触发warning: unknown conversion type character 0x20 in format [-Wformat] - Patrizio Bertoni

205
我想你的意思是:
unsigned long n;
printf("%lu", n);   // unsigned long

或者

long n;
printf("%ld", n);   // signed long

96

在大多数平台上,longint的大小相同(32位)。但是,它确实有自己的格式说明符:

long n;
unsigned long un;
printf("%ld", n); // signed
printf("%lu", un); // unsigned

对于64位,你需要使用long long

long long n;
unsigned long long un;
printf("%lld", n); // signed
printf("%llu", un); // unsigned

哦,当然,在Windows上是不同的:

printf("%l64d", n); // signed
printf("%l64u", un); // unsigned

经常情况下,当我打印64位的值时,我发现以十六进制形式打印它们会更有帮助(通常这样大的数字是指针或位域)。

unsigned long long n;
printf("0x%016llX", n); // "0x" followed by "0-padded", "16 char wide", "long long", "HEX with 0-9A-F"

将打印:

0x00000000DEADBEEF

顺便提一句,在主流的x64平台上,“long”已经不再有太多意义了。“int”是平台默认的整数大小,通常为32位。“long”通常是相同大小的。但是,在旧平台(和现代嵌入式平台!)上,它们具有不同的可移植性语义。“long long”是一个64位数字,通常是人们想要使用的,除非他们确实知道在编辑跨平台可移植代码时在做什么。即使那样,他们可能也会使用宏来捕获类型的语义含义(例如uint64_t)。

char c;       // 8 bits
short s;      // 16 bits
int i;        // 32 bits (on modern platforms)
long l;       // 32 bits
long long ll; // 64 bits 

以前,“int”是16位。尽管现在它应该是64位,但这样做会导致疯狂的可移植性问题。当然,即使这也是复杂而历史悠久的真相的简化版。参见维基:整数


7
需要澄清的是:除了x86和x64之外,还有更多种架构,在这些架构中,char、short、int、long和long long具有不同的含义。例如,一个32位的微控制器,具有16位的内存对齐方式,可以使用: char = short = int = 16位; long = 32位; long long = 64位。 - AndresR
2
@AndresR - 绝对没错,这对于从事嵌入式编程的人们来说非常重要(我曾经为一个烟雾报警器构建了一个内核模块)。可怜那些试图使用不具备可移植性的代码的可怜之人。 - Dave Dopson
2
我不太确定“大多数平台都有一个大小为32的long”是否仍然正确。例如,我在Oracle Linux x86_64/amd64上使用nvcc时,long是8个字节。 - interestedparty333
哦,当然,在Windows中它是不同的。有跨平台的解决方案吗? - Aaron Franke
@interestedparty333 是的,我有95%以上的把握,在Linux中long与字/指针大小相同(因此在32位Linux上为32位,在64位Linux上为64位)。如果您查看Linux内核代码或Linux驱动程序内部,它们通常将指针存储在longunsigned long变量中。实际上,几周前,我的一位同事将一些代码从Windows移植到Linux时,不得不将我们所有的long更改为uint32_t,因为我们在Windows下开发时经常误用它们。 - adentinger
声明“在大多数平台上,long和int的大小相同(32位)”是错误的...大多数Unix和类Unix系统使用LP64模型,其中int为32位,而long为64位-https://en.wikipedia.org/wiki/64 -bit_computing#64-bit_data_models - Nick Dowell

17

这要看具体情况,如果你指的是无符号长整型,格式字符是"%lu"。 如果你指的是有符号长整型,格式字符是"%ld"



13

我需要打印 unsigned long long,所以我发现这个方法可行:

unsigned long long n;
printf("%llu", n);

对于所有其他组合,我认为您可以使用printf手册中的表格,根据您要打印的类型取行和列标签(如我在上面使用printf("%llu", n))。


-3

我认为要明确回答这个问题需要知道您使用的编译器名称和版本以及它所编译的平台(CPU类型、操作系统等)。


4
你的回答应该是一条评论,而不是一个独立的答案。 - Jaime Hablutzel
不会有平台依赖于打印“long”的正确格式 - 正确答案是“%ld”。可以打印的值的范围取决于平台 - 在某些平台上,“long”将是32位类型(特别是在2008年之前),而在其他平台上,它将是64位类型(特别是在2022年及以后)。但是,如果数据类型是“long”,则正确的“printf()”转换说明符是“%ld”(尽管您可以使用“%li”)。 - Jonathan Leffler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接