C什么时候不需要address-of运算符?
When does C not need the address-of operator?
在 C 语言中,除了数组之外,还有其他时候不需要寻址运算符吗?例如,我知道这段代码需要运算符的地址:
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 语言中发生这种转换吗?我怎么知道这些演员什么时候会发生?
在这个表达式中
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;
}
但传递的参数将是原始参数的副本,更改将仅应用于本地副本。
在指针版本中,参数指向结构在内存中的存储位置,因此直接对 指针 指向的相同数据执行更改.
所以你不需要获取数组的地址,因为它会自动衰减到指向它的第一个元素的指针,当这样使用时,而当你传递分配在堆栈上的对象时,你想在接收函数中改变它,你需要传递一个指向它的指针,为此你使用运算符的地址。
我所知道的隐式地址获取的唯一“其他”(见评论)案例是函数指针[1, 2]。给定一个函数
int
f(void);
以下两行意思相同
int (*fptr1)(void) = f;
int (*fptr2)(void) = &f;
两者都使 fptr1
和 fptr2
分别成为指向 f
的函数指针。
字符串文字按地址分配给指针,"value" 当用作初始化的 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" */
在 C 语言中,除了数组之外,还有其他时候不需要寻址运算符吗?例如,我知道这段代码需要运算符的地址:
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 语言中发生这种转换吗?我怎么知道这些演员什么时候会发生?
在这个表达式中
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;
}
但传递的参数将是原始参数的副本,更改将仅应用于本地副本。
在指针版本中,参数指向结构在内存中的存储位置,因此直接对 指针 指向的相同数据执行更改.
所以你不需要获取数组的地址,因为它会自动衰减到指向它的第一个元素的指针,当这样使用时,而当你传递分配在堆栈上的对象时,你想在接收函数中改变它,你需要传递一个指向它的指针,为此你使用运算符的地址。
我所知道的隐式地址获取的唯一“其他”(见评论)案例是函数指针[1, 2]。给定一个函数
int
f(void);
以下两行意思相同
int (*fptr1)(void) = f;
int (*fptr2)(void) = &f;
两者都使 fptr1
和 fptr2
分别成为指向 f
的函数指针。
字符串文字按地址分配给指针,"value" 当用作初始化的 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" */