0

Assuming we have 32bit integer, 8bit char, gcc compiler and Intel architecture:

What would be the fastest way (with no assembler usage) to extract, say, third octet of integer variable? To store it to a char of some specific place of char[] for example?

em70
  • 6,088
  • 6
  • 48
  • 80
lithuak
  • 6,028
  • 9
  • 42
  • 54
  • 2
    Never mind the "fastest"; do you know how to do this at all? Then do that, let the compiler optimise it. – Greg Hewgill Mar 14 '12 at 17:51
  • 2
    Use the most obvious way and let the compiler transform it into something more efficient? E.g. `(some_integer>>16)&0xff`. – André Caron Mar 14 '12 at 17:51
  • 2
    Why do you think that you need the *fastest* way for such an operation? Do you have a performance bottleneck in precisely this operation? Is there any point in doing anything other than the obvious? – David Rodríguez - dribeas Mar 14 '12 at 17:52
  • 1
    It seems like there are only two remotely sensible ways: `(char) (i >> 16)`, as arc suggests, and `((char*)&i)[2]`. (The latter could also be done via a `union`.) I would guess that the former is generally faster (no pointer arithmetic, no requirement that `i` have a memory location), but why not just try both ways and see which runs faster in your program? – ruakh Mar 14 '12 at 17:54
  • @ruakh: Or the union trick... – David Rodríguez - dribeas Mar 14 '12 at 17:56
  • @ruakh: the union trick is what I didn't know and actually what I've asked this question for. Thank you! A lot of loud words said here about "try it yourself", "profile", etc. while this is the answer I was looking for. – lithuak Mar 14 '12 at 17:59
  • Note: which octet is the third, or even if the third octet exists at all, involve system-specific assumptions. – Robᵩ Mar 14 '12 at 18:02
  • 1
    @DavidRodríguez-dribeas The union trick is formally undefined behavior (although I've never heard of a compiler where it wouldn't work). On the other hand, both it and the pointer cast are very architecture dependent, and will have different semantics on different machines. – James Kanze Mar 14 '12 at 18:04
  • 1
    @izhak: you are actually wrong in your last comment, or your question is ill-formed. You ask about the fastest way, and there is nothing that says that either one of the three options (lets assume that we are fine with the undefined behavior of two of them) is any *faster* than the rest. You would have to compile the three options, and measure or see what the compiler generates. I would be surprised if the results were much different. – David Rodríguez - dribeas Mar 14 '12 at 18:19
  • the union if it works should result in a shift and mask, or an int write and a char read with an adjusted address. shift and mask is very safe to code yourself, the pointing at memory thing is not, nor is the union. Probably faster but not safe/portable/reliable. the code could work for days/weeks/years and then fail when the compiler changes or the code moves to a different platform. as you would be relying on compiler nuances and not the language. – old_timer Apr 27 '12 at 04:16

4 Answers4

6

For the 3rd octet (little endian):

int i = 0xdeadbeef;
char c = (char) (i>>16); // c = 0xad
arc
  • 584
  • 2
  • 5
3

use a Union:

union myCharredInt
{
    int myInt;
    struct {
        char char1;
        char char2;
        char char3;
        char char4;
    }
};

myCharredInt a = 5;

char c = a.char3;
Yochai Timmer
  • 48,127
  • 24
  • 147
  • 185
  • 3
    This is not guaranteed to work since compilers can add padding between members of a structure. – Thomas Matthews Mar 14 '12 at 18:35
  • anonymous structs are a Microsoft extension. Does GCC really support it? Also using unions this way in C++ is undefined behavior. – bames53 Mar 14 '12 at 19:25
  • 1
    Also, the bits of an `int` aren't guaranteed to be laid out in this order. (Big-endian vs Litte-endian). And Real Programmers count from 0 ;) – MSalters Mar 15 '12 at 10:56
  • The int isn't guaranteed to be layed in any order. But the chars are. and the 3rd char will be the 3rd chat in the memory. The OP wanted that one, so i guess he knows the layout. And anyway, counting from 0 is just a concept that was invented to signify the offset from the start. You don't really use it to count. – Yochai Timmer Mar 15 '12 at 12:13
  • using a union in this manner is not required nor defined to work by the language, it HAPPENS to work on pretty much any compiler I have tried but I have had it pointed out and confirmed for myself that it is not guaranteed to work. – old_timer Mar 22 '12 at 13:34
0

shift the octet to the least significant octet and store it

somewhat like this but it depends exactly what you mean by 3rd octet, as the majority of my experience has been in big-endian architecture

char *ptr;
....
*ptr = val >> 8;
Tom Tanner
  • 9,244
  • 3
  • 33
  • 61
  • If using bit-shifts, endianness doesn't matter. If you casted the integer to a char pointer and accessed the bytes directly, then it would matter. – André Caron Mar 14 '12 at 17:55
  • 2
    @AndréCaron: From the way the question is posed, I think the opposite is true: if you access the bytes directly, then the "third octet" is always the third byte, but if you're using bit-shifts then you need to know if the third octet is the second-most-significant (as on a little-endian architecture) or the third-most-significant (as on a big-endian one). – ruakh Mar 14 '12 at 17:56
0

Whenever you are looking for the "fastest" or "best" way to do something in very particular circumstances, the answer almost always will be: experiment, and find out.

While there are rules of thumb to follow, they will not conclusively give you the best answer for your particular system, architecture, compiler, etc.

You will notice there are a few different answers to your question already, using different techniques.

How will you know which is best?

Answer: Try them out. Profile them.

N.b.: I'm being a little facetious. I suspect what you really want to know is how to do this at all, and not how to do it fastest.

jwd
  • 10,837
  • 3
  • 43
  • 67
  • How I can profile something I'm not even aware about? How would I compare the speed of "union trick" vs "shift and mask" if I don't even know that the former exists? Why would I ask the question meaning something that I don't mean? The reaction of yours and many others in this topic is pointlessly aggressive and ignorant which is suprising to see at SO. – lithuak Mar 14 '12 at 18:12
  • @izhak: this behavior is a response two phenomenons: 1) too many programmers over-concerned with micro-optimization; and 2) so many *actually unjustified* questions about optimization on SO. Unless you describe a specific scenario in which this is needed (e.g. "I'm writing a video codec and run this stuff 10^6 times per second in a tight loop...") and whatever solutions you've come up so far, then there's no real answer to the question. The real answer depends on your compiler and hardware and we have nothing to benchmark against. – André Caron Mar 14 '12 at 18:30
  • @izhak: There's a question I'd like to link to as an example, but I can't find it anymore. – André Caron Mar 14 '12 at 18:33
  • @AndréCaron: the compiler and hardware were specified in the very first line of the question along with other info. My question really lucks the description of problem which seemed irrelevant to me. I never knew that could become a problem. I will update the question with results of benchmark later. – lithuak Mar 14 '12 at 18:35
  • @izhak: Strictly speaking, the question asked "the fastest way to do X", not "how to do X". I thought I made that distinction clear in my last line. If you want to know how to do it, see the other fine answers. If you want to know how best to do it in your particular case, see my answer. I apologize for coming off as aggressive, though. I really felt I was answering the question asked, albeit with a wink-wink of glibness. – jwd Mar 14 '12 at 21:51