2013-03-20 23 views
18

これらの文では、両方が同じエンコーディング(UTF-8)でソースコードに入力され、ロケールが正しく設定されている場合、実際の違いは?printf-wide文字列とマルチバイト文字列リテラルを使用したUTF-8文字列の印刷

printf("ο Δικαιοπολις εν αγρω εστιν\n"); 
printf("%ls", L"ο Δικαιοπολις εν αγρω εστιν\n"); 

結果的に、出力を行う際に、どちらか一方を優先する理由がありますか?私は2番目がかなり悪いことをすると思いますが、マルチバイトリテラルよりも利点(または不利益)がありますか?

編集:これらの文字列の印刷に問題はありません。しかし、私はprintfなどを使用できるようにするために、ワイド文字列関数を使用していません。ですから問題は、上記の状況を考慮して、これらの印刷方法が異なることです。そうであれば、2番目の方法は利点がありますか?

EDIT2:以下のコメントに続いて、私は今、このプログラムが動作していることを知っている - 私は可能ではなかったと思っている:

int main() 
{ 
    setlocale(LC_ALL, ""); 
    wprintf(L"ο Δικαιοπολις εν αγρω εστιν\n"); // wide output 
    freopen(NULL, "w", stdout);     // lets me switch 
    printf("ο Δικαιοπολις εν αγρω εστιν\n"); // byte output 
} 

EDIT3:私はすることにより、いくつかの更なる研究を行ってきました2つのタイプで何が起こっているのか見てみましょう。より簡単な文字列を使用してください:

wchar_t *wides = L"£100 π"; 
char *mbs = "£100 π"; 

コンパイラが異なるコードを生成しています。第二ですが

.string "\243" 
.string "" 
.string "" 
.string "1" 
.string "" 
.string "" 
.string "0" 
.string "" 
.string "" 
.string "0" 
.string "" 
.string "" 
.string " " 
.string "" 
.string "" 
.string "\300\003" 
.string "" 
.string "" 
.string "" 
.string "" 
.string "" 

:ワイド文字列がある

.string "\302\243100 \317\200" 

とUnicodeのエンコーディングを見て、第二は、プレーンUTF-8です。ワイド文字表現はUTF-32です。これは実装に依存することになります。

おそらく、リテラルのワイド文字表現はより移植性がありますか?私のシステムはUTF-16/UTF-32エンコーディングを直接出力しないので、出力のためにUTF-8に自動的に変換されます。

+0

あなたはどちらの例は、UTF-8で入力されていると述べました。 2番目のサンプル行で、そのテキストが実際にはワイドエンコーディングではなくUTF-8である場合は、L接頭語を使用しないでください。したがって、 '%ls'ではなく'%s'を使用します。あるいは、私はまだその質問を誤解しています。 –

+0

@AdrianMcCarthy - ソースコードの両方の文字列はUTF-8です。しかし、文字列リテラルは常にマルチバイトです。 "文字列リテラルは、" xyz "のように、ダブルクォートで囲まれた0個以上のマルチバイト文字のシーケンスです。ワイド文字リテラルは、文字Lであらかじめ固定されている場合を除いて同じです。 "標準から。 – teppic

+0

AFAIR、Basic Source Character Set(US-ASCII-7の*サブセット*)にない文字は、実装定義の動作を呼び出します。つまり、ここで説明するすべてのものは、使用するコンパイラによって効果的です。あなたが本当にそれを安全に(そして携帯に)したいのであれば、あなたは\ u ...と\ Uに頼らなければならないでしょう。 – DevSolar

答えて

20
printf("ο Δικαιοπολις εν αγρω εστιν\n"); 

リテラル文字列印刷(const char*を、特殊文字がマルチバイト文字として表現されています)。正しい出力が見えるかもしれませんが、このような非ASCII文字を扱う際には他の問題があります。例えば:

char str[] = "αγρω"; 
printf("%d %d\n", sizeof(str), strlen(str)); 

出力9 8、これらの特殊文字のそれぞれを2つのchar Sで表されるからです。

あなたはワイド文字(const wchar_t*)からなるリテラルと%ls書式指定子を持つL接頭辞を使用している間マルチバイト文字(UTF-8)に変換されるこれらのワイド文字の原因となります。すなわち、この場合には、ロケールを適切に設定する必要がありますそうでない場合は、この変換は、出力が無効であることにつながるかもしれない:

#include <stdio.h> 
#include <wchar.h> 
#include <locale.h> 

int main(void) 
{ 
    setlocale(LC_ALL, ""); 
    printf("%ls", L"ο Δικαιοπολις εν αγρω εστιν"); 
    return 0; 
} 

が、ワイド文字で作業する場合、いくつかの物事がより複雑になるかもしれないが、他の物事がはるかに簡単かもしれませんし、より簡単。たとえば、

wchar_t str[] = L"αγρω"; 
printf("%d %d", sizeof(str)/sizeof(wchar_t), wcslen(str)); 

は当然のように出力されます。5 4

ワイド文字列を使用すると、wprintfを使用して、ワイド文字を直接印刷できます。また、Windowsコンソールの場合には、stdoutの変換モードが明示的に_setmodeを呼び出すことによって、Unicodeのモードのいずれかに設定する必要があることをここで注意することは価値がある:

#include <stdio.h> 
#include <wchar.h> 

#include <io.h> 
#include <fcntl.h> 
#ifndef _O_U16TEXT 
    #define _O_U16TEXT 0x20000 
#endif 

int main() 
{ 
    _setmode(_fileno(stdout), _O_U16TEXT); 
    wprintf(L"%s\n", L"ο Δικαιοπολις εν αγρω εστιν"); 
    return 0; 
} 
+0

それは私です:) 'wprintf'もマルチバイトに変換しますが、私は標準関数に興味があります。 – teppic

+0

@teppic:今私の答えを見てください。それは最終的には私が推測するより満足しているはずです:) – LihO

+5

UTF-16は** "ワイド"ではなく、この神話のビットがまだ残っているのは本当に残念です。 2^16以上のUnicode文字があり、UTF-16はそれらを1つまたは2つの16ビットコード単位の**可変**幅でエンコードします。 「ワイド」を望むなら、UTF-32に頼らざるを得ません。 'n'ビットで全員に十分なはずだという考えの罠に入るのをやめてみましょう。 – DevSolar

関連する問題