質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

4回答

3663閲覧

2進数で表示された数値をビッグエンディアンで表示させる方法

n6n9Qsmt8gLjwKw

総合スコア29

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

1クリップ

投稿2016/01/21 12:05

こんにちは
305419896(16進数0x12345678)をバイト、ワード、ビットで表示するプログラムを作成しています。
ビットで表示する際に2進数変換後にリトルエンディアンからビッグエンディアンに変換したときbit[0]~bit[15]に不明な文字が入力されてしまいます。bit[16]以降は正常に表示されているのですが何が原因なのかわかりません。

下記コードの何が原因なのかご教授いただきたいです。
可能ならば修正コードも載せていただけると非常にありがたいです。

C

1#define _CRT_SECURE_NO_WARNINGS//scanf警告解除 2#include <stdio.h> 3#include <stdlib.h> 4#include <string.h> 5 6#define WORD_SIZE (2) 7#define BYTE_SIZE (4) 8#define BIT_SIZE (32) 9 10typedef union 11{ 12 unsigned int data; /* 4byte */ 13 unsigned short word[WORD_SIZE]; /* 2byte×2 */ 14 unsigned char byte[BYTE_SIZE]; /* 1byte×4 */ 15 unsigned char bit[BIT_SIZE]; /* 1byte×32 */ 16}DATA; 17 18//変数宣言 19int byte_cnt;//バイトサイズカウンタ 20int bit_cnt;//ビットサイズカウンタ 21 22//関数プロトタイプ宣言 23void output_data(DATA *data); 24 25//メイン関数 26int main(int argv, char* arg[]) { 27 28 DATA init_data;//入力用データ初期化用 29 DATA *union_data;//入力用データ 30 31 union_data = &init_data;//ポインタ初期化 32 33 union_data->data = 305419896; 34 35 printf("入力データ:"); 36 printf("%d\n", union_data->data); 37 printf("=======================================\n"); 38 39 output_data(union_data);//データ出力関数呼び出し 40 41 42//デバッグ用 43#if 1 44 int debag; 45 scanf("%d", &debag); 46#endif 47 48 return 0; 49} 50 51//データ出力関数 52void output_data(DATA *data) { 53 54 DATA endian_init;//出力用データ初期化用 55 DATA *endian_data;//出力用データ 56 57 endian_data = &endian_init;//ポインタ初期化 58 59 /***************************/ 60 /*データ名表示 */ 61 /***************************/ 62 printf("=======================================\n"); 63 printf("DATA : 0x%08X\n", data->data); 64 65 /***************************/ 66 /*ワード表示 */ 67 /***************************/ 68 printf("=======================================\n"); 69 endian_data->word[0] = data->word[1];//エンディアン変換 70 endian_data->word[1] = data->word[0];//エンディアン変換 71 printf("WORD(Hi) : 0x%04X\n", endian_data->word[0]); 72 printf("WORD(Lo) : 0x%04X\n", endian_data->word[1]); 73 74 /***************************/ 75 /*バイト表示 */ 76 /***************************/ 77 printf("=======================================\n"); 78 79 for (byte_cnt = 0; byte_cnt < BYTE_SIZE; byte_cnt++) { 80 81 endian_data->byte[byte_cnt] = data->byte[(BYTE_SIZE-1)- byte_cnt];//エンディアン変換 82 83 printf("BYTE(%d) : 0x%02X\n", byte_cnt, endian_data->byte[byte_cnt]); 84 85 } 86 87 /***************************/ 88 /*ビット表示 */ 89 /***************************/ 90 printf("=======================================\n"); 91#if 0 92 for (bit_cnt = 0; bit_cnt<BIT_SIZE; bit_cnt++) { 93 /* ビットの表示 */ 94 printf("BITS(%d) : %u\n", bit_cnt, (data->data>> bit_cnt) & 1); 95 } 96#endif 97 for (bit_cnt = 0; bit_cnt<BIT_SIZE; bit_cnt++) { 98 if (((data->data >> bit_cnt) & 1 )== 1) {//2進数変換した値が1の場合 99 endian_data->bit[(BIT_SIZE-1)- bit_cnt] = '1';//エンディアン変換 100 } 101 else if (((data->data >> bit_cnt) & 1) == 0) {//2進数変換した値が0の場合 102 endian_data->bit[(BIT_SIZE-1)- bit_cnt] = '0';//エンディアン変換 103 } 104 printf("BITS(%d) : %c\n", bit_cnt, endian_data->bit[bit_cnt]); 105 } 106 107}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

直接の回答からはそれるかもしれませんが・・・
バイト並び順の違いは、ネットワーク通信の際に問題になります。
ですので、標準ライブラリにはこの問題に対処するための関数が用意されています。
man htonl 等で調べれば仕様は分かると思います。

C

1#include <stdio.h> 2#include <arpa/inet.h> 3int main(int argv, char* arg[]) { 4 5 unsigned int data1; 6 unsigned int data2; 7 8 data1 = 305419896; 9 data2 = htonl( data1 ); 10 11 printf( "%08X\n", data1 ); 12 printf( "%08X\n", data2 ); 13 14 return 0; 15}

以下はインテル系CPU上で動作する ubuntu 上の動作結果です。

sh

1$ gcc -o sample sample.c 2$ ./sample 312345678 478563412 5

投稿2016/01/21 12:54

編集2016/01/21 12:56
kozuchi

総合スコア1193

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

n6n9Qsmt8gLjwKw

2016/01/21 13:18

kozuchiさん回答ありがとうございます。 標準ライブラリにこのような関数があることを知りませんでした。 非常に参考になりました。 私のPCもintel系なので同じ動作結果が出ると思いますのでman htonlを調べて試してみようと思います。
guest

0

念のため指摘しておきますが、エンディアンは**「バイトデータ」**の並び順のことです。エンディアンを反転するのにビット操作はしません。

投稿2016/01/21 12:39

catsforepaw

総合スコア5938

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

n6n9Qsmt8gLjwKw

2016/01/21 13:13

勉強不足でした。 エンディアンの意味のとらえ方を誤解していました。 回答ありがとうございます。
guest

0

ベストアンサー

こんにちは。

単純ミスです。
bit_cnt=0の時、(BIT_SIZE-1)- bit_cnt31ですのでendian_data->bit[31]に設定してます。
そして、そのままendian_data->bit[0]を表示してますが、まだここには値が設定されていませんね。

投稿2016/01/21 12:29

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

n6n9Qsmt8gLjwKw

2016/01/21 13:05

Chironianさん、回答ありがとうございます。 コードを落ち着いて見直すと仰る通り非常に単純なミスでした。 printf関数をbit_cntのループ後に記載して同じようにループ出力することで 解決できました。 本当にありがとうございます。
guest

0

unionのデータの配置はコンパイラ依存となります。パディング(詰め物)が途中に入る可能性があります。
従って32ビットデータ(int)をバイトデータ(char)で取り出したときに同じならびになる保障はありません。
一度DATAをダンプして確認したほうがいいと思います。

投稿2016/01/21 12:16

cateye

総合スコア6851

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

n6n9Qsmt8gLjwKw

2016/01/21 13:11

基本的にこのコードは勉強用のため自分の環境でしか動かさないですが、今回のように回答してもらうときに他の人のコンパイラだと仰る通り私と同じデータ配置にならないかもしれませんし、ゴミが入ってしまうかもしれませんね。 改善案を探してみます。
Chironian

2016/01/21 13:46

unionのメンバ変数は重なりますから「間」がないので「途中」にバディングが入ることはないですよ。また、配列にもバディングが入ることはないです。でないとsizeof(array)/sizeof(array[0])で要素数を計算できませんから。ですので、今回のケースではパディングは入らないです。 とは言え、struct/classを含むunionではstruct/class内のパディングには要注意ですね。 パディング(アライメント)については↓が詳しいです。 http://www5d.biglobe.ne.jp/~noocyte/Programming/Alignment.html
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問