returns 指向数组的指针的 C 函数语法正确吗?
C function that returns a pointer to an array correct syntax?
在 C 中,您可以像这样声明一个指向数组的变量:
int int_arr[4] = {1,2,3,4};
int (*ptr_to_arr)[4] = &int_arr;
尽管实际上它与声明一个指向 int 的指针是一样的:
int *ptr_to_arr2 = int_arr;
但在句法上有所不同。
现在,returns 这样一个指向数组(例如 int)的指针的函数会是什么样子?
int
的声明是 int foo;
。
4 int
数组的声明是 int foo[4];
.
一个指向4int
数组的指针的声明是int (*foo)[4];
.
返回指向 4 int
数组指针的函数的声明是 int (*foo())[4];
。 ()
可以填写参数声明。
在这种情况下,typedef
关键字可以使事情变得很多clearer/simpler:
int int_arr[4] = { 1,2,3,4 };
typedef int(*arrptr)[4]; // Define a pointer to an array of 4 ints ...
arrptr func(void) // ... and use that for the function return type
{
return &int_arr;
}
注意:正如评论和 , using a typedef
to hide/bury a pointer is a practice that is frowned-upon by (most of) the professional C programming community – and for very good reasons. There is a good discussion about it here.
中所指出的
但是,尽管在您的情况下,您没有定义 actual 函数指针(这是大多数程序员会接受的 'rule' 的例外) ,您 是 定义复杂(即难以阅读)函数 return 类型。链接 post 末尾的讨论深入探讨了“太复杂”的问题,这就是我用来证明在像您这样的情况下使用 typedef
的理由。但是,如果你要选择这条路,那就要小心了。
如前所述,正确的语法是 int (*foo(void))[4];
正如您所知,它很难阅读。
有问题的解决方案:
使用 C 语言让您编写的语法。在我看来,这是你应该避免的事情,因为它非常难以阅读,以至于它完全没有用。这应该在您的编码标准中被简单地禁止,就像任何合理的编码标准强制函数指针与 typedef
.
一起使用一样
哦所以我们只是 typedef
这就像使用函数指针时一样?确实有人可能会想把所有这些东西都隐藏在 typedef
后面,但这也是有问题的。这是因为数组和指针都是 C 中的基本“构建块”,具有程序员希望在处理它们时看到的特定语法。并且缺少该语法表明可以像任何其他变量一样寻址、“访问左值”和复制的对象。将它们隐藏在 typedef
之后可能最终会造成比原始语法更多的混乱。
举个例子:
typedef int(*arr)[4];
...
arr a = create(); // calls malloc etc
...
// somewhere later, lets make a hard copy! (or so we thought)
arr b = a;
...
cleanup(a);
...
print(b); // mysterious crash here
所以这个“隐藏在 typedef 后面”的系统在很大程度上依赖于我们命名类型 somethingptr
来表明它是一个指针。或者让我们说... LPWORD
... 这就是“匈牙利表示法”,Windows API.
中备受批评的类型系统
稍微明智的work-around是通过其中一个参数return数组。这也不是很漂亮,但至少更容易阅读,因为奇怪的语法集中在一个参数上:
void foo (int(**result)[4])
{
...
*result = &arr;
}
即:指向 int[4]
的 pointer-to-array 的指针。
如果有人准备将类型安全抛出 window,那么 void* foo (void)
当然可以解决所有这些问题……但会产生新的问题。非常容易阅读,但现在的问题是类型安全和函数实际 return 的不确定性。也不好
那么,如果这些版本都有问题怎么办?有一些非常明智的方法。
好的解决方案:
将分配留给调用者。这是 迄今为止 最好的方法,如果可以的话。您的函数将变为 void foo (int arr[4]);
可读且类型安全。
老派 C。只是 return 指向数组中第一项的指针,并单独传递大小。这可能会或可能不会被接受,具体情况视情况而定。
将其包装在结构中。例如,这可能是一些通用数组类型的合理实现:
typedef struct
{
size_t size;
int arr[];
} array_t;
array_t* alloc (size_t items)
{
array_t* result = malloc(sizeof *result + sizeof(int[items]));
return result;
}
在 C 中,您可以像这样声明一个指向数组的变量:
int int_arr[4] = {1,2,3,4};
int (*ptr_to_arr)[4] = &int_arr;
尽管实际上它与声明一个指向 int 的指针是一样的:
int *ptr_to_arr2 = int_arr;
但在句法上有所不同。
现在,returns 这样一个指向数组(例如 int)的指针的函数会是什么样子?
int
的声明是 int foo;
。
4 int
数组的声明是 int foo[4];
.
一个指向4int
数组的指针的声明是int (*foo)[4];
.
返回指向 4 int
数组指针的函数的声明是 int (*foo())[4];
。 ()
可以填写参数声明。
在这种情况下,typedef
关键字可以使事情变得很多clearer/simpler:
int int_arr[4] = { 1,2,3,4 };
typedef int(*arrptr)[4]; // Define a pointer to an array of 4 ints ...
arrptr func(void) // ... and use that for the function return type
{
return &int_arr;
}
注意:正如评论和 typedef
to hide/bury a pointer is a practice that is frowned-upon by (most of) the professional C programming community – and for very good reasons. There is a good discussion about it here.
但是,尽管在您的情况下,您没有定义 actual 函数指针(这是大多数程序员会接受的 'rule' 的例外) ,您 是 定义复杂(即难以阅读)函数 return 类型。链接 post 末尾的讨论深入探讨了“太复杂”的问题,这就是我用来证明在像您这样的情况下使用 typedef
的理由。但是,如果你要选择这条路,那就要小心了。
如前所述,正确的语法是 int (*foo(void))[4];
正如您所知,它很难阅读。
有问题的解决方案:
使用 C 语言让您编写的语法。在我看来,这是你应该避免的事情,因为它非常难以阅读,以至于它完全没有用。这应该在您的编码标准中被简单地禁止,就像任何合理的编码标准强制函数指针与
一起使用一样typedef
.哦所以我们只是
typedef
这就像使用函数指针时一样?确实有人可能会想把所有这些东西都隐藏在typedef
后面,但这也是有问题的。这是因为数组和指针都是 C 中的基本“构建块”,具有程序员希望在处理它们时看到的特定语法。并且缺少该语法表明可以像任何其他变量一样寻址、“访问左值”和复制的对象。将它们隐藏在typedef
之后可能最终会造成比原始语法更多的混乱。举个例子:
typedef int(*arr)[4]; ... arr a = create(); // calls malloc etc ... // somewhere later, lets make a hard copy! (or so we thought) arr b = a; ... cleanup(a); ... print(b); // mysterious crash here
所以这个“隐藏在 typedef 后面”的系统在很大程度上依赖于我们命名类型
中备受批评的类型系统somethingptr
来表明它是一个指针。或者让我们说...LPWORD
... 这就是“匈牙利表示法”,Windows API.稍微明智的work-around是通过其中一个参数return数组。这也不是很漂亮,但至少更容易阅读,因为奇怪的语法集中在一个参数上:
void foo (int(**result)[4]) { ... *result = &arr; }
即:指向
int[4]
的 pointer-to-array 的指针。如果有人准备将类型安全抛出 window,那么
void* foo (void)
当然可以解决所有这些问题……但会产生新的问题。非常容易阅读,但现在的问题是类型安全和函数实际 return 的不确定性。也不好
那么,如果这些版本都有问题怎么办?有一些非常明智的方法。
好的解决方案:
将分配留给调用者。这是 迄今为止 最好的方法,如果可以的话。您的函数将变为
void foo (int arr[4]);
可读且类型安全。老派 C。只是 return 指向数组中第一项的指针,并单独传递大小。这可能会或可能不会被接受,具体情况视情况而定。
将其包装在结构中。例如,这可能是一些通用数组类型的合理实现:
typedef struct { size_t size; int arr[]; } array_t; array_t* alloc (size_t items) { array_t* result = malloc(sizeof *result + sizeof(int[items])); return result; }