グローバル変数を別Cファイルで使用すると暴走

このQ&Aのポイント
  • 現在ATMELのATxmega128A1でプログラミングを行っています。ブザーを鳴らす機能で、必ずならしたらすぐに消すというコードを作成したつもりなのですが、ずっとなり続けてしまうという動作が出てしまいます。
  • グローバル変数を使用してブザーを制御し、5秒間ブザーが鳴り続けた場合に強制停止するようにしたいです。そのために、u32型のグローバル変数BuzzerTimeLimit_GetTimeを作成し、ブザーを鳴らしたタイミングで現在時刻に5秒を足して代入しています。
  • しかし、このグローバル変数を別のCファイルでも使用するためにextern宣言を行ったところ、プログラムが暴走してしまいます。原因やチェックすべき箇所について教えていただきたいです。
回答を見る
  • ベストアンサー

グローバル変数を別Cファイルで使用すると暴走

現在ATMELのATxmega128A1でプログラミングを行っています。ブザーを鳴らす機能で、必ずならしたらすぐに消すというコードを作成したつもりなのですが、ずっとなり続けてしまうという動作が出てしまいます。現在のソースコードで抜けが出ているとか、ソースコードにuCOSというOSプログラムも使用しているために起きているのか原因がつかめていませんが、複数タスクの動作のタイミングで起きているなどを疑っています。 そこで、ブザーを鳴らしたと同時に、5秒間計るタイマグローバル変数を作成して、もし5秒間ブザーを鳴らし続けてしまったとしても、このタイマ数値で検知したらブザーを強制停止できるようにするために u32 BuzzerTimeLimit_GetTime=0; このグローバル変数を作成しました。 ブザーを鳴らしたと同時にBuzzerTimeLimit_GetTime に現在時刻+5秒後の時刻を代入しています。 set_buzzer_drv(true); BuzzerTimeLimit_GetTime = OSTimeGet() + OS_TICKS_PER_SEC * 5; この変数をmenu.cというファイルで宣言しています。 BuzzerTimeLimit_GetTime のグローバル変数は他のCファイルの menu.c Oper.c rf_task.c これらのファイルでも使用しているためextern宣言も必要だなと思ったのですが、menu.hファイルに extern u32 BuzzerTimeLimit_GetTime と記述したところ、コンパイル後にダウンロード後、暴走したような動作をします。 試しにmenu.c以外に記述している BuzzerTimeLimit_GetTime変数のコードを削除すると、正常に動作できます。 なぜこのようなことが起きるのかとか、チェックしたほうがよい箇所や方法など、ご教示頂きますよう、よろしくお願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
  • wormhole
  • ベストアンサー率28% (1621/5656)
回答No.2

>バッファオーバーランについてですが、これを見つける方法などご教示頂けると幸いです。Debugフォルダの中にあるmapファイルなどで見つけ出すことなど可能でしょうか? バッファオーバランというのは例えば10バイトの領域しか確保していないのに、11バイトや12バイトなどそれより多く読み書きしようとすることですのでmapファイルなどではわかりませんよ。 基本的にはソースコードを詳細に読んで、そのような処理になっているところがないかを調べていくしかないです。

techhouse
質問者

お礼

回答頂きありがとうございます。返事が遅くなり申し訳ありません。 その後、この問題が解決できました。 原因が完全に判明したわけではないのですが、システム起動時にEEPROM領域に保存されているシステムの各機能の使用有無の設定データの領域を必ずグローバル変数領域に読み込む動作を行っているのですが、EEPROM領域に今後追加されるであろう機能のためにリザーブ領域としてすべて確保していたのですが、それ以外のグローバル変数領域も合わせるとData Memory Usage :8121 bytes 99.1 % Full もうギリギリまで使用していて起こっていた現象のようで、EEPROM領域のグローバル変数への確保を30byte程度減らすコードに修正したところ u32 BuzzerTimeLimit_GetTime この変数を宣言しても暴走する現象は起きなくなりました。 ”99.1%だったので、あと0.9%残ってる”という考えは甘かったようです。Data memory領域は限界に近いということのようでした。他に影響がないかを調べる予定です。 助かります。

その他の回答 (1)

  • wormhole
  • ベストアンサー率28% (1621/5656)
回答No.1

バッファオーバーランなどが起こるようになっていないかソースをしらみつぶしに調べてくしかないかと思います。 http://okwave.jp/qa/q9212502.html で書かれていたソースもNUL文字終端の文字列を扱う関数にNUL文字終端になっていない文字列を渡すなどされていましたし。 また sprintf((char *)str,"%04dZ",pass16); を sprintf((char *)str,"%04d\x5a",pass16); で直ったように思われてるようですけど、実際にはこれで直るはずはありませんから(たぶんほかの要因も絡んで見かけ上直ったように思えるだけかと)。 補足 文字列"%04d\x5a"の解釈はコンパイル時に行われ"%04dZ"に変換されます。 sprintfの書式の解釈はsprintf実行時なのでコンパイル時に変換された"%04dZ"が渡されます。 リテラル文字列のエスケープ文字の解釈はコンパイル時です。 printfやscanfなどの書式の解釈はその関数実行時です。

techhouse
質問者

お礼

回答頂きありがとうございます。助かります。 バッファオーバーランについてですが、これを見つける方法などご教示頂けると幸いです。Debugフォルダの中にあるmapファイルなどで見つけ出すことなど可能でしょうか? 今まで正常に動作できていた際のビルド結果と今回のビルド結果を比較すると、 (前回の正常に動作するさビルド結果のリポート) ------ Build started: Project: MainUnit, Configuration: Debug AVR ------ Build started. Project "MainUnit.cproj" (default targets): Target "PreBuildEvent" skipped, due to false condition; ('$(PreBuildEvent)'!='') was evaluated as (''!=''). Target "CoreBuild" in file "C:\Program Files (x86)\Atmel\Atmel Studio 6.2\Vs\Compiler.targets" from project "C:\mywork\source\TestWatch\branches\TestWatch_20160607\MainUnit\MainUnit.cproj" (target "Build" depends on it): Task "RunCompilerTask" Shell Utils Path C:\Program Files (x86)\Atmel\Atmel Studio 6.2\shellUtils C:\Program Files (x86)\Atmel\Atmel Studio 6.2\shellUtils\make.exe all make: Nothing to be done for `all'. Done executing task "RunCompilerTask". Task "RunOutputFileVerifyTask" Program Memory Usage : 51546 bytes 37.0 % Full Data Memory Usage : 8079 bytes 98.6 % Full Done executing task "RunOutputFileVerifyTask". Done building target "CoreBuild" in project "MainUnit.cproj". Target "PostBuildEvent" skipped, due to false condition; ('$(PostBuildEvent)' != '') was evaluated as ('' != ''). Target "Build" in file "C:\Program Files (x86)\Atmel\Atmel Studio 6.2\Vs\Avr.common.targets" from project "C:\mywork\source\TestWatch\branches\TestWatch_20160607\MainUnit\MainUnit.cproj" (entry point): Done building target "Build" in project "MainUnit.cproj". Done building project "MainUnit.cproj". Build succeeded. ========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ========== (今回の暴走してしまうファームのビルド結果のリポート) ------ Build started: Project: MainUnit, Configuration: Debug AVR ------ Build started. Project "MainUnit.cproj" (default targets): Target "PreBuildEvent" skipped, due to false condition; ('$(PreBuildEvent)'!='') was evaluated as (''!=''). Target "CoreBuild" in file "C:\Program Files (x86)\Atmel\Atmel Studio 6.2\Vs\Compiler.targets" from project "C:\mywork\source\TestWatch\branches\TestWatch_20160804\MainUnit\MainUnit.cproj" (target "Build" depends on it): Using "RunCompilerTask" task from assembly "C:\Program Files (x86)\Atmel\Atmel Studio 6.2\Extensions\Application\AvrGCC.dll". Task "RunCompilerTask" Shell Utils Path C:\Program Files (x86)\Atmel\Atmel Studio 6.2\shellUtils C:\Program Files (x86)\Atmel\Atmel Studio 6.2\shellUtils\make.exe all make: Nothing to be done for `all'. Done executing task "RunCompilerTask". Using "RunOutputFileVerifyTask" task from assembly "C:\Program Files (x86)\Atmel\Atmel Studio 6.2\Extensions\Application\AvrGCC.dll". Task "RunOutputFileVerifyTask" Program Memory Usage : 52564 bytes 37.7 % Full Data Memory Usage : 8121 bytes 99.1 % Full Done executing task "RunOutputFileVerifyTask". Done building target "CoreBuild" in project "MainUnit.cproj". Target "PostBuildEvent" skipped, due to false condition; ('$(PostBuildEvent)' != '') was evaluated as ('' != ''). Target "Build" in file "C:\Program Files (x86)\Atmel\Atmel Studio 6.2\Vs\Avr.common.targets" from project "C:\mywork\source\TestWatch\branches\TestWatch_20160804\MainUnit\MainUnit.cproj" (entry point): Done building target "Build" in project "MainUnit.cproj". Done building project "MainUnit.cproj". Build succeeded. ========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ========== 前回と今回のビルド結果の違いは、 前回はData Memory Usageは98.6%だったのですが、今回 u32 BuzzerTimeLimit_GetTime このグローバル変数を加えてからは Data Memory Usage : 8121 bytes 99.1 % Full になっていることぐらいだと思うのですが、気づいた点など教えていただけると助かります。

techhouse
質問者

補足

http://okwave.jp/qa/q9212502.html こちらの件でもお世話になっております。 この件に関しましては、 sprintf((char *)str,"%04d%s",pass16,"M1#"); sprintf((char *)str,"%04d%s",pass16,"Z"); と書いて解決しました。 助かりました。

関連するQ&A

  • Visual C++とVisual Fortranの変数を共用したい

    FORTRANで作成したサブルーチンを活用し、C++からコールする形でコードを再利用しようと考えています。 C++からFORTRANを呼び出すのはすぐに出来たのですが、データの引渡しで困っています。 FORTRAN側ではグローバルな変数を多数(100個以上)宣言しており、引数としては渡せないのでC++側でも同名の変数を宣言して共用し、データのアクセスをしようと目論んでいます。FORTRAN側のコードは極力触りたくありません。 しかし、FORTRANでexternに相当する宣言の仕方が分からず、うまく同じ領域を共用できるようになっていません。 具体的にどんなことをすれば良いのかご存知の方がいらっしゃいましたら、ぜひご教授願います。 宜しくお願いします。

  • SolarisとLinuxのグローバル変数の扱いについて

    Solaris用のソースをLinuxで使えるように変更したいのですが、 グローバル変数について以下のようなことが発生していて困っています。 なにか、コンパイルオプションなどで対応はできないものでしょうか? Solaris (CC)では 特にextern宣言しなくても同じシンボルの外部変数はコモンセグメントに1つだけ作成しコンパイル自体は正常である。 しかし、Linux (g++)では externを宣言しないと同じシンボルを再定義したことになりエラーとなる。 これにより、グローバル変数を多用しているプログラムはLinuxでうまくコンパイルができない。 しかし、単純にextern宣言での対応は難しい。 extern宣言は外部で定義してあるグローバル変数を参照する というものだがLinux では 1つの定義を意外は全てexternしなければ、2重定義エラーになってしまう。 つまり、実体が1つであとはそれを参照しているという形でなければいけない。 ところが、その実体をどこにするか特定することができない。 例えば、gというグローバル変数を仮定する。 A.c,B.c,C.cはその3つのソースよりAA.aという静的ライブラリを構成する。 gはA.cで定義してありB.c,C.cはそれを参照する。 ところが C.cは個別にC.oというオブジェクトで他からの呼び出しがあり 別LMにリンクされる。 その時C.c内のgは実体を失うことになり未定義となる。 つまり、どれが実体になるかは何にリンクするかで決まるため 実態を特定できない。 また、共通のヘッダにグローバル変数が定義されている場合も、重複するというエラーを起こすため、 共通ヘッダからグローバル変数を分離し、何れかのソースにグローバル変数の実態を定義させる必要がある。 共通ヘッダを使っている他のソースはそのグローバル変数の実態を参照するようにexternの宣言をする。

  • JNAでc言語ファイルの読み込み方が分かりません

    JNAでc言語ファイルの読み込み方が分かりません JNAを使用して、javaからcを読み込み動作するプログラムを作っています。 なんとなく定義は分かってきたのですが、 javaのソースコードに CLibrary.INSTANCE.printf(); のように、c言語を書き込んでいる状況なのですが、 JNAを利用した.javaファイルから.cファイルを読み込む方法はありますか? c言語の場合、.cファイルごとに分割された関数をmainが呼び出すとき、 extern void Sample(); とプロトタイプ宣言の後に Sample(); で呼び出せるみたいなので、 これを使って、 CLibrary.INSTANCE.extern void Sample(); とやってみましたが、コンパイルできませんでした;; 他にやり方がありますか? 知ってる方がいらっしゃいましたら、教えてください。 よろしくお願いします。

    • ベストアンサー
    • Java
  • 複数ファイルで使うグローバル変数の位置

    メイン関数の処理で、関数A→関数B→関数Cという順序で関数が呼び出される場合(1関数1ファイルとします)、関数A,B,Cすべてで使用するグローバル変数の宣言を関数Bのファイルでおこなって、他のファイルではそれをexternするというのでも問題ないでしょうか?

  • C言語のヘッダファイルの使い方

    ヘッダファイルの使い方について質問です。 ソースファイルA、ソースファイルBで共有して使用したい変数がある場合、 Aでは「int a」と宣言し、Bでは「extern int a」と宣言すれば 同じ変数を共有出来ると認識しています。 それをヘッダファイルへ記述しておきたい場合にはどのように 宣言しておけば良いのでしょうか? ヘッダファイルに「int a」と宣言した場合は両方のソースファイルで includeした時に多重定義でエラーとなります。 では「extern int a」と宣言しておいて、両方のソースファイルで includeするのが正しいのでしょうか? 初歩的な質問で申し訳ないですが、有識者の方、教えてください。

  • CファイルとCPPファイルのDLL作成

    CファイルとCPPファイルを同一DLLに取り込むことは可能でしょうか?もし可能であれば実現方法も教えて頂きたいのですが。 現状は別DLLを作成しているのですが、両ファイルを取り込んでビルドすると外部関数宣言をしている箇所がエラーになってしまいます。(extern "C"の箇所が・・・)

  • visual c++ のグローバル変数宣言について

    visual c++で、 例えば下記のようにグローバル変数宣言するが 下記プログラムの「FileMei1[0][n1] = 0;」のところでブレークをかけてプログラムを走らせると、ウォッチウィンドウで「FileMei1エラー: 識別子 'FileMei1' はスコープ外です」とでてきます。 グローバル変数宣言のやり方間違っているのでしょうか? namespace TestCpp { extern char FileMei1[300][100]={ 0 }; public void aa{ for(n1=0; n1 < 100 ; n1++) { FileMei1[0][n1] = 0; } }

  • グローバル変数

    分割コンパイルで、持ちいる変数をヘッダーファイルに宣言しました。 ヘッダーファイル内で次のように宣言し、メインの関数でない場合にはexternになるようにしました。 メインなら FILEは1 それ以外なら0 #if FILE   unsinged int inputNo; #else  extern unsigned int inputNo; #endif しかし、リンクをさせると error LNK2001: 外部シンボル "_inputNo" は未解決です と出てしまいます。解決策はあるでしょうか? プロジェクトの設定の関係でしょうか?よろしくお願い致します。

  • 外部変数について

    今Vine Linuxを使ってC++でプログラムを書いているのですが教えて頂きたいことがあります. C++の初心者の為,変なことをお聞きしますがお許しください. extern宣言で他のソースのローカル変数を参照する方法はないのでしょうか? 例えば,a.cとb.cというソースがあったとします. a.cの関数内でint i;と宣言されている変数をb.cからextern int i;という風にしたいのですが, こうするにはa.cでグローバル変数としてint i;を定義する以外方法はないのでしょうか? できればグローバル変数を使いたくないのですがこれ以外では無理でしょうか? あともう一つお聞かせ下さい. メイン関数の引数を別の関数,またはソースで使うということはできないのでしょうか? int main( int argc, char *argv[] )のargv[1]というのを別の関数で使用したいのですがこれも無理でしょうか? 馬鹿な質問だとは思いますが,どなたかお答え頂けますでしょうか? よろしくお願いします.

  • BEGIN{}での変数宣言

    'perl'では変数の有効範囲について、'c' と考えかたが違うようですが、違和感があります。 1000行を超えるような'perl'で、随処で頻繁に使うような重要なグローバル変数では、BEGIN 内で明示的に宣言したほうが、引き継いだひとにも親切にかんじるのですが、みなさんはどうお感じになりますか? 'perl'を作られたかたは、'c'の自動変数を'my'で、'extern'を宣言不要という思想でつくられたのでしょうか? (2回目の質問です。変な質問でしたら、ごめんなさい<ToT>)

    • ベストアンサー
    • Perl

専門家に質問してみよう