3

I'm having a problem working with the TI/Stellaris EK-LM3S6965 demo board and associated software, specifically the OLED display driver. My problem is not that it doesn't work, it's that it mostly works. Except for this one section:

//
// Clear out the buffer used for sending bytes to the display.
//
*(unsigned long *)&g_pucBuffer[0] = 0;  //Line 438
*(unsigned long *)&g_pucBuffer[4] = 0;  //Line 439

which causes gcc to complain:

rit128x96x4.c:438: warning: dereferencing type-punned pointer will break strict-aliasing rules.

The problem occurs because g_pucBuffer is declared as a character array:

//*****************************************************************************
//
// Buffer for storing sequences of command and data for the display.
//
//*****************************************************************************
static unsigned char g_pucBuffer[8];

but we're accessing it as a long (32-bit, 4 characters) and so clearing the array in 2 lines of code instead of 8. The uC is a 32-bit processor, so it should do this in 2 cycles after setup. It actually uses 4 instructions, instead of the possible 1 store-multiple instruction in 2 cycles, but at this point I'm more than happy with the compiler's performance (It's a fairly new architecture, and the compiler's only a few months old).

But, when I write each byte sequentially to 0,

g_pucBuffer[0] = 0;
g_pucBuffer[1] = 0;
g_pucBuffer[2] = 0;
g_pucBuffer[3] = 0;
g_pucBuffer[4] = 0;
g_pucBuffer[5] = 0;
g_pucBuffer[6] = 0;
g_pucBuffer[7] = 0;

it does each write as a single instruction. I know, it's 4 cycles, but I want to do this right, and I think I have a clever and safe piece of code. It's more a personal issue now. I've got full optimization turned on, but it can't figure out that I really just want this 64 bits to be 0 as simply as possible.

However, what the warning wants me to do is access the variables as characters, because I'm crossing byte boundaries (Writing g_pucBuffer[0, 1, 2, and 3] in a single step). I know that they're dword aligned, I know that the code works in the original, but I want the warning to go away.

How can I either cause gcc to ignore this specific cast/aliasing issue, or do it properly?

Nick T
  • 12,360
  • 2
  • 44
  • 71
Kevin Vermeer
  • 19,989
  • 8
  • 57
  • 102

5 Answers5

6

An intermediate cast to (void *), then cast to (long *) can get rid of the warning. I verified this earlier today (at least with gcc 3.4.5), that

*(long*)(void*)&buffer[0] = 0;

disabuses the compiler of the notion that the sky will fall if you cast &buffer[0] to (long *).

I would contend that this is better than using a -fno-strict-aliasing option, since -fno-strict-aliasing will have global effect, whereas the intermediate cast can be used on a case by case basis, and it's explicitly obvious in your actual source where you have dealt with the problem.

JustJeff
  • 19,163
  • 3
  • 48
  • 75
4

Personally I think compiler warnings are there for a reason. Disabling or ignoring them (as some of the other answers seem to advocate) is a bad idea. -fno-strict-aliasing prevents a bunch of other optimizations, in the end, you'll probably lose a lot more performance than the 4 cycles you save by doing the C code hack.

davr
  • 6,802
  • 2
  • 25
  • 37
4

Can you instead declare your variable as a union of a byte array and a long array?

I don't know if this is any more "legal" than your original code without a careful reading of the spec but it might be worth looking into.

John Burton
  • 2,086
  • 4
  • 23
  • 34
  • Just learned the union keyword in another piece of code - This is probably the best answer! (Am I allowed to change the selection after this much time has elapsed?) The union keyword is little known and little used, but this is a perfect example. – Kevin Vermeer Jul 15 '10 at 22:05
2

Wouldn't -fno-strict-aliasing do the job?

cesare
  • 111
  • 1
  • 3
  • Ah! This is the gcc-option type of solution I was going for. It doesn't look like what I wanted to do (cast my chars to long) is actually valid C, so this is what I'll have to do. If I understand the other posts about this on the web correctly, though, this prevents some optimizations (at higher levels) from changing other stuff elsewhere in my code. But I'm not doing a lot of goofy casting elsewhere in my code (Just this buffer), so this should work. – Kevin Vermeer Jul 09 '10 at 12:44
  • just be aware - suppressing warnings has a way of coming back to haunt you, though, since once you have the suppression switch in your build, subsequent warnings about new situations tend to get smothered. – JustJeff Jul 09 '10 at 20:50
  • Yes, of course this could prevent some optimizations. – cesare Jul 09 '10 at 23:53
1

Quick answer: remove -Werror from your Makefile. Only with this option enabled will the warning be treated as an error.

Toby Jaffey
  • 28,796
  • 19
  • 96
  • 150