C语言 传递变量uint16_t函数,预期uint8_t变量危险



我一直在尝试解决工作中的一个错误,终于找到了。事实证明,一个函数将大小uint16_t变量传递给另一个接受大小uint8_t变量的函数,即使没有任何显式强制转换也是如此。

每当检测到无效 ID 时,这都会间歇性地导致软件内较低层的断言。

下面的代码显示了所发生情况的简化版本。

问题是调用者函数的 ID 值不能大于 0xFF即使它的大小为 uint16_t。因此,几乎始终将值传递给被调用方函数,该值是有效的。

有趣的是,问题/断言仅在启用尺寸优化时发生。

我很想知道这里到底发生了什么。我试图正确理解它。似乎传递的变量有时大于 0xFF(但不应该),然后在传递给函数时必须被截断,从而导致无效 ID。

另外,简单地传递变量的效果是什么,就像下面所做的那样,而不是将变量强制转换为uint8_t,如func((uint8_t)ID);

?我很惊讶编译器在我的情况下甚至没有警告这一点。

已编辑:变量值的代码示例导致混淆

提前非常感谢。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
void func(uint8_t);
int main()
{
uint16_t ID;
// more code
// ID gets assigned a value from 0 to 0xFF somewhere 
//....
func(ID);
return 0;
}

void func(uint8_t ID )
{
// Processing of ID
//........
//........
printf("%xn", ID);
}

如果您使用的是 gcc,-Wconversion 将为此代码生成以下警告:

$ gcc -Wconversion tmp.c tmp.c: In function ‘main’: tmp.c:11:10: warning: conversion to ‘uint8_t {aka unsigned char}’ from ‘uint16_t {aka short unsigned int}’ may alter its value [-Wconversion] func(ID);

编辑:我不知道MinGW的gcc是否支持这个标志。

EDIT2:回答问题的另一部分 - 效果是截断,它将截断您是否使用func((uint8_t)ID)(澄清)强制转换变量。

无论您提到什么 - 没有优化级别会导致标准行为偏离。我的意思是,即使您传递了一个无法保存在类型变量中的值uint8_t它也只会包装在模UINT8_MAX+1 上,然后打印该值。

默认情况下使用的编译器未启用将启用类型转换错误的开关。启用后,转换将很重要。如果对于任何级别,非铸造传递会产生警告,则不会。这就是显式投射出现的地方。

在您没有启用开关的情况下,这根本不重要。 不管你是否投。

在启用所有可能的优化级别的情况下gcc测试您的上述代码会导致44的输出,这正是上述模块化算法之后应该的样子。

如果您看到任何偏离当前行为的行为 - 应该仔细检查是否有任何中间操作正在更改值 - 但即使发生这种情况,它也不会保持大于UINT8_MAX的值。

最新更新