Verifying the recommendation "Don't do the compilers job" from the book "The Ultimate Question of Programming, Refactoring, and Everything".

Note. The article was first published in Russian on livejournal.com. The article and is translation are posted on our website with the author's permission.

In the blog of PVS-Studio team you can find many examples of errors made by programmers and the recommendations of how you can avoid these mistakes (http://www.viva64.com/en/b/0391/).

The first piece of advice: don't do the compilers job. Do not optimize manually those fragments that will be optimized anyway. As an example we see a code fragment taken from MySQL project where a programmer deployed a loop manually and made a mistake. Further on, the author says if we write this function with a loop, the compiler will most likely deploy it itself. Let's check it with the help of the online compiler. I copied the source code of function from the article and edited them a little bit so that they would compile without any additional files. The compilation was done with the help of clang 3.9 compiler for the arm target with the optimization level -O2 (with these settings the compiler deploys the loops).

So, here is the original source code:

``````int rr_cmp(unsigned char *a, unsigned char *b)
{
if (a[0] != b[0])
return (int) a[0] - (int) b[0];
if (a[1] != b[1])
return (int) a[1] - (int) b[1];
if (a[2] != b[2])
return (int) a[2] - (int) b[2];
if (a[3] != b[3])
return (int) a[3] - (int) b[3];
if (a[4] != b[4])
return (int) a[4] - (int) b[4];
if (a[5] != b[5])
return (int) a[5] - (int) b[5];
if (a[6] != b[6])
return (int) a[6] - (int) b[6];
return (int) a[7] - (int) b[7];
}``````

The result for arm:

``````rr_cmp(unsigned char*, unsigned char*):
@ @rr_cmp(unsigned char*, unsigned char*)
ldrb    r2, [r1]
ldrb    r3, [r0]
cmp     r3, r2
bne     .LBB0_7
ldrb    r2, [r1, #1]
ldrb    r3, [r0, #1]
cmp     r3, r2
bne     .LBB0_7
ldrb    r2, [r1, #2]
ldrb    r3, [r0, #2]
cmp     r3, r2
bne     .LBB0_7
ldrb    r2, [r1, #3]
ldrb    r3, [r0, #3]
cmp     r3, r2
bne     .LBB0_7
ldrb    r2, [r1, #4]
ldrb    r3, [r0, #4]
cmp     r3, r2
bne     .LBB0_7
ldrb    r2, [r1, #5]
ldrb    r3, [r0, #5]
cmp     r3, r2
bne     .LBB0_7
ldrb    r2, [r1, #6]
ldrb    r3, [r0, #6]
cmp     r3, r2
ldrbeq  r1, [r1, #7]
ldrbeq  r0, [r0, #7]
subeq   r0, r0, r1
bxeq    lr
.LBB0_7:
sub     r0, r3, r2
bx      lr``````

The source code, suggested by the author from PVS-Studio:

``````int rr_cmp(unsigned char *a,unsigned char *b)
{
for (int i = 0; i < 7; ++i)
{
if (a[i] != b[i])
return a[i] - b[i];
}
return a[7] - b[7];
}``````

Result:

``````rr_cmp(unsigned char*, unsigned char*):
@ @rr_cmp(unsigned char*, unsigned char*)
ldrb    r2, [r1]
ldrb    r3, [r0]
cmp     r3, r2
bne     .LBB0_7
ldrb    r2, [r1, #1]
ldrb    r3, [r0, #1]
cmp     r3, r2
bne     .LBB0_7
ldrb    r2, [r1, #2]
ldrb    r3, [r0, #2]
cmp     r3, r2
bne     .LBB0_7
ldrb    r2, [r1, #3]
ldrb    r3, [r0, #3]
cmp     r3, r2
bne     .LBB0_7
ldrb    r2, [r1, #4]
ldrb    r3, [r0, #4]
cmp     r3, r2
bne     .LBB0_7
ldrb    r2, [r1, #5]
ldrb    r3, [r0, #5]
cmp     r3, r2
bne     .LBB0_7
ldrb    r2, [r1, #6]
ldrb    r3, [r0, #6]
cmp     r3, r2
ldrbeq  r1, [r1, #7]
ldrbeq  r0, [r0, #7]
subeq   r0, r0, r1
bxeq    lr
.LBB0_7:
sub     r0, r3, r2
bx      lr``````

Well... "Find 10 differences".

It's all the same.

However, oddly enough, the result for x86-64 will be slightly different. But this is another story.

##### Use PVS-Studio to search for bugs in C, C++, C# and Java

We offer you to check your project code with PVS-Studio. Just one bug found in the project will show you the benefits of the static code analysis methodology better than a dozen of the articles.

409
14 072