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

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

ただいまの
回答率

90.50%

  • C

    4524questions

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

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

解決済

回答 4

投稿

  • 評価
  • クリップ 1
  • VIEW 1,286

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

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

#define _CRT_SECURE_NO_WARNINGS//scanf警告解除
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define WORD_SIZE (2)
#define BYTE_SIZE (4)
#define BIT_SIZE  (32)

typedef union
{
     unsigned int data;                    /* 4byte    */
     unsigned short word[WORD_SIZE];    /* 2byte×2 */
     unsigned char byte[BYTE_SIZE];     /* 1byte×4 */
     unsigned char bit[BIT_SIZE];       /* 1byte×32 */
}DATA;

//変数宣言
int byte_cnt;//バイトサイズカウンタ
int bit_cnt;//ビットサイズカウンタ

//関数プロトタイプ宣言
void output_data(DATA *data);

//メイン関数
int  main(int argv, char* arg[]) {

    DATA init_data;//入力用データ初期化用
    DATA *union_data;//入力用データ

    union_data = &init_data;//ポインタ初期化

    union_data->data = 305419896;

    printf("入力データ:");
    printf("%d\n", union_data->data);
    printf("=======================================\n");

    output_data(union_data);//データ出力関数呼び出し


//デバッグ用    
#if 1
    int debag;
    scanf("%d", &debag);
#endif

    return 0;
}

//データ出力関数
void output_data(DATA *data) {

    DATA endian_init;//出力用データ初期化用
    DATA *endian_data;//出力用データ

    endian_data = &endian_init;//ポインタ初期化

    /***************************/
    /*データ名表示       */
    /***************************/
    printf("=======================================\n");
    printf("DATA      : 0x%08X\n", data->data);

    /***************************/
    /*ワード表示         */
    /***************************/
    printf("=======================================\n");
    endian_data->word[0] = data->word[1];//エンディアン変換
    endian_data->word[1] = data->word[0];//エンディアン変換
    printf("WORD(Hi)  : 0x%04X\n", endian_data->word[0]);
    printf("WORD(Lo)  : 0x%04X\n", endian_data->word[1]);

    /***************************/
    /*バイト表示         */
    /***************************/
    printf("=======================================\n");

    for (byte_cnt = 0; byte_cnt < BYTE_SIZE; byte_cnt++) {

        endian_data->byte[byte_cnt] = data->byte[(BYTE_SIZE-1)- byte_cnt];//エンディアン変換

        printf("BYTE(%d)  : 0x%02X\n", byte_cnt, endian_data->byte[byte_cnt]);

    }

    /***************************/
    /*ビット表示         */
    /***************************/
    printf("=======================================\n");
#if 0
    for (bit_cnt = 0; bit_cnt<BIT_SIZE; bit_cnt++) {
        /* ビットの表示 */
        printf("BITS(%d)  : %u\n", bit_cnt, (data->data>> bit_cnt) & 1);
    }
#endif
    for (bit_cnt = 0; bit_cnt<BIT_SIZE; bit_cnt++) {
        if (((data->data >> bit_cnt) & 1 )== 1) {//2進数変換した値が1の場合
            endian_data->bit[(BIT_SIZE-1)- bit_cnt] = '1';//エンディアン変換
        }
        else if (((data->data >> bit_cnt) & 1)  == 0) {//2進数変換した値が0の場合
            endian_data->bit[(BIT_SIZE-1)- bit_cnt] = '0';//エンディアン変換
        }
        printf("BITS(%d)  : %c\n", bit_cnt, endian_data->bit[bit_cnt]);
    }

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+1

こんにちは。

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/01/21 22:05

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

    キャンセル

+1

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/01/21 22:11

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

    キャンセル

  • 2016/01/21 22:46

    unionのメンバ変数は重なりますから「間」がないので「途中」にバディングが入ることはないですよ。また、配列にもバディングが入ることはないです。でないとsizeof(array)/sizeof(array[0])で要素数を計算できませんから。ですので、今回のケースではパディングは入らないです。

    とは言え、struct/classを含むunionではstruct/class内のパディングには要注意ですね。
    パディング(アライメント)については↓が詳しいです。
    http://www5d.biglobe.ne.jp/~noocyte/Programming/Alignment.html

    キャンセル

+1

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/01/21 22:13

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

    キャンセル

+1

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

#include <stdio.h>
#include <arpa/inet.h>
int  main(int argv, char* arg[]) {

    unsigned int data1;
    unsigned int data2;

    data1 = 305419896;
    data2 = htonl( data1 );

    printf( "%08X\n", data1 );
    printf( "%08X\n", data2 );

    return 0;
}

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

$ gcc -o sample sample.c
$ ./sample
12345678
78563412

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/01/21 22:18

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

    キャンセル

同じタグがついた質問を見る

  • C

    4524questions

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