C言語関係掲示板

過去ログ

No.55. 変数の型を求める


たぶん、初めて質問させていただきます。

プログラム内で使われている変数が何型か解るような関数を作りたいんです。
switch文で最初に書いてしまうと、キャストしたときにおかしくなります。
int や char もちろんポインタもですが、データ自体とは別の場所に、データ型を識別するところでもあるんでしょうか?
それともどこかにそう言った関数なんかがありますか?


たぶん、初めて書き込みをさせていただきます。

いま思いついた方法。かなりいいけかげん。
ポインタや配列とかは未対応。

はじめに。
引数の引き渡しのときにキャストがかかるので
関数では無理です。なので、マクロで実現する
ことになると思います。

まず、実数か整数かを判定。
((X=0.1),(X==0.1))
# 0.5のほうがいいかも

次に、sizeofで大きさを判定し、limits.h などを
参照して型を判定。int が short ないし long と
区別がつかない可能性がありますが(他にも区別が
つかない型がある可能性あり)。

最後に、整数なら最上位ビットをいじって符号が
反転するかを調べ、符号付きかどうかを判定。
変数の内容を壊したくない場合は、2の補数をとった
値が単項のマイナス演算子を適用(要はマイナスを
つける)した場合と同じになるかを判定する。

こんなとこでしょうか。これをマクロで実現します。
めんどくさいわりには穴がありそう。。
使い物になるかもあやしいし。。。

では。


>たぶん、初めて質問させていただきます。
>
>プログラム内で使われている変数が何型か解るような関数を作りたいんです。
>switch文で最初に書いてしまうと、キャストしたときにおかしくなります。
>int や char もちろんポインタもですが、データ自体とは別の場所に、データ型を識別するところでもあるんでしょうか?
>それともどこかにそう言った関数なんかがありますか?


しっぱい。

>まず、実数か整数かを判定。
>((X=0.1),(X==0.1))
># 0.5のほうがいいかも

これじゃ、常に真ですね。

((X=0.5),((double)X==0.5))
# floatでもいいかも

で大丈夫。たぶん。
doubleより大きい型だった場合も、0.5なら精度は
落ちないはず。

でも、この方法だと、変数の内容が変わってしまい
ますね。もっといい方法があるかもしれません。

左シフトしたのが2倍したのと同じになるかってのも
考えましたが、0のとき(ほかにもあるかも)うまく
いきません(常に真)。

では。


またまちがい。

キャストですが、精度はおちます。

では。


>いま思いついた方法。かなりいいけかげん。
>ポインタや配列とかは未対応。
>
ポインタも知りたいのです。

>こんなとこでしょうか。これをマクロで実現します。
>めんどくさいわりには穴がありそう。。
>使い物になるかもあやしいし。。。
>
>では。

いろいろ思考錯誤ありがとうございます。
残念ながらおっしゃるとうりのようです。
使い物になるかもあやしいです。。。

自分でもいろいろ考えたんですが、
雰囲気としてはこんな感じになればいいではと思います。
<pre>
#include <stdio.h>

int main(void)
{
int a = 10;
char ch;
int d;
long ld;
float f;
double lf;

if(ch = a) { puts("char"); }
if(d = a) { puts("int"); }
if(ld = a) { puts("long"); }
if(f = a) { puts("float"); }
if(lf = a) { puts("double"); }

return 0;
}
</pre>
型が違ったら代入不可になる様な仕掛けができればいいんですが、
やっぱりその辺は難しいのかな〜・・・。


こんばんは、ともじです。

>自分でもいろいろ考えたんですが、
>雰囲気としてはこんな感じになればいいではと思います。
#include <stdio.h>
int main(void)
{
        int a = 10;
        char ch;
        int d;
        long ld;
        float f;
        double lf;
        
        if(ch == a) { puts("char"); }
        if(d  == a) { puts("int"); }
        if(ld == a) { puts("long"); }
        if(f  == a) { puts("float"); }
        if(lf == a) { puts("double"); } 
        
        return 0;
}

>型が違ったら代入不可になる様な仕掛けができればいいんですが、
>やっぱりその辺は難しいのかな〜・・・。

C++なら、関数の多重定義が可能です。

#include <stdio.h>
int     abs(int x)
{
        return((x < 0) ? -x : x);
}

long    abs(long x)
{
        return((x < 0L) ? -x : x);
}

double  abs(double x)
{
        return((x < 0.0) ? -x : x);
}

int     main(void)
{
        printf("abs(-6) = %d\n",abs(-6));
        printf("abs(7L) = %ld\n",abs(7L));
        printf("abs(-7.9) = %f\n",abs(-7.9));
}


以上、プログラムは「CプログラマのためのC++入門」柴田望洋著より


C++ですと、こんな感じですね。
ただし、関数内でaを使っていなのでWarningが出ますが。

#include <stdio.h>
void sub(char   a) { puts("char"); }
void sub(int    a) { puts("int"); }
void sub(long   a) { puts("long"); }
void sub(float  a) { puts("float"); }
void sub(double a) { puts("double"); }  

int main(void)
{
        char ch;
        int d;
        long ld;
        float f;
        double lf;
        
        sub(ch);
        sub(d);
        sub(ld);
        sub(f);
        sub(lf);

        return 0;
}


>C++ですと、こんな感じですね。

たしかにC++だと可能みたいですね。
いろいろと参考になりました、ありがとうございした。
試してみます。


>たぶん、初めて書き込みをさせていただきます。

kikkさん、書き込みありがとうございます。

>いま思いついた方法。かなりいいけかげん。

無理やりやるなら、こんな感じかなと、私も思っていました。
変数の型は、プログラマが管理すべきなので、やはりその型を検知するのは
難しいかもしれませんね。
複数の型を関数の引数にする場合、Cだと型ごとに関数を用意するしか方法は
無いでしょう。C++ですと、関数の多重定義が可能ですが。


ども。

>無理やりやるなら、こんな感じかなと、私も思っていました。
>変数の型は、プログラマが管理すべきなので、やはりその型を検知するのは
>難しいかもしれませんね。
>複数の型を関数の引数にする場合、Cだと型ごとに関数を用意するしか方法は
>無いでしょう。C++ですと、関数の多重定義が可能ですが。

実はこの問題を見たとき、真っ先にC++とJAVAのコードを思いついたんですが
ここってC言語掲示板じゃなかったっけ?と思い、無謀にもCでがんばって
みました。。。と、おもったら、C言語「関係」掲示板でした。まいっか。

ちなみにポインタや配列(型としては同じですが)の対応を避けたのは
ポインタのポインタのポインタの...といったケースに対応する手段を
思いつけなかったためです。なお、配列とポインタ(およびその他の型)
の区別はsizeofを使えばつきます。。。と、おもったけど、配列の
要素数が1のときはやっぱり区別がつきませんね。
# わかってる人はわかってると思いますが、sizeofの動作は配列名が
# ポインタとは動作の異なる(数少ない)ケースのひとつです

ついでに、提示した方法について、わかっている(小さな)穴を告白して
おくと、負数の内部表現が2の補数っていうのは、単なる決め付けです。
まあ、まず、この仮定がはずれることはありませんが。

どーしてもCじゃ実現できない場合はC++のコードを混ぜるのも現実的な
解決法ですね。多くのコンパイラはC/C++コンパイラですし。

では。

戻る


「初心者のためのポイント学習C言語」 Last modified:2001.10.7
Copyright(c) 2000-2002 TOMOJI All Rights Reserved