是C赋值和参数传递导致隐式转换,还是应该显式转换?

时间:2019-04-19 22:55:22

标签: c casting

以下两个代码段之间有什么区别吗?

A:

int x = get_some_int();
uint8_t y = x;

B:

int x = get_some_int();
uint8_t y = (uint8_t) x;

此外,如果y是函数的uint8_t自变量并且将x传递到函数中(有或没有显式强制转换)怎么办?

编辑::请允许我重新表述一个问题:在C中,在分配或传递给其他类型时始终显式转换变量是否是C的优良作法?还是将其留给编译器是一种好习惯?程序员应该做的“默认”是什么?

2 个答案:

答案 0 :(得分:1)

问题不是强制转换之一(不需要分配是直接转换为POST http://localhost:9200/myindex/mytype/_bulk C11 Standard - 6.5.16.1 Simple assignment(p2)),问题是范围之一。 uint8_t是一个32位带符号整数,能够保存int x;范围内的值。相反,-2147483648 to 2147483647是一个无符号的8位值,能够保存值uint8_t y;

您可以轻松地为0 - 255分配一个超出x范围的值。那会发生什么呢?如果y的值超出了x的范围,则y的值将以模数x降到1 + max_for_type C11 Standard - 6.2.5 Types(p9)以内,因此如果y的值超出了y = x % 256;的范围,则分配等同于x

例如,uint8_tx = 25306708;x转换为uint8_t时,y = x;的模数为x,以适应{ {1}}。 (例如256

如果您想避免默示地减少价值以适合y,那么您可以测试y == 84的价值是否适合y而不会减少。您可以使用简单的条件和x中定义的常量来做到这一点,例如

y

将显示该行为的简短示例放在一起,您可以这样做:

stdint.h

使用/输出示例

    y = x;  /* direct assignment, no cast required */

    if (0 <= x && x <= UINT8_MAX)   /* validate x within the range of uint8_t */
        printf ("int x: %d is in range of uint8_t y: %" PRIu8 "\n", x, y);
    else
        /* handle the error as required */

回答:

  

“始终显式转换变量是否是C的良好做法”

否。如果您正在执行的操作涉及不兼容的类型,则强制转换将屏蔽编译器将生成的警告。您应该只进行很少的转换,并且只应在库API等要求的明确需要的地方进行转换。

仔细检查一下,如果还有其他问题,请告诉我。

答案 1 :(得分:1)

C 2018标准在第6.5.16.1节第2段中指出:

  

简单赋值=)中,将右操作数的值转换为赋值表达式的类型,并替换存储在由左操作数指定的对象中的值。

因此,是的,转换是隐式进行的。 C标准不要求您使用强制转换。

但是,仅允许某些操作数。第1段在很大程度上表示,左操作数和右操作数必须都为算术类型或必须具有兼容的类型。 1 因此,如果左操作数和右操作数不满足第1段中的条件,您必须使用强制转换将正确的操作数转换为满足条件的类型。

这给了我们这些情况:

  • C标准允许左右操作数,并且编译器会毫无保留地接受它们:不需要强制转换。如果您想向阅读代码的人传达某种意图,则可以使用一个,但是通常不建议强制转换,因为强制转换可以隐藏警告和错误消息,可能有助于发现错误。
  • C标准允许左右操作数,但是您使用的编译器会发出警告消息:如果要取消显示警告,则需要强制类型转换。但是,编译器试图通过警告告诉您一些信息,例如强制转换可能隐藏溢出。在插入演员表之前,您应该确保了解警告的原因。
  • C标准不允许左右操作数:需要强制转换。同样,在插入演员表之前,您应该充分理解语义。

脚注

1 第1段的全文为:

  

应满足以下条件之一:

     

-左侧的操作数具有原子,合格或不合格的算术类型,右侧的操作数具有算术类型;

     

-左操作数具有与右类型兼容的结构或联合类型的原子,合格或不合格版本;

     

-左操作数具有原子,合格或不合格的指针类型,并且(考虑到左操作数在左值转换后将具有的类型)两个操作数都是指向兼容类型的合格或不合格版本的指针,并且类型由左侧具有右侧所指类型的所有限定词;

     

-左操作数具有原子,限定或不限定的指针类型,并且(考虑到左操作数在左值转换后将具有的类型),一个操作数是指向对象类型的指针,另一个是指向限定类型​​的指针或void的非限定版本,并且左侧指向的类型具有右侧指向的类型的所有限定符;

     

-左操作数是原子,限定或不限定的指针,而右是空指针常量;或

     

-左边的操作数的类型是原子,限定或不限定的_Bool,而右边的是指针。