如何正确使用size_t和其他整数类型?

时间:2015-12-02 09:29:20

标签: c types type-conversion size-t

对于C中的典型循环,可以写:

for (unsigned int i = 0; i < 10; i++) {}

但是,有些人建议改为使用size_t

for (size_t i = 0; i < 10; i++) {}

因为unsigned int在索引增长超过UINT_MAX时可能会失败。

虽然我理解这一点,但有时我需要将size_t与其他固定长度类型(例如uint32_t)一起使用,或者将一些size_t写入网络。如果处理不当,这些操作容易出错。我认为同样适用于其他整数类型,例如ssize_tsocklen_t等。

处理这些不同整数和大小类型的混合并在必要时安全转换它们的正确方法是什么?

EDIT。关于类型长度的另一个问题是在printf语句中打印其值。 size_t有自己的格式说明符z。并非所有整体类型都有这种奢侈。如果printf在变量上接受typeof运算符,可能会更容易,但不幸的是,它不会。

3 个答案:

答案 0 :(得分:1)

您可以将目标/源整数类型的范围与大小类型的范围进行比较。数字应自动提升到足够大的类型进行比较(假设不涉及负数)。

size_t的最大值在stdint.h中定义(自C99起):SIZE_MAX。固定宽度整数类型的限制也可以在该标题中找到,例如UINT64_MAX

整数类型的范围在limits.h中定义:例如ULONG_MAX

供参考:

答案 1 :(得分:0)

规则摘要如下:

http://en.cppreference.com/w/c/language/types

总之,固定长度类型是唯一可以并且应该依赖的大小类型。类型之间存在相对限制(例如long永远不会短于int),而整数类型具有强制 minumum 长度(例如int保证至少为16位)。 / p>

因此,对于网络通信,您需要固定长度类型(以网络字节顺序进行传输和接收)或编码协议(例如谷歌协议缓冲区)。

答案 2 :(得分:0)

  

处理这些不同整数和大小类型的混合并在必要时安全转换它们的正确方法是什么?

是的,这具有挑战性和广泛性 以下是一些有用但尚未完成的公理。有些有限制:

  1. 对数组size_t索引使用[]。 (如果代码知道索引范围很小,可以使用较小的类型。)

  2. 使用size_t

    注意低于零
    size_t i,a,b;
    // for (i = a; i-1 < b; i++) { // `i-1` may wrap
    for (i = a; i < b + 1; i++) { // `b+1u` may wrap but far less likely.
    
  3. 当两种类型具有相同的符号或已知有符号类型比无符号类型更宽时,只需编码而不使用强制转换

    if (sg <  un)
    
  4. 否则单独处理潜在负值

    if (sg < 0 || sg < un)
    
  5. 通常安全转换,测试范围:

    // typea --> typeb
    if (vara < typeb_MIN || vara > typeb_MAX) Handle_Error()
    else varb = vara;
    
  6. 避免将typea投射到typeb,除非代码必须转换为typeb。而是乘以((typeb)1)。这样可以防止截断(也见前文)

    (typeb) vara // avoid
    ((typeb) 1) * vara
    
  7. 当打印和代码在类型的范围/宽度上不清楚时,请使用最大宽度类型

    ssize_t ssz = foo();
    printf("%jd\n", ((intmax_t)1) * ssz);
    printf("%lld\n", 1LL * ssz);
    
  8. 计算2D数组的字节大小时,先乘以size_t类型

    p = malloc(width * height * sizeof *p);   // potential overflow in width * height
    p = malloc(sizeof *p * width * height);   
    
  9. 注意:一些C整数类型

    • 已签名:signed charshortintlong long long intmax_t
    • 未签名:unsigned charunsigned shortunsignedunsigned long unsigned long long uintmax_t
    • 此外char已签名或未签名。
    • 特殊:(未签名)size_t(已签名)ptrdiff_t
    • 确切宽度(可选)示例:int8_tuint32_t以及可能令人惊讶的uint24_t
    • 最小宽度(至少8种类型)int_least8_t,...,uint_least64_t
    • 快速宽度(至少8种类型)int_fast8_t,...,uint_fast64_t
    • wchar_twint_tsig_atomic_tmax_align_t,...,...,...等等。
    • 位字段。

    其中许多类型只是其他类型的typedef。其他像intlong可能具有相同的范围,但保持其独特的类型。