【问题标题】:When does C not need the address-of operator?C什么时候不需要地址运算符?
【发布时间】:2015-01-19 01:45:13
【问题描述】:

在 C 语言中,除了数组之外,还有什么时候不需要地址操作符?比如我知道这段代码需要operator的地址:

typedef struct foo_t {
    int bar;
} foo_t;

void foo_init(foo_t *f) { f->bar = 123; }

... {
    foo_t f;

    foo_init(&f);
}

但是这段代码不需要地址操作符:

... {
    char buffer[1024];
    memset(buffer, 0, 1024);
}

这里memset被声明为:

void *memset(void *ptr, int value, size_t num);

在 C 中,它会自动将 char[] 转换为 void* - 但尝试对 foo_t 执行相同的操作,如下所示:

 foo_t f;
 memset(f, 0, sizeof(foo_t));

不起作用,并且会产生预期的编译时类型错误。就像char[] 示例一样,如果我们使用数组,它将起作用:

foo_t list[16];
memset(foo, 0, sizeof(list));

它会再次自动将foo_t[] 转换为void*

这是唯一一次在 C 中发生这种类型转换的情况吗?我怎么知道这些演员何时会发生?

【问题讨论】:

  • 唯一的其他隐式“地址获取操作”是函数名到函数指针。
  • @5gon12eder 请将其添加为答案。
  • 任何参考文献都很棒。我能找到的 C 规范并不完全是 light 阅读材料。
  • 另外,伙计们,我把这个问题放在这里是因为我在 stackoverflow.com 上找不到答案,并认为这个问题会被问到。如果有人能找到一个类似的问题来回答这个问题,那就太好了。
  • @JonathonReinhart 我认为这可能不值得回答,但多亏了你的动力,它现在是一个。

标签: c pointers casting reference upcasting


【解决方案1】:

我知道的唯一“其他”(参见 cmets)隐式地址获取情况是使用函数指针 [1, 2]。给定一个函数

int
f(void);

以下两行含义相同。

int (*fptr1)(void) = f;
int (*fptr2)(void) = &f;

两者都使fptr1fptr2 分别成为指向f 的函数指针。

【讨论】:

  • 我会说这是唯一的情况。对于数组,您“不需要”& 运算符是不正确的。相反,使用或不使用 & 运算符会给出截然不同的结果。 arrayname 本身等同于&arrayname[0],而不是&arrayname
  • @R.. 确实如此。这也是为什么我使用“隐式地址获取”而不是“衰减”这个黄鼠狼的措辞,因为这里发生的情况不一样。我现在也将“其他”放在引号中。
【解决方案2】:

在这个表达式中

char buffer[1024];
memset(buffer, 0, 1024);

数组在传递给memset 时衰减为一个指针,memset 在它的第一个参数中需要一个指向可写内存的指针。

这个函数

void foo_init(foo_t *f) 
{ 
    f->bar = 123; 
}

也可以写成

void foo_init(foo_t f) 
{ 
    f.bar = 123; 
}

但传递的参数将是原始参数的副本,并且更改将仅适用于本地副本。

在指针版本中,参数指向结构体存储在内存中的位置,因此直接对指针指向的相同数据进行更改。

所以你不需要获取数组的地址,因为它会自动衰减到指向它的第一个元素的指针,当这样使用时,而当你传递一个分配在堆栈上的对象并且你想要在reciever函数中改变它,你需要传递一个指向它的指针,你使用operator的地址。

【讨论】:

  • 谢谢@iharob,我想我明白这个问题。我担心的是这种隐式转换何时会在 C 中发生。我主要是在 C 规范(任何方式)中寻找它概述了这种行为的位置,以便我可以理解它可能适用于其他什么。
【解决方案3】:

字符串字面量通过地址分配给指针,并在用作初始化的 rhs 时通过“值”分配:

const char *str_ptr = "foo";  /* str_ptr points to a string "foo",
                                 in read-only memory. */

char chr_ar[] = "barbar";     /* chr_ar is 7 bytes, and is initialized
                                 with the bytes "barbar" */

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-23
    • 1970-01-01
    相关资源
    最近更新 更多