ejolson wrote: ↑Sat Sep 16, 2023 5:52 pm
lurk101 wrote: ↑Sat Sep 16, 2023 5:46 pm
jahboater wrote: ↑Sat Sep 16, 2023 5:35 pm
Does that work if the array is zero length ?
I suspect not for various reasons
'Counting down to 0' in the problem statement implies a non zero length array, doesn't it?
I'll check with the head of the legal department and dog treats what down to 0 actually means.
When it's known the array length is non-zero, as in this case, it's a reasonable optimization to skip the first test. Does the optimizing compiler not omit the first test automatically with the original code? In fact, I'm a little surprised it doesn't unroll the loop entirely when there are only 3 or 4 entries.
Given the program
Code: Select all
#include <stdio.h>
int main(){
static const char *x[]={ "bark","meow","woof","scratch" };
for(size_t n=sizeof(x)/sizeof(x[0])-1;;--n){
printf("%s ",x[n]);
if(!n) break;
}
printf("\n");
}
after compiling with
the output from objdump -S is
Code: Select all
int main(){
6c0: a9be7bfd stp x29, x30, [sp, #-32]!
static const char *x[]={ "bark","meow","woof","scratch" };
for(size_t n=sizeof(x)/sizeof(x[0])-1;;--n){
printf("%s ",x[n]);
6c4: 90000001 adrp x1, 0 <__abi_tag-0x278>
6c8: 9121c021 add x1, x1, #0x870
int main(){
6cc: 910003fd mov x29, sp
6d0: f9000bf3 str x19, [sp, #16]
printf("%s ",x[n]);
6d4: 90000013 adrp x19, 0 <__abi_tag-0x278>
6d8: 9121e273 add x19, x19, #0x878
6dc: aa1303e0 mov x0, x19
6e0: 97ffffe4 bl 670 <printf@plt>
6e4: aa1303e0 mov x0, x19
6e8: 90000001 adrp x1, 0 <__abi_tag-0x278>
6ec: 91220021 add x1, x1, #0x880
6f0: 97ffffe0 bl 670 <printf@plt>
6f4: aa1303e0 mov x0, x19
6f8: 90000001 adrp x1, 0 <__abi_tag-0x278>
6fc: 91222021 add x1, x1, #0x888
700: 97ffffdc bl 670 <printf@plt>
704: 90000001 adrp x1, 0 <__abi_tag-0x278>
708: 91224021 add x1, x1, #0x890
70c: aa1303e0 mov x0, x19
710: 97ffffd8 bl 670 <printf@plt>
if(!n) break;
}
printf("\n");
714: 52800140 mov w0, #0xa // #10
718: 97ffffda bl 680 <putchar@plt>
}
71c: f9400bf3 ldr x19, [sp, #16]
720: 52800000 mov w0, #0x0 // #0
724: a8c27bfd ldp x29, x30, [sp], #32
728: d65f03c0 ret
This shows GCC version 12.2.0 unrolls the loop.
When the loop reads
Code: Select all
for(size_t n=sizeof(x)/sizeof(x[0]);n;){
--n;
printf("%s ",x[n]);
}
or
Code: Select all
for(size_t n=sizeof(x)/sizeof(x[0]);n-->0;){
printf("%s ",x[n]);
}
or
Code: Select all
for(size_t n=sizeof(x)/sizeof(x[0]);n>0;--n){
printf("%s ",x[n-1]);
}
the generated code is the same.
Moreover, after stripping the debug symbols the binaries are exactly the same size.
Code: Select all
$ strip rev?
$ ls -l rev?
-rwxr-xr-x 1 ejolson users 67592 Sep 16 21:06 rev1
-rwxr-xr-x 1 ejolson users 67592 Sep 16 21:06 rev2
-rwxr-xr-x 1 ejolson users 67592 Sep 16 21:06 rev3
-rwxr-xr-x 1 ejolson users 67592 Sep 16 21:06 rev4
Weirdly, however, the md5sums are different.
Code: Select all
$ md5sum rev?
15b1afb0dfbfc389dc974ec62808430a rev1
ad12e40dd89409117a45ab9e9b486a8a rev2
20657d43a5f43dcf4df62b226ca5ae58 rev3
d8071e3dbb3658222b872bf5fd87e074 rev4
Why are the md5sums different?