raw(音楽ファイル)データを配列rawに読み込みたいのですが,バイナリファイルの読み込み方がわかりません.
サンプルで以下のようなソース(途中略)があるのですが,
・なぜrawの型としてshortを使っているのか
・データ数の半分(file_size = ftell(fp) / 2)しか読み込んでいない
・fgetc(fp) << 8
あたりの意味がわからないので教えて下さい.
--------------------------------------------------------
short *raw;
if((fp=fopen(argv[1], "rb")) == NULL){
fprintf(stderr, "can't open %s.\n", argv[1]);
exit(1);
}
fseek(fp, 0, SEEK_END);
file_size = ftell(fp) / 2;
fseek(fp, 0, SEEK_SET);
raw = (short *)malloc((size_t)(file_size * sizeof(short)));
if(raw == NULL){
fprintf(stderr, "malloc error\n");
exit(1);
}
for(i=0;i<file_size;i++)
raw[i] = (short)((fgetc(fp) << 8) | fgetc(fp));
-----------------------------------------------------
No.3ベストアンサー
- 回答日時:
動作自体はNo.1,No.2の方のとおりですが、このサンプルには不都合な点が2点あります。
>file_size = ftell(fp) / 2;
2というマジックナンバを使っている、正式にはsizeof(short)でないとまずい。
file_size = ftell(fp) / sizeof(short);
>raw[i] = (short)((fgetc(fp) << 8) | fgetc(fp));
fgetcを式の中で2回呼び出している、C言語規格では未定義の動作で、fgetcを実行する順序がどうなるか分からないので、下のように書かないと駄目。
raw[i] = fgetc(fp) << 8;
raw[i] |= fgetc(fp);
または
raw[i] = fgetc(fp);
raw[i] |= fgetc(fp) << 8;
どちらかになるかは、元データのエンディアンによります。
回答ありがとうございます。
>どちらかになるかは、元データのエンディアンによります。
入力データがリトルエンディアンかビッグエンディアンかでどちらかに決まる、ということですね。
No.4
- 回答日時:
No.3の訂正です。
------ ここから ------
動作自体はNo.1,No.2の方のとおりですが、このサンプルには不都合な点が1点あります。
>raw[i] = (short)((fgetc(fp) << 8) | fgetc(fp));
fgetcを式の中で2回呼び出している、C言語規格では未定義の動作で、fgetcを実行する順序がどうなるか分からないので、下のように書かないと駄目。
ビッグエンディアンのとき
raw[i] = fgetc(fp) << 8;
raw[i] |= fgetc(fp) & 0xff;
または
リトルエンディアンのとき
raw[i] = fgetc(fp) & 0xff;
raw[i] |= fgetc(fp) << 8;
------ ここまで ------
以下は間違えていました。
>>file_size = ftell(fp) / 2;
>2というマジックナンバを使っている、正式にはsizeof(short)でないとまずい。
>file_size = ftell(fp) / sizeof(short);
逆でしたsizeof(short)がまずくて2の方が正式でした。
元ファイル自体が2バイトずつ書かれているのをsizeof(short)で計算するのは間違いでした。
回答ありがとうございます。
>raw[i] = fgetc(fp) & 0xff;
8ビット全てで1とのアンドをとる、ということですよね。
なぜこのような操作をしているのでしょうか?
No.2
- 回答日時:
rawファイルのデータ構造の知識はありませんが、サンプルソースを読むかぎりでは、
16ビットのデータが、リトルエンディアン(上位アドレスに下位バイトのデータが配置されている)
で格納されている、という前提でバイナリファイルを読み込む処理を行っています。
> なぜrawの型としてshortを使っているのか
確実に16ビットのデータとして扱いたいのだと思います。intでは処理系によってサイズが変わってきます。
> データ数の半分(file_size = ftell(fp) / 2)しか読み込んでいない
ftell、fseek、fgetc、などは全て、ファイルを1バイト単位で扱います。
ftellの返す値は、ファイルサイズをバイトで数えた数値です。
これに対し、raw = (short *)malloc((size_t)(file_size * sizeof(short)));
では、2バイト単位で領域を確保しているので、ftellの返す値の半分で十分です。
また、最後のforループでは、1回のループ内でfgetcを2回呼び出して、2バイトづつ読み込んでいますので
ファイル全体を読み込めています。
> fgetc(fp) << 8
バイトオーダーが変わらないように、fgetcで1バイトづつ読み込み、先に取得した8ビットのデータを
8ビット分上位にシフトして、空いた下位8ビットに、次に取得した8ビットをビット演算で格納し、
16ビットのデータにしてから、raw[i] に代入するための処理です。
回答ありがとうございます。
ソースの内容はだいだいわかりましたが、
エンディアンあたりの話がよく分からないのでもう少し勉強してみます。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# leetcode 155 minstack 1 2022/05/07 16:43
- Windows 10 VirtualBox 7のゲストOSでの物理HDDパーティションのマウント方法 2 2023/05/04 13:01
- Excel(エクセル) VBA フォルダ見える化のコードについて 2 2023/06/19 15:04
- PHP ファイルの書き込みについて教えて下さい。 1 2023/03/20 12:01
- Visual Basic(VBA) ExcelVBAに関する質問 3 2023/02/17 10:47
- フィナンシャルプランナー(FP) FP検定は「エフピーけんてい」で読み方会ってますか汗 2 2022/04/20 22:37
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
c言語でのfscanfについて
-
C言語でファイル読み書きを早く...
-
C言語を用いて、csvファイル内...
-
fopenでファイル名に、変数を使...
-
構造体のメンバにファイルポイ...
-
CSVファイルの内容を構造体に格...
-
ガンマ変換 C言語でプログラ...
-
複数ファイルの同時読み込みの...
-
セグメンテーションエラーです
-
ファイルへの書込み処理が異常...
-
C言語について
-
csvファイルの読み込みで失敗し...
-
ファイル出力で改行を入れたい!
-
fgets( ) の返り値は何?
-
C言語にてXMLファイルから任意...
-
C言語 Segmentation fault
-
C言語でファイル名を変数にした...
-
大量の入力ファイルを扱うとき...
-
InternetReadFileを使ったファ...
-
ファイルからの全文読み込み
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
複数ファイルの同時読み込みの...
-
ファイルへの書込み処理が異常...
-
C言語でファイル読み書きを早く...
-
c言語でのfscanfについて
-
fopenでファイル名に、変数を使...
-
ファイル出力で改行を入れたい!
-
C言語にてXMLファイルから任意...
-
CRC32の計算方法
-
fgets( ) の返り値は何?
-
InternetReadFileを使ったファ...
-
【C言語】ファイルを読み込んで...
-
VisualStudioでのファイルの入...
-
commons-netでのFTP送信について
-
日本語ファイル名のFTPについて
-
fgets関数の利用 c言語
-
C言語でコマンドmvを実行
-
「コマンドライン引数チェック...
-
C言語でセグメンテーションエ...
-
構造体のメンバにファイルポイ...
-
エラー C2664
おすすめ情報