C 函数指针算法

C 函数指针算法,c,pointers,C,Pointers,为什么这段代码可以正确编译函数指针上的算术运算 void my_func(void); int main(void) { void (*p)(void) = &my_func; // Compile (void) (*p); (void) *(p + 0); // Does not compile (void) p[0]; return 0; } 我一直认为p[0]=*(p+0)适用于完整类型。显然,p[0]!=*(p+0

为什么这段代码可以正确编译函数指针上的算术运算

void my_func(void);

int main(void)
{
    void (*p)(void) = &my_func;

    // Compile
    (void) (*p);
    (void) *(p + 0);

    // Does not compile
    (void) p[0];

    return 0;
}
我一直认为
p[0]=*(p+0)
适用于完整类型。显然,
p[0]!=*(p+0)
用于函数指针

注意:C标准没有明确禁止函数指针算法。它一点也不禁止。它说它是未定义的。那是另一回事。许多符合标准条款的语言扩展都有标准未定义的行为


此外,如果使用指向不完整类型的指针,则我们有:

int main(void)
{
    int (*p)[];

    // Compile
    (void) (*p);

    // Does not compile
    (void) *(p + 0);
    (void) p[0];

    return 0;
}

然后有效地
p[0]=*(p+0)
,因为两者都会在指向不完整类型的指针上触发相同的算术错误。尽管在这里,C标准明确禁止对指向不完整类型的指针进行算术运算。

数组订阅
a[b]
需要
a
b
中的一个作为指向完整对象类型的指针。函数类型不是完整的对象类型

6.5.2.1阵列订阅

约束条件

1其中一个表达式的类型为“指向完整对象类型的指针”,另一个表达式的类型为整数,结果的类型为“类型”

请注意,
p+0
出于同样的原因也应该是一个错误,我认为编译器无法生成所需的诊断消息。我问这个为什么不生产:

6.5.6加法运算符

约束条件

对于加法,两个操作数都应具有算术类型,或者一个操作数具有算术类型 操作数应为指向完整对象类型的指针,另一个为 应具有整数类型。(增加等于增加1。)


你不能有函数指针算法-它是UB。我想知道第一件事是否可行,因为编译器实现了它的+0,并简单地将它从*(p+0)更改为*p。@anarrayofffunctions是的,你可以。它是由GCC和Clang作为扩展实现的。我不清楚为什么
p+0
会编译,因为
+
的条件是两个参数都是算术类型,或者一个是指向完整对象类型的指针,所以我认为这个答案中缺少了一些东西。那么
*(p+0)
编译只是因为这是一个由编译器处理的错误/警告,并且根据C标准仍然是未定义的行为?因为是,C标准明确禁止函数指针算术。@eigenslacker:C标准没有明确禁止函数指针算术。它一点也不禁止。它说它是未定义的。那是另一回事。许多符合标准条款的语言扩展都有标准未定义的行为。如果“未定义”意味着“禁止”,那就不可能了。它并不意味着“禁止”。@EricPostpischil我相信C标准确实禁止函数指针算法,编译器需要生成错误消息。我问了标准的链接。@Egenslacker我想你是对的,标准禁止它,但我认为编译器也需要生成诊断消息,因为它违反了约束。我问了这个问题,并链接到标准: