0

我一直在尝试解决工作中的一个错误,终于找到了。事实证明,一个函数将一个大小为 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("%x\n", ID);
}
4

2 回答 2

3

如果您使用 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)(澄清)转换变量,它都会截断。

于 2018-01-22T16:18:52.427 回答
0

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

您默认使用的编译器没有启用将启用类型转换错误的开关。在你启用它之后,铸造就很重要了。如果对于非演员传递的任何级别都会产生警告,那么演员就不会。这就是显式转换出现的地方。

在您的情况下,当没有启用任何开关时,这并不重要。无论你投与否。

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

如果您看到任何偏离当前行为的行为 - 应该密切关注是否有任何中间行为正在改变值 - 但即使发生这种情况,它也不会保持值大于UINT8_MAX.

于 2018-01-22T16:12:39.853 回答