Почему компиляция этого кода как C и C ++ генерирует разные сборки?

Я написал следующий код:

int main()
{
int i;
int arr[4];
for (i = 0; i < 4; i++)
arr[i] = 0;

return 0;
}

сохранил его в двух файлах: test.c и test.cpp
Я запускаю следующие команды:

gcc -O0 test.c
objdump -Mintel -d a.out > decompilec
g++ -O0 test.cpp
objdump -Mintel -d a.out > decompilecpp

Я отредактировал и decompilec, и decompilecpp, чтобы они содержали только основную функцию.

Теперь я бегу diff decompilec decompilecpp и я получаю следующий вывод:

12,21c12,19
<  80483fe: 7e eb                   jle    80483eb <main+0xf>
<  8048400: b8 00 00 00 00          mov    eax,0x0
<  8048405: c9                      leave
<  8048406: c3                      ret
<  8048407: 66 90                   xchg   ax,ax
<  8048409: 66 90                   xchg   ax,ax
<  804840b: 66 90                   xchg   ax,ax
<  804840d: 66 90                   xchg   ax,ax
<  804840f: 90                      nop
<
---
>  80483fe: 0f 9e c0                setle  al
>  8048401: 84 c0                   test   al,al
>  8048403: 75 e6                   jne    80483eb <main+0xf>
>  8048405: b8 00 00 00 00          mov    eax,0x0
>  804840a: c9                      leave
>  804840b: c3                      ret
>  804840c: 66 90                   xchg   ax,ax
>  804840e: 66 90                   xchg   ax,ax

Может ли кто-нибудь объяснить это различие?

вот файлы:

decompilec

080483dc <main>:
80483dc:   55                      push   ebp
80483dd:   89 e5                   mov    ebp,esp
80483df:   83 ec 20                sub    esp,0x20
80483e2:   c7 45 ec 00 00 00 00    mov    DWORD PTR [ebp-0x14],0x0
80483e9:   eb 0f                   jmp    80483fa <main+0x1e>
80483eb:   8b 45 ec                mov    eax,DWORD PTR [ebp-0x14]
80483ee:   c7 44 85 f0 00 00 00    mov    DWORD PTR [ebp+eax*4-0x10],0x0
80483f5:   00
80483f6:   83 45 ec 01             add    DWORD PTR [ebp-0x14],0x1
80483fa:   83 7d ec 03             cmp    DWORD PTR [ebp-0x14],0x3
80483fe:   7e eb                   jle    80483eb <main+0xf>
8048400:   b8 00 00 00 00          mov    eax,0x0
8048405:   c9                      leave
8048406:   c3                      ret
8048407:   66 90                   xchg   ax,ax
8048409:   66 90                   xchg   ax,ax
804840b:   66 90                   xchg   ax,ax
804840d:   66 90                   xchg   ax,ax
804840f:   90                      nop

decompilecpp

080483dc <main>:
80483dc:   55                      push   ebp
80483dd:   89 e5                   mov    ebp,esp
80483df:   83 ec 20                sub    esp,0x20
80483e2:   c7 45 ec 00 00 00 00    mov    DWORD PTR [ebp-0x14],0x0
80483e9:   eb 0f                   jmp    80483fa <main+0x1e>
80483eb:   8b 45 ec                mov    eax,DWORD PTR [ebp-0x14]
80483ee:   c7 44 85 f0 00 00 00    mov    DWORD PTR [ebp+eax*4-0x10],0x0
80483f5:   00
80483f6:   83 45 ec 01             add    DWORD PTR [ebp-0x14],0x1
80483fa:   83 7d ec 03             cmp    DWORD PTR [ebp-0x14],0x3
80483fe:   0f 9e c0                setle  al
8048401:   84 c0                   test   al,al
8048403:   75 e6                   jne    80483eb <main+0xf>
8048405:   b8 00 00 00 00          mov    eax,0x0
804840a:   c9                      leave
804840b:   c3                      ret
804840c:   66 90                   xchg   ax,ax
804840e:   66 90                   xchg   ax,ax

в соответствии с запросом, здесь вывод gcc -v:

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-linux-gnu/4.7/lto-wrapper
Target: i686-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.7.2-2ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-4.7/README.Bugs --enable-languages=c,c++,go,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.7 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.7 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --enable-targets=all --disable-werror --with-arch-32=i686 --with-tune=generic --enable-checking=release --build=i686-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu
Thread model: posix
gcc version 4.7.2 (Ubuntu/Linaro 4.7.2-2ubuntu1)

4

Решение

Существует множество способов выполнить определенную операцию с ассемблером. Особенно, когда вы выполняете какую-либо оптимизацию, которая может тесно зависеть от целевого процессора, ассемблер может выполнять неочевидные операции, которые в основном предназначены для ускорения работы конкретного процессора. Даже если у вас один и тот же компилятор и один и тот же флаг оптимизации, фактический используемый компилятор все еще различен для C и C ++, поэтому они могут создавать различный код.

Сборка С должна быть простой. Версия C ++ более интересна. Что там происходит, объясняется в эта ссылка. По сути, они преобразуют простой «переход, если меньше или равно» кода C, в «установлен ноль или ненулевое значение, в зависимости от того, меньше или равно, то переход основан на нуле или ненулевом».

Я не знаю, почему компилятор C ++ создает такой код. Он может быть изменен с более высоким уровнем оптимизации, или тогда он будет произведен даже с уровнем оптимизации 0, потому что он помогает предсказанию ветвления ЦП по умолчанию для создания правильного прогноза большую часть времени. И тогда компилятор C имеет другое поведение по умолчанию. Как я уже сказал, фактический компилятор отличается, поэтому я на самом деле немного удивлен, что код идентичен в противном случае!

2

Другие решения

Разные языки используют разные интерфейсы компилятора, которые могут создавать разные потоки инструкций (в противном случае эквивалентных семантических эффектов).

Если бы вы оптимизировали вывод, вполне вероятно (хотя и не гарантировано), что оптимизатор уменьшит оба потока инструкций до одного и того же вывода … но нет никакой гарантии, и я не понимаю, почему вы ожидаете такого.

1

По вопросам рекламы [email protected]