For array indices and pointer arithmetic, types which are of the same size as a pointer (typically, size_t and ptrdiff_t) can be better, as they avoid the need to zero or sign extend the register. Consider
float onei(float *a, int n) { return a[n]; } float oneu(float *a, unsigned n) { return a[n]; } float onep(float *a, ptrdiff_t n) { return a[n]; } float ones(float *a, size_t n) { return a[n]; }
With GCC 4.4 -O2 on x86_64 the following asm is generated:
.p2align 4,,15 .globl onei .type onei, @function onei: .LFB3: .cfi_startproc movslq %esi,%rsi movss (%rdi,%rsi,4), %xmm0 ret .cfi_endproc .LFE3: .size onei, .-onei .p2align 4,,15 .globl oneu .type oneu, @function oneu: .LFB4: .cfi_startproc mov %esi, %esi movss (%rdi,%rsi,4), %xmm0 ret .cfi_endproc .LFE4: .size oneu, .-oneu .p2align 4,,15 .globl onep .type onep, @function onep: .LFB5: .cfi_startproc movss (%rdi,%rsi,4), %xmm0 ret .cfi_endproc .LFE5: .size onep, .-onep .p2align 4,,15 .globl ones .type ones, @function ones: .LFB6: .cfi_startproc movss (%rdi,%rsi,4), %xmm0 ret .cfi_endproc .LFE6: .size ones, .-ones
As can be seen, the versions with the int and unsigned int index (onei and oneu) requires an extra instruction (movslq/mov) to sign/zero extend the register.
As was mentioned in a comment, the downside is that encoding a 64-bit register takes more space than the 32-bit part, bloating the code size. Secondly, ptrdiff_t/size_t variables need more memory than the equivalent int; if you have such arrays it can certainly affect performance much more than the relatively small benefit of avoiding the zero/sign extension. If unsure, profile!