gcc -O3 诊断警告:'<U ea0>' 未初始化 - UB、bug 或“名称修改”?

问题描述 投票:0回答:1

在回答这个问题时,我萌生了一个想法,想偷偷地绕过不将浮点数转换为指针的 C 约束,并想出了这段令人讨厌的异国情调的人工代码:

(显然我们不应该像这样编写真正的产品代码 - 请注意“语言律师”标签。)

#include <stdio.h>

void get_value (void* data)
{
    printf("Value %f \r\n", *(float*)&(int){(int)data});
}


int main(void) {
    float di = 10.10f;

    get_value( (void*) ((union cheeky{int i; float f;}){.f=di}.i) ); 
    return 0;
}

据我所知,这是有效的 C。 main() 中的联合应该意味着严格的别名不适用,尽管我不确定这里的“有效类型”是什么,因为该对象具有多种表示形式。通过在中间转换为

int
来初始化另一个
void*
,但至少会打印正确的结果。

当然,整数到指针的转换是实现定义的,

int
float
的大小也是如此,gcc 会相应地抱怨。显然,如果指针未对齐或陷阱表示等,可能会出现 UB。

但是,当我添加优化时,我得到了这个真正奇怪的诊断。

gcc -std=c2x -pedantic-errors -Wall -Wextra -O3

<source>:5:29: warning: '<U ea0>' is used uninitialized [-Wuninitialized]
    5 |     printf("Value %f \r\n", *(float*)&(int){(int)data});
      |                             ^~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:5:44: note: '({anonymous})' declared here
    5 |     printf("Value %f \r\n", *(float*)&(int){(int)data});
  |                                            ^

所以 this 指的是函数内部的复合文字。这是由

void*
的演员们清楚地初始化的。此警告仅在
-O3
和使用 gcc 11 或更高版本的组合下弹出。较旧的 gcc 不会发出警告,clang 也不会发出警告。

我似乎还得到了一个不同的神秘“十六进制代码”

<U ea0>
等,具体取决于gcc版本,但这可能(?)只是因为我每次在编译器资源管理器中得到不同的构建。

问题:

  • 这里是否有我没有发现的未定义行为,或者这段代码只是实现定义的?
  • 这是有意的、某种方式的匿名复合文字的内部“名称修改”吗?如果是这样,为什么它只出现在
    -O3
    下?我尝试过
    __attribute__((noinline))
    ,但没有什么区别。
  • 或者这是 gcc 中的诊断错误?
c gcc language-lawyer strict-aliasing
1个回答
0
投票

我编译了代码的一个小变体(在定义之前明确声明了

get_value()
以避免出现
-Wmissing-prototypes
错误):

/* SO 7840-1960 */
#include <stdio.h>

extern void get_value (void* data);

void get_value (void* data)
{
    printf("Value %f \r\n", *(float*)&(int){(int)data});
}


int main(void) {
    float di = 10.10f;

    get_value( (void*) ((union cheeky{int i; float f;}){.f=di}.i) ); 
    return 0;
}

我使用了 Clang (

Apple clang version 15.0.0 (clang-1500.3.9.4)
) 并得到了以下输出:

$ clang -Weverything -Wno-poison-system-directories -Werror -c ll67.c
ll67.c:8:45: error: cast to smaller integer type 'int' from 'void *' [-Werror,-Wvoid-pointer-to-int-cast]
    printf("Value %f \r\n", *(float*)&(int){(int)data});
                                            ^~~~~~~~~
ll67.c:8:29: error: implicit conversion increases floating-point precision: 'float' to 'double' [-Werror,-Wdouble-promotion]
    printf("Value %f \r\n", *(float*)&(int){(int)data});
    ~~~~~~                  ^~~~~~~~~~~~~~~~~~~~~~~~~~
ll67.c:15:16: error: cast to 'void *' from smaller integer type 'int' [-Werror,-Wint-to-void-pointer-cast]
    get_value( (void*) ((union cheeky{int i; float f;}){.f=di}.i) ); 
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 errors generated.
$

我不确定这告诉了你什么(如果有的话)。但输出太大,在评论中不合理。

© www.soinside.com 2019 - 2024. All rights reserved.