• 締切済み

GCCで関数の引数が渡らない

gcc Ver2.9 でSH-2の開発をしています。 通常に関数を作成し、引数を渡しているのですが、引数が渡らないという現象が起きています。 現象は、 1.引数はポインタではなく値渡しである 2.引数の値が0の時だけ正しく渡らない。値が0以外の時は正常にわたる 3.引数の型は一致している 4.引数は複数あるが、後半のいくつかがだめ(何個とまでは詳しく調べていません) 5.ある特定の関数の特定の呼び出しのみがだめで全てだめというわけではない 6.コンパイルオプションに -m2 をつけるとだめだが、-m1 オプションだと問題ない 7.最適化オプションをなくしても同じだった といった状況です。 上記5からある特定の記述方法とか順序になるとだめになるのではないかといろいろ試してみたのですが見つけられません。6から記述方法に誤りがあるとも考えにくい状況です。コンパイラのバグといって片付けていいものなのかどうかです。どなたか同じような経験をされた方はいらっしゃいませんか。また関数呼び出しの場合、コンパイラがどうやって引数を渡すかご教授願えませんか。

  • dabo
  • お礼率61% (44/72)

みんなの回答

  • toysmith
  • ベストアンサー率37% (570/1525)
回答No.3

イミディエイト値の0だけで発生する現象のようですね。 0Lや0Uでも同じ現象でしょうか? イミディエイトな0だけが問題を起こすならint ZERO = 0;のようなグローバル変数を定義して、0の代わりに使うという手も…

dabo
質問者

お礼

ご意見ありがとうございます。 残念ながらイミディエイト値の0だけで発生するわけではありません。 変数であってもその値が0とコンパイル時にわかる場合はだめなようです。 したがってローカル変数でint ZERO = 0;のように定義してもだめです。 しかし仰るようにグローバル変数でint ZERO = 0;のように定義すればコンパイル時にその値が0であるかどうかはわかりませんのでうまく回避できるようです。 しかし調子に乗って、const int ZERO = 0;などとやると変数の値が固定されてしまうのでコンパイラに0であることがバレて(笑)だめになってしまいます。 一応、その他の回避方法を試行錯誤で調べましたので書いておきます。但しコンパイラそのものを解析したわけではありませんので絶対にOKという保証はありません。 1.引数の数を4個以下にする。 2.引数リストの中にコンパイル時点で0になる計算式を含めない 3.0の引数は、引数リストの先頭に持ってくる とりあえずこれで問題は起きてないみたいです。

  • toysmith
  • ベストアンサー率37% (570/1525)
回答No.2

現在スタックへのプッシュ・ポップで引数を渡すコンパイラというのはほとんど存在しないでしょう。 効率が悪すぎ、関数呼び出しの度に大きなオーバーヘッドになります。 SH-2のアーキテクチャを良く知らないで、以下は一般論です。 1.レジスタが豊富で引数用レジスタが用意できる場合(RISCに多い) SPARCなどで採用されている方法です。 レジスタのうちの10~20個程度を引数要に割り当てます(引数がそれ以上の場合は2の方法を併用)。 更に下位の関数を呼び出す場合はスタックに退避し、関数から戻ったときにレジスタに復帰します。 下位関数の呼び出しが無ければスタックへのアクセスが発生しないため、非常に高速です。 2.ベースポインタを利用する(CISCに多い) スタック上の引数に対してベースポインタからの相対アドレッシングで直接アクセスします。 ベースポインタが用意されていないCPUでは汎用アドレスレジスタを流用します。 稀にスタックポインタをベースポインタとして利用することもあるようです。 3.引数領域を別途用意する スタックが無く、レジスタに余裕が無い場合にのみ利用されます。 汎用コンピュータのCコンパイラで見られます。 スタックを利用する場合でもPUSH・POP(PULL)系の命令が使われることはほとんどありません。 1ワードを超えるデータ長の引数を扱うときに効率が悪くなるため、ベースポインタからの相対アドレスに対してMOVE系の命令を使うことが多いでしょう。 gccなら-Sオプションでコンパイルすればアセンブラ展開形が確認できると思います。

dabo
質問者

お礼

詳しい解説をありがとうございます。 デバッガで逆アセンブルをかけて解読しました。 結論は、コンパイラのバグのようです。 SH2は汎用レジスタの数が比較的少ないため、引数はレジスタとスタックで渡されています。 スタックはレジスタの相対アドレッシングで参照しています。問題の引数は通常、レジスタにイミディエイトで値をセットし、それをスタックにセットするという手順で渡されています。 ところが、問題の箇所で引数が0の場合、イミディエイトで値をセットする代わりに、MACレジスタの値を転送しています。 このMACレジスタがクリアされていれば問題ないわけですがそれは行われていません。 デバッガでクリアされない値が渡っていくことを確認しました。 コードで書くとこんな具合です。 (XXXXには相対アドレスが入ります) 正常時: MOV     #0, R1 MOV.L   R1, @(XXXX,R15) ;これで引数セット NG時: STS    MACL, R1 MOV.L   R1, @(XXXX,R15) ;これで引数セット 残る問題は対策です。コンパイラのbugfixを待つのは正攻法ですが、そんな悠長なことは言ってられません。引数に0を使わないというのも無理があるし、引数0があるたびにMACレジスタクリアの命令を挿入するのも面倒だし弱っています。どういう記述をするとそうなるのかという法則を見出すしかないのでしょうか。

  • hidebu-
  • ベストアンサー率53% (45/84)
回答No.1

引数がいくつかっていうのが気になりますが、 0というのは定数リテラルで渡してるんでしょうか? それともConst定数でしょうか?それとも変数に格納したもので? 引数を渡すときは、最終的にスタック領域にプッシュして関数ポインタにジャンプしてスタックからポップという動きになるのはどのコンパイラでも一緒ですからねえ。。。 単なるコンパイラのバグと片付けてしまっていいと思いますよ。 どうしても気になるんでしたら、逆アセンブルをかけてアセンブラにしてトレースしていけば詳しい動きがわかりますよ。(結果は同じなんですけどね^^;)

関連するQ&A

  • gccのインラインアセンブラ

    コンパイラはgccで、コンパイルオプションでintel形式でコンパイルしています。 shl命令で左シフトしたいのですが、初期値0xfffffffなのに実行結果は0xffdf0000になってしまいます。 コード: asm(" shl %0, 4 " : "=r" (val)) #defineでマクロにしています(valは引数です)。 どうすれば結果が0xfffffff0になりますか。

  • クラスのアドレスを引数として渡したい

    関数の引数として,クラスのアドレスを渡すにはどうしたら良いですか. void func(MyClass mc) { mc = ~ } としたとき,これは参照渡しとなっているのですか? それとも値渡しとなっているのですか? もし値渡しとなっているのでしたら,クラスの場合 どのようにすれば参照渡しにできるのでしょうか. よろしくお願いします.

  • cygwin gcc c99 での isnormal と strtold の使用

    Cygwinのgccで-std=c99オプションを付けて 以下のコードをコンパイルしようとしています。 #include <stdlib.h> #include <math.h> int main() { isnormal(0.123); strtold("0.123", NULL); return 0 ; } $> gcc -std=c99 test_strtold.c ですが、コンパイルできず、2つの関数とも'undefined reference'になります。 -std=c99を付けてコンパイルする方法または この記述と同等の別の記述がありましたらご教授願います。 よろしくお願いいたします。

  • C言語のポインタによる関数の引数の書き方について教えてください。

    C言語を今勉強中の大学生です。 一気に複数の値をmainに返せる、参照による呼び出しによる関数の引数の書き方で困っています。配列を自作関数に引き渡したいのですが、どう書けばいいのでしょうか。 下の3つは、それぞれ(1)mainからの呼び出し、(2)自作関数での引数の引き受け、です。どこをどう変えたらエラーが出なくなるのか、分かる方、お願いいたします! (1)school(&m,h); (2)void school(int *m, float *h){ ※ちなみに変数は int m,float h[10][10]

  • 関数引数に対する制限値チェック方法

    引数に対する制限値チェック方法  プログラミング(組み込み系C言語)関数作成時にいつも私が迷ところなのですが、  関数の引数に対する制限値(範囲外)チェックどうするか、次の(1)、(2)で悩んでます。。   【1】関数内で制限値チェックで行い、制限値外であれば戻り値でエラーコードを返す。   【2】関数呼び出し時に、引数となる値(変数)をチェックし、制限値内であることを確認してから、関数を呼び出す。  上記の【1】、【2】の方法どちらがよいでしょうか?  状況にもよるとは思うのですが、その場合はどういった状況時に(1)||(2)がよいのか教えてください。  (【3】もあればお願いします。)  --【1】がお勧めの場合の質問  (1)本関数での"結果"を返したいときどうすればよいかアドバイスください。     戻り値("結果")と、エラーコードを兼用するのはなんかイヤです。。     エラーコード付き関数は、全て同じ戻り値(1:OK時、-1:NG時 みたいに)     としてまとめたいからです。  (2)極端にほとんどの関数の戻り値を、OK/NG とす。これってどうですか?、 ///////////////////////  【1】、【2】の利点、欠点を僕なりに考えてみました。  ##【1】の利点/欠点  利点:   ・本関数呼び出し時に、毎回制限チェックをしなくてよくなる。    (汎用的に様々な場面で、使用するのであればこれは良い利点だと思います。)  欠点:   ・戻り値のとして、エラーコードを返さなくてはならないため、本関数での結果を返したい場合、    以下方法をとらないといけない。      1、引数をポインタとして、その引数で値を返す。      2、戻り値として、エラーコードと兼用して返す。        (例:エラー時の戻り値 = 0、正常にの戻り値 = 1~ 255)  ##【2】の利点/欠点  利点:   ・エラーコードを返す必要がなくなるため、戻り値が有効利用できる。  欠点:   ・関す呼び出し毎に、制限チェックが発生し、制限チェック忘れが発生する。    (汎用的に使うにのであればなお・・・)

  • LinaxのCコンパイラ gcc の内部構造を教えて下さい

    今、コンパイラの仕組みについて勉強しています。 gccの仕組みについていろいろ調べているのですが なかなか資料が見当たりません。そこで是非これ に関して情報をお持ちのかたは御提供下さい。ど のような情報でも構いませんができれば次の情報 についてをお願いします。 1)gcc の構文解析の仕組み 2)最適化オプション -O2 を用いた時と通常のコンパイル時との構文解析の違い 3)ターゲットプロセッサ(CPU)に依存した構文解析の動作

  • 引数について質問

    私プログラミング初心者ですので、できるだけ優しい解説をしていただければ幸いです! 引数について、以下のような解説がありました。 「引数には仮引数と実引数の2種類が存在する。仮引数は、関数を定義する際に変数で指定する引数である。また、実引数は、プログラムの実行時に関数に引き渡される値となる引数である。つまり、関数の実行時には、実引数の値が仮引数に代入されることになる。」 質問:1「関数を定義する際に変数で指定する引数である。」という記述の中で「関数を定義」とありますが、実際のソースコードにおいて何に対応するかわかりません。簡潔なソースコードを交えて解説していただければ幸いです。 質問2:「関数を定義」に限らず、プログラミングにおいて「定義」という言葉をよく見ますが、これは本質的にどういう意味をもっているのでしょうか?具体的なソースコースコードを交えて解説してくださると幸いです。 もしかして、その定義とは例えば「public static void main(String arg[]){」のような「メソッド宣言」のことですか? 質問3:「関数の実行時には、実引数の値が仮引数に代入されることになる。」と書いてありますが、 これはどういうことですか、僕が実際にソースコードで記述してみるので、その考えが正しいか判定してください package 第4章; public class A { public static void main(String arg[]){ double x; x=Math.sqrt(2.0); System.out.println("2.0の平方根は"+x); } } 僕の考え:String arg[]が仮引数で、実引数2.0がString arg[]に代入されるってことでしょうか? 「定義」といえば、上記のソースコードでは、public static void main(String arg[]){ 以外見当たらないので、、 僕の考え2:Mathクラスは、標準クラス(javaが最初から備えているクラス)だから、プログラマが「関数を定義」しなくても予め関数が定義されているから、関数を定義する必要がない、ということでしょうか?

    • ベストアンサー
    • Java
  • 【PHP】usort()関数内の引数について

    【PHP】usort()関数内に出てくる関数の引数の意味を教えてください。 usort(ユーザー定義関数) 以下のような配列があります。ここで'score'を小さな順番(昇順)で並べ替えるためにusort()関数を使いたいと思います。 $data= [ ['name' => 'yamada', 'score'=> 80], ['name' => 'suzuki', 'score'=> 60], ['name' => 'tanaka', 'score'=> 70], ['name' => 'okada', 'score'=> 60], ]; usort( $data, function($a, $b){ if ($a['score']=== $b['score']){ return 0; } return $a['score'] > $b['score'] ? 1: -1; } ); echo "<pre>"; print_r($data); echo "</pre>"; ----------------------------------------------------------------- サンプルでは上記のように$a,$bが使用されています。 スコアの数値を比較して、あるスコアの値と別のスコアの値が同じであれば「0」を返す。$aの値が$bより大きければ「1」を返す、そうでなければ「-1」を返す。 返ってきた値、「-1」,「 0」,「 1」と小さな順に並べる… こういうことかと思います。添付画像のように表示された値も合っています。 が、functionの引数($a, $b)の意味がよくわかりません。 foreachなどでループさせ値を一つづつ比較するというよう作業を行うのであればまだ理解できるかもしれませんが、ただ単に引数に function($a, $b)…としただけでscoreの値が$a、$bにどうやって代入されていくのでしょうか?? $a, $bと記述しただけで全てのscoreの値をなぜ比較してくれるのかわかりません。 また、現在$dataの中には4つしか配列がありません。-1,0,1だけで順番をつけられるでしょうが、これが50, 100個と配列データが増えた場合でもこのやり方でできるのでしょうか? 初学者です。分かる方いらっしゃいましたら教えて下さい。よろしくお願いいたします。

    • ベストアンサー
    • PHP
  • コンパイルオプションの書籍

    お世話になります。 C言語を始めたばかりですが、コンパイル、リンクオプションを書いた 本(または、情報)はありませんか。現状、 bcc32 test.c gcc test.c ぐらいでコンパイルしてます。 算術関数を使っていてgccの場合、-lmを着けないとだめというのに かなり時間がかかりました。 borlandとgccの2つがあれば良いのですが、宜しくお願いします。

  • 手続き型と関数型について。

    手続き型言語の定義は、「記述された命令を逐次的に実行し、処理の結果に応じて変数の内容を変化させていくプログラミング言語」となっていて、関数型言語の定義は、「数学的な言語仕様をもつプログラミング言語のこと。一度値を与えられた変数は常にその値を維持し、計算は計算結果を引数とした関数呼び出しの繰り返しとして行われる。」とあります。 関数型の、「一度値を与えられた変数は常にその値を維持し」はどういう意味ですか? 例えば、a=2とした後に、a=3などとすればaの値は変わっているのですが。 簡単な例で説明してください。