-1

次のコードは、関数のパラメーターのストレージ クラスがint *check(register int,register int);他のストレージ クラスとして宣言されている場合にエラーを表示します。

GNU GCC Compilerを使用してCode::Blocks 10.05 IDEでこのコードをコンパイルしました。エラーの背後にある理由は何ですか? コンパイラ固有のエラーですか、それとも一般的なエラーですか? コード セクションは次の場所から始まります。

int *check(register int, register int);

int main()
{
  int *c;
  c = check(10, 20);
  printf("%d\n", c);
  return 0;
}

int *check(register int i,register int j)
{
  int *p = i;
  int *q = j;
  if(i >= 45)
    return (p);
  else
    return (q);
}
4

5 に答える 5

2

最初のタイプの不一致:

int *p=i;
int *q=j;

2 番目の注意事項&は、レジスタ変数には適用されません/有効です。

From: C および C++ のレジスタ変数のアドレス

registerC では、ストレージを使用して変数のアドレスを取得することはできません。参照。C11 6.7.1/6:

ストレージ クラス指定子を使用したオブジェクトの識別子の宣言は、オブジェクトregister へのアクセスが可能な限り高速であることを示唆しています。そのような提案が有効である範囲は、実装によって定義されます。

3 番目:ローカル オブジェクトの戻りアドレスは未定義の動作です (関数のパラメーターはローカル変数でカウントされます)。関数が戻るまで、そのアドレスを返さないでください。

提案:

アドレスを返すには、動的割り当てを行い、そのアドレスを返す必要があります。例えば:

int *check(int i,int j){
    int *p= malloc(sizeof (int));
    int *q= malloc(sizeof (int));
    *p = i;
    *q = j; 
    if(i >= 45){
      free(q);
      return (p);
    }
    else{
      free(p);
      return (q);
   }
}

返されるアドレスはi,jではなく、動的に割り当てられたメモリのアドレスであることに注意してください。free(a)電話することを忘れないでくださいmain()

于 2013-07-23T11:39:50.083 に答える
2
int *check(register int i,register int j)
{
int *p=i;
int *q=j;
if(i >= 45)
return (p);
else
return (q);
}

registerパラメーター宣言ではストレージ クラス指定子を使用できますが、パラメーターiおよびjint型は whileおよびpqint *です。これによりpandの宣言がq無効になります。

これを次のように変更することはできません。

int *p=&i;
int *q=&j;

演算子は、ストレージ クラス&のオペランドを持つことを許可しないためです。register

register int i また、パラメーター宣言を変更してregister int jから変更int iし、オブジェクトint jのアドレスを返すこともできません。これらの有効期間は関数の終了時に終了するためです。ij

あなたの場合、ポインターを使用しないでください。intパラメーターとint戻り値を使用してください。

于 2013-07-23T11:47:15.857 に答える
1

Ubuntu 13.04 で GCC 4.7.3 を使用している私のマシンでは、出力は次のようになります。

$gcc test.c
test.c: In function ‘main’:
test.c:7:3: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
test.c:7:3: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat]
test.c: In function ‘check’:
test.c:13:12: warning: initialization makes pointer from integer without a cast [enabled by default]
test.c:14:12: warning: initialization makes pointer from integer without a cast [enabled by default]
$./a.out
20

多くの警告を伴うプログラムを受け入れます。そして、「ストレージ クラス」という言葉は 1 つもありません。使用しているGCCのバージョンは何ですか?

最初の 2 つの警告は、への printf 関数呼び出しで修正#include <stdio.h>および変更できます。ここではそれらを無視して、残りの 2 つに注目しましょう。やりたいことに応じて、それらを排除するためのさまざまなオプションを使用できます。%d%p

iまたはのアドレスをスタックベースの変数として返したい場合j(呼び出し元に戻った後は無効になるため、これは珍しいことです)、次のことができます。

int *check( int i, int j)
{   
    int *p = &i;
    int *q = &j;
    ...

レジスタ変数のアドレスを取得できないため、それらを削除する必要があります。この場合、関数を使用すると、プログラムは私のマシンのmainように出力されます。0x7fffc83021f8これは変数へのポインター値jですが、出力する時点では有効ではありませんが、逆参照を試みない限り、すべて問題ありません。

これがあなたが望むものではない場合、おそらく整数を強制するij、ポインターを表現したい場合は、次のことを行う必要があります

 int *check(register int i,register int j)
 {
    int *p=(int *)i;
    int *q=(int *)j;
    if(i >= 45)
        return (p);
    else
        return (q);
 }

この場合、register キーワードの使用は問題ありませんが、効果は非常に限られていることに注意してください。また、一部のマシン (特に 64 ビット GCC) でコードをコンパイルするときにも警告が表示されます。

奇妙ですが、このコードにはある程度の意味があります。通常、ゼロに近すぎる整数は有効なポインターではありません。

したがって、このコードが行うことは次のとおりです。iの値が有効なポインター (値が 45 より大きい) である場合は、 の値をポインターとして返すか、またはjs の値を返します。この場合の結果は次のようになり0x14ます ( を に置き換える必要が%dある%pため、出力は 16 進数になります)。

編集

あなたのmain機能を見た後、私はここで何が求められていると信じています

 int check(register int i,register int j)
 {
    int p=i;
    int q=j;
    if(i >= 45)
        return (p);
    else
        return (q);
 }

とにかく、このコードは次のように簡略化できます

 int check(register int i,register int j)
 {
    if(i >= 45)
        return i;
    else
        return j;
 }

あるいは

 int check(register int i,register int j)
 {
    return i>=45 ? i : j;
 }

これらの場合、main関数は

int main()
{
    int c;
    c = check(10, 20);
    printf("%d\n", c);
    return 0;
}

のデータ型が になってcいるintため、%pforprintfが に復元されることに注意してください%d。出力は元のコードと同じです: 20.

于 2013-07-23T11:48:24.913 に答える
0

OK now I see what you are asking.

If you have a function prototype declaration like this:

int *check(register int, register int);

As soon as the compiler sees this, it can enforce a rule that no code will attempt to obtain the address of the parameters. It is up to the compiler to consider a consistent way to generate code for function calls through out the program based on this fact. This may or may not be the same as

int *check(int, int);

Which performs the default treatment of parameters (but again the compiler will ensure it is consistent through out the program).

But consider the following:

int *check(auto int, auto int);

The compiler do not know weather the address of the parameter is going to be used or not unless it sees the actual implementation. So it cannot assume anything. The programmer obviously want some optimization, but the compiler do not have any further information to do so.

So it does not make sense to specify a parameter to be auto.

What if use auto for parameters of function definition? Again this makes little sense. The compiler can have a strategy that if there is no attempt to obtain the parameter address then treat it as register other use stack for it. But for parameters that do not use auto the rule would be the same. So it does not gives the compiler any further information.

Other storage classes are even makes no sense for parameters in function definition. It is not possible to pass a parameter through static data area or the heap (you can only pass pointers - which actually in the stack or registers).

于 2013-07-24T04:51:58.327 に答える