可以`mem​​set`函数调用由编译器中删除? [英] Can `memset` function call be removed by compiler?

查看:174
本文介绍了可以`mem​​set`函数调用由编译器中删除?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已阅读这里的编译器是免费删除调用 memset的,如果它知道,通过内存缓冲区永远不会再次使用。这怎么可能?这在我看来,(从观的核心语言的角度) memset的只是一个普通的功能,编译器无权假设里面无论发生什么事情,都会有无副作用。

I have read here that compiler is free to remove call to memset if it knows that passed memory buffer is never used again. How is that possible? It seems to me that (from the point of view of core language) memset is just a regular function, and compiler has no right to assume that whatever happens inside it, will have no side effects.

链接文章,他们展示了如何去除视觉C ++ 10 memset的。我知道,微软编译器不符合标准的领导,所以我想问 - 是按照标准,或只是MSVC主义?如果它按照标准,请详细说明;)

In linked article they show how Visual C++ 10 removed memset. I know that Microsoft compilers are not leading in standard compliance, so I ask - is it according to standard, or is it just msvc-ism? If it's according to standard, please elaborate ;)

编辑:
@Cubbi

@Cubbi

继code:

void testIt(){
    char foo[1234];
    for (int i=0; i<1233; i++){
        foo[i] = rand()%('Z'-'A'+1)+'A';
    }
    foo[1233]=0;
    printf(foo);
    memset(foo, 0, 1234);
}

在MinGW的编译与行:

Compiled under mingw with lines:

g++ -c -O2 -frtti -fexceptions -mthreads -Wall -DUNICODE -o main.o main.cpp
g++ -Wl,-s -Wl,-subsystem,console -mthreads -o main.exe main.o
objdump -d -M intel -S main.exe > dump.asm

都给输出:

 4013b0:    55                      push   ebp
 4013b1:    89 e5                   mov    ebp,esp
 4013b3:    57                      push   edi
 4013b4:    56                      push   esi
 4013b5:    53                      push   ebx
 4013b6:    81 ec fc 04 00 00       sub    esp,0x4fc
 4013bc:    31 db                   xor    ebx,ebx
 4013be:    8d b5 16 fb ff ff       lea    esi,[ebp-0x4ea]
 4013c4:    bf 1a 00 00 00          mov    edi,0x1a
 4013c9:    8d 76 00                lea    esi,[esi+0x0]
 4013cc:    e8 6f 02 00 00          call   0x401640
 4013d1:    99                      cdq    
 4013d2:    f7 ff                   idiv   edi
 4013d4:    83 c2 41                add    edx,0x41
 4013d7:    88 14 1e                mov    BYTE PTR [esi+ebx*1],dl
 4013da:    43                      inc    ebx
 4013db:    81 fb d1 04 00 00       cmp    ebx,0x4d1
 4013e1:    75 e9                   jne    0x4013cc
 4013e3:    c6 45 e7 00             mov    BYTE PTR [ebp-0x19],0x0
 4013e7:    89 34 24                mov    DWORD PTR [esp],esi
 4013ea:    e8 59 02 00 00          call   0x401648
 4013ef:    81 c4 fc 04 00 00       add    esp,0x4fc
 4013f5:    5b                      pop    ebx
 4013f6:    5e                      pop    esi
 4013f7:    5f                      pop    edi
 4013f8:    c9                      leave  
 4013f9:    c3                      ret   

在行4013ea有memset的调用,因此MinGW的没有删除它。由于MinGW的真的是GCC在窗口皮肤,我想GCC做它一样的 - 我会检查它,当我重新开机进入Linux

In line 4013ea there is memset call, so mingw haven't removed it. Since mingw is really GCC in windows skin, I suppose GCC does it the same - I will check it when I reboot into linux.

不过很难找到这样的编译器?

Still having trouble finding such compiler?

EDIT2:

我刚刚发现了GCC的 __ attribute__((折纯))。所以它不是编译器知道什么特别的memset和elides它,它只是它允许在它的头 - 在程序员使用它也应该看到它;)我的MinGW没有这个属性在 memset的声明,因此,它不是从组装eliding不管是什么 - 如我期望的那样。我会进行调查。

I just found out about GCC's __attribute__ ((pure)). So it's not that compiler knows something special about memset and elides it, it's just that it's allowed in it's header - where programmer using it should also see it ;) My mingw doesn't have this attribute in memset declaration, thus it's not eliding from the assembly no matter what - as I would expect. I will have to investigate this.

推荐答案

编译器无权假设里面无论发生什么,不会有任何副作用。

"compiler has no right to assume that whatever happens inside it, will have no side effects."

这是正确的。但如果事实上编译器知道什么实际的发生里面并能确定其真正的无副作用,则不需要任何假设。

That's correct. But if the compiler in fact knows what actually happens inside it and can determine that it really has no side effects, then no assumption is needed.

这是所有的编译器优化几乎是如何工作的。在code说:X。编译器确定,如果Y是真的,那么它可以代替codeX与codeZ和不会有任何检测的差异。它决定了Y是真实的,然后它替换X和Z。

This is how almost all compiler optimizations work. The code says "X". The compiler determines that if "Y" is true, then it can replace code "X" with code "Z" and there will be no detectable difference. It determines "Y" is true, and then it replaces "X" with "Z".

例如:

void func()
{
  int j = 2;
  foo();
  if (j == 2) bar();
   else baz();
}

编译器可以优化这富();酒吧(); 。编译器可以看到不能合法修改Ĵ的价值。如果富()不知何故神奇地计算出其中Ĵ是在栈上,并修改它,然后优化将改变在code的行为,但是这是程序员的使用魔术。

The compiler can optimize this to foo(); bar();. The compiler can see that foo cannot legally modify the value of j. If foo() somehow magically figures out where j is on the stack and modifies it, then the optimization will change the behavior of the code, but that's the programmer's fault for using "magic".

void func()
{
  int j = 2;
  foo(&j);
  if (j == 2) bar();
   else baz();
}

现在不能因为可以依法修改Ĵ的值没有任何魔法。 (假设编译器不能往里,在某些情况下就可以了。)

Now it can't because foo can legally modify the value of j without any magic. (Assuming the compiler can't look inside foo, which in some cases it can.)

如果你做的神奇,那么编译器可以使你突破code优化。遵守规则,不要使用魔法。

If you do "magic", then the compiler can make optimizations that break your code. Stick to the rules and don't use magic.

在您连接到例如,code依赖于编译器困扰把一个特定的值在被从未访问,并立即停止存在一个变量。编译器不需要做任何事情,对你的code的操作没有影响。

In the example you linked to, the code relies on the compiler bothering to put a particular value in a variable that is never accessed and immediately ceases to exist. The compiler is not required to do anything that has no effect on the operation of your code.

这可能影响了code的唯一方法是,如果它偷看栈的未分配部分或它们previously有其堆栈值依赖于新的分配。要求编译器执行,将产生巨大的优化数量不可能的,包括寄存器代替局部变量。

The only way that could effect the code is if it peeked at unallocated portions of the stack or relied on new allocations on the stack having values they previously had. Requiring the compiler to do that would make a huge number of optimizations impossible, including replacing local variables with registers.

这篇关于可以`mem​​set`函数调用由编译器中删除?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆