首页 文章

C运算符中的隐式类型转换规则

提问于
浏览
142

我想知道什么时候应该投出更好 . 在添加,乘法等时,C中的隐式类型转换规则是什么 . 例如,

int + float = ?
int * float = ?
float * int = ?
int / float = ?
float / int = ?
int / int = ?
int ^ float = ?

等等...

表达式是否总是被评估为更精确的类型? Java的规则有所不同吗?如果我不准确地说出这个问题,请纠正我 .

9 回答

  • -1

    在C运算符(对于POD类型)中,始终对相同类型的对象执行操作 .
    因此,如果它们不相同,则将提升以匹配另一个 .
    操作结果的类型与操作数相同(转换后) .

    If either is      long          double the other is promoted to      long          double
    If either is                    double the other is promoted to                    double
    If either is                    float  the other is promoted to                    float
    If either is long long unsigned int    the other is promoted to long long unsigned int
    If either is long long          int    the other is promoted to long long          int
    If either is long      unsigned int    the other is promoted to long      unsigned int
    If either is long               int    the other is promoted to long               int
    If either is           unsigned int    the other is promoted to           unsigned int
    If either is                    int    the other is promoted to                    int
    Both operands are promoted to int
    

    注意 . 最小操作大小为 int . 所以 short / char 在操作完成之前被提升为 int .

    在所有表达式中, int 在执行操作之前被提升为 float . 操作的结果是 float .

    int + float =>  float + float = float
    int * float =>  float * float = float
    float * int =>  float * float = float
    int / float =>  float / float = float
    float / int =>  float / float = float
    int / int                     = int
    int ^ float =>  <compiler error>
    
  • 16

    涉及 float 的算术运算结果为 float .

    int + float = float
    int * float = float
    float * int = float
    int / float = float
    float / int = float
    int / int = int
    

    有关详细解答 . 看看C标准的第5/9节是什么

    许多期望算术或枚举类型操作数的二元运算符会以类似的方式导致转换并产生结果类型 . 目的是产生一个通用类型,它也是结果的类型 . 此模式称为通常的算术转换,其定义如下: - 如果任一操作数的类型为long double,则另一个操作数应转换为long double . - 否则,如果任一操作数为double,则另一个操作数应转换为double . - 否则,如果任一操作数是浮点数,则另一个操作数应转换为浮点数 . - 否则,应对两个操作数执行整数提升(4.5).54) - 然后,如果任一操作数为无符号长,则另一操作数应转换为无符号长整数 . - 否则,如果一个操作数是long int而另一个是unsigned int,那么如果long int可以表示unsigned int的所有值,则unsigned int应该转换为long int;否则两个操作数都应转换为unsigned long int . - 否则,如果任一操作数很长,则另一个操作数应转换为long . - 否则,如果任一操作数是无符号的,则另一个操作数应转换为无符号 . [注意:否则,唯一剩下的情况是两个操作数都是int]

  • 1

    由于其他答案没有谈到C 11中的规则,这里是一个 . 从C 11标准(草案n3337)§5/ 9:

    此模式称为通常的算术转换,其定义如下: - 如果任一操作数是作用域枚举类型,则不执行任何转换;如果另一个操作数的类型不同,则表达式格式不正确 . - 如果任一操作数的类型为long double,则另一个操作数应转换为long double . - 否则,如果任一操作数为double,则另一个操作数应转换为double . - 否则,如果任一操作数是浮点数,则另一个操作数应转换为浮点数 . - 否则,应对两个操作数执行整体促销 . 然后,以下规则将应用于提升的操作数: - 如果两个操作数具有相同的类型,则不需要进一步转换 . - 否则,如果两个操作数都有有符号整数类型或两者都有无符号整数类型,则具有较小整数转换等级类型的操作数应转换为具有更高等级的操作数的类型 . - 否则,如果具有无符号整数类型的操作数的秩大于或等于另一个操作数的类型的秩,则带有符号整数类型的操作数应转换为具有无符号整数类型的操作数的类型 . - 否则,如果带有符号整数类型的操作数的类型可以表示具有无符号整数类型的操作数类型的所有值,则具有无符号整数类型的操作数应转换为带有符号整数类型的操作数的类型 . - 否则,两个操作数都应转换为与带符号整数类型的操作数类型相对应的无符号整数类型 .

    有关经常更新的列表,请参阅here .

  • 2

    这个答案在很大程度上取决于@RafałDowgird的评论:

    “操作的最小大小是int . ” - 这将是非常奇怪的(有效支持char / short操作的架构怎么样?)这是否真的在C规范中?

    请记住,C标准具有非常重要的“假设”规则 . 请参见第1.8节:程序执行:

    3)这项规定有时被称为“假设”规则,因为只要结果好像符合要求,实施可以自由地忽视标准的任何要求,只要可以从程序的可观察行为 .

    编译器不能将 int 的大小设置为8位,即使它是最快的,因为标准要求最小16位 int .

    因此,在理论计算机具有超快速8位操作的情况下,隐式升级到 int 算术可能很重要 . 但是,对于许多操作,您无法判断编译器是否实际以 int 的精度执行了操作,然后转换为 char 以存储在您的变量中,或者操作是否始终在char中完成 .

    例如,考虑 unsigned char = unsigned char + unsigned char + unsigned char ,其中加法会溢出(让我们假设每个值为200) . 如果你升级到 int ,你将获得600,然后将隐式向下转换为 unsigned char ,这将包装模256,从而给出88的最终结果 . 如果你没有这样的促销,你必须在前两个添加,将把问题从 200 + 200 + 200 减少到 144 + 200 ,即344,减少到88.换句话说,程序不知道差异,因此编译器可以自由地忽略执行中间操作的任务 int 如果操作数的排名低于 int .

    这通常是加法,减法和乘法 . 对于除法或模数,一般情况并非如此 .

  • 184

    如果排除无符号类型,则存在有序层次结构:signed char,short,int,long,long long,float,double,long double . 首先,在上面的int之前的所有内容都将转换为int . 然后,在二进制操作中,较低等级的类型将被转换为较高的,并且结果将是较高的类型 . (您将注意到,从层次结构中,只要涉及浮点和整数类型,整数类型将转换为浮点类型 . )

    无符号使事情变得复杂:它扰乱了排名,并且部分排名变为实现定义 . 因此,最好不要在同一个表达式中混合使用signed和unsigned . (大多数C专家似乎都避免使用无符号,除非涉及按位操作 . 至少,Stroustrup建议使用 . )

  • 30

    我的solution到了problem得到了WA(错误答案),然后我将 int 中的一个更改为 long long int 并且它给了AC(accept) . 以前,我试图做 long long int += int * int ,并在我纠正到 long long int += long long int * int 之后 . 谷歌搜索我想出来,

    1.算术转换

    类型转换的条件:

    条件符合--->转换

    • 任一操作数的类型为 long double . --->其他操作数转换为 long double 类型 .

    • 未满足前置条件且任一操作数的类型为 double . --->其他操作数转换为 double 类型 .

    • 未满足前置条件且任一操作数的类型为 float . --->其他操作数转换为 float 类型 .

    • 未满足前置条件(没有任何操作数是浮点类型) . --->对操作数执行整体促销,如下所示:

    • 如果任一操作数的类型为 unsigned long ,则另一个操作数将转换为 unsigned long 类型 .

    • 如果未满足先前条件,并且任一操作数的类型为 long 且另一个类型为 unsigned int ,则两个操作数都将转换为 unsigned long 类型 .

    • 如果不满足前两个条件,并且任一操作数的类型为 long ,则其他操作数将转换为 long 类型 .

    • 如果不满足前面的三个条件,并且任一操作数的类型为 unsigned int ,则另一个操作数将转换为 unsigned int 类型 .

    • 如果不满足上述条件,则两个操作数都将转换为 int 类型 .

    2 . 整数转换规则

    • 整数促销:

    在对它们执行操作时,将提升小于int的整数类型 . 如果原始类型的所有值都可以表示为int,则较小类型的值将转换为int;否则,它将转换为unsigned int . 整数促销作为通常算术转换的一部分应用于某些参数表达式;一元, - 和〜运算符的操作数;移位运算符和操作数 .

    • 整数转换排名:

    • 没有两个有符号整数类型具有相同的等级,即使它们具有相同的表示 .

    • 有符号整数类型的等级应大于精度较低的任何有符号整数类型的等级 .

    • long long int 的等级应大于 long int 的等级,该等级应大于 int 的等级,该等级应大于 short int 的等级,该等级应大于 signed char 的等级 .

    • 任何无符号整数类型的等级应等于相应的有符号整数类型的等级(如果有) .

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

    • char 的等级应等于 signed charunsigned char 的等级 .

    • 任何扩展有符号整数类型相对于具有相同精度的另一个扩展有符号整数类型的等级是实现定义的,但仍然受制于确定整数转换等级的其他规则 .

    • 对于所有整数类型T1,T2和T3,如果T1具有比T2更大的秩并且T2具有比T3更大的秩,则T1具有比T3更大的秩 .

    • 通常的算术转换:

    • 如果两个操作数具有相同的类型,则不需要进一步转换 .

    • 如果两个操作数具有相同的整数类型(有符号或无符号),则具有较小整数转换等级类型的操作数将转换为具有较高等级的操作数的类型 .

    • 如果具有无符号整数类型的操作数的秩大于或等于另一个操作数的类型的等级,则带有符号整数类型的操作数将转换为具有无符号整数类型的操作数的类型 .

    • 如果带有符号整数类型的操作数的类型可以表示具有无符号整数类型的操作数类型的所有值,则具有无符号整数类型的操作数将转换为带有符号整数类型的操作数的类型 .

    • 否则,两个操作数都转换为无符号整数类型,对应于带有符号整数类型的操作数类型 . 特定操作可以添加或修改通常的算术运算的语义 .

  • 1

    整个第4章讨论了转换,但我认为你应该最感兴趣的是:

    4.5 Integral promotions [conv.prom]
    如果int可以表示源类型的所有值,则可以将char,signed char,unsigned char,short int或unsigned short int类型的rvalue转换为int类型的rvalue . 其他-
    明智的是,源rvalue可以转换为unsigned int类型的右值 .
    类型为wchar_t(3.9.1)或枚举类型(7.2)的右值可以转换为第一个的右值
    可以表示其基础类型的所有值的以下类型:int,unsigned int,
    长或无符号长 .
    如果int可以表示all,则可以将积分位域(9.6)的rvalue转换为int类型的rvalue
    位域的值;否则,如果unsigned int可以代表它,它可以转换为unsigned int
    重新发现位域的所有值 . 如果位字段较大,则不适用整数提升 . 如果
    bit-field具有枚举类型,它被视为该类型的任何其他值以用于促销目的 .
    bool类型的rvalue可以转换为int类型的rvalue,false变为零和true
    成为一体 .
    这些转化称为整体促销 .

    4.6 Floating point promotion [conv.fpprom]
    float类型的右值可以转换为double类型的右值 . 该值保持不变 .
    此转换称为浮点提升 .

    因此,所有涉及浮点数的转换 - 结果都是浮点数 .

    只涉及两个int - 结果是int:int / int = int

  • 3

    当两个部分属于同一类型时,表达式的类型将被转换为两者中最大的 . 这里的问题是要了解哪一个比另一个大(它与字节大小没有任何关系) .

    在涉及实数和整数的表达式中,整数将被提升为实数 . 例如,在int float中,表达式的类型为float .

    另一个区别与该类型的能力有关 . 例如,涉及int和long int的表达式将生成long int类型 .

  • 5

    警告!

    转换从左到右进行 .

    试试这个:

    int i = 3, j = 2;
    double k = 33;
    cout << k * j / i << endl; // prints 22
    cout << j / i * k << endl; // prints 0
    

相关问题