整数转换(缩小,扩展),未定义的行为

我很难以我能够轻易理解的方式找到关于这个主题的信息,所以我要求对我发现的内容进行审查。这只是转换和转换的全部内容。


在示例中,我将指的是:

(signed/unsigned) int bigger; (signed/unsigned) char smaller; 
  1. 截断整数。 (超大化>小)

    • 首先在MSB截断 bigger以匹配smaller尺寸。
    • 第二,根据较小的类型截断的结果转换为有符号/无符号

    如果较大的值太大而不适合较小的类型,则会导致不确定的行为(纠正我)。 但是我的规则应该是在所有机器上工作(对此也是正确的),结果应该是可预测的。

  2. 加宽整数(小 – >更大)

    a) signed char – > signed int

    • 使用MSB(1或0)前置较小以匹配较大的大小
    • 转换为签名

    b) signed char – > unsigned int

    • 使用MSB(1或0)前置较小以匹配较大的大小。
    • 转换为无符号

    c) unsigned char – > signed int

    • 以0为前缀以匹配更大的尺寸
    • 转换为签名

    d) unsigned char – > unsigned int

    • 以0为前缀以匹配更大的尺寸
    • 转换为无符号

哪些未定义/未指定的行为,我没有提到可以弹出?

积分转换永远不会产生未定义的行为(它可以产生实现定义的行为)。

转换为可以表示转换值的类型始终是明确定义的:值只是保持不变。

转换为无符号类型始终是明确定义的:以UINT_MAX + 1(或目标类型允许的任何最大值)为模取值。

转换为无法表示正在转换的值的带符号类型会导致实现定义的值或实现定义的信号。

注意,上述规则是根据整数值定义的,而不是根据比特序列定义的。

从C标准文件(p.50草案版本201x我相信而不是确切的报价):

  • 没有两个有符号整数应具有相同的等级

  • 有符号整数的秩应大于精度较低的任何有符号整数的秩。

  • long long int大于long int,大于int,大于int,大于short int,大于signed char。

  • 有相同精度的有符号和无符号具有相同的等级(例如:signed int与unsigned int相同)

  • 任何标准整数类型的等级应大于相同宽度的任何扩展整数类型的等级。

  • char的等级等于unsigned char等于signed char。

(因为你把它们从你的问题中排除在外,我正在抛弃bool)

  • 任何扩展有符号整数相对于另一个扩展有符号整数的等级是实现定义的,但仍受其他整数转换等级规则的约束。

  • 对于所有整数类型T1 T2和T3,T1具有比T2更大的秩,并且T2具有比T3更大的秩,而T1具有比T3更大的秩。

具有整数类型(int和signed int除外)的对象,其整数等级低于或等于int和unsigned int的等级,类型为_Bool,int,signed int或unsigned int的位字段; 如果int可以表示原始类型的所有值,则该值将转换为int。 否则为unsigned int。 所有其他类型都由整数提升更改。

简单来说:

当转换为其他类型的更高级别时,任何比int或unsigned int“更小”的类型都会被提升为int。 这是编译器的工作,以确保为给定机器(体系结构)编译的C代码在这方面符合ISO-C。 char是实现定义的(被签名或未签名)。 所有其他类型(促销或“降级”)都是实现定义的。

什么是实现定义? 这意味着给定的编译器将在给定的机器上系统地表现相同。 换句话说,所有“实现定义的”行为都依赖于编译器和目标机器。

制作便携式代码:

  • 始终将价值提升到更高级别的标准C类型。
  • 永远不要将值降级为较小的类型。
  • 避免代码中的所有“实现定义”实现。

如果它破坏程序员的努力,为什么存在实现定义的疯狂? 系统编程基本上需要这些实现定义的行为。

所以更具体地针对你的问题:

  • 截断很可能不会成为可能。 或者在维护,错误跟踪等方面需要更多的努力,而不仅仅是通过使用更高级别的类型来维护代码。
  • 如果您的实现运行的值大于所涉及的类型,那么您的设计是错误的(除非您参与系统编程)。
  • 根据经验,从无符号到签名保留值但不是相反。 因此,当一个无符号值从一个有符号的值转到脚趾时,将unsigned提升为signed而不是相反。
  • 如果在应用程序中使用尽可能小的整数类型对内存至关重要,则应该重新审视整个程序的架构。