我已阅读 this thread并四处搜索更多信息,但大多数人只是说“不要像这样使用 typedef”。这种做事方式很吸引我,而且我也在尝试学习新事物,所以我想坚持下去。
我使用的是 gcc 版本 9.2.1
这是我正在做的事情的最小可重现示例:
#define TABLE_SZ 10
typedef int vec_t[3];
typedef struct {
vec_t table_one[TABLE_SZ];
} tables;
void foo(vec_t * foo_vec) {
(*foo_vec)[0] = 0;
}
void bar (tables bar_table, vec_t bar_vec) {
foo(&(bar_table.table_one[0]));
foo(&bar_vec);
}
int main() {
vec_t vector;
foo(&vector);
}
/home/happy/CLionProjects/os_2019_p5/tests/test_array_typedef_ops.c: In function ‘bar’:
/home/happy/CLionProjects/os_2019_p5/tests/test_array_typedef_ops.c:18:7: warning: passing argument 1 of ‘foo’ from incompatible pointer type [-Wincompatible-pointer-types]
18 | foo(&bar_vec);
| ^~~~~~~~
| |
| int **
/home/happy/CLionProjects/os_2019_p5/tests/test_array_typedef_ops.c:12:18: note: expected ‘int (*)[3]’ but argument is of type ‘int **’
12 | void foo(vec_t * foo_vec) {
| ~~~~~~~~^~~~~~~
我认为这与“指针衰减”有关,我想将 bar_vec 转换为 int ** 吧? 具体来说,为什么 bar_vec 是 int ** 时 &(bar_table.table_one[0]) int (*)[3] 的类型?
我显然不想抑制 gcc 中所有不兼容的指针类型警告。
转换指针似乎是一件杂事。
我想保留 typedef。我不想将它隐藏在结构中。
是否有编译器标志或其他解决方案来告诉编译器按照我的预期处理这种情况? 我应该了解更多关于此的信息吗?
谢谢。
附:堆栈溢出是否有漂亮的编译器输出打印?
最佳答案
void bar (tables bar_table, vec_t bar_vec)
在很多方面都很糟糕:
- 如果函数位于不同的翻译单元中,则按值传递结构非常低效并且无法被编译器优化。
typedef vec_t
不会阻止数组类型在作为参数传递时进行调整(“衰减”),因此vec_t bar_vec
相当于int*
。因此,该数组不是通过值传递,而只是通过其地址传递。
编译器错误的原因是这样的:foo(&bar_vec);
。您传递一个指向隐藏在 typedef 下的 int*
的指针,这意味着您传递一个 int**
。然而,该函数需要一个 vec_t *
,即 int(*)[3]
类型的数组指针。这就是编译器告诉您的内容。
没有编译器标志来解决这个问题,因为代码没有任何意义。通过删除 typedef 来解决这个问题,然后重写代码。
关于c - 当数组是另一个函数的形式参数时,函数参数中 typedef 常量大小数组的地址会导致指针类型不兼容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58683406/