Reputation: 605
I've encountered the following RGB-to-int method in various places:
//r,g, and b are bytes
int c = r;
c = (C << 8) | g;
c = (c << 8) | b;
return c;
But isn't it more efficient to say:
return (r << 16) | (g << 8) | r;
It seems like the first way results in a lot of unnecessary store/load instructions. Is there a reason everyone seems to prefer the first way over the second?
Upvotes: 0
Views: 2446
Reputation: 3891
In the 2nd expression, you make small typo: twice used "r", and never "b". I assume, you meaning:
return (r << 16) | (g << 8) | b;
Regarding your question: result is very dependent on your computer architecture and compiler version. I build both versions with clang CC, FreeBSD OS, -O3. Source code:
int rgb1(int r, int g, int b) {
int c = r;
c = (c << 8) | g;
c = (c << 8) | b;
return c;
}
int rgb2(int r, int g, int b) {
return (r << 16) | (g << 8) | b;
}
unsigned int rgb3(unsigned int r, unsigned int g, unsigned int b) {
return (r * 256*256) + (g * 256) + b;
}
Assembly code following:
rgb1:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
sall $8, %eax
orl 12(%ebp), %eax
sall $8, %eax
orl 16(%ebp), %eax
popl %ebp
ret
.size rgb1, .-rgb1
.p2align 4,,15
.globl rgb2
.type rgb2, @function
rgb2:
pushl %ebp
movl %esp, %ebp
movl 12(%ebp), %eax
movl 8(%ebp), %edx
sall $8, %eax
orl 16(%ebp), %eax
popl %ebp
sall $16, %edx
orl %edx, %eax
ret
.size rgb2, .-rgb2
.p2align 4,,15
.globl rgb3
.type rgb3, @function
rgb3:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
sall $8, %eax
addl 12(%ebp), %eax
sall $8, %eax
addl 16(%ebp), %eax
popl %ebp
ret
As you see, 1st function is 9 instructions, 2nd function is 10. Therefore, 1st seems little more efficient. But, in real life, it very depends on your compiler behavior. For example, rgb3() uses many math operations, but compiler optimized it to something, very close to rgb1().
Upvotes: 1