c - 为什么启用优化后 GCC 11 编译器会产生奇怪的输出?

标签 c pointers gcc optimization casting

请看一下这段代码:

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

int main()
{
    uint8_t run = 1;

    /* Define variable of interest and set to random value */
    uint32_t dwTime = 0xdeadc0de;

    /* Define uint16_t pointer */
    uint16_t* tmpU16;
    /* Assign least 16 bits from dwTime to tmpU16 by downcasting from uint32_t to uint16_t */
    tmpU16 = (uint16_t*)&dwTime;

    /* Print content of tmpU16 */
    fprintf(stderr, "TEST: %04x\n", *tmpU16); /* Will print "TEST: c0de" here */

    /* This loop will run exactly once */
    while (run)
    {
        /* Print content of tmpU16 AGAIN (content of tmpU16 should not have changed here!) */
        /* Will print "TEST: 0000" here when optimization is enabled */
        /* Will print "TEST: c0de" here when optimization is disabled */
        fprintf(stderr, "TEST: %04x\n", *tmpU16);

        /* Increment tmpU16 pointer by 1 (yes, this does not make sense but it should not do any harm
        either, unless something gets written to its address AFTER incrementing */
        tmpU16++;
        run--;
    }

    return 0;
}

当使用 GCC 11 并启用优化(例如 -O2)编译此代码时,它将产生以下输出:

TEST: c0de
TEST: 0000

当此代码在未经优化的情况下编译时(-O0),它将产生:

TEST: c0de
TEST: c0de

我假设第一个fprintf执行后,while循环中的下一个fprintf将立即执行。在这两个 fprintf 之间不应发生任何事情,因此 tmpU16 的内容保持不变。

但是,当我注释掉 tmpU16++ 指针增量时,它会通过优化产生正确的输出。

为什么会这样,这里发生了什么?

最佳答案

在这一行:

tmpU16 = (uint16_t*)&dwTime;

您将一种类型的对象视为另一种不兼容的类型,从而犯了严格的别名冲突。

C standard 第 6.5p7 节列出了可能发生混叠的情况:

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:88)

  • a type compatible with the effective type of the object,
  • a qualified version of a type compatible with the effective type of the object,
  • a type that is the signed or unsigned type corresponding to the effective type of the object,
  • a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
  • an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
  • a character type.

88 ) The intent of this list is to specify those circumstances in which an object may or may not be aliased

使用指向 uint16_t 的指针来访问 uint32_t 不属于这些类别中的任何一个。这种违规行为会触发undefined behavior .

特别是对于 gcc,除非您使用 -O2 或更高版本,或者显式使用 -fstrict-aliasing,否则不会启用严格的别名规则。通过强制执行此规则,编译器能够进行其他方式无法进行的优化。

关于c - 为什么启用优化后 GCC 11 编译器会产生奇怪的输出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71410943/

相关文章:

c - 奇偶查找表生成

c - C 中的结构指针未返回正确的值

c - C 中的 Realloc 函数

c - 键入 C 时自动添加一个点 (.)

c - 独立可移植的snprintf(),独立于标准库?

c - 为 int* 动态分配 100 个字节,然后尝试使用指针算法为其设置值有什么影响?

以指针为返回值的C++嵌套函数

c++ - 返回 ARM NEON 下的 Z 标志

c++ - 如何在 ubuntu 14.04 中通过 apt-get 安装以前版本 (4.4.7) 的 gcc/g++?

c++ - MIPS 32 位上缺少 __sync_fetch_and_add_8 的替代方法