0

私は一般的に新しいプログラマーで、c で作業を開始しました。IDEv3 mp3 タグをデコードしようとしていますが、さまざまな問題に遭遇しました。fread() および strncpy() コマンドを使用しているときに、どちらも終了参照点として \n 文字が必要であることに気付きました。(たぶん私は間違っているかもしれませんが、これは単なる観察です)

出力を印刷すると、判読できない文字が生成されます。この問題を解決するための解決策として、(8)\n 文字 (バイト全体) を生成するために 3 バイトではなく 4 バイトに fread() を使用しています。印刷に使用しているメモリ。理論的には、fread() を使用している場合、この問題は発生しないはずです。

コードのサンプル:

#include <stdio.h>
#include <stdlib.h>

typedef struct{
  unsigned char header_id[3]; /* Unsigned character 3 Bytes (24 bits) */
}mp3_Header;

int main (int argc, char *argv[]) {

mp3_Header first;
unsigned char memory[4];

FILE *file = fopen( name.mp3 , "rb" );

if ( (size_t) fread( (void *) memory , (size_t) 4 , (size_t) 1 , (FILE *) file) !=1 ) {
  printf("Could not read the file\n");
  exit (0);
} /* End of if condition */

strncpy( (char *) first.header_id , (char *) memory , (size_t) 3);

printf ("This is the header_ID: %s\n", first.header_id);

fclose(file);

} /* End of main */
return 0;
4

4 に答える 4

5

'\n' 終端文字列を使用した観察は正しくありません。C の文字列は、0 バイト (\0) で終了する必要があります。ただし、ファイルから行を読み取ることになっている fgets() などの一部の関数は、行末の \n をターミネータとして使用します。

あなたのコードの問題は、 fread() がバイナリ データに対応していて、そのデータを文字列として解釈しようとしないことです。つまり、最後に \0 を配置しません。しかし、 のような文字列関数でstrcpyは、文字列の終わりを認識するためにこの 0 バイトが必要です。strncpy\0 をコピーした後も停止しますが、バッファ オーバーフローを防ぐために受信文字列にそれ以上のバイトを挿入することはありません。したがって、3 バイトがコピーされますが、文字列が長さの引数よりも短い場合のように、文字列の末尾に \0 は付けられません。

したがって、実際に必要な 1 つの MORE 要素で header_id を宣言し、strcpy の後に、この余分な要素を \0 に設定する必要があります。このような:

strncpy( first.header_id , memory , 3);
first.header_id[3] = '\0';

3 つのヘッダー バイトが配列要素 0..2 に送られるので、要素 3 にはターミネータが必要です。もちろん、追加の \0 のためのスペースを確保するために、header_id[4] を宣言する必要があります。

また、型キャストを省略したことに注意してください。型が正しい場合は必要ありません。配列を関数に渡すと、とにかく最初の要素へのポインターが渡されるため、配列の header_id を のポインターにキャストする必要はありませんstrncpy( (char *) first.header_id , (char *) memory , (size_t) 3);

于 2013-12-29T23:37:44.013 に答える
2

バッファ間でバイナリ データをコピーする場合は、 memcpy()など、ジョブに適した関数を使用する必要があります。バイナリ データを扱っているため、データの終わりを示すヌル文字がないため、バッファの長さを正確に把握する必要があります。

これを文字列にするには、単純に長さ + 1 のバッファーを割り当て、最後のバイトを '\0' に設定すると、文字列が作成されます。ただし、コピーしたバイナリ データに既に null 文字が含まれている可能性があるため、実際に必要な文字列であると信頼する前に、いくつかのサニティ チェックを行う必要があります。\001 のようなものは、mp3 形式の無効な ID かもしれません..しかし、壊れたファイルかもしれません。何を扱っているかわかりません。

于 2013-12-29T23:44:30.850 に答える
2

はい、C 文字列は常に null (0x00) 文字で終わります。それを理解し、適切にコーディングするのはプログラマーの責任です。

たとえば、header_id が最大 3 文字の印刷可能な文字列になる場合、末尾の null を許可するために、その配列に 4 文字を割り当てる必要があります。(そして、null が実際に存在することを確認する必要があります。) そうしないと、printf は停止するタイミングを認識できず、0 バイトが見つかるまで印刷を続けます。

于 2013-12-29T23:36:34.960 に答える