1
char *buffer; 
short num; 
memcpy(&num, buffer, sizeof(short)); 

*buffer - pointer to the buffer, where number is situated in HEX view. I want to put this number in the variable num without calling memcpy. How can I do it?

number = (short) buffer; //DOESN'T work! 
unkulunkulu
  • 11,576
  • 2
  • 31
  • 49
user2439344
  • 13
  • 1
  • 3
  • 1
    `number = (short) *buffer` – Noctua May 31 '13 at 06:51
  • 2
    @Noctua: This wont take `sizeof(short)` from `buffer`, but just `sizeof(char)` and promote it to a `short`. Wont get the expected result. :) – raj raj May 31 '13 at 06:59
  • @Noctua And what's even worse, it's UB. –  May 31 '13 at 07:08
  • It is **important** to know the endianness (the order of the bytes) in the buffer. Without that information any solution, be it your `memcpy`, the undefined cast or the byte shifting of perreal will be wrong. – Patrick Schlüter May 31 '13 at 09:42
  • @tristopia that depends on how the short got there, right? If it were created on the platform and memcpy'd there, then you wouldn't have to worry about it, right? – xaxxon May 31 '13 at 15:46
  • In the case of `memcpy` it would be indeed not a problem. My comment was more in the context of perreal's answer which assumed a big-endian value in the buffer. – Patrick Schlüter May 31 '13 at 16:02
  • @xaxxon if it was created on the platform, how come it ended up in a character buffer? It would have been in a short to begin with! No, the fact that it's in a character buffer clearly indicated that it's pulled in from an external source, and then all bets are off. – Mr Lister May 31 '13 at 18:52

4 Answers4

4

All answers so far suggested using *(short *)buf, but that's not any good - it breaks the strict aliasing rule (the alignment of short is greater than that of char, so you can't do this without invoking undefined behavior).

The short answer is: you'd be better off using memcpy(), but if you really don't want that, then you can use unions and "type punning" (note that this may result in a trap representation of the buffer of bytes which may or may not be what you want):

union type_pun {
    char buf[sizeof(short)];
    short s;
};

union type_pun tp;
tp.buf[0] = 0xff;
tp.buf[1] = 0xaa; // whatever, if `short' is two bytes long
printf("%hd\n", tp.s);
  • Calling memcpy for 2 bytes - is prodigally. – user2439344 May 31 '13 at 07:24
  • @user2439344 It will be optimized out, and it will make your program behave *correctly.* –  May 31 '13 at 07:24
  • This doesn't help if the source data is already in a char array, though. You still have to load it into the union with a memcpy or somsething, right? at which point, why not just use memcpy directly to a short. – xaxxon May 31 '13 at 09:54
  • @xaxxon Right, but still better than UB. –  May 31 '13 at 09:59
2

Based on your memcpy of sizeof(short) bytes, I'm guessing you want to get the first sizeof(short) bytes from where buffer is pointing at.

number = * (short *) buffer;

will do that for you, as other have pointed out.

You cannot take the pointer's address and put it in a short, so you need to dereference it to get the value in the memory instead.

xaxxon
  • 19,189
  • 5
  • 50
  • 80
  • ***This answer is WRONG, stop upvoting it!*** –  May 31 '13 at 07:11
  • Given that being able to do this is a common requirement and most people get it wrong, I wonder why there isn't a language feature 'number = interpret_as(buffer)' or some such thing that does this in a safe way. – jcoder May 31 '13 at 07:42
  • Yeah, it's only sort of wrong, except it works, right? it's frustrating. – xaxxon May 31 '13 at 07:51
  • @trisopia But it's not the same. I don't want to copy the data anywhere, I want to say please access the data at this address as if it's a "short" and please arrange to make sure this is safe. Which in many cases won't require any actual work by the compiler. memcpy makes a copy of the data which isn't the same. I'm aware it might optimize out the copy but it's not the same thing really at all. – jcoder May 31 '13 at 09:43
  • Ok, I was too literal with your example `'number = interpret_as(buffer)'` which is perfectly translated by `memcpy(&number, buffer, sizeof (short));` but I hadn't considered it could be part of an expression. – Patrick Schlüter May 31 '13 at 16:07
2

For two byte short:

number = (short)(
           ((unsigned char)buffer[0]) << 8 | 
           ((unsigned char)buffer[1])
          );

For different short:

for (int i = 0; i < sizeof(short); i++)
        number = (number << 8) + ((unsigned char) buffer[i]);

or you'll have some macros for each size.

Also, see tristopia's comment about this making assumptions about endianness.

xaxxon
  • 19,189
  • 5
  • 50
  • 80
perreal
  • 94,503
  • 21
  • 155
  • 181
0

Assuming that with "situated in HEX view" you mean the number is stored in the string like "89AB", you can use the strtol function.

char* end;
num = (short)strtol(buffer, &end, 16);

This function converts the string to a long integer. There is no corresponding function that converts to a short directly, so you'll have to do a (short) anyway, but that wasn't the problem, was it?

Mr Lister
  • 45,515
  • 15
  • 108
  • 150
  • Thanks. I mentioned "put two bytes in the short variable" I am misunderstood myself) – user2439344 May 31 '13 at 07:09
  • @user2439344 Yeah, I understood that later. Not sure what's the underlying cause of your problem though. I mean, how did the short value end up in a char* in the first place? – Mr Lister May 31 '13 at 07:11