以下のように構造体、配列が宣言されています。
struct SYM_INFO {
char *name ;
long adr ;
char typ ;
} ;
SYM_INFO sym_Tbl[3] ;
この配列 sym_Tbl に格納された値を指定された次元の要素
によってソートをかけたいと考えています。例えば
name {CFI_KP, B_EXTR, DA12_GS, ACR_OUT }
adr {00000CAC, 00014346, 00000B98, 000143F4}
typ {W, W, B, D }
という順に格納されている場合、name に対してソートをかけると
name {ACR_OUT, B_EXTR, CFI_KP, DA12_GS }
adr {000143F4, 00014346, 00000CAC, 00000B98}
typ {D, W, W, B }
という具合に、組み合わせは変わらずに変更をかけたいのです。
もとは VC++Ver1.5 でコンパイルされたプログラムでその時の処理は
int sym_number ;
/*プロトタイプ*/
static int compare_adr(const struct SYM_INFO *, const struct SYM_INFO *);
int main(int argc, char *argv[])
{
<中略>
qsort(sym_tbl, sym_number, sizeof(struct SYM_INFO), compare_mdf);
<中略>
}
static int compare_mdf(const struct SYM_INFO *k, const struct SYM_INFO *y)
{
return(strcmp(k -> name, y -> name));
}
となっています。
現開発環境は VC++.NET であり、この環境では qsort の第四引数に関して
コンパイルエラーが発生してしまいます。関数 compare_mdf の引数の型の
問題なのは分かっているのですが、どうもうまくいきません。できれば構造体
や配列の型をかえずに処理をしたいのですが、どなたかご教授願えませんで
しょうか。よろしくお願い致します。
>static int compare_mdf(const struct SYM_INFO *k, const struct SYM_INFO *y)
static int compare_mdf(const void *k, const void *y)
とすればよいと思います。
isshiさん。早速の御回答ありがとうございます。
ただこの変更だと関数 compare_mdf 内で構造体 SYM_INFO の要素
name にアクセスできないのですが。この関数内の return 文には
どのような値を返せばよいのでしょうか?
> 関数 compare_mdf 内で構造体 SYM_INFO の要素
> name にアクセスできないのですが
キャストしませう。
シャノンさん。御回答ありがとうございます。
ただ、SYM_INFO型へのキャスト処理がどうしてもうまくいかないのですが、
どんな方法を使うのでしょうか。よろしければ教えていただきたいのですが。
( const struct SYM_INFO* )k
とかでは?
# C++だと
# reinterpret_cast< struct SYM_INFO* >( k )
# かな。。。(constはどうなるんだっけ?)
> ただ、SYM_INFO型へのキャスト処理がどうしてもうまくいかないのですが、
どんなことやっているのかわからないのでソースを提示してもらえませんか?
Blueさん。御回答ありがとうございます。
static int compare_mdf(const struct SYM_INFO *k, const struct SYM_INFO *y)
{
return(strcmp(k -> name, y -> name));
}
を
static int compare_mdf(const void *k, const void *y)
とし、内部の return文の k を
( struct SYM_INFO* )k や
static_cast< struct_SYM_INFO* >( K )
など色々試しておりました。
そしてBlueさんの御回答
reinterpret_cast< struct SYM_INFO* >( k )
で解決致しました。本当にありがとうございます。
isshiさん、シャノンさんも本当にありがとうございます。
void * から T *(T は任意の型)へのキャストは static_cast でよかったハズ。
> reinterpret_cast< struct SYM_INFO* >( k )
あと、C++ では struct キーワードは要らねぇです。
ついでに、比較関数ではメンバの値を書き換えませんから、const にします。
static_cast< const SYM_INFO * >( k )
> (constはどうなるんだっけ?)
const void * から const T * への変換は static_cast で。
const void * から const でない void * へは const_cast で。
const void * から const でない T * への変換は reinterpret_cast しかありませんが、上の2つの方法を組み合わせたほうがいいかも。
reinterpret_cast は T * と DWORD_PTR の相互変換くらいにしか使わないほうがいいです。
reinterpret_castの使い方を誤認識していました。
ポインタ→ポインタもreinterpret_castだとおもっていました。
constをつけるのもstatic_castでいいのでしょうか?
(いまはconst_castだと思っている。)
ところで、
> ( struct SYM_INFO* )k や
> static_cast< struct_SYM_INFO* >( K )
>
> など色々試しておりました。
でなぜうまくいかななかったのかなぞです。
> constをつけるのもstatic_castでいいのでしょうか?
外すのには const_cast が必要ですが、つけるのはキャスト要らずで巣。
char c = 'A';
char * pc = &c;
const char * cpc = pc;
char * pc2 = const_cast< char * >( cpc );
> constをつけるのもstatic_castでいいのでしょうか?
> (いまはconst_castだと思っている。)
const と volatile の除去と付加はいずれも const_cast ですが、
非 const から const には暗黙で変換できますからあまり明示しない気も。
キャストとは、プログラミングにおいてトップクラスに危険な操作です。
コンパイラが型の不一致エラーを出そうとするのを、強制的に黙らせるわけですから、バグを作りこむ可能性を孕んでいます。
できるならば、使わないに越したことはありません。
const をつけることは常に安全ですが、外すのには危険が伴います(変更不可能とされているものを変更可能にするわけですから)。
だからつけるのにはキャストが要りません。
reinterpret_cast は最も強引なキャストです。つまり、最も危険なキャストです。
void * → T * の変換や、基底クラスのポインタ → 派生クラスのポインタのキャストなどは reinterpret_cast でもできますが、static_cast でもできます。
こういう場合、より適用範囲が狭い static_cast を使うべきでしょう。
基底クラス → 派生クラスには、dynamic_cast を使うとよりよいかも。
ちと長いけどサンプル:
#include <iostream>
#include <string>
#include <exception>
using std::cout;
using std::endl;
using std::string;
using std::bad_cast;
class Base
{
public:
virtual ~Base();
};
class Derived : public Base
{
public:
void Hoge();
};
int main()
{
char c = 'A';
char * pc = &c;
const char * cpc = pc; // 常に安全
// プログラマには安全だとわかっている(元々 const でないものを元に戻しただけ)が、
// コンパイラにはわからないのでキャストが必要
char * pc2 = const_cast< char * >( cpc );
*pc2 = 'B';
// こういうことはコンパイルエラーにはならないが、
// 実行時エラーになる(元々 const)のでやってはいけない。
const char * cstr = "ABC";
char * str = const_cast< char * >( cstr );
*str = 'X';
Base b;
Derived d;
Base * pb = &d; // 常に安全
// プログラマには安全だとわかっている(元々 Derived * なのを元に戻しただけ)が、
// コンパイラにはわからないのでキャストが必要
Derived * pd = static_cast< Derived * >( pb );
pd->Hoge();
// こういうことはコンパイルエラーにはならないが、
// 実行時エラーになる(Base には Hoge がない)のでやってはいけない。
Derived * pd2 = static_cast< Derived * >( &b );
pd2->Hoge();
// プログラマには安全だとわかっている(元々 Derived * なのを元に戻しただけ)が、
// コンパイラにはわからないのでキャストが必要
Derived * pd3 = dynamic_cast< Derived * >( pb );
// dynamic_cast を使うと、より安全
// (元々変換不能なポインタを変換しようとすると、結果は NULL になる)
Derived * pd4 = dynamic_cast< Derived * >( &b );
Base & rb = d; // 常に安全
// プログラマには安全だとわかっている(元々 Derived & なのを元に戻しただけ)が、
// コンパイラにはわからないのでキャストが必要
Derived & rd = static_cast< Derived & >( rb );
rd.Hoge();
// こういうことはコンパイルエラーにはならないが、
// 実行時エラーになる(Base には Hoge がない)のでやってはいけない。
Derived & rd2 = static_cast< Derived & >( b );
rd2.Hoge();
// プログラマには安全だとわかっている(元々 Derived & なのを元に戻しただけ)が、
// コンパイラにはわからないのでキャストが必要
Derived & rd3 = dynamic_cast< Derived & >( rb );
try
{
// dynamic_cast を使うと、より安全
// (元々変換不能な参照を変換しようとすると、例外を投げる)
Derived & rd4 = dynamic_cast< Derived & >( b );
}
catch( const bad_cast & ex )
{
cout << ex.what() << endl;
}
return 0;
}
シャノンさん。多大なるご指摘感謝いたします。
先程は解決マークを付けてしまったので書きませんでしたが、
reinterpret_cast< struct SYM_INFO* >( k )
ではコンパイルが通りませんでした。
reinterpret_cast< const SYM_INFO* >( k )で通っていましたが、
ご指摘頂いた static_cast に変更させて頂きました。
シャノンさん、Blueさん、Banさん本当にありがとうございました。
> reinterpret_cast< struct SYM_INFO* >( k )
> ではコンパイルが通りませんでした。
const void * から SYM_INFO * への変換では、const を外さなければなりませんが、reinterpret_cast ではこれができないのでエラーになります。
const void * から const SYM_INFO * への変換であれば、const を外す必要は無いので、static_cast で十分です。
reinterpret_cast でもできますが、これは極力使わないほうが良いです。
ちょっと横から。
シャノンさんわかりやすい解説ご苦労様です。
アップキャスト&ダウンキャストのわかりやすい例だと思います。
const_castについても勉強になります。
> アップキャスト&ダウンキャストのわかりやすい例だと思います。
ありがとうございます。
実は自分でも良くわかってなくて、こうして書いてみることですっきりしました(笑
明示的に const_cast で const をつける例を考えると、
例えば const 版と非 const 版がオーバーロードされた関数で、
const 版を明示的に呼びたい場合などでしょうか。
一般的にはかなり限られた状況だと思いますが、
上記のようなオーバーロードは主に効率化のためにされるものですから、
時には効率面で有益なのかも...。
# 誤操作したらしく、解決チェックが付いてました.....orz
ZUKI-MU さん、申し訳ありません。m(_ _)m
Banさん、シャノン様、
どうも解説ありがとうございました。(*- -)(*_ _)ペコッ
C++のキャストはあんまり慣れていないので勉強になりました。
# 仕事では全部Cタイプのキャスト
# 特に規約もなく、周りの人に合わせる感じになっています。
# 定数も#defineも多様してますし。。。
一ヶ所嘘つきました@17:56
> const void * から const でない T * への変換は reinterpret_cast しかありませんが、上の2つの方法を組み合わせたほうがいいかも。
reinterpret_cast じゃできません。
まず const_cast で non-const void * にしてから、static_cast を使うしかないです。
解決とあるものの,誰も言わなかったので一応。
qsortではなくstd::sortを使えばキャストの問題は全て解決します。
個人的には,この方法を推奨。
ref) Effective STL 第46項
#include <functional> // 追加
#include <algorithm> // 追加
struct compare_mdf : std::binary_function<SYM_INFO, SYM_INFO, bool)
{
bool operator() (const SYM_INFO & lhs, const SYM_INFO & rhs) const
{
return strcmp(lhs.name, rhs.name) < 0;
}
};
// main内
std::sort(sym_tbl, sym_tbl + sym_number, compare_mdf());
YuOさん。御回答ありがとうございます。
以前このサイトでYuOさんが std::sort を使用した例があり
それも参考にしてやっていたのですがうまくいかなかったので、
これを見てすっきり致しました。
ツイート | ![]() |