char*型変数のexternについて


パタコ  2011-12-15 15:32:42  No: 73041  IP: 192.*.*.*

http://madia.world.coocan.jp/cgi-bin/Vcbbs/wwwlng.cgi

char*型変数のexternについて

最近勉強しているプログラムで頓挫してしまったのでご教授いただきたく存じます。

現在、VisualStudio2008のc++、win32コンソールアプリケーションでDLLを作成
しています。
DLLの構成は、デフォルトで構成されるファイルとは別に2つのクラスA、Bを追加
しています。
例)①main.cppとmain.h、②a.cppとa.h、③b.cppとb.h

a.cppには、「構造体の変数に値を入れる関数X」があり、a.cppで定義する構造
体の変数に値を格納します。
a.cppでは、「構造体BOXのポインタ」を定義しており、構造体にはint型の変数
idやchar*型の変数nameがあります。
ここで、main.cppやb.cppでも値を変更する必要があるため、main.cppの頭に
---
extern struct BOX{
       int id;
       char* name;
};
extern struct BOX *g_box;
---
しかし、出力結果を確認したところ、
a.cpp内での出力(関数X内で値を格納した後)では、
int型:fprintf( file, "%d\n", g_box.id);⇒正解
char*型:fprintf( file, "%s\n", g_box.name); ⇒正解
main.cpp内での出力(関数Xを呼び出した後)では、
int型:fprintf( file, "%d\n", g_box.id);⇒正解
char*型:fprintf( file, "%s\n", g_box.name); ⇒不正解
となりました。

何が原因なのかよくわからなかったので、試しにint型とchar*型の変数を別に
作って同様に確認したところ、
("extern int id"や"extern char* name"を追加しました)
結果も同様になり、int型の変数は"extern"できていて、char*型の変数はできて
いませんでした。
ただ、char*の変数には何か値が入っているよう(NULLではない)です。
最終的にやり方が悪いのか、出力の仕方が悪いのかがわからなくなってしまいました。

どなたかご教授願えませんでしょうか?

編集 削除
tetrapod  2011-12-15 16:34:47  No: 73042  IP: 192.*.*.*

具体的コードが無いのでなんともいえない。まあ予想するに、
・ポインタに対して実体を確保していないのでは?
・自動変数へのポインタを有効寿命外で使っているのでは?

編集 削除
パタコ  2011-12-15 17:32:52  No: 73043  IP: 192.*.*.*

お返事有難うございます。
すみません。ワタシ、よくわかっておりません。汗
ソースは、
-----
□CBoxクラスのb.cpp
(#include後の箇所)
//値格納用データ
struct BOX{
       int id;
       char* name;
};
struct BOX *g_box;  //定義
//読み込み用データ
struct TBox {
       _bstr_t id;
       _bstr_t name;
};
TBox box;   //定義

(構造体BOXの各変数にファイルから読み込んだ値を入れる関数X内)
//メモリ確保
g_box = new BOX[1];
//
//bstr_t型にファイルから読み込んだ値を格納する処理
//出力確認
正解⇒fprintf( file, "%s\n",  (LPCSTR)box.id);
正解⇒fprintf( file, "%s\n",  (LPCSTR)box.name);
//
//_bstr_tをchar*に変換して格納
//id
char nstring[100];
strcpy_s(nstring, (char *)box.id);
box[0].id = atoi(nstring);
//name
char nstring2[100];
strcpy_s(nstring2, (char *)box.name);
box[0].name = nstring2
//出力確認
正解⇒fprintf( file, "%d\n", box[0].id ;
正解⇒fprintf( file, "%s\n", box[0].name );

□a.cpp
(#include後の箇所)
//値格納用データ
extern struct BOX{
       int id;
       char* name;
};
extern struct BOX *g_box;  //定義
(関数内)
CBox* box = new CBox;
box->関数X();
//出力確認
正解⇒fprintf( file, "%d\n", box[0].id ;
不正解⇒fprintf( file, "%s\n", box[0].name );
-----
もしおかしい箇所があればご教授下さい。
よくわからないので引き続き勉強します。。汗

編集 削除
仲澤@失業者  2011-12-15 17:48:03  No: 73044  IP: 192.*.*.*

1.まず、C言語か、C++言語かをはっきりしましょう(質問)。
2.次に中途半端なstructの定義はコードがとっちらかるだけです。
  typedef を使って整理しましょう。
  またそれを「main.exe」「a.dll」「b.dll」で共通に使用するなら
  独立したヘッダーにし、必要なコードで#includeましょう。
  <BOX.h>---
  typedef struct BOX
  {
    int     id;
    char *  name;
  }BOX;// 以降 BOX型として使える
  例) BOX   box;
      box.id = 5;
      box.name = malloc( 35);  // (1)確保
      strcpy( box.name, "リュシータ・トエル・ウル・ラピュタ");
3.externの意味
  externな変数xxの宣言とは、この翻訳単位(ソース)にはその実体は
  存在しないが、他のソースに実体があるので、とりあえず
  あるものとしてコンパイルしてください。
  リンク時に他の*.objに見つかったらそれを使ってね。
  という意味です。その意味で使ってますでしょうか。

tetrapodさんの最初の指摘は(1)「等」のことですね。

編集 削除
仲澤@失業者  2011-12-15 17:52:15  No: 73045  IP: 192.*.*.*

追加。orz.
DLL内の変数はexternでは参照できません。この場合
それにアクセスするための__declspec(dllexport)された関数を
使うのが普通です。
変数をエクスポートするのは初心者には無理(きっぱり)なので、
説明を省略します。

編集 削除
tetrapod  2011-12-15 22:41:57  No: 73046  IP: 192.*.*.*

予想したとおりポインタが [寿命の尽きた自動変数] を指しているようだ。

void foofunc() {
  char nstring2[100];
  box[0].name = nstring2
}
のようになっているとき nstring2 は } までしか存在しないという仕様だ。
foofunc() の外では nstring2 はもはや存在しない。
box[0].name は死んだ変数を指しているので、そこから値を拾うことはできない。

どう直すかは、どうしたいのか次第。
まあ多分 struct BOX の name を char* でなく std::string にするのが正しいのだろう。
でも _bstr_t から変換するのなら wchar_t なり std::wstring なり使うほうが自然だと思うぞ。

編集 削除