在C中使用自然类型从数组到ptr衰减的标准数组用法
@Bo Persson在此处的正确答案中正确指出:
当传递数组作为参数时,这
void arraytest(int a[])
的意思与
void arraytest(int *a)
但是,我还要补充一点,上述两种形式也是:
意思与
void arraytest(int a[0])
意思和
void arraytest(int a[1])
意思和
void arraytest(int a[2])
意思和
void arraytest(int a[1000])
等等
在上面的每个数组示例中int *
,即使-Wall -Wextra -Werror
打开了构建选项,输入参数的类型也会衰减为,并且可以在没有警告和错误的情况下进行调用(例如,有关这3个构建选项的详细信息,请参见我的仓库),例如这个:
int array1[2];
int * array2 = array1;
arraytest(array1);
arraytest(array2);
作为事实上,“大小”值([0]
,[1]
,[2]
,[1000]
,等)的阵列参数这里面显然只是为了美观/自文件的目的,并且可以是任意正整数(size_t
键入我觉得)你想!
但是,实际上,您应该使用它来指定期望函数接收的数组的最小大小,以便在编写代码时可以轻松地跟踪和验证。在MISRA-C-2012标准(购买/下载标准的236-PG 2012版本的PDF为£15.00这里)走得更远,国家(重点):
规则17.5与声明为具有数组类型的参数相对应的函数自变量应具有适当数量的元素。
...
如果将一个参数声明为具有指定大小的数组,则每个函数调用中的相应参数应指向一个对象,该对象至少具有与数组一样多的元素。
...
使用数组声明符作为函数参数比使用指针更清楚地指定函数接口。该函数期望的最小元素数已明确说明,而使用指针则不可能。
换句话说,即使C标准在技术上没有强制执行,他们还是建议使用显式的大小格式-至少可以帮助您作为开发人员和使用代码的其他人澄清该函数期望的大小数组你通过
在C中对数组强制类型安全
正如@Winger Sendon在我的答案下方的评论中指出的那样,我们可以强制C根据数组大小将数组类型视为不同!
首先,您必须在上面的示例中认识到,使用int array1[2];
如下方法:arraytest(array1);
导致array1
自动衰减为int *
。但是,如果您取而代之的地址 array1
并致电arraytest(&array1)
,则会得到完全不同的行为!现在,它不会衰减为int *
!而是类型为&array1
is int (*)[2]
,表示“指向int的2大小的数组的指针”或“指向int类型的2的数组的指针”。因此,您可以强制C检查数组上的类型安全性,如下所示:
void arraytest(int (*a)[2])
{
}
这种语法很难阅读,但是类似于函数指针的语法。在线工具cdecl告诉我们,这int (*a)[2]
意味着:“将a声明为指向int数组2的指针”(指向2 int
s数组的指针)。:不与版本没有括号混淆int * a[2]
,这是指:“声明一个作为指针整型阵列2”(2点数组的指针到int
)。
现在,此函数要求您使用这样的地址运算符(&
)来调用它,将POINTER TO CORRECT SIZE SIZE!用作输入参数:
int array1[2];
arraytest(&array1);
但是,这将产生警告:
int array1[2];
arraytest(array1);
您可以在此处测试此代码。
为了强制C编译器将此警告变成错误,以便您必须始终arraytest(&array1);
仅使用正确大小和类型的输入数组(int array1[2];
在这种情况下)进行调用,请添加-Werror
到构建选项中。如果在onlinegdb.com上运行上面的测试代码,请单击右上角的齿轮图标,然后单击“额外的编译器标志”以键入此选项,以执行此操作。现在,此警告:
main.c:34:15: warning: passing argument 1 of ‘arraytest’ from incompatible pointer type [-Wincompatible-pointer-types]
main.c:24:6: note: expected ‘int (*)[2]’ but argument is of type ‘int *’
会变成这个构建错误:
main.c: In function ‘main’:
main.c:34:15: error: passing argument 1 of ‘arraytest’ from incompatible pointer type [-Werror=incompatible-pointer-types]
arraytest(array1);
^~~~~~
main.c:24:6: note: expected ‘int (*)[2]’ but argument is of type ‘int *’
void arraytest(int (*a)[2])
^~~~~~~~~
cc1: all warnings being treated as errors
请注意,您还可以创建指向给定大小的数组的“类型安全”指针,如下所示:
int array[2];
int (*array_p)[2] = &array;
...但是我并不一定推荐这样做,因为它使我想起了很多C ++滑稽动作,它们在各处强加了类型安全性,但付出的代价是语言语法复杂性,冗长性和构造代码的难度非常高,我不喜欢这样做,并且之前已经抱怨了很多次(例如:参见“我的C ++思想”)。
有关其他测试和实验,请参见下面的链接。
参考文献
请参阅上面的链接。也:
- 我的在线代码实验:https://onlinegdb.com/B1RsrBDFD