私たちのチームは現在、GCC 4.5.1のカスタマイズされたバージョンを使用して、古いアーキテクチャからARMCortexM3プラットフォームに基づく新しい製品に移植されたコードを使用しています。通信リンクからデータを読み取り、生のバイト配列を構造体にキャストしてデータをクリーンに解析しようとしています。ポインターを構造体にキャストして逆参照した後、「型のパンニングされたポインターを逆参照すると、厳密なエイリアシング規則に違反します」という警告が表示されます。
いくつかの調査の結果、char配列には整列規則がなく、構造体は単語整列する必要があるため、ポインターをキャストすると未定義の動作(悪いこと)が発生することに気付きました。私たちが試みていることを行うためのより良い方法があるかどうか疑問に思います。
GCCの「属性((aligned(4)))」を使用して、char配列を明示的にワードアラインできることはわかっています。これによりコードが「より安全」になると思いますが、警告によってビルドが乱雑になるため、この状況が再び発生した場合に備えて警告を無効にしたくありません。私たちが望んでいるのは、私たちが試みていることを安全に行う方法です。それでも、後で別の場所で安全でないことをしようとしても、それは私たちに知らせてくれます。これは組み込みシステムであるため、RAMの使用量とフラッシュの使用量はある程度重要です。
移植性(コンパイラーとアーキテクチャー)は大きな問題ではありません。これは1つの製品にのみ当てはまります。ただし、ポータブルソリューションが存在する場合は、それが推奨されます。
これが私たちが現在行っていることの(非常に単純化された)例です:
#define MESSAGE_TYPE_A 0
#define MESSAGE_TYPE_B 1
typedef struct MessageA __attribute__((__packed__))
{
unsigned char messageType;
unsigned short data1;
unsigned int data2;
}
typedef struct MessageB __attribute__((__packed__))
{
unsigned char messageType;
unsigned char data3;
unsigned char data4;
}
// This gets filled by the comm system, assume from a UART interrupt or similar
unsigned char data[100];
// Assume this gets called once we receive a full message
void ProcessMessage()
{
MessageA* messageA;
unsigned char messageType = data[0];
if (messageType == MESSAGE_TYPE_A)
{
// Cast data to struct and attempt to read
messageA = (MessageA*)data; // Not safe since data may not be word aligned
// This may cause undefined behavior
if (messageA->data1 == 4) // warning would be here, when we use the data at the pointer
{
// Perform some action...
}
}
// ...
// process different types of messages
}