You do however realize that an optimizing compiler will produce exactly the same code whether you use the obfuscated version or not?
up.c
int main(){
volatile char buf[10000];
volatile int limit = 10000;
for(int i = 0; i < limit; ++i){
buf[i] = 0;
}
}
down.c
int main(){
volatile char buf[10000];
volatile int limit = 10000;
for(int i = limit; i--;){
buf[i] = 0;
}
}
up.s
.file "up.cpp"
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
subq $9904, %rsp
.cfi_def_cfa_offset 9912
movl $10000, -108(%rsp)
movl -108(%rsp), %eax
testl %eax, %eax
jle .L5
xorl %eax, %eax
.p2align 4,,10
.p2align 3
.L4:
movslq %eax, %rdx
addl $1, %eax
movb $0, -104(%rsp,%rdx)
movl -108(%rsp), %edx
cmpl %eax, %edx
jg .L4
.L5:
xorl %eax, %eax
addq $9904, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Debian 4.8.1-10) 4.8.1"
.section .note.GNU-stack,"",@progbits
down.s
.file "down.cpp"
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
subq $9904, %rsp
.cfi_def_cfa_offset 9912
movl $10000, -108(%rsp)
movl -108(%rsp), %edx
testl %edx, %edx
leal -1(%rdx), %eax
je .L6
.p2align 4,,10
.p2align 3
.L8:
movslq %eax, %rdx
subl $1, %eax
cmpl $-1, %eax
movb $0, -104(%rsp,%rdx)
jne .L8
.L6:
xorl %eax, %eax
addq $9904, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Debian 4.8.1-10) 4.8.1"
.section .note.GNU-stack,"",@progbits
They aren't identical, and the counting down version has one fewer instruction (compiled with gcc -O3 -S). Yes, cleaner code is better. However, it is all too easy to say that they compile to the same instructions.
You don't have to do this practice, for sure. However, it does generate smaller code in some cases. I'm just saying that there's a reason. You may prioritize whichever goal you prefer.
EDIT: In a lot of other cases, the compiler can optimize heavily and generate similar instructions. It's possible. However, there is not a case that I have encountered where counting down resulted in larger code.
EDIT2:
In addition to making sure that it doesn't all get optimized out, the volatile limit simulates register pressure; it is entirely possible for that counter to spill to RAM.