toupper()関数やtolower()関数について

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
やまだ

toupper()関数やtolower()関数について

#1

投稿記事 by やまだ » 10年前

いずれも戻り値、引数の指定がint型なのにchar型の配列の要素を渡すことができるのは何故なのでしょうか?
ご教授お願いします

夕月

Re: toupper()関数やtolower()関数について

#2

投稿記事 by 夕月 » 10年前

環境はよくわかりませんが、VisualStudio2010で以下のコードを組んだところキャストエラーがまず起きます。

コード:

#include <stdio.h>
#include <ctype.h>
int main()
{
	char* p = "abc";
	printf_s("%s\n",toupper(p));//ここでchar*からintへの変換ができません。
}
次に

コード:

	printf_s("%s\n",toupper((int)p));
と書いたところ、コンパイルがとおり、(何故か)文字列が表示されました。
ただし、元の"abc"のままでしたが

環境がわからないのでなんともいえないのですが、
文字列はマルチバイトの場合charのポインタ型で、ポインタはintと同じ32bitなので
コンパイラがポインタをintに勝手に変換した可能性はあります。

box
記事: 2002
登録日時: 12年前

Re: toupper()関数やtolower()関数について

#3

投稿記事 by box » 10年前

コード:

/*
 * char型の配列の要素(つまりchar型)は、「int型よりせまい範囲の整数」が
 * 入る、という意味において、int型の部分集合となります。
 * 従って、toupperなどにchar型の配列の要素を渡すことは、何も問題ありません。
 */

#include <stdio.h>
#include <ctype.h>

int main(void)
{
    char p[] = "abc";
    int i;

    for (i = 0; p[i]; i++) {
        printf("%c", toupper(p[i]));
    }
    putchar('\n');
    return 0;
}
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

non
記事: 1097
登録日時: 12年前

Re: toupper()関数やtolower()関数について

#4

投稿記事 by non » 10年前

夕月さんのコードは何をしたいのか、または何を説明したいのかわかりません。
non

やまだ

Re: toupper()関数やtolower()関数について

#5

投稿記事 by やまだ » 10年前

夕月さん、ハッカーさん返答ありがとうございます!!
なるほど、整数の格納範囲においてchar型はint型の部分集合ということですか
納得です!!

やまだ

Re: toupper()関数やtolower()関数について

#6

投稿記事 by やまだ » 10年前

ん?しかしchar型が英字を扱える以上、完全な部分集合とは言えませんよね?
あくまで整数範囲に限っては、と注釈がついてしまいます
そういう場合でもint型指定の中でchar型を扱ってもいいんでしょうか?
理解が悪くて申し訳ないです

non
記事: 1097
登録日時: 12年前

Re: toupper()関数やtolower()関数について

#7

投稿記事 by non » 10年前

コンピュータで扱う文字はすべてコードで覚えているので、数値(整数)ですよ。
non

かずま

Re: toupper()関数やtolower()関数について

#8

投稿記事 by かずま » 10年前

やまだ さんが書きました:いずれも戻り値、引数の指定がint型なのにchar型の配列の要素を渡すことができるのは何故なのでしょうか?
厳密なことを言うと、toupper 関数の int型の引数に char型配列の要素を渡すことは規格違反です。

最新の規格は ISO/IEC 9899:2011 (通称C11)ですが、JIS は JIS X3010:2003 で、
これは ひとつ前の ISO/IEC 9899:1999 (C99) です。
toupper などの <ctype.h> に属する関数に関してはどれをみても同じなので、
C99 から引用してみます。

コード:

7.4 Character handling <ctype.h>
The header <ctype.h> declares several functions useful for classifying and mapping
characters.166) In all cases the argument is an int, the value of which shall be
representable as an unsigned char or shall equal the value of the macro EOF. If the
argument has any other value, the behavior is undefined.
引数は int だけれど、そこに渡せる値は unsigned char で表現できる値、
または EOF の値に限られていて、それ以外だど動作は未定義となっています。

値の範囲というのは処理系定義ですが、私たちが普段使うコンパイラでは、
unsigned char は 0~255、EOF は -1 です。
すなわち、toupper の引数は intですが、-1~255 の値しか渡してはいけません。
ところが、char の範囲は -128~127 が一般的です。
char をそのまま引数に使うと -128~-2 の値に対しては、動作が未定義となります。

具体例をあげると、Shift-JIS で半角カタカナの 'ア' は 0xb1 ですが、これを char型の
変数に入れるとその値は -79 です。

toupper でググって、そこに出てきたサイトのサンプルプログラムを見ると、ほとんど
すべてが toupper に char を渡しています。それでうまくいくのは、渡しているの文字が
7ビット ASCII の文字だけだからです。
あるいは、toupperの実装が、未定義の動作に対して、うまく処理をして、本当に
小文字である場合以外は、元の引数の値を返すようになっているのかもしれません。

夕月さんの無茶苦茶なプログラムも、ポインタを int に変換して、とんでもない値を
toupper に渡しているのに、それは小文字の範囲外なので、元のポインタの値がそのまま
返ってきて、文字列が表示されているのでしょう。

フリオ

Re: toupper()関数やtolower()関数について

#9

投稿記事 by フリオ » 10年前

 ctype.h関数以外にも、strchr関数の第2引数、printf関数の%cに対応する引数もint型です。
また、Cでは、文字定数('A'など)もint型です。

閉鎖

“C言語何でも質問掲示板” へ戻る