如所提到的在这里,在这里和在这里的函数(在C99或更新版本)以这种方式定义
void func(int ptr[static 1]){
//do something with ptr, knowing that ptr != NULL
}
具有一个ptr
指向int类型指针的参数(),并且编译器可以假定该函数永远不会以null为参数调用。(例如,编译器可以优化空指针检查,或者警告是否使用nullpointer调用了func-是的,我知道,编译器不需要执行任何操作……)
C17第6.7.6.3节功能声明符(包括原型)第7段规定:
参数声明为“类型数组”应调整为“类型的合格指针”,其中类型限定符(如果有)是在数组类型派生的[和]中指定的那些。如果关键字static也出现在数组类型派生的[和]中,则对于函数的每次调用,相应实际参数的值应提供对数组第一个元素的访问,该元素至少具有指定数量的元素通过大小表达式。
在上述定义的情况下,必须使用的值ptr
提供对至少具有元素的数组的第一个元素的访问1
。因此,很明显参数不能为空。
我正在徘徊的是,使用不属于数组一部分的int地址调用这样的函数是否有效。例如(从func
上面的定义来看)这在技术上是有效的还是未定义的行为:
int var = 5;
func(&var);
我知道这几乎不会成为问题,因为我所知没有编译器会区分指向int数组成员的指针和指向局部int变量的指针。但是考虑到c中的指针(至少从标准的角度来看)可以不仅仅是具有特殊编译时间类型的某个整数,所以如果标准中有某些部分,我徘徊了,这使它有效。
我确实怀疑它实际上是无效的,因为第6.5.6节“加法运算符”第8段包含:
[...]如果指针操作数和结果都指向同一数组对象的元素,或者指向数组对象的最后一个元素之后,则求值不应产生溢出;否则,行为是不确定的。[...]
对我来说,听起来好像任何指向数组元素添加的指针1
都是有效的操作,而添加1
到指向常规变量的指针将是UB 。这意味着,指向数组元素的指针与指向普通变量的指针之间确实存在差异,这会使摘要高于UB ...
就这些运算符而言,指向不是数组元素的对象的指针的行为与指向长度为1且对象类型为其元素类型的数组的第一个元素的指针的行为相同。
由于该段以“出于这些运营商的目的”开头,我怀疑在其他情况下会有所不同吗?
标准中是否有某些部分规定,指向类型为正则变量的T
指针与长度为1的数组(类型为array)的元素的指针之间没有区别T[1]
?
从表面上看,我认为你有一点。我们并没有真正将指针传递给数组的第一个元素。如果我们在真空中考虑标准,则可能是UB。
除了您在6.5.6中引用的段落外,标准中没有段落将单个对象等同于一个元素的数组。而且不应该这样,因为两者是不同的。当一个数组(甚至包含一个元素)出现在大多数表达式中时,都会隐式转换为指针。显然,这不是大多数对象类型拥有的属性。
static
关键字的定义[]
提到要传递的指针必须指向至少包含一定数量元素的数组的初始元素。您引用的措词还有另一个问题,那
int a[2];
func(a + 1);
显然,传递的指针不是数组的第一个元素。如果我们对6.7.6.3p7进行字面解释,也就是UB。
放开static
关键字,当函数接受指向对象的指针时,对象是否是数组(任何大小)的成员,仅在以下一种情况下很重要:指针算术。
在没有指针算术的情况下,使用指针访问数组的元素或独立对象时,行为没有明显区别。
我认为6.7.6.3p7背后的意图考虑了指针算法。因此,所提到的语义与尝试对传递给函数的指针进行指针算术相结合。
static 1
简单地自然而然地使用有用的成语,也许不是从一开始就打算这样做。虽然规范性文本可能会稍作修改,但我认为其意图很明确。这并不意味着是标准定义的行为。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句