printf/fprintf/sprintf ファミリは、その書式指定子で幅フィールドをサポートしています。(非ワイド) char 配列引数の場合には疑問があります。
幅フィールドはバイトまたは文字を意味するはずですか?
char 配列が (たとえば) 生の UTF-8 文字列に対応している場合、(正しい事実上の) 動作は何ですか? (通常、ワイド文字型を使用する必要があることはわかっていますが、それは重要ではありません)
たとえば、
char s[] = "ni\xc3\xb1o"; // utf8 encoded "niño"
fprintf(f,"%5s",s);
その関数は、5 バイト (プレーンな C 文字) だけを出力しようとすることになっていますか (2 バイトがテキスト文字になる場合は、ミスアラインメントやその他の問題の責任を負います) ?
それとも、配列の「テキスト文字」の長さを計算しようとすることになっていますか? (現在のロケールに従ってデコードしますか?)(この例では、文字列に 4 つの Unicode 文字があることがわかるため、パディング用のスペースが追加されます)。
更新:私は答えに同意します.printfファミリがプレーンC文字とバイトを区別しないのは論理的です. 問題は、ロケールが以前に設定されていて、(今日最も使用されている) LANG/LC_CTYPE=en_US.UTF-8 がある場合、私の glibc がこの概念を完全に尊重していないように見えることです。
適例:
#include<stdio.h>
#include<locale.h>
main () {
char * locale = setlocale(LC_ALL, ""); /* I have LC_CTYPE="en_US.UTF-8" */
char s[] = {'n','i', 0xc3,0xb1,'o',0}; /* "niño" in utf8: 5 bytes, 4 unicode chars */
printf("|%*s|\n",6,s); /* this should pad a blank - works ok*/
printf("|%.*s|\n",4,s); /* this should eat a char - works ok */
char s3[] = {'A',0xb1,'B',0}; /* this is not valid UTF8 */
printf("|%s|\n",s3); /* print raw chars - ok */
printf("|%.*s|\n",15,s3); /* panics (why???) */
}
そのため、非 POSIX-C ロケールが設定されている場合でも、printfは幅をカウントするための正しい概念を持っているようです: バイト (c プレーン文字) であり、ユニコード文字ではありません。それはいいです。ただし、彼のロケールでデコードできない char 配列を指定すると、静かにパニックが発生します (中止 - 最初の '|' の後に何も出力されません - エラーメッセージなし)... 幅をカウントする必要がある場合のみ。必要な/必要なときに、utf-8 から文字列をデコードしようとする理由がわかりません。これは glibc のバグですか?
glibc 2.11.1 (Fedora 12) でテスト済み (glibc 2.3.6 も)
注:端末の表示の問題とは関係ありません- od にパイプすることで出力を確認できます:これ$ ./a.out | od -t cx1
が私の出力です:
0000000 | n i 303 261 o | \n | n i 303 261 | \n
7c 20 6e 69 c3 b1 6f 7c 0a 7c 6e 69 c3 b1 7c 0a
0000020 | A 261 B | \n |
7c 41 b1 42 7c 0a 7c
UPDATE 2 (2015 年 5 月) : この疑わしい動作は、新しいバージョンの glibc で修正されました (2.17 以降のようです)。それは私にとってはうまくいきglibc-2.17-21.fc19
ます。