none
変数”名”の参照 RRS feed

  • 質問

  • 変数”名”の参照は可能でしょうか?

    ちょっと問題が曖昧なのでもうしわけありません。具体的には下のソースのような状況にあります。

    ref.txtに書かれている変数にプログラム内で参照したいのです。下の例ではref.txtに"valx"と書かれているとして、その変数valxに参照したいと考えています。

     CString valx = (LPCTSTR)"aaA";
     CString valy = (LPCTSTR)"bbB";
     CString valz = (LPCTSTR)"ccC";
    ・・・

     CString refstr;
     FILE *fp;
     char line[100];
      fopen_s(&fp,"ref.txt", "r");
     fgets(line,100,fp);
     refstr = (LPCTSTR)line; // refstr = (LPCTSTR)"valx";と同じ状況になった
     printf("refstr = %s\n",refstr);
     while(1){
      UpdateAllValues()//update value
      printf("%s = %s\n",refstr,???);//???がvalxとすることと同じ効果を得るのが目標、この場合、出力は valx = aaA としたい
      Sleep(1000);
     }
    もちろん以下のようにすれば問題ないのですが、ソースの中の変数であるvalx, valy, valzがそれだけでは済まなくてvalaa, valab, valac・・・とずっとに続くことをを想定すれば、いちいちソースの書き換え→コンパイルはやりたくないところなのです。

     while(1){
      UpdateAllValues()//update value
      if(refstr = "valx")
       printf("%s = %s\n",refstr,valx);
      if(refstr = "valy")
       printf("%s = %s\n",refstr,valy);
      if(refstr = "valz")
       printf("%s = %s\n",refstr,valz);
      //...永遠に続く
      Sleep(1000);
     }

    開発環境はVC++2008なのですが、何らかのスクリプト言語(DOSやperl)の併用も覚悟しています。

    • 編集済み VamcAlerts 2010年7月23日 14:39 FixContent
    2010年7月4日 7:44

回答

  • C++言語では、変数名は、コンパイルされた時点でなくなります(正確には消滅するわけではありませんが、原則残っていません)。

    ですので、何らかの名称と値の二種類を保持する場合は、std::map や、CMap のようなコレクションクラスを利用するのが一般的です。

    あと。。。こちらは、どうでもいいとも言えますが、MFCを使ってるのであれば、FILE* を使うのではなく、CStdioFile などのMFCのファイルオブジェクトを利用することをお勧めします。

     


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    • 回答の候補に設定 山本春海 2010年7月29日 1:27
    • 回答としてマーク 山本春海 2010年7月30日 6:25
    2010年7月4日 8:30

すべての返信

  • C++言語では、変数名は、コンパイルされた時点でなくなります(正確には消滅するわけではありませんが、原則残っていません)。

    ですので、何らかの名称と値の二種類を保持する場合は、std::map や、CMap のようなコレクションクラスを利用するのが一般的です。

    あと。。。こちらは、どうでもいいとも言えますが、MFCを使ってるのであれば、FILE* を使うのではなく、CStdioFile などのMFCのファイルオブジェクトを利用することをお勧めします。

     


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    • 回答の候補に設定 山本春海 2010年7月29日 1:27
    • 回答としてマーク 山本春海 2010年7月30日 6:25
    2010年7月4日 8:30
  • あと。。。こちらは、どうでもいいとも言えますが、MFCを使ってるのであれば、FILE* を使うのではなく、CStdioFile などのMFCのファイルオブジェクトを利用することをお勧めします。

    型キャストとかむちゃくちゃですし。変換したいからそう書いているのではなく、エラー・警告が出てるから黙らせるためにねじ伏せてる感じ。
    単に動けばいいというところでしょうか。

    if()の中が比較でなく代入なのは写し間違いなのでしょうか?

    本題については、同じことの繰り返しならCPPでコンパイル前に展開する手もありますが、なんらかコレクションを使った方がいいでしょうね。

    2010年7月4日 9:15
  • すでに本筋はとっちゃんさんが述べているので、指摘だけ。 CString valx = (LPCTSTR)"aaA"; CString valy = (LPCTSTR)"bbB"; CString valz = (LPCTSTR)"ccC"; こんなキャストはしないでください。 LPCTSTR は文字セットによって、LPCSTR や LPCWSTR に変わります。 キャストの右にある文字列は、char* ですので、もしも、このソースコードを Unicode 文字セットでビルドしたら、正しい動作になりません。 あるべき姿としては、以下のような形でしょうか。 CString valx = _T("aaA"); // これ自体は良くないので、後の指摘して頂いている投稿をお読みください。 _T は文字セットに応じて適切に置換してくれます。("aaA" or "aaA"L) 被り気味なのでもう 1 点。 char と wchar_t の違い、TCHAR の位置づけあたりを勉強してください。 そうすれば、何が間違っているかが見えてくると思います。 キーワードを羅列するだけでもいくつか見えてくるかも。 http://www.google.com/search?hl=ja&lr=lang_ja&ie=UTF-8&oe=UTF-8&num=50&q=tchar+wchar+lpctstr -------------------------------------------------------------------------------- 質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年7月4日 9:15
    モデレータ
  • とっちゃん様

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

    本題の方ですが、なるほど、そのようにstd::mapを使用すれば解けるのはおっしゃる通りですね。しかし1つ問題がありまして。

    今回作っているものですが、メインの(CString valx, valy, valz, ...がでてくる)プログラムのユティリティ的存在のもので、

    つまり、CString valx, valy, valz, ... が出てくるプログラムAと、CString hellox, helloy, helloz, ... が出てくるプログラムBと、CString aaax, bbby, cccz, ... が出てくるプログラムCと、CString vx, vy, vz, ... が出てくるプログラムDと、という感じで、たくさんのプログラムがあり、毎回各プログラムでプログラマ側(結局私なのですが)がおっしゃるようなコレクションで

    mymap map<CString, CString>;

    name.insert(map<CString, CString>::value_type(...));

    ...

    とプログラム側で手打ちをするより、必要になったときにファイルで(私の初めの拙例ではref.txt)に書き込んでおけば読みに行ける、という形にしたかったのです。A,B,C,D,。。。と結構プログラムの量だけは多いので、各プログラムで共通的な関数(拙例のような)を読んでおき解決できる方法があればいいなあ、何かしら手を抜ける方法はないのかな、と思って質問している次第です。

    当方の説明が悪くなり申し訳ありませんが、もし対処のやりようがあれば、ご教授いただければと思います。

     

    >あと。。。こちらは、どうでもいいとも言えますが、MFCを使ってるのであれば、FILE* を使うのではなく、CStdioFile などのMFCのファイルオブジェクトを利用することをお勧めします。

    ありがとうございます。余りにも基本が出来ていないのは認めます。。 注意してくれる方は私の宝です。

     

    2010年7月4日 10:59
  •  

    佐祐理様

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

    >型キャストとかむちゃくちゃですし。変換したいからそう書いているのではなく、エラー・警告が出てるから黙らせるためにねじ伏せてる感じ。
    まさにおっしゃる通りで、私の力不足の致すところです。コメントありがとうございます。

    >本題については、同じことの繰り返しならCPPでコンパイル前に展開する手もありますが、なんらかコレクションを使った方がいいでしょうね。

    はい、CPPでコンパイル前に展開するより、後付けで対処中です。

    コレクションについては上記とっちゃん様に回答させていただいた通りです。お知恵を頂けるとありがたいです。

    ではありがとうございます。

    2010年7月4日 11:10
  • あるべき姿としては、以下のような形でしょうか。

    CString valx = _T("aaA");

    どうせなら

    CString valx( _T("aaA") );

    と呼んだ方がいいかと。ついでにprintf()も_tprintf()ですし、言い出したらきりがないのであえて具体例は書きませんでした。

    2010年7月4日 11:11
  • Azulean様

    基本中の基本、ですよね。ご指摘ありがとうございます。勉強になりました。

    本題の対処方法については上記とっちゃん様への返答したとおり、まだコレクションが使えるかが疑問ですので、お知恵を貸して頂ければ幸いです。

    それではよろしくお願いします。

    2010年7月4日 11:16
  • 例えばですが、

    vals.hに

    VAL(valx, "aaA")
    VAL(valy, "aaB")
    VAL(valz, "aaC")

    と書いておくと

    #define VAL(V, S) CString V( _T(S) );
    #include "vals.h"
    #undef VAL

    とすれば

    CString valx( _("aaA") );
    CString valy( _("aaB") );
    CString valz( _("aaC") );

    に展開できます。また

    #define VAL(V, S) if(refstr = S) printf("%s = %s\n",refstr,V);
    #include "vals.h"
    #undef VAL

    とすればif文も展開できます。

    CPPにはこういう使い方もある、ということで。

    2010年7月4日 11:21
  • とっちゃん様

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

    本題の方ですが、なるほど、そのようにstd::mapを使用すれば解けるのはおっしゃる通りですね。しかし1つ問題がありまして。

    今回作っているものですが、メインの(CString valx, valy, valz, ...がでてくる)プログラムのユティリティ的存在のもので、

    つまり、CString valx, valy, valz, ... が出てくるプログラムAと、CString hellox, helloy, helloz, ... が出てくるプログラムBと、CString aaax, bbby, cccz, ... が出てくるプログラムCと、CString vx, vy, vz, ... が出てくるプログラムDと、という感じで、たくさんのプログラムがあり、毎回各プログラムでプログラマ側(結局私なのですが)がおっしゃるようなコレクションで

    mymap map<CString, CString>;

    name.insert(map<CString, CString>::value_type(...));

    ...

    とプログラム側で手打ちをするより、必要になったときにファイルで(私の初めの拙例ではref.txt)に書き込んでおけば読みに行ける、という形にしたかったのです。A,B,C,D,。。。と結構プログラムの量だけは多いので、各プログラムで共通的な関数(拙例のような)を読んでおき解決できる方法があればいいなあ、何かしら手を抜ける方法はないのかな、と思って質問している次第です。

    当方の説明が悪くなり申し訳ありませんが、もし対処のやりようがあれば、ご教授いただければと思います。

    コメントの最初にも書いていますが、コンパイル時点で変数の名前は消失します。C++では、変数はどこにあるか?がわかればその名前は特に必要とされません。

    ですので、コンパイル&リンクが完了した時点で、変数の名前はなくなり、どこにあるものかという情報だけが残ります(クラスオブジェクトの先頭から何バイト目とか...)。

    ですので、ソース上の変数名をもとに実行時に何かをするためには、ビルド後でも参照可能な情報として名前と実際の変数エリアとのマッピングを行う仕組みを用意する必要があります。

    どういう形で用意すれば既存のものへの変更が少ないのかについては、ソースを見てないので何とも言えません。ソース見ればどうにかなるというものでもありませんが。。。

     


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    2010年7月4日 11:26
  • 佐祐理様

    ご回答ありがとうございます。完全に当方の説明不足ですので、もう少し補足させてください。。

    まず当方のやりたいことですが、ProgXというプログラムがあり、プログラムA,B,C,D,。。。Z内の変数に自由にアクセスしたいのです。プログラム間の共有メモリはCreateFileMappingを使用することを想定しています。

    例えばProgXからAのvalXにアクセスしたければ、OpenFileMappingからMapViewOfFileをAから呼ぶ必要があり、その際にAからvalXを参照する必要があります。もちろん、プログラムA,B,C,と順に開いていき、その部分の関数を足していってハードコーディングでコンパイルするのは不可能ではないのですが、実はそのそれぞれのプログラム内の変数の数が多く、後付け的なやり方を考えている次第です。

    結局ProgXを開発することに集中したいのです。例えばプログラムAのヘッダーを開いて「ああ、この変数valxが必要だ」と言って足す時に、いちいちAを改修して変数を加えコンパイルするよりも、テキストファイル+共通の新しいコードで対処できないかな、ということです。

    #define文を使用しても、結局いちいちAを改修して変数を加えコンパイルする状況になるのが、困っています。

    最初私がやりたいことを要約しすぎて投稿して、多大な混乱を招いたようです。申し訳ありませんでした。もし、まだご協力頂けるようであれば、幸いです。どうぞよろしくお願いします。

    2010年7月4日 12:03
  • とっちゃん様

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

    >ですので、ソース上の変数名をもとに実行時に何かをするためには、ビルド後でも参照可能な情報として名前と実際の変数エリアとのマッピングを行う仕組みを用意する必要があります。

    なるほど、私がまさに必要なのはこの仕掛けのような気がします。

    先程佐祐理様への回答内で触れましたが、結局私のやりたいことは共有メモリからのアクセスの時にプログラムAのvalx他多数、プログラムBのhellox他多数、・・・他多数をProgXという新しく開発プログラムから参照したいことです。

    先程佐祐理様への回答内でプログラムA、B,C,・・・に出したい変数をハードコーディングするのは手間がかかるので避けたい、と言ったのですが、それをするには

    Step1.プログラムA、B,C・・・内の全ての変数を出す(変数タグ~そのメモリ領域)ペアのstd::map準備をして(そういうソースを今から私が書く)

    Step2.プログラムProgXでファイルref.txtを読む

    Step3. プログラムA、B,C,内で合致した変数タグのメモリ領域を参照して使用してメモリ領域を参照し、MapViewOfFileを呼ぶ

    Step4.プログラムProgX側でそのデータを入手する

    ことを出来るコードが作成できればよいということのような気がします。

    それで、核心なのですが、

    >ですので、ソース上の変数名をもとに実行時に何かをするためには、ビルド後でも参照可能な情報として名前と実際の変数エリアとのマッピングを行う仕組みを用意する必要があります。

    これはそんな方法があるのでしょうか?私は聞いたことがないのですが・・・要はポインタに参照可能なタグが付いていればいいのでしょうが・・・

    大変お世話になっておりあますが、またどうぞよろしくお願いします。

     

    2010年7月4日 12:29
  • 要約ではなく、当初の質問と方向性が全然違いますよね?

    「コンパイル前に展開する手」と表現しました、それが当初の質問内容ですよね。それとは別に実行時にファイルから読み込む方法があります。
    実行時に読み込む方法の場合、質問のタイトル「変数"名"の参照」とは全く異なる方法になります。

    私としてはどちらで実現しても構いませんが、後日タイトルを見て訪れた人の参考になればと思い、CPPによる展開方法を提示しました。
    ちなみにコンパイルオプションで#includeするファイル名を変更することも可能です。ファイルをそれぞれ切り替えながらコンパイルしていきProgA、ProgB、ProgC…が作れます。

    実行時にファイルから読み込む方法については、質問の前提が崩れすぎていてアドバイスのしようがありません。(何の足がかりもありませんから)
    最初にとっちゃんさんが書かれているように、使用可能なクラスを提示することが限界です。

    2010年7月4日 12:34
  • 情報が錯そうしてるというか。。。やりたいことをきちんと表現できていないというか。。。

    まず、本当にやりたいことがなんなのかを簡潔に表現する必要があるようです。後付けでいろいろやりたいらしいのはわかりますが、何がやりたいのか?そのためにどうしようとしているのか?という肝心な部分が表現できていないため、得られる回答も自分が望むものに近いものとなっていないのではないか?と思います。

    ただ、私がここまでの流れで読み取ったことをまとめると。。。

    既存のツールの変数の内容を外部から動的に変える、デバッガのようなツールを作りたい。。。

    と読めました。

    実際

    >ビルド後でも参照可能な情報として名前と実際の変数エリアとのマッピングを行う仕組みを用意する必要があります。

    は、PDBというファイルがこれにほぼ等しい情報を持っています。たしかフォーマットは公開されているので(英語の情報ですけどw)MSDNあたりに載っていたと思います。

    自分ではデバッガを作ったことはありませんが、VisualStudioでも上記のことはできますし、デバッガ用のAPIとかを見てる限りでは実現は可能だと思います。後は根性と時間があれば何とかなるんじゃないでしょうか。とはいえ、情報は英語「しか」ありませんけどw

    まずは、自分が実現したいことがなんなのか。そのためにどこで困っているのか?をまとめてみてはどうでしょう?


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    2010年7月4日 13:11
  • 佐祐理様 とっちゃん様
    情報が断片的になっていて混乱をさせて大変申し訳なかったです。
    数回コンピューターがクラッシュして返答も遅れてすみませんでした。
    >まずは、自分が実現したいことがなんなのか。そのためにどこで困っているのか?をまとめてみてはどうでしょう?
    ごもっともです。長文になりますが、ご容赦ください。

    実現したいのは、以下のようなシステムです。
    1-1.LAN上にコンピューターが5台程度(便宜的にA,B,C,D,E)
    1-2.それぞれのマシンに別途のプログラムが7つ程度走っている(便宜的にA1-A7,B1-B7,...,E1-E7、現状、個別に製作中、完成のものもあってインテグレーション待ち)
    1-3.全てのプログラムが同時に走り、リアルタイム(1秒に5回程度)でプログラム間データのやり取りをしたい、それぞれのマシン内のデータとりまとめと分配、通信を行うプログラムをそれぞれのマシンに1つずつ走らせる(便宜的にAX,BX,CX,DX,EX)、これらを現在設計・製作中
    →これらをやることによって、それぞれがモジュラーにプログラムを開発できるメリットがあると考えています

    そこで私が取っているアプローチは:
    2-1.まずA1-A7, AXを試験する
    2-2.共有メモリでプログラム間のデータのやり取りを行うCreateFileMapping->OpenFileMapping
    2-3.それぞれのプログラムで必要なデータの指定はそれぞれのプログラム内に附属したテキストファイルで実施(A1.txt, ..., E7.txt)モジュール名、変数のセットで指定
    例えばA1.txtには
    A2 valA2x
    A2 valA2z
    A3 valA3y
    D5 valD5x
    E2 valE2x
    E2 valE2z
    2-4.ヘッダーを入れた共用ディレクトリがあり、A1からはそれをincludeしてプログラムA1内でコンパイルする

    私がやりたいことは共有メモリのラッパーを実装することです。
    今回の具体的な質問は、例示すると、
    例えばプログラムA1でA2内のvalA2xが必要とする
    ・A1.cppでinclude "A2.h"とし、valA2xは参照できる
    ・実際に共有するときに、A1.txtで
    A2 valA2x
    と指定し、すぐに使えるようにしたい。CreateFileMapping(...)で共有メモリのタグとしてvalA2xを指定、読み込み側は問題ない
    ・書きこみ側のA2でも同じくCreateFileMappingで実際にタグをvalA2xとして指定、値もvalA2xを入れるのが正道だが、A2がA1より先に開発されていた場合に、コンパイル済みのA2.cpp内でvalA2xがA1に必要とされていることが分からない
    (はい、このような大きいプログラムを開発するときにはきちんと計画すべきなのは分かっていてそこはつっこみどころ満載ですが、プロトタイプを作っている段階で試行錯誤が繰り返されているところなので、そうもいかないところがミソで・・・)

    そこでA2(書き込み)側でvalA2xに対しCreateFileMappingを呼んでいない状況が問題、これがなんとかならないかなあと思っている点です。もし、A2のプログラムがA1.txt(プラス他全てのテキストファイル)を読んで、そこに指定されているA2向けの変数名を洗い出し、変数名からプログラム内の変数を参照し、随時書き込み用CreateFileMappingをおこなえればいいなあと。そういう趣旨です。

    いかがでしょうか?やはりA2側でハードコーディングでCreateFileMappingを呼んでコンパイルするほか手はないでしょうか?

    長くなってしまいました。また、もともと言っていたことが霞んでしまったことは否めなく、大変申し訳ない思っています。
    何かしら手がかりがあれば、度々申し訳ないのですが手を差し伸べて頂ければ幸甚と思います。

    2010年7月4日 16:20
  • 要約すると、
    「別のPC上で稼働中のEXE内の任意の変数の値を取得したい」
    「ただし、その稼働中のEXEの変更を伴わない方法とする」

    ということでしょうか。アイデアとしては面白いのですが、
    デバッガの作成が目的でないかぎりにおいては、
    その仕様は大変困難であると言っておきます。

    さて、参考になるかどうかわかりませんが、
    LAN上の複数のPCを協調させて演算を行わせる手法については
    何十年も前から研究されて論文も出ているようです。
    20数年ほど前に、自分の後輩もやってました。
    これらの研究に共通するアイデアは各PC間で統一された

    1.「仮想CPU」を定義している
    2.または「仮想言語」を定義している

    など、仮想的で共通の仕様を基にしている点です。当たり前ですよね。また、当然ですが

    3.各PC間での、通信インターフェースの統一した仕様を定義している

    のですが、まぁ普通にTCP/IP(バークレーソケット)でやってました。
    1.の前提では、「PC_A」の「Exe_A」が「PC_B」の「Exe_B」上の
    仮想レジスタReg_Nの値が欲しければ、「Exe_A」が「Exe_B」に対して
    3.の手段を使用して、そのように要求し、要求された「Exe_B」はそれを
    戻せるようにしてあれば良いだけです。

    2.の前提では「仮想言語」上の任意の変数を取得する方法の定義がされていなければ
    ならないのは自明です。

    いずれにしても、平凡で極普通の設計方針で実現してました。

    2010年7月5日 2:07
  • まず、プロトタイピング的な手法でやろうとしていて製造段階で全てを想定しきれないのであれば、
    その都度、各モジュールに改変が入るのは仕方がない事なのであきらめると言うのが普通かと思います。

    そうでなければ、各モジュールの全変数を共有メモリ上に載せるようにしておくくらいだと思います。
    むしろプロトタイピングの段階ならそっちの方が手っ取り早いのではないかと思います。
    つまり最初からそのつもりで作るという話。

    後付でなんとか辻褄を合わせようとしても自ずと限界があります。
    最初から各モジュール内で使用する変数を全てマッピングで管理するようにして
    特定のキーワードで操作可能な状態を作成しておき、何らかの方法で外部から指定された変数を
    共有メモリ上に置くような仕組み立てを作成するならわからなくもないですが、
    仕組み立てを作るだけで工数がかかりすぎると思います。
    書かれている内容からするとかなり汎用的な作りにしないと実現出来そうに有りません。
    プロトタイプで試す為だけに作成するにしては規模が大きくなりすぎな気がします。
    あと、仕組み立てが大掛かりになりすぎてパフォーマンスも悪そうです。

    他の人も書かれていますが、
    アプローチ方法の設定をいう時点ですでに拙い状態になっていると思うので
    それを方法論だけで何とかしようとするには無理があると思いますよ。


    解決した時は、参考になったレスポンスの所にある[回答としてマーク]ボタンをクリックしてスレッドを締めましょう。
    2010年7月5日 6:23
  • こんにちは、yneedshelp さん。

    アクセス エラーとなっておりましたこちらのスレッドの復旧作業が完了しました。
    大変お待たせいたしました。申し訳ございませんでした。
                                                                                   
    マイクロソフト株式会社 フォーラム オペレーター 山本 春海

    2010年7月26日 0:34
  • testing

    • 編集済み shanthi NVS55 2011年1月28日 19:12 <html> <html> shanthi()
    2011年1月28日 19:12