Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
GCC中的奇怪优化(删除函数)_C_Gcc_Optimization - Fatal编程技术网

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

GCC中的奇怪优化(删除函数),c,gcc,optimization,C,Gcc,Optimization,我在GCC4.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 = (ui

我在GCC4.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;
}
为什么?

提前谢谢


对不起,我没有说清楚

问题不是“删除函数”,而是“函数不影响参数”

Matt McNabb指出了原因,严格的别名规则。
非常感谢。

如果函数实际被删除,您的输出将更像:

touch...
a
touch...
10000000000000a
为了回答你的问题,它正在打印这个,因为你告诉它按那个顺序打印这三行

increase()
的调用不会输出任何内容,然后使用
printf(“%lx\n”,vector)
输出
a

然后,调用
increase2()
并按设计输出
touch…
,然后使用
printf(“%lx\n”,vector)输出
100000000000a



您是否检查了未优化的输出?

如果函数实际被删除,您的输出将更像:

touch...
a
touch...
10000000000000a
为了回答你的问题,它正在打印这个,因为你告诉它按那个顺序打印这三行

increase()
的调用不会输出任何内容,然后使用
printf(“%lx\n”,vector)
输出
a

然后,调用
increase2()
并按设计输出
touch…
,然后使用
printf(“%lx\n”,vector)输出
100000000000a



是否检查了未优化的输出?

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

uint32_t *p = (uint32_t *)vector;
uint32_t tmp = p[0];
vector
指向的内存是类型为
uint64\u t
的对象,但是您可以通过类型为
uint32\u t
的左值读取它。这违反了严格的别名规则

由于您的程序总是调用此函数,因此整个程序的行为是未定义的。因此,当优化器切断通向UB的路径时,您可能会看到奇怪的优化工件


另一个问题是,您正在使用
%lx
打印
uint64\u t
。除非您的系统使用64位长,否则这将无法工作。要获得正确的说明符,请使用
printf(“%”PRIx64“\n”,vector)。为此,您可能需要
#包括


在修复printf格式说明符后,我的系统在
-O2
和更低的位置提供以下信息,或者如果使用
-fno strict aliasing
开关:

10000000000000a
touch...
20000000000000a

和垃圾在
-O3

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

uint32_t *p = (uint32_t *)vector;
uint32_t tmp = p[0];
vector
指向的内存是类型为
uint64\u t
的对象,但是您可以通过类型为
uint32\u t
的左值读取它。这违反了严格的别名规则

由于您的程序总是调用此函数,因此整个程序的行为是未定义的。因此,当优化器切断通向UB的路径时,您可能会看到奇怪的优化工件


另一个问题是,您正在使用
%lx
打印
uint64\u t
。除非您的系统使用64位长,否则这将无法工作。要获得正确的说明符,请使用
printf(“%”PRIx64“\n”,vector)。为此,您可能需要
#包括


在修复printf格式说明符后,我的系统在
-O2
和更低的位置提供以下信息,或者如果使用
-fno strict aliasing
开关:

10000000000000a
touch...
20000000000000a

和垃圾在
-O3

我知道你的问题是“为什么”。马特·麦克纳布解释得很好。但如何修复呢

通常编译器和CPU更喜欢值而不是指针,因为它们有更多(更安全)的优化空间。因此,让我们完全避免指针技巧,只进行值转换:

#include <endian.h>

void swap(uint64_t *vector)
{
    *vector = htobe64(le64toh(*vector));
}
#包括
无效交换(uint64_t*向量)
{
*向量=htobe64(le64toh(*向量));
}

这使您的程序行为对优化不敏感。

我知道您的问题是“为什么”。马特·麦克纳布解释得很好。但如何修复呢

通常编译器和CPU更喜欢值而不是指针,因为它们有更多(更安全)的优化空间。因此,让我们完全避免指针技巧,只进行值转换:

#include <endian.h>

void swap(uint64_t *vector)
{
    *vector = htobe64(le64toh(*vector));
}
#包括
无效交换(uint64_t*向量)
{
*向量=htobe64(le64toh(*向量));
}

这使您的程序行为对优化不敏感。

我看不出您描述的问题。似乎正在调用
increase()
increase2()
。。。问题是什么?学习如何使用gnu调试器一步一步地查看执行情况。@Wedapasi老实说,对初学者来说,调试优化后的代码会非常混乱。在这种特定情况下,即使是
main
操作也会重新排序。另一方面,当然知道
gdb
是合理的。你能检查一下你实际上正在运行这段代码吗?比如说,在每次调用
increase
之前,你没有打印
printf
?@dlask:非常正确。我完全同意你的意见。但是,我怀疑这是否会成为这个特定代码的一个问题,因为输出是预期的、未定义的行为。我个人认为,看到步骤viz代码的执行和实际调试之间有细微的区别。查看步骤viz代码的执行可以真正帮助理解代码流,不一定是在出现问题的情况下。我没有看到您描述的问题。似乎正在调用
increase()
increase2()
。。。问题是什么?学习如何使用gnu调试器一步一步地查看执行情况。@Wedapasi老实说,对初学者来说,调试优化后的代码会非常混乱。在这种特定情况下,即使是
main
操作也会重新排序。另一方面,房委会