C中自定义整数类型的正确格式说明符,以确保可移植性

时间:2016-09-09 18:19:31

标签: c cross-platform portability

我想知道自定义整数类型的正确printf格式说明符是什么,例如time_tsocklen_t等。

例如,

#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);
}

虽然这个程序编译并且运行正常,但我不满意使用%d打印ai_addrlensocklen_tstruct addrinfo中定义为socklen_t类型,因为有int无法保证socklen_t的类型为time_t

我们如何才能正确打印定义为socklen_t.tomato a[href]{color:#F00;} 等的整数?我担心这里的便携性。当程序在具有.tomato [href]{color:#F00;} 的不同定义的不同实现上编译时,我不必修改格式说明符。

2 个答案:

答案 0 :(得分:4)

使用intmax_t%jd说明符的中间演员:

printf("%jd\n", (intmax_t) ai->ai_addrlen);

强制转换将整数放大到最大可能大小的整数,该大小能够表示任何其他有符号整数类型的值。这里有一个小小的警告:如果sizeof(intmax_t) == sizeof ai->addrlenai->addrlen是无符号的,那么大的值将不符合有符号整数(intmax_t)将会被截断。

如果您确定打印类型未签名,请改用uintmax_t%ju

j字符是“长度子说明符”,特别适合处理intmax_t / uintmax_t的大小,它可以与d或{一起使用{1}}说明符字符(适用于i)或intmax_tuoX个字符(适用于x)。< / p>

答案 1 :(得分:1)

@Blagovest Buyukliev回答是该类型的 sign-ness 的最佳方法。

// if some unsigned type
printf("%ju\n", (uintmax_t) ux);

// if some signed type
printf("%jd\n", (intmax_t) x);

当该迹象未知时,就会发生挑战。宏预处理不考虑类型。以下说明了签名问题。如果值只能在intmax_tuintmax_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);
  }

}

请注意,如果类型比int/unsigned窄,那么所采用的路径都可以通过以下方式定义:“一个提升类型是有符号整数类型,另一个提升类型是相应的无符号整数类型,并且这两个类型的值都可以表示; ......“C11dr§6.5.2.26

尝试打印time_t时出现一个特殊问题,C规范没有定义符号,也不是整数或浮点数,只是它是实数类型

对于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

注意:time()可能会返回(time_t)(-1)

(u)intmax_t以及上述其他一些依赖于C99 / C11 C99之前的可移植性增加了未经讨论的其他问题,导致使用(long)(double)