配列から構造体へデータのコピーをしたいのですが、
構造体のメンバがビットフィールドで構成されている時の処理がわかりません。
--------test.c-----------
#include <stdio.h>
#include <string.h>
typedef struct{
unsigned char aaa :1;
unsigned char bbb :1;
unsigned char ccc :1;
unsigned int ddd :13;
unsigned char eee :2;
unsigned char fff :2;
unsigned char ggg :4;
}test_t;
int main(void)
{
test_t test_t;
unsigned char data[]={0x5F, 0xFE, 0x1C};
memcpy(&test_t, data, 4);
printf("aaa = %X\n", test_t.aaa);
printf("bbb = %X\n", test_t.bbb);
printf("ccc = %X\n", test_t.ccc);
printf("ddd = %d\n", test_t.ddd);
printf("eee = %X\n", test_t.eee);
printf("fff = %X\n", test_t.fff);
printf("ggg = %X\n", test_t.ggg);
return 0;
}
------期待出力---------
aaa = 0
bbb = 1
ccc = 0
ddd = 1FFE
eee = 0
fff = 1
ggg = 12
「test.c」を実行した時に「期待出力」のような出力を期待していたのですが、実際には
aaa = 1
bbb = 1
ccc = 1
ddd = 1
eee = 0
fff = 0
ggg = 0
と表示されてしまいます。
ビットフィールドで構成された構造体に、配列の値をそのままあてる事は出来ないのでしょうか?
出来るだけ、マスクやシフト演算を使用しないで、配列からビット単位で値を抽出したいのですが・・・
A 回答 (4件)
- 最新から表示
- 回答順に表示
No.4
- 回答日時:
「data は 3バイトしかないのに memcpy で 4バイト目にアクセスしてる」って問題もあるんだけど....
そもそもビットフィールドを使った時点で「処理系依存」の嵐です:
・_Bool と (signed/unsigned) int 以外の型が使えるかどうかは処理系定義
・ビットをどの順に割り当てるかは処理系定義
・当該ビットフィールドをすべて入れることができれば, どのような記憶単位を割り当ててもいい (そのアラインメントは指定しない)
・ビットフィールドを順に詰めていって余裕がなくなったときに「とりあえず入るところだけ入れて後は別の記憶単位にする」か「詰めるのをあきらめて新しい記憶単位にする」かは処理系定義
つまり, sizeof(test_t) は 3~12 まで考えられます. ま, 「11」とかになることはないけど.
さらに, エンディアンの問題も発生するのでこのような方法は十分に処理系を理解し, かつ「その処理系と心中する」意気込みがなければ避けるべきでしょう.
No.3
- 回答日時:
>出来るだけ、マスクやシフト演算を使用しないで、配列からビット単位で値を抽出したいのですが・・・
ビットフィールドを使ったとしても、結局のところコンパイラが代わりにマスクやシフト演算をするコードを出力するだけなので、できあがるプログラムはそんなに変わらないですよ。
ビットの並びとかを思うように制御したいのなら、ビットフィールドは使わずにマスクやシフトを使うほうが確実です。マクロやインライン関数などをうまく使えば、実行効率もほとんど問題ないはずです。
No.2
- 回答日時:
処理系依存ですのでマクロを組むか事前に条件を確認する必要があります。
1)パディングサイズ
2)ビィットフィールドの並び(LMBから並ぶのかHMBから並ぶのか)
aaaがバイトフィールトの1ビット目に取られるのか8ビット目にとられるのか。
ちなみにMaicroSoftのCコンパイラでx86プラットフォームの場合は0ビット目に取られます。
質問の期待値を得るには::パディングサイズ1でx86系の場合::
unsigned char data[]={0x03,0xFE,0x1F,0xC4};になると思います。
※MS-Cでは13ビットにするとintじゃなくてshort intになるみたいです。
ざっくり、こんなコード書けば簡単に確認できます。
パディングサイズはコンパイルオプションでも変わるので決めておかないと困ったことになります。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct{
unsigned char aaa :1;
unsigned char bbb :1;
unsigned char ccc :1;
unsigned int ddd :13;
unsigned char eee :2;
unsigned char fff :2;
unsigned char ggg :4;
}test_t;
int main( )
{
int n,l ;
unsigned char *data ;
test_t *test ;
n = sizeof(test_t) ;
printf("sizeof(test_t) = %d\n",n) ;
data = malloc(n) ;
memset(data,0,n) ;
test = (test_t *)data ;
test->aaa = 1 ;
test->eee = 3 ;
for (l=0;l<n;l++) {
printf("%02d: %X\n",l,data[l]) ;
}
}
No.1
- 回答日時:
ビットフィールドでデーターを詰めたい場合、型をむやみに変えてはいけません。
(通常の構造体でも同じようなことは言えますがパディングが起こります)
あと、ビッグエンディアンの配置を期待されているようですが
実行結果でみると、リトルエンディアンのようです。
配置の取り方を変えましょう。
以下サンプル(期待出力が意味不明だったので %d の位置を変更しました)
#include <stdio.h>
#include <string.h>
typedef struct
{
unsigned aaa:1;
unsigned bbb:1;
unsigned ccc:1;
unsigned ddd:13;
unsigned eee:2;
unsigned fff:2;
unsigned ggg:4;
} test_t;
int
main (void)
{
test_t test_t;
unsigned data[] = {0x00c4fff2};
memcpy (&test_t, data, sizeof data);
printf ("aaa = %X\n", test_t.aaa);
printf ("bbb = %X\n", test_t.bbb);
printf ("ccc = %X\n", test_t.ccc);
printf ("ddd = %X\n", test_t.ddd);
printf ("eee = %X\n", test_t.eee);
printf ("fff = %X\n", test_t.fff);
printf ("ggg = %d\n", test_t.ggg);
return 0;
}
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C言語初心者 構造体 課題について 2 2023/03/10 19:48
- SQL Server ACCESSで3ファイルを結合して、表を作成するやり方を教えて下さい。 17 2022/08/15 20:34
- Excel(エクセル) ¥マークを含むパスの処理について(マクロ、または関数) 2 2022/12/25 02:11
- SQL Server ACCESSで複数テーブルを結合して、リストを作る方法を教えてください。 2 2022/08/12 19:32
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# カードシャッフルのブログラムを使ってc言語でブラックジャックをしたい 2 2022/04/12 15:13
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- C言語・C++・C# c言語でユーザ関数を利用して入力された文字列を反転させるプログラムを作りたいです。 3 2023/01/29 19:47
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- その他(データベース) カラム上の重複を削除するクエリを教えてください 3 2022/04/12 14:11
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Enterキーを押されたら次の処理...
-
C言語で複数列のデータを1列の...
-
C言語のプログラムで、途中で止...
-
空白を含んだ文字列がうまく格...
-
C言語についてです。
-
printf による16進表示について
-
#defineが使用するメモリ領域に...
-
なぜ無限ループになるかが分か...
-
reallocでエラー
-
NetBIOS名のエラー
-
エラーについて質問です。
-
ビルドエラーの対処がわからな...
-
バイナリファイル(画像)のよみ...
-
[C言語 Windows] Visual Cでの...
-
「an=(n-1)/(n+1)のときlim[n→∞...
-
マイナスからプラスへ転じた時...
-
C言語での引数の省略方法
-
「指定されたキャストは有効で...
-
DWORDの実際の型は何でしょうか
-
fgetsなどのときのstdinのバッ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Enterキーを押されたら次の処理...
-
printf による16進表示について
-
#defineが使用するメモリ領域に...
-
空白を含んだ文字列がうまく格...
-
char型2つを結合し、short型に...
-
【C言語】全角文字の配列を、全...
-
プログラミングの授業の課題です
-
C言語のプログラムで、途中で止...
-
C++で指定文字列のカウント方法...
-
C言語で複数列のデータを1列の...
-
C言語でのCSVファイルの読み出...
-
構造体メンバの初期化
-
なぜ無限ループになるかが分か...
-
reallocでエラー
-
Ç言語でファイルサイズを変更す...
-
ファイル操作で全角空白を消す
-
矢印キーを押下してコンソール...
-
セグメンテーションエラーの原...
-
static付き宣言の初期化
-
ファイルから数字列を16進数の...
おすすめ情報