GCC中的奇怪优化(删除函数)

Bin*_* Wu 1 c optimization gcc

我在GCC 4.8.2中遇到了一个奇怪的优化 - -O2,它删除了一个函数.

请参阅以下代码.

increase()和increase2()相同,只是后者有一个printf().

但是,如果在GCC中使用-O2,则会删除increase().

#include <stdio.h>
#include <stdint.h>
#include <arpa/inet.h>

void swap(uint64_t *vector)
{
    uint32_t *p = (uint32_t *)vector;
    uint32_t tmp = p[0];
    p[0] = htonl(p[1]);
    p[1] = htonl(tmp);
}

void increase(uint64_t *vector)
{
    swap(vector);
    (*vector)++;
    swap(vector);
}
void increase2(uint64_t *vector)
{
    swap(vector);
    (*vector)++;
    printf("touch...\n");
    swap(vector);
}


int main()
{
    uint64_t vector = 0xa;

    increase(&vector);
    printf("%lx\n", vector);

    increase2(&vector);
    printf("%lx\n", vector);

    return 1;
}
Run Code Online (Sandbox Code Playgroud)

输出是:

a
touch...
10000000000000a
Run Code Online (Sandbox Code Playgroud)

为什么?

提前致谢


对不起,我没说清楚.

问题不在于"删除功能",而是"功能不会影响参数".

Matt McNabb指出了原因,即严格的混叠规则.非常感谢你.

M.M*_*M.M 5

此代码导致未定义的行为:

uint32_t *p = (uint32_t *)vector;
uint32_t tmp = p[0];
Run Code Online (Sandbox Code Playgroud)

指向的内存vector是类型的对象uint64_t,但是您通过类型的左值读取它uint32_t.这违反了严格的别名规则.

由于您的程序始终调用此函数,因此未定义整个程序的行为.因此,当优化器切断导致UB的路径时,您可能会看到奇怪的优化工件.


另一个问题是你%lx用来打印出来的uint64_t.除非您的系统使用64位长,否则这将无效.要获得正确的说明符,请使用printf("%" PRIx64 "\n", vector);.你可能需要#include <inttypes.h>这个.


修复printf格式说明符后,我的系统会提供以下内容-O2,或者使用-fno-strict-aliasing开关:

10000000000000a
touch...
20000000000000a
Run Code Online (Sandbox Code Playgroud)

和垃圾在-O3.