C语言 当传递给函数时,我如何强制使用错误大小的数组发出警告?



假设你有一个函数接受一个字符串作为参数:

void foo(char *arg);

如果我们确定数组(不要与字符串长度混淆,谢谢chux)总是有一定的大小,比如8,那么我们可以这样做:

void bar(char (*arg)[8]);

,然后像这样调用:

char str[8] = "Hello";
bar(&str);

我们需要添加&以使其正常工作,但是如果传递错误大小或类型的数组,上面的代码将发出警告,这正是我想要实现的。但我们显然需要稍微修改一下身体。所以我的问题很简单,如果这个包装技术可以工作:

void bar(char (*arg)[8]) {
char *tmp = (char*) arg;
foo(tmp);
}

我在这里想要实现的是,如果使用错误大小的数组调用,应该发出警告。上述解决方案安全吗?转换指针到char数组到char指针是安全的吗?我试过了,它的工作原理,并发出没有警告与-Wall -Wextra -pedantic。只要我改变str的大小,我就得到:

<source>: In function 'main':
<source>:18:9: warning: passing argument 1 of 'bar' from incompatible pointer type [-Wincompatible-pointer-types]
18 |     bar(&str);
|         ^~~~
|         |
|         char (*)[9]
<source>:9:17: note: expected 'char (*)[8]' but argument is of type 'char (*)[9]'
9 | void bar(char (*arg)[8]) {
|          ~~~~~~~^~~~~~~

这正是我想要的。但它安全吗,还是UB?我想做到这一点,不仅通过包装器,而且通过重写原始函数,如

void foo(char (*argaux)[8]) {
char *arg = *argaux;
// Copy body of original foo

我知道我可以使用结构体实现基本相同的功能,但我想避免这种情况。

可运行代码:https://godbolt.org/z/GnaP5ceMr

char *tmp = (char*) arg;是错误的,这些是不兼容的指针类型。你可以很容易地修复这个问题:

char *tmp = *arg;

*arg给出一个char[8],然后衰减为指向其第一个元素的指针。这是安全且定义良好的。是的,指针有更强的"类型"。

请注意,但这会导致其他问题:你不能再拥有const正确性。
参见数组指针的Const正确性?

这是不安全的:

char *tmp = (char*) arg;

因为您正在尝试将char (*)[8]转换为char *。由于指向数组的指针(至少在x86-64上)与指向数组的第一个成员的指针具有相同的数值,因此可能不受影响,但标准并不保证它会起作用。首先需要取消对参数的引用:

char *tmp = *arg;

理论上你应该可以这样做:

void foo(char arg[static 8]);

这意味着arg必须是至少大小的数组。

该语法的描述在C标准的6.7.6.3p7节中:

将形参声明为" array of type "应进行调整到"限定类型指针",其中类型限定符(ifany)是在数组的[]中指定的派生类型。如果关键字static也出现在[]的数组类型派生,然后分别调用对于函数,对应的实际参数的值应提供对数组第一个元素的访问,至少为size表达式指定的多个元素

但是,大多数实现都没有强制执行此限制,并且它不会阻止您传递大于预期的数组。

相关内容

  • 没有找到相关文章

最新更新