将size_t转换为unsigned long int是否安全?

时间:2017-11-29 15:22:14

标签: c c89

我需要一种可移植的方式来打印size_t类型的变量 n 的值。由于我使用ANSI C89,因此无法使用z长度修饰符。我目前的做法是将值转换为long unsigned int

printf("%lu\n", (long unsigned int) n);

如果size_t被定义为unsigned intlong unsigned int,我无法看到它会如何失败。演员安全吗?

1 个答案:

答案 0 :(得分:2)

size_t n = foo();
printf("%lu\n", (long unsigned int) n);
  

前提是size_t被定义为unsigned intlong unsigned int ...是否安全?

是的,演员阵容是安全的,没有未定义的行为,也没有关于C89,C99,C11的信息丢失。

但是,附带条件是不是真的?

假设size_t的范围在unsigned long范围内是非常合理的。添加编译时测试:ref

#include <limits.h>
#if defined(__STDC__)
#if defined(__STDC_VERSION__)
#if (__STDC_VERSION__ >= 199901L)
#include <stdint.h>
#if SIZE_MAX > ULONG_MAX
#error Re-work printf size code
#endif
#endif
#endif
#endif

关键是当代码具有依赖性时 - 添加测试。即使它在今天和历史上所有已知机器都可以接受,但未来还是未知数。

C今天,凭借其巨大的灵活性确实允许SIZE_MAX > ULONG_MAX,但它确实很少见。国际海事组织,SIZE_MAX > ULONG_MAXbeyond the pale

此类测试虽然可能很常见,但编写超级可移植代码根本不可行或预算不足。

#include <limits.h>
#if CHAR_BIT != 8 && CHAR_BIT != 16 && CHAR_BIT != 32 && CHAR_BIT != 64
  #error Code depends on char size as a common power of 2.
#endif
  

我需要一种可移植的方法来打印size_t类型的变量n的值。

然而,要解决OP的顶级目标,可以编写一个简单的可移植辅助函数。

// This approach works with any unsigned type
void print_size_t(size_t n) {
  if (n >= 10) print_size_t(n/10);
  putchar((int) (n%10) + '0');
}

为避免递归,功能稍长:

#include <limits.h>
void print_size_t(size_t n) {
  char buf[sizeof n * CHAR_BIT / 3 + 2];  // 1/3 is more than log2(10)
  char *p = &buf[sizeof buf - 1];          // Start at end of buf[]
  *p = '\0';
  do {
    p--;
    *p = (char) (n%10 + '0');
    n /= 10;
  } while (n);    // Use a do {} while so print_size_t(0) prints something
  fputs(p, stdout);
}