While Learning compiler Optimisation, I write codes in C under Linux with GCC version gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5.1)
To understant not a statement (nop) in C. I written two codes first y.c second x.c and generate their compiled assembly code using gcc -S option.     
Fist code y.c
desktop:~$ cat y.c
main()
{
int i=0;
}
desktop:~$ gcc -S y.c
desktop:~$ 
Second code 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
NOTICE:  This time Last two lines in x.c are commented.
And as I was expecting. There is no difference in their generated assembly codes. I compared x.s and y.s using diff command.     
desktop:~$ diff x.s y.s
1c1
<   .file   "x.c"
---
>   .file   "y.c"
desktop:~$
But When I uncomment last(or say add) two lines in x.c.  
i && i;  
i || i; 
Again compile x.c with -S option and compared with 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:~$ 
Question:
I just can not understand why expressions i || i and i && i are not equivalent to 'not a statement'?   
Why compiler transfer this two statements into executable( we can disassemble with objdump will get same code). What is special in this two expression. they do not includes = operation.  
Does they change (set/reset) CPU flag-registers ? I guess no!
Even / division operation discarded that may cause an divided by zero fault.      
EDIT : Added answer
There is nothing special in i || i and i && i expressions. Both are equivalent to 
NOT A STATEMENT. And can be removed by GCC compiler  with some extra effort. 
To remove this:  -o2 and -o3 flags are useful:
Here is my Try!!  
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
The extra lines in at RHS are because of misalignment between files.
I also like to add information that JAVA and C# compilers discard this expressions without any flags.