Что касается оптимизации для «не заявления» в c?

Изучая оптимизацию компилятора, я пишу коды в C под Linux с GCC версией gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5.1)
Чтобы понять not a statement (nop) в C. Я написал два кода: сначала y.c, затем x.c и generate their compiled assembly code, используя опцию gcc -S.

Первый код y.c

desktop:~$ cat y.c
main()
{
int i=0;
}
desktop:~$ gcc -S y.c
desktop:~$ 

Второй код x.c

desktop:~$ cat x.c
main()
{
int i=0;

/* Loops and if*/
while(0);
for(;0;);
if(0);

/* Arithmetic Operations */
i * i;
i / i;
i - i;
i + i;
i % i;
 +i;
 -i;

/* Comparison operators */
i == i;
i != i;
i < i;
i > i;
i >= i;
i <= i;

/* Bitwise Operations*/
i ^ i;
i | i;
i & i;
 ~i;
i << i;
i >> i;

/* Address Operatins*/ 
 &i;
 *(&i);
 (&i)[i];

/* Ternary conditional operation*/
 i? i : i;

/* Other Operations*/ 
 sizeof(i);
 (char)i;

/* Not-Logical Operation*/ 
 !i; 

/* Logical AND , OR Operators */ 
// i && i;  // Commented && operation 
// i || i;  // Commented || operation
}
desktop:~$ gcc -S x.c

ВНИМАНИЕ: на этот раз последние две строки в x.c прокомментированы.
Как я и ожидал. Нет никакой разницы в их генерируемых ассемблерных кодах. Я сравнил x.s и y.s с помощью команды diff.

desktop:~$ diff x.s y.s
1c1
<   .file   "x.c"
---
>   .file   "y.c"
desktop:~$

Но когда я раскомментирую последние (или скажу добавить) две строки в x.c.

i && i;  
i || i; 

Снова скомпилируйте x.c с опцией -S и сравните с y.s.

desktop:~$ tail  x.c  
 sizeof(i);
 (char)i;

/* Not-Logical Operation*/ 
 !i; 

/* Logical AND , OR Operators */ 
i && i;  // unCommented && operation 
i || i;  // unCommented || operation
}
desktop:~$ gcc -S x.c
desktop:~$ diff x.s y.s
1c1
<     .file    "x.c"
---
>     .file    "y.c"
10,21d9
<     movl    -4(%ebp), %eax
<     testl    %eax, %eax
<     je    .L3
<     movl    -4(%ebp), %eax
<     testl    %eax, %eax
< .L3:
<     movl    -4(%ebp), %eax
<     testl    %eax, %eax
<     jne    .L8
<     movl    -4(%ebp), %eax
<     testl    %eax, %eax
< .L8:
desktop:~$ 

Вопрос:
Никак не могу понять, почему выражения i || i и i && i не эквивалентны 'not a statement'?

Почему компилятор переводит эти два оператора в исполняемый файл (мы можем дизассемблировать с помощью objdump, получим тот же код). Что особенного в этих двух выражениях. они не включают операцию =.

Изменяют ли они (устанавливают/сбрасывают) регистры флагов процессора? Думаю, нет!

Даже операция деления / отброшена, что может вызвать ошибку деления на ноль.

EDIT: добавлен ответ

В выражениях i || i и i && i нет ничего особенного. Оба эквивалентны NOT A STATEMENT. И может быть удален GCC compiler с дополнительными усилиями.

Чтобы удалить это: Полезны флаги -o2 и -o3:
Вот моя попытка!!

desktop:~$ gcc -o2 -S y.c 
desktop:~$ gcc -o2 -S x.c 
desktop:~$ diff x.s y.s -y
    .file   "x.c"                         |     .file   "y.c"
    .text                               .text
    .p2align 4,,15                        <
.globl main                         .globl main
    .type   main, @function                     .type   main, @function
main:                               main:
    pushl   %ebp                            pushl   %ebp
    movl    %esp, %ebp                      movl    %esp, %ebp
    popl    %ebp                          |     subl    $16, %esp
                                  >     movl    $0, -4(%ebp)
                                  >     leave

Дополнительные строки в RHS вызваны несоответствием между файлами.

Я также хотел бы добавить информацию о том, что компиляторы JAVA и C# отбрасывают эти выражения без каких-либо флагов.


person Grijesh Chauhan    schedule 26.11.2012    source источник
comment
I think compiler should discard last two expressions too!, ** Не** ?   -  person Grijesh Chauhan    schedule 26.11.2012
comment
Попросите его оптимизировать, и я ожидаю, что он их удалит. Не уверен, почему он оставляет их неоптимизированными, возможно, ему нужно будет проанализировать код немного больше, чем без оптимизации, чтобы убедиться, что они не имеют побочных эффектов.   -  person Daniel Fischer    schedule 26.11.2012
comment
Одно важное отличие состоит в том, что логические операторы C && и || реализуют логическую логику короткого замыкания, и это обычно включает поток управления. Это сильно отличается от обычного арифметического или логического оператора.   -  person Paul R    schedule 26.11.2012


Ответы (1)


Включите оптимизацию с помощью -O2, и вы должны увидеть, как лишний код исчезнет.

person Alexey Feldgendler    schedule 26.11.2012
comment
$ gcc -02 -S x.c результаты gcc: unrecognized option '-02' - person Grijesh Chauhan; 26.11.2012
comment
@GrjeshChauhan это O («О»), а не 0 («ноль»). - person Igor Skochinsky; 26.11.2012
comment
Спасибо, Алексей Фельдгендлер, ваш пост был полезен и работал на меня! - person Grijesh Chauhan; 28.11.2012