2011-04-18 16 views
4

このコードは、DACチップのドライバ用です。ユニオンをパラメータとして関数に渡す方法

私は24ビットレジスタを表すビットフィールドを持っています。だから、私がする必要があるのは、ビットフィールドにデータを入力してSPIをチップに書き込むことです。

typedef struct { 
     uint8_t rdwr_u8:  1; 
     uint8_t not_used_u8: 3; 
     uint8_t address_u8: 4; 
     uint8_t reserved_u8: 8; 
     uint8_t data_u8:  8; 
     uint8_t padding_u8: 8; 
    } GAIN_REG_st; 

私の初期化関数では、以下のように共用体を作成します。

union{ 
     GAIN_REG_st GAIN_st; 
     uint32_t G_32; 
    } G_u; 

今、私はそれを移植する関数にGAIN_REG_stビットフィールドを渡す必要があります。

値が入力されると、ビットフィールドを32ビット整数に割り当て、その整数を低レベル関数に渡してSPIを上書きすることができます。

ユニオンの内部にある場合、ビットフィールドGAIN_REG_stを関数に渡すにはどうすればよいですか? (関数のプロトタイプを表示して呼び出すことはできますか?)

この関数は、ビットフィールドのメンバーにどのようにアクセスしますか? (それはG_u.GAIN_st.rdwr_u8 = 1ようになる?)

+0

ここに遭遇した問題を回避しようとしていますか?http://stackoverflow.com/questions/5675299/how-to-pass-a-bitfield-by-reference-to-a-function? 32ビットintを持つ構造体の和集合を持つ必要があることを示すシステムに関するいくつかの情報を見つけましたか? –

+4

_ビットフィールドを使用してデータプロトコルをマッピングしないでください。アライメント、ビットオーダー、エンディアンは分かりません。規格で定義されているものもありません。また、コンパイラは任意の数のパディングバイトをビットフィールドに自由に追加することができます。次に、任意の数のパディングバイトを自由にユニオンに追加できます。適切な解決方法は、単純なuint32_tをビットマスクとビットワイズ演算子で使用することです。あなたのコードは決定論的で100%移植可能になります。今のように、特定のコンパイラ実装の詳細がわからない限り、そのビットチャンクをSPIに送信するときに何が起こるかは誰にも分かりません。 – Lundin

答えて

1

プロトタイプ:

st->data_u8 = 1; 

使用:

G_u g; 
... 
populateGainRegSt(&(g.GAIN_st)); 
5
union G_u 
    the_union; 

the_union.GAIN_st.address_u8 = 0x4; 

function_call(&the_union); 

void function_call(union G_u *the_union) 
{ 
    uint8 
     address; 

    address = the_union->GAIN_st.address_u8; 

    return; 
} 

int populateGainRegSt(GAIN_REG_st *st); 

関数->演算子を使用して、構造体のフィールドにアクセスすることができます。

この?それは組合だから、なぜ内部のメンバーに合格するのですか?何の違いもありません。それらはすべて同じメモリオフセットで開始します。

0
#include <stdint.h> 
#include <stdio.h> 

typedef struct 
{ 
    uint8_t rdwr_u8:  1; 
    uint8_t not_used_u8: 3; 
    uint8_t address_u8: 4; 
    uint8_t reserved_u8: 8; 
    uint8_t data_u8:  8; 
    uint8_t padding_u8: 8; 
} GAIN_REG_st; 

union G_u 
{ 
    GAIN_REG_st GAIN_st; 
    uint32_t G_32; 
}; 

static void foo (GAIN_REG_st *data) 
{ 
    printf ("%x %x %x\n", 
     data->rdwr_u8, 
     data->not_used_u8, 
     data->address_u8); 
} 

int main() 
{ 
    union G_u udata; 
    udata.G_32 = 1986; 
    foo (&udata.GAIN_st); 
    return 0; 
} 
3

タイトルは合格を過ぎることですが、合格する構造についての質問があります。あなたはどちらかを行うことができます。それに応じて単に関数の引数を宣言し、メンバまたは全体を渡します。

すべての現在の回答は参照渡しを示していますが、それを行う必要はありません。コピーで渡すことができます。これは最終的に32ビットの値である構造体または共用体の場合、いわゆる関数なので、より効率的かもしれません。

void fn(union G_u arg); 

int main() 
{ 
    union G_u param; 
    ... 
    fn(param); 
} 

や構造を渡すために:あなたは、構造体を持っているとして、あなたは労働組合をtypedefの可能性が

void fn(GAIN_REG_st arg); 

int main() 
{ 
    GAIN_REG_st param; 
    ... 
    fn(param); 
} 

注:

typedef union 
{ 
    GAIN_REG_st GAIN_st; 
    uint32_t G_32; 
} G_u ; 

その後、最初の例は単純になります。

void fn(G_u arg); 

int main() 
{ 
    G_u param; 
    ... 
    fn(param); 
} 

構造体または共用体を渡す間にオーバーヘッドにほとんど違いはありません。内部表現の知識を公開することを選択するのは単なる問題です。

0

C89には、ユニオンを引数として直接初期化して渡すための実質的な手段はありません。 C89では、共用体は変数または変数参照のみを使用して宣言でき、その変数を使用して初期化する必要があります。しかし、ポインタを使用せずにこれらの変数を値渡しして返すことができます。

返される構造体と共用体は、通常のリターンパラメータのようにレジスタに収まる必要はありません。この場合、コンパイラはあなたのために(スタック上で)すべてを行い、深く最適化され、インライン化されている場合は、通常、オーバーヘッドはほとんどありません(読んでください:注意深く手に最適化されたCコードは高速ですが、よくやった)。

以下はコード例です。

ユーティリティ関数create_GAIN_REG_stGAIN_REG_st_to_G_uを使用すると、関数の呼び出し時に引数リストのstruct/unionをオンザフライで作成できます。これは、これらをパラメータとして受け入れます。

これは、ポインターがどこかを指している必要があるため、これは非ポインタータイプの場合にのみ有効です。ポインタを使用する場合は、malloc/freeが必要です。しかし、データ型全体を返すと、その必要はありません。 1つの重要なことは、オンザフライで作成されたデータへのポインタを得ることができますが、データはコール中にスタック内の変数として通常通りに存続することです - これはすぐに "フリー後に使用"使用スタック領域。もちろん

void 
spi(G_u u) 
{ 
    if (u.GAIN_st.rdwr_u8) 
    { 
     /* implement rdwr_u8==1 here */ 
    } 
    else 
    { 
     /* implement rdwr_u8==1 here */ 
    } 
} 

int 
main() 
{ 
    spi(GAIN_REG_st_to_G_u(create_GAIN_REG_st(1,19,255))); 
    return 0; 
} 

:(。だから、常に返されたり一時的な変数である引数として渡される構造体/共用体へのポインタを避ける)

#define __inline__ /*if not using GCC*/ 

typedef struct { 
    uint8_t rdwr_u8:  1; 
    uint8_t not_used_u8: 3; 
    uint8_t address_u8: 4; 
    uint8_t reserved_u8: 8; 
    uint8_t data_u8:  8; 
    uint8_t padding_u8: 8; 
} GAIN_REG_st; 

typedef union { 
    GAIN_REG_st GAIN_st; 
    uint32_t G_32; 
} G_u; 

GAIN_REG_st __inline__ 
create_GAIN_REG_st(uint8_t rdwr, uint8_t address, uint8_t data) 
{ 
    GAIN_REG_st g = { 0 }; 
    g.rdwr_u8 = rdwr; 
    g.address_u8 = address; 
    g.data_u8 = data; 
    return g; 
} 

G_u __inline__ 
GAIN_REG_st_to_G_u(GAIN_REG_st g) 
{ 
    G_u u = { 0 }; 
    u.GAIN_st = g; 
    return u; 
} 

今、あなたは直接あなたの関数spiを呼び出すことができますあなたは二重のコール平らできます。

G_u __inline__ 
create_G_u_bits(uint8_t rdwr, uint8_t address, uint8_t data) 
{ 
    return GAIN_REG_st_to_G_u(create_GAIN_REG_st(rdwr, address, data)); 
} 

int 
main() 
{ 
    spi(create_G_u_bits(1,19,255)); 
    return 0; 
} 

をしたり、特殊な機能を作成することができます。

void 
spi_bits(uint8_t rdwr, uint8_t address, uint8_t data) 
{ 
    spi(GAIN_REG_st_to_G_u(create_GAIN_REG_st(rdwr, address, data))); 
} 

int 
main() 
{ 
    spi_bits(1,19,255); 
    return 0; 
} 
関連する問題