这对我来说是一个真正的WTF,看起来像GCC中的一个bug,但我想让社区看看,为我找到一个解决方案.

下面是我能想到的最简单的程序:

#include <stdio.h>
#include <stdint.h>

int main(void)
{
 uint16_t i = 1;
 uint16_t j = 2;
 i += j;
 return i;
}

我试着用-Werror=conversion旗在GCC上编译这段代码,我的大部分代码都用到了它.

结果如下:

.code.tio.c: In function ‘main’:
.code.tio.c:9:7: error: conversion to ‘uint16_t {aka short unsigned int}’ from ‘int’ may alter its value [-Werror=conversion]
  i += j;

此代码将出现相同的错误:

uint16_t i = 1;
i += ((uint16_t)3);

错误是

.code.tio.c: In function ‘main’:
.code.tio.c:7:7: error: conversion to ‘uint16_t {aka short unsigned int}’ from ‘int’ may alter its value [-Werror=conversion]
  i += ((uint16_t)3);
       ^

为了清楚起见,这里的错误出现在+=运算符上,而不是强制转换.

看起来+=号和uint16_t号的操作员超载是乱七八糟的.还是我错过了一些微妙的东西?

供你使用:MCVE

编辑:更多相同的内容:

.code.tio.c:8:6: error: conversion to ‘uint16_t {aka short unsigned int}’ from ‘int’ may alter its value [-Werror=conversion]
  i = i + ((uint16_t)3);

但至少i = (uint16_t)(i +3);元还能用……

推荐答案

隐式转换的原因是由于+=运算符与=+的等价性.

C standard号文件的第6.5.16.2节开始:

3形式为E1 op=E2的复合赋值等同于简单赋值表达式E1=E1 op(E2),除了左值 E1仅判断一次,并且相对于 不确定顺序的函数调用,复合赋值的操作是单次求值

所以这就是:

i += ((uint16_t)3);

相当于:

i = i + ((uint16_t)3);

在这个表达式中,+运算符的操作数被提升为int,而int又被赋回uint16_t.

第6.3.1.1节详细说明了出现这种情况的原因:

2在可能使用intunsigned int的任何地方,都可以在表达式中使用以下内容:

  • 整数类型(intunsigned int以外)的对象或表达式,其整数转换秩小于或等于 intunsigned int的排名.
  • 类型为_Boolintsigned intunsigned int的位字段.

如果int可以表示原始类型(如受限)的所有值 比特字段的宽度),将该值转换为int; 否则,它将转换为unsigned int.这些被称为 integer promotions.所有其他类型的整数都保持不变 升职.

因为uint16_t(又称ANunsigned short int)的秩低于int,所以当用作操作数时,这些值会提升到+.

您可以通过分解+=运算符并在右侧投射来解决此问题.此外,由于升级,值3上的强制转换不起作用,因此可以将其删除:

i =  (uint16_t)(i + 3);

但是请注意,此操作会发生溢出,这是在没有强制转换时发出警告的原因之一.例如,如果i值为65535,则i + 3具有类型int和值65538.当结果转换回uint16_t时,从该值中减go 值65536,得到值2,然后将该值分配回i.

此行为在本例中定义良好,因为目标类型是无符号的.如果目标类型已签名,则结果将是实现定义的.

C++相关问答推荐

strftime函数中%s的历史意义是什么?为什么没有记录?

是否有任何情况(特定类型/值),类型双关在所有符合标准的C实现中产生相同的行为?

Ebpf内核代码:permission denied:invalid access to map value

在使用GTK 4 Columnview列表模型时,如何为多列添加排序函数.C编码,Linux/GNOME环境

正在try 将文件/文件夹名从目录 struct 存储到链接列表

为什么删除CAP_DAC_OVERRIDE后创建文件失败?

在C++中通过空指针隐式访问常量变量的值

双指针指向常量双指针的指针类型赋值不兼容

如何按顺序将所有CSV文件数据读入 struct 数组?

强制转换变量以在 struct 中蚕食

接受任何参数的函数指针是否与接受不同参数的函数兼容

-Wnonnull-Compare警告不是具有误导性吗?

我在C程序的Flex/Bison中遇到语法错误

如何使用空元素块声明指针数组

If语句默认为true

尽管将其标记为易失性,但 gcc 是否优化了我的等待代码?

无法在线程内用 C 打印?

C 中从 Unix 纪元时间转换的损坏

仅使用其内存地址取消引用 C 中的 struct

在 atmega4809 上使用 UART1 发送多个字符会导致发送 0xFF