-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

5
int *check(register int i,register int j)
{   
    int *p=i;
    int *q=j;

p q和的类型不匹配i j。也许你想要的是:

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

更正:注意register不能与&. 此外,关键字register几乎没有什么用处,因为编译器通常会忽略它并自己进行优化。

于 2013-07-23T11:38:15.863 回答
2
int *check(register int i,register int j)
{
int *p=i;
int *q=j;
if(i >= 45)
return (p);
else
return (q);
}

虽然register在参数声明中允许使用存储类说明符,但参数ij具有int类型,而pq属于 类型int *。这使得声明pq无效。

您不能将其更改为:

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

因为&运算符不允许您拥有register存储类的操作数。

您也不能更改参数声明 fromregister int iregister int jtoint i然后int j返回ij对象的地址,因为它们的生命周期在函数退出时结束。

在您的情况下,您不应该使用指针:使用int参数和int返回值。

于 2013-07-23T11:47:15.857 回答
2

一种类型不匹配:

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

第二个注释&不适用于寄存器变量/无效。

From:C和C++中寄存器变量的地址

在 C 中,您不能将变量的地址用于register存储。参照。C11 6.7.1/6:

使用存储类说明符为对象声明标识符register 建议尽可能快地访问该对象。此类建议的有效程度由实施定义。

第三:本地对象的返回地址是未定义的行为(函数的参数计入本地变量)。在函数返回之前,不要返回生命存在的地址。

建议:

要返回地址,您需要对其进行动态分配和返回地址。例如:

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 回答
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

它接受带有大量警告的程序。而且没有一个词说“存储类”。所以我想知道您使用的是什么版本的 GCC?

前两个警告可以通过printf 函数调用来修复#include <stdio.h>和更改。让我们暂时忽略这些并关注其余两个。取决于你想做什么,你可以有不同的选择来消除它们。%d%p

如果要返回ij作为基于堆栈的变量的地址(这是不寻常的,因为返回给调用者后无效),你可以这样做

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,所以输出是十六进制的)。

编辑

在查看您的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;
}

请注意,由于现在的数据类型cint,所以%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 回答