C言語関係掲示板

過去ログ

No.431.wchar_tについて

[戻る] [ホームページ]
No.3058

wchar_tのコンパイラによる扱いの違い?
投稿者---トロ(2002/10/23 00:44:02)


文字列の並びを逆順にする関数を作成したところ、
LSI-CとBCCにおいて表示が異なりました。

"51はイチロー"という例文を処理すると
LSI-Cではきちんと逆順になりますが、
BCCでは正しく表示されませんでした。

"51はイチローの背番号"という例文は、
LSI-C、BCCともきちんと逆順になりました。

wchar_tの扱いがLSI-CとBCCで異なっているのでしょうか?

以下に作成したソースを示しておきます。

#include <stdio.h>
#include <string.h>


typedef unsigned short wchar_t;

wchar_t *strrev2(wchar_t *s)
{  
	 wchar_t *ret;
	 wchar_t *tmp;
	 wchar_t work;
	 ret = s;
	 tmp = s;
	 
	 while(*tmp != '\0'){
	 	tmp++;
	 }
	 
	 tmp--;
	 
	 while(tmp > s){
	 	work = *s;
		*s = *tmp;
		s++;
		*tmp = work;
		tmp--;
	 }
     return ret;

void main(void)
{
	wchar_t nihon[80];
	
	strcpy((char *)nihon, "51はイチロー");
	
	printf("%s\n",nihon);
	strrev2(nihon);
	printf("%s\n",nihon);

	return ;
}



No.3061

Re:wchar_tのコンパイラによる扱いの違い?
投稿者---kikk(2002/10/23 02:27:20)


ども。


> strcpy((char *)nihon, "51はイチロー");

結論から言うと、上記コードによってヌル文字が1バイトになっているのが
原因です。

> while(*tmp != '\0'){

反転関数の上記部で、ヌル文字判定をwchar_t(unsigned short)で行って
います(注)が、終端部で1バイト分しか0になっていないため、もう片方の
バイトがたまたま0でない限り、終端であると判定されません。

注) 厳密に言うと、'\0'のほうはint型なので、intへの格上げが起こる。
「Cでは」文字定数はint型。sizeof('\0')等で確認可。


とりあえず、現在の方針のままでなんとかするならば、wchar_t版ヌル文字
で終端する(つまり、終わり2バイトを0にする)ような自前のmy_strcpy()を
初期化時に使う等が考えられます。LSI Cがwchar_tおよびワイド文字系の
関数をサポートしていれば、別の方法もあるのでしょうが。。


あと、これは余計なお世話かもしれませんが、いまのままの方法では、
1バイト文字と多バイト文字が混ざった文字列を扱う場合に、動作が
かなり危うい気がします。十分、気をつけてください。


では。

No.3165

Re:wchar_tのコンパイラによる扱いの違い?
投稿者---トロ(2002/10/27 03:37:06)


kikk様、御回答ありがとうございます。

>> while(*tmp != '\0'){
>
>反転関数の上記部で、ヌル文字判定をwchar_t(unsigned short)で行って
>います(注)が、終端部で1バイト分しか0になっていないため、もう片方の
>バイトがたまたま0でない限り、終端であると判定されません。

tmpがwchar_tで宣言されているので1バイト分の0では正しく文字列の終端
であると判定していなかったのですね。

>注) 厳密に言うと、'\0'のほうはint型なので、intへの格上げが起こる。
>「Cでは」文字定数はint型。sizeof('\0')等で確認可。

'\0'がint型,tmpがwchar_t(unsigned short)型なので整数の昇格が
が起こり、int型での判定が行われるのですね。
sizeof('\0')はBCCでは4バイト、LSI-Cでは1バイトでした。
BCCの4バイトはint型なので分かるのですが、LSI-Cの1バイトはどうしてなのでしょうか?
LSI-Cではint型は2バイトですよね?

>とりあえず、現在の方針のままでなんとかするならば、wchar_t版ヌル文字
>で終端する(つまり、終わり2バイトを0にする)ような自前のmy_strcpy()を
>初期化時に使う等が考えられます。

なるほど。

>LSI Cがwchar_tおよびワイド文字系の
>関数をサポートしていれば、別の方法もあるのでしょうが。。

LSI-Cはワイド文字系を扱う関数のライブラリをもっていないのですか?

>あと、これは余計なお世話かもしれませんが、いまのままの方法では、
>1バイト文字と多バイト文字が混ざった文字列を扱う場合に、動作が
>かなり危うい気がします。十分、気をつけてください。

御忠告ありがとうございます。
1バイト文字だけを扱う反転関数、2バイト文字だけを扱う反転関数、
1+2バイト文字を扱う反転関数という順序で作成しようと考えていまして、
今の段階は2バイト文字だけを扱う場合だけを想定しています。

No.3064

Re:wchar_tのコンパイラによる扱いの違い?
投稿者---かずま(2002/10/23 04:00:50)


wchar_t は setlocale() と一緒に使わないと、日本語処理ができません。
次のプログラムは、Borland C++, Visual C++, gcc で動きます。
LSI C-86 試食版ではダメです。
#include <stdio.h>
#include <locale.h>

wchar_t *strrev2(wchar_t *s)
{  
    wchar_t *a, *b = s, wc;

    if (*s == 0) return s;
    while (*++b != 0)
        ;
    for (a = s; a < --b; a++)
        wc = *a, *a = *b, *b = wc;
    return s;
}

int main(void)
{
    wchar_t nihon[80] = L"51はイチロー";
    
    setlocale(LC_ALL, "");
    printf("%S\n", nihon);
    strrev2(nihon);
    printf("%S\n", nihon);
    return 0;
}


No.3069

Re:wchar_tのコンパイラによる扱いの違い?
投稿者---かずま(2002/10/23 14:23:01)


> printf("%S\n", nihon);

printf("%S\n", nihon); に訂正します。

規格書 JIS X 3010:1996 (ISO/IEC 9899:1990/Amd.1:1993) を見てみると、
wchar_t の文字列の printf での書式は、%S ではなく %ls でした。

でも、各処理系での拡張により、%S でもうまくいくみたいです。