人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

C言語では、ポインタ型で表される値を、直接、int型の関数の返却値として指定できませんよね。
(具体例は最下行に表示)

なぜ、C言語はそのような仕様になっているのでしょうか?

両者を混同すると具体的にどのような不都合が生じるのでしょうか?
---------------------------------------------------------------------
例えば以下のような関数の2行目のreturnの括弧内の(int)を削除してmakeしようとすると、
コンパイラから、キャスト演算子が必要だと文句を言われますよね。

/* int cと同じ文字が*str内にあればその文字が格納されている場所を返す関数 */
int adstrchr(const char *str, int c){
while(*str++)if(*str==(char)c)return((int)str);
return(0);

●質問者: Xenos
●カテゴリ:学習・教育 科学・統計資料
✍キーワード:Char const C言語 make STR
○ 状態 :終了
└ 回答数 : 6/6件

▽最新の回答へ

1 ● pahoo
●100ポイント

話を簡単にするため、ポインタ char* で示されるデータは半角英数字からなる文字列、int で示される整数は16ビット符号付(範囲は-32768?+32767)という前提で回答します。


ポインタ char* で示される文字列も、int で示される整数も、CPUから見たらビットの並びに過ぎません。しかし、論理的な構造が異なります。

半角英数字1文字は8ビット、すなわち1バイトで表現されます。たとえば 1, 2, 3‥‥という文字列は、メモリ上では下記のようなデータ(16進数2桁=1バイト=1文字)が並んでいます。

31 32 33 ‥‥

これに対し、int は16ビット(2バイト)です。1, 2, 3‥‥という整数の並びは、下記のようになります。(Intel系CPUの場合)

01 00 02 00 03 00 ‥‥

"01 00" でワンセットで、整数の 1 を表します。


このようにメモリ上のデータ構造が異なることをCPUに知らせるため、C言語ではキャストという仕組みが備わっています。

文字列が日本語(2バイト)、整数が32ビット長になった場合も話は同じです。


蛇足ながら、JavaScriptやPHPなどの最近のスクリプト言語は、キャストをせずとも、プログラムの方で自動的に型判定を行ってくれます。しかし、ある条件下でキャストに失敗することがあり、これがシステムの脆弱性に繋がることがあります。なので、C言語と同様のキャストを指定することもできる仕様になっています。

個人的には、予想外のデータが入ってきたときにCPUが混乱しないよう、どんな言語であっても、キャスト指定はした方が良いと思います。


参考サイト

◎質問者からの返答

メモリ上のデータ構造が異なるとは、その型の変数のサイズが異なる(=sizeof(型)が異なる)ということで良いのでしょうか?だとすると、質問文のソースの1行目の「const char *str」を「const int *str」にするとノーエラーでmakeできそうですね。後で試してみます。


2 ● zzz_1980
●33ポイント

1) sizeof(int) と sizeof(char *)が正しいという保証はありません。

% cat hoi.c
#include <stdio.h>
const char *adstrchar(const char *str,int c);
const char samplestrings[]="ABCDEFG";
int main(int argc,char *argv[])
{
 const char *s;
 s = adstrchar(samplestrings,(int)'C');
 if(s){
 printf("%c\n",*s);
 }else{
 printf("not found\n");
 }
 return 0;
}
const char *adstrchar(const char *str,int c)
{
 while(*str++)if(*str==(char)c) return (str);
 return (NULL);
% cc -Wall hoi.c -o hoi
% ./hoi
C
%

url はダミーです。

http://www.cs.princeton.edu/~bwk/

◎質問者からの返答

ご回答ありがとうございます。質問文のソースを書き換えて以下のようにしてmakeを行ったところやはり、castが必要だとのエラーが返ってきました。

---------------

int adstrchr(const int *str, int c){

while(*str++)if(*str==c){return((int)str);}

return(0);}

-----

データ構造について詳しく調べたいと思います。


3 ● dev_zer0
●100ポイント

> C言語はそのような仕様になっているのでしょうか?

ポインタ型の実装を隠蔽したいからです。

# 多くの実装では単なるメモリアドレス値になってしまっていますが...


> 両者を混同すると具体的にどのような不都合が生じるのでしょうか?

今回は文字へのポインタ型ですが、他にも

・数値へのポインタ

・配列へのポインタ

・構造体型へのポインタ

とほぼポインタ型はほぼ無限に定義でき、かつ

違う型同士を比較や代入、返却することは大抵誤りであることが多いからです


int i = 100;

int *p = 100;

上下では意味が全く異なるのは理解できますよね?


あなたが作った関数で似たような関数が標準関数で存在します(strchr)が、その戻り値はchar *です。

http://www.linux.or.jp/JM/html/LDP_man-pages/man3/strchr.3.html


ドライバとかのかなり低レベルなI/Oで無い限り、ポインタ型と数値を混同するのは

百害あって一理なしです。

◎質問者からの返答

ご回答ありがとうございます。

int i=100;はint型の変数iを整数100で初期化。

int *p = 100;は pを100番地?を指すポインタとして定義する。

ということでしょうか?int *pがちょっと自信がないですが。

> ドライバとかのかなり低レベルなI/Oで無い限り、ポインタ型と数値を混同するのは

百害あって一理なしです。

そうですね、自分にとってはポインタはややこしいので、きちんとキャストをつけようと思います。


4 ● quintia
●33ポイント

内容的には2の回答と同じなのですがちょっと補足です。

int よりも char* の方がサイズが大きいことが普通にありえます。64bit環境では、ポインタ型が64bit、int型が32bitになります。

http://www.cc.u-tokyo.ac.jp/publication/news/VOL9/No2/64bitmode....

http://docs.sun.com/app/docs/doc/806-0018/6j9dcmg4t?l=ja&a=view


この場合、 質問のソースでは「cと同じ文字が*str内にあればその文字が格納されている場所を返す関数」にはなりません。

intにキャストした時点で情報が落ちていますから、あとでchar*にキャストしても元のところを指し示す保証がないのです。この関数の型をintにするのは明確な間違いです。

◎質問者からの返答

ご回答ありがとうございます。

64bit環境では、ポインタ型が64bit、int型が32bitになるのですね。

そうするとint型にしてはまずいですね。

後で試してみます。


5 ● fuentebella
●34ポイント

他の方の解答に加えて思いつくのは、Cでは、「NULLポインタ値が規定されていないので、NULLポインタの時キャストしないと0になるとは限らない」からというものあると思います。

http://www.sophia-it.com/content/%E3%83%8C%E3%83%AB%E3%83%9D%E3%...

◎質問者からの返答

NULLは盲点でした。ありがとうございます。


1-5件表示/6件
4.前の5件|次5件6.
関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ