26

両方が同じエンコーディング(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 ""

2番目は:

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

そして、Unicodeエンコーディングを見ると、2番目はプレーンなUTF-8です。ワイド文字表現はUTF-32です。これは実装に依存することになると思います。

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

4

1 に答える 1

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

文字列リテラル ( const char*、特殊文字はマルチバイト文字として表されます) を出力します。正しい出力が表示される場合もありますが、これらのような非 ASCII 文字を処理する際に対処する可能性のある他の問題があります。例えば:

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

9 8これらの特殊文字はそれぞれ 2 で表されるため、出力はcharです。

プレフィックスを使用すると、ワイド文字 ( ) でL構成されるリテラルがあり、書式指定子により、これらのワイド文字がマルチバイト文字(UTF-8) に変換されます。この場合、ロケールを適切に設定する必要があることに注意してください。そうしないと、この変換によって出力が無効になる可能性があります。const wchar_t*%ls

#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 コンソールの場合、 の変換モードをを呼び出して明示的に Unicode モードの 1 つに設定する必要があることにも注意してください。stdout_setmode

#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;
}
于 2013-03-20T15:50:47.700 に答える