[英]Correct format specifiers for custom integer types in C to ensure portability
I want to know what is the right printf
format specifier for custom integer types such as time_t
, socklen_t
, etc.我想知道自定义整数类型(例如time_t
、 socklen_t
等)的正确printf
格式说明符是什么。
For example,例如,
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
int main()
{
struct addrinfo *ai;
if (getaddrinfo("localhost", "http", NULL, &ai) != 0) {
printf("error\n");
return EXIT_FAILURE;
}
printf("%d\n", ai->ai_addrlen);
}
Although this program compiles and runs fine, I am not happy about using %d
to print ai_addrlen
which is defined to be of type socklen_t
in struct addrinfo
because there is no guarantee that socklen_t
is type int
.尽管该程序编译并运行良好,但我对使用%d
打印ai_addrlen
并ai_addrlen
,它在struct addrinfo
定义为socklen_t
类型,因为不能保证socklen_t
是int
类型。
How can we correctly print such integers that are defined as socklen_t
, time_t
, etc.?我们如何正确打印定义为socklen_t
、 time_t
等的整数? I am concerned about portability here.我担心这里的便携性。 I should not have to modify the format specifier when the program is compiled on a different implementation with different definitions for socklen_t
.当程序在具有不同socklen_t
定义的不同实现上编译时,我不应该修改格式说明符。
Use an intermediate cast to intmax_t
and the %jd
specifier:使用中间转换为intmax_t
和%jd
说明符:
printf("%jd\n", (intmax_t) ai->ai_addrlen);
The cast enlarges the integer to an integer of the largest possible size which is able to represent the values of any other signed integer type.强制转换将整数放大为最大可能大小的整数,该整数能够表示任何其他有符号整数类型的值。 There is a slight caveat here: in case sizeof(intmax_t) == sizeof ai->addrlen
and ai->addrlen
is unsigned, large values which do not fit into a signed integer ( intmax_t
) will be truncated.这里有一个小小的警告:如果sizeof(intmax_t) == sizeof ai->addrlen
并且ai->addrlen
是无符号的,则不适合有符号整数 ( intmax_t
) 的大值将被截断。
In case you are sure that the printed type is unsigned, use uintmax_t
and %ju
instead.如果您确定打印的类型是无符号的,请改用uintmax_t
和%ju
。
The j
character is a "length sub-specifier" especially suited for handling the size of intmax_t
/ uintmax_t
and it can go together with the d
or i
specifier characters (for intmax_t
) or the u
, o
, X
and x
characters (for uintmax_t
). j
字符是一个“长度子说明符”,特别适合处理intmax_t
/ uintmax_t
的大小,它可以与d
或i
说明符字符(对于intmax_t
)或u
、 o
、 X
和x
字符(对于uintmax_t
)。
@Blagovest Buyukliev answer is the best approach when the sign-ness of the type is known.当类型的符号已知时, @Blagovest Buyukliev答案是最好的方法。
// if some unsigned type
printf("%ju\n", (uintmax_t) ux);
// if some signed type
printf("%jd\n", (intmax_t) x);
A challenge occurs when that sign-ness is not known.当该符号未知时,就会出现挑战。 Macro preprocessing does not account for types.宏预处理不考虑类型。 The following accounts for the sign-ness issue.以下说明了符号问题。 This is useful if the value is representable in only one of intmax_t
and uintmax_t
.如果该值只能在intmax_t
和uintmax_t
之一中表示,则这很有用。
int main(void) {
mystery_integer_type x = rand() - RAND_MAX/2;
// Compiler can easily optimized one of the 2 paths out
if (x * 0 - 1 > 0) {
printf("Unigned %ju\n", (uintmax_t) x);
} else {
printf("Signed %jd\n", (intmax_t) x);
}
}
Note that if the type is narrower than int/unsigned
, the path taken is well defined either way per "... one promoted type is a signed integer type, the other promoted type is the corresponding unsigned integer type, and the value is representable in both types; ..." C11dr §6.5.2.2 6请注意,如果类型比int/unsigned
窄,则所采用的路径按“...两种类型;..." C11dr §6.5.2.2 6
A special issue occurs when trying to print time_t
, which the C spec does not define sign-ness nor if it is an integer or floating-point, just that it is a real type .尝试打印time_t
时会出现一个特殊问题,C 规范没有定义符号,也没有定义它是整数还是浮点数,只是它是一个实数类型。
For the rare case where time_t
needs to be portable printed, some ideas, ranging from pedantic to casual.对于time_t
需要便携式打印的罕见情况,一些想法,从迂腐到随意。
// pedantic
printf("%La\n", (long double) time());
printf("%.*Le\n", LDBL_DECIMAL_DIG - 1, (long double) time());
printf("%.*e\n", DBL_DECIMAL_DIG - 1, (double) time());
printf("%jd\n", (intmax_t) time());
printf("%lld\n", (long long) time());
printf("%ld\n", (long) time());
// casual
Note: time()
may return (time_t)(-1)
.注意: time()
可能返回(time_t)(-1)
。
(u)intmax_t
and some others of the above rely on C99/C11. (u)intmax_t
和上述其他一些依赖于 C99/C11。
Portability to pre-C99 adds additional issues not discussed typically resulting in using (long)
or (double)
.对 C99 之前的可移植性增加了未讨论的其他问题,通常会导致使用(long)
或(double)
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.