質問があります。
voidポインタが指しているメモリエリアのサイズを取得する
関数なんてあるのでしょうか?
(API関数とかで)
UNIX上で動作しているCUIプログラム(C言語で作成)をWindowsXP上で
動作させる必要があり、ソースファイルをVC++でビルドして実行しています。
ところが、ある関数(以下参照)でメモリアクセスエラーが発生してしまいます。
(UNIX上では正常に動作している。)
FuncA(void *pIn, union DATA *pOut)
{
memcpy(pOut, pIn, sizeof(union DATA));
}
※pInは、様々なサイズのテーブルを指す。
ただし、それらのテーブルサイズは union DATAより小さい。
case文で分岐させ、memcpyすれば、できないことはないのですが、
pInの指すテーブルの種類が多く、修正&テストが大変です。
pInの指すテーブルサイズが動的に取得できれば、
すぐに修正できそうなのですが...
>voidポインタが指しているメモリエリアのサイズを取得する
>関数なんてあるのでしょうか?
ポインタはアドレスを指してるだけなのにそんな関数があるわけない。
void型に限らないぞ。
たとえばint型へのポインタが指しているメモリはsizeof (int)分の
領域はあるだろうがint型の配列へのポインタだったらどうだ?
Cでは配列の要素数はプログラマが自分で管理しなきゃならないだろ。
追加
> ※pInは、様々なサイズのテーブルを指す。
> ただし、それらのテーブルサイズは union DATAより小さい。
これはWindows環境で確認したのか?
_msize() とか?
ただ,malloc は,指定されたサイズ以上を確保することもあるので、
_msizeで得たサイズを利用してあれこれするのはやめたほうがよいとは思います。
_msize() は malloc 等でヒープに確保したメモリにしか使えません。
自動変数等へのポインタに対しては無意味です。
次のような使い方をされても無意味です。
foo_t* p=malloc(sizeof(foo_t)*100);
funcA(p+1, ...);
C の文法上、ポインタになってしまった後から元メモリサイズを
調べることは絶対に不可能です。
kajiki さんのご意見に1票。
>FuncA(void *pIn, union DATA *pOut)
>{
> memcpy(pOut, pIn, sizeof(union DATA));
>}
この FuncA を呼び出す側はサイズを知っているでしょうから FuncA にサイズを渡すようにす
るとか、あるいは pIn の先頭には必ずデータサイズが入っているようにするとかするのがよい
のではないでしょうか。
構造体がこのような定義になっているのを見かけたことはありませんか?これはそのためなんで
すよ。
struct INPUTDATAHEADER {
DWORD dwSize;
...
};
FuncA( size_t cbIn, void *pIn, union DATA *pOut)
{
memcpy(pOut, pIn, cbIn );
}
FuncA( INPUTDATAHEADER* pIn, union DATA *pOut)
{
memcpy(pOut, pIn, pIn->dwSize );
}
# タメ口は見苦しいからやめてほしいなあ。。。
みなさん、レスありがとうございます。
質問した経緯について、もう少し詳しく説明します。
UNIXで動作しているプログラムのソースファイルを、
出来る限り修正せず、VisualStudioでビルドし、
Windows上で動作させようとしています。
本来だったら、引数にvoidポインタなど使用したくないのですが、
元々は他人の作ったプログラムで、UNIX上での動作実績がある
というのと、結構規模が大きく、
関数のコール先や、pInの指し示す構造体種類も多いため
できるだけ修正箇所を少なくし、関数内で閉じた修正が
出来ないかと思い質問してみました。
この関数は、様々な型の情報を一元管理する、union DATA型の配列
(キューとして使用)に書き込む処理の一部として動作しています。
pIn の指すテーブルの作成元と、pOutを参照するところでは、
もちろんテーブルサイズは認識できるようになっています。
質問したあと、自分でも色々調査したところ、
API関数で、ReadProcessMemory()というのを見つけました。
これは使えば、何とかなりそうです。
後ほど結果を書き込みます。
それと、team3 さんに教えていただいた _msize() ですが、
malloc()で確保したものに対しては使えそうですが、
今回の場合、pInが指しているのは、スタックエリアなので
うまくいきませんでした。
(でも、勉強になりました。)
以下のAPI関数を使用して、問題を解決することができました。
BOOL ReadProcessMemory(
HANDLE hProcess, // プロセスのハンドル
LPCVOID lpBaseAddress, // 読み取り開始アドレス
LPVOID lpBuffer, // データを格納するバッファ
DWORD nSize, // 読み取りたいバイト数
LPDWORD lpNumberOfBytesRead // 読み取ったバイト数
);
以下が修正後の処理です。
FuncA(void *pIn, union DATA *pOut)
{
HANDLE hProcess = GetCurrentProcess();
ReadProcessMemory(hProcess, pIn, pOut, sizeof(*pOut), NULL);
}
メモリアクセスエラーとならないように
コピーするという当初の目的を果たすことができました。