2013-04-15 9 views
5

I、すなわち、data 16ビット変数がある:エンディアンに依存しない方法で下位バイトへのポインタを取得できますか?

volatile uint16_t data; 

Iは、外部センサ上の2つの8ビット・レジスタの内容に基づいて、この値を移入する必要があります。これらはI2C/TWIを介してアクセスされます。

マイTWIルーチンは非同期*で、署名を持っています

bool twi_read_register(uint8_t sla, uint8_t reg, uint8_t *data, void (*callback)(void)); 

これは、*dataslaregの値を読み取り、その後callback()を呼び出します。

私はuint16_tが、私は何ができる、MSB LSB、たとえば、などのメモリに配置されていた知っていた場合は、次の

twi_read_register(SLA, REG_MSB, (uint8_t *)&data, NULL); 
twi_read_register(SLA, REG_LSB, (uint8_t *)&data + 1, NULL); 

しかし、私は自分のコードにエンディアン依存性を焼く好きではありません。これをエンディアンに依存しない方法で実現する方法はありますか?

(サイドノート:現時点での私の実際の問題を回避するには、構造体を使用することを含む、すなわち:

typedef struct { 
    uint8_t msb; 
    uint8_t lsb; 
} SensorReading; 

が、私はシンプルuint16_tでそれを行うことができれば、私は好奇心が強い)

EDIT

(* asyncはスプリットフェーズを意味します。つまり、将来、ある時点で*dataが設定されます。要求された場合、callback関数を介して着信通知が通知されます)

+1

は、なぜあなたは16ビット値へのアクセスをポインタに自分自身を制限したいですか?ほとんどの人はshiftとaddまたはor演算子でこれを行います。しかし、実際にポインタでそれをやりたければ、エンディアンを検出し補うマクロを使用することができます。 –

+0

いいえ、信頼できません。信頼性と移植性の高いコードが必要な場合は、マスクとシフトを使用してください。 –

+0

実際にはマスクとシフトがうまくいきませんか? –

答えて

4

次は動作しませんか?

uint8_t v1, v2; 
twi_read_register(SLA, REG_MSB, &v1, NULL); 
twi_read_register(SLA, REG_LSB, &v2, NULL); 
data = ((uint16_t)v1<<8)|v2; 

またはtwi_read_registerがそれを書き込む必要があるように揮発性dataです。その場合は、エンディアンに依存するコードに悩まされていると思います。

dataが実際には揮発性であることを指摘したので、まだ別のデバイスがそれを読んでいるためです。したがって、エンディアンが異なる可能性のある2つのデバイス間でメモリマップされた接続が確立されます。これは、エンディアン依存のコードに悩まされていることを意味します。

構造体は回避策として言及していますが、これはこれを処理する標準的な方法です。その上で

#ifdef BIGENDIAN 
typedef struct 
{  uint8_t msb, lsb; 
} uint16_as_uint8_t; 
#else 
typedef struct 
{  uint8_t lsb, msb; 
} uint16_as_uint8_t; 
#endif 

あなたはunionの一つのフィールドを書いてから読んで、あなたの明確な意思であるとして、後者はC89標準に違反しているとunion

union 
{  uint16_as_uint8_t as8; 
     uint16_t   as16; 
}; 

注意を置くことができます別のものは、不特定の値をもたらす。オフC99からこれは(幸いにも)サポートされています。 C89では、ポインタの変換を(char*)で行い、移植性のある方法でこれを行います。

上記はポータブルな方法でエンディアンを隠しているように見えますが、構造のパッキングはターゲットごとに異なる可能性があり、ターゲットによってはまだ破損している可能性があります。上記の例ではこれは起こりそうもないが、いくつかの奇妙なターゲットがある。私が言っていることは、おそらくこのデバイスレベルでポータブルをプログラムすることは不可能であり、それを受け入れ、コンパクトなターゲットインターフェイスのすべての詳細を隠すように努めることで、ターゲットのヘッダーファイルを1つ変更するそれをサポートするのに十分でしょう。コードの残りの部分は、ターゲットから独立して見ることができます。

+1

あなたは 'volatile'をなぜ言及しているのかよくわかりません。 –

+0

'twi_read_register'は非同期/分割フェーズなので、あなたの例では' v1'と 'v2'は未定義の時刻まで設定されません。 'data'は未定義の値を持ちます。 – sapi

+0

私は参照してください。そして、値が用意されていることがわかったら、あなたは 'uint16_t'に結合することができます。 –

0

どうやってこのようなことができますか?

uint16_t myValue = ...; 
uint8_t LSB = (uint8_t)(myValue % 256); 
uint8_t MSB = (uint8_t)(myValue/256); 
+0

これは一般的なアプローチですが、質問の読んだところでは、別の方向に問題があり、2つの8ビットの値から16ビットの値を取り込むということです。 –

+0

「myValue = MSB * 256 + LSB;」では何の問題もありません。 –

0
volatile uint16_t data; 
    uint16_t v = 1; 
    twi_read_register(SLA, REG_MSB, (uint8_t *)&data + *((uint8_t *)&v), NULL); 
    twi_read_register(SLA, REG_LSB, (uint8_t *)&data + *((uint8_t *)&v + 1), NULL); 
関連する問題