0

I don't understand why this code triggers off aliasing warning:

char buf[15];

*(uint16_t*) buf = 0x4040;

There is no any thinkable "alignments" within char type. And anyway, how do I do this in graceful way? So far I can't think of anything better than

char buf[15];
uint16_t foo = 0x4040;
memcpy(buf, &foo, 2);

The warning is this:

warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
wick
  • 1,995
  • 2
  • 20
  • 31
  • http://en.wikipedia.org/wiki/Anti-aliasing // http://en.wikipedia.org/wiki/Aliasing_(computing) - don't mix them up – Mat May 09 '14 at 17:56
  • Please add the actual warning(s). – this May 09 '14 at 17:56
  • @self.Thanks, you are right - it's my DSP past kicks in :-) – wick May 09 '14 at 18:08
  • You already accepted an answer, otherwise I would post mine, but the gist is that you can declared a `char` array, and you can only cast that to a compatible type which in this case is only a `char`. So the cast is illegal according to standard. If you declared a `uint16_t` array then you could cast that to `uint16_t` or `char`. – this May 09 '14 at 18:19
  • Actually the warning that you get is a wrong one, hopefully this is not a very new compiler version. Aliasing is allowed with any character types, so the compiler shouldn't complain about these. As nos answer shows correctly there is a problem with alignment, so the compiler should have talked about this. – Jens Gustedt May 09 '14 at 19:56
  • @JensGustedt *Aliasing is allowed with any character types, so the compiler shouldn't complain about these.* Not true. You can alias to a compatible type or a char. char's only compatible type is char. If you start with char you can't just cast to anything else. You can however start with a type, cast to char, and then back to type. In this case the effective type of the casted object is char. If you take a look at standard 6.5(7) you can read about that. – this May 10 '14 at 11:39

1 Answers1

0

There is no any thinkable "alignments" within char type.

And that's the problem, a char array normally have the smallest possible alignment requirement, of 1.

However your code tries to treat it as an uint16_t, which might have a different alignment requirement than 1 (typically 2).

The solution you have here is reasonable:

char buf[15];
uint16_t foo = 0x1234; //changed this to demonstrate endian issue
memcpy(buf, &foo, 2);

The caveat is with both these approaches is the content of buf will depend on the endian of your host, i.e. on a little endian system you will end up with

buf[0] == 0x34;
buf[1] == 0x12;

While on a big endian system the values will be reversed. If this is of no concern, then all is well. If it is a concern, instead of the memcpy() you could do:

 buf[0] = foo & 0xff;
 buf[1] = foo >> 8;
nos
  • 223,662
  • 58
  • 417
  • 506
  • I'm sorry I though you talked about the casting example. – this May 09 '14 at 18:06
  • @self Well, it will depend on the host endian in both cases. – nos May 09 '14 at 18:09
  • As long as OP doesn't send the data he is fine, please edit or I can't undownvote. – this May 09 '14 at 18:10
  • @nos: I see - so some systems may not go easy about alignment of uint32_t itself - I forgot about it. And yes endian issue is all accounted for, in fact it wasn't 0x4040, it was htons() – wick May 09 '14 at 18:11
  • *You last voted on this answer 8 mins ago. Your vote is now locked in unless this answer is edited.* <-- this – this May 09 '14 at 18:12