C - GCC 优化标志:它"fixes"代码



基本上,我有一段代码可以将函数指针转换为对象指针类型。在编译过程中,我看到这个警告

ISO C forbids conversion of function pointer to object pointer type

如果优化标志处于活动状态,例如,则代码可以正常工作

gcc -O1

一旦我删除了所有的优化,代码就会中断,例如

gcc -O0 -ggdb

经过几个月的研究,我发现了破坏代码的问题,但我不明白为什么发布构建(优化活动(有效。

基本上,我在代码中拥有的是一个数组,其中数组中的每个对象都是一个函数指针。这些函数是用宏定义的,并且具有void返回类型。为了通过数组访问函数,我需要用(void *)强制转换函数定义,而这正是编译器抱怨的地方。

优化标志是幕后的魔法吗?

EDIT:添加了代码示例

下面是一个代码示例:

static const struct
{
UINT8       parameter1;
UINT8       parameter2;
UINT8       parameter3;
void *      function1;
void *      function2;
} handlerList[] =
{
{ 8, 12, 0, (void *)FUNC1, (void *)FUNC2 },
{ 12, 24, 1, (void *)FUNC3, (void *)FUNC4 },
{ 3, 12, 2, (void *)FUNC5, (void *)FUNC6 },
};

FUNC1FUNC2。。。是定义具有void返回类型的所有函数的宏。

当我必须将函数指针传递(返回(到其他代码时,我使用以下代码段:

return handlerList[i].function1

通过哪种方式,我可以定义函数指针数组并调用它,而无需将函数指针转换为对象指针?

编辑:添加编译标志

它不适用于gcc -O0 -ggdb,但它可以工作,只使用gcc -O0 -ggdb -ftree-coalesce-vars重建包含示例中代码的源代码。

ftree联合变量的作用是什么?

您没有显示您的代码,但我会尝试猜测。假设你有:

int main(void)
{
int *p = main; // This is UB!
*p = *p;
return 0;
}

p是一个对象类型指针,但它包含函数指针值。在许多体系结构中,代码和数据位于同一地址空间中,但带有代码部分的页面是只读的。使用-O1编译器,只需将*p=*p作为无用的操作消除,就不会发生任何事情。使用-O0编译器生成尝试写入只读页的代码。

C标准没有定义函数指针和数据指针之间的转换的原因是它们可能有不同的表示形式,包括不同的大小。如果目标体系结构上的代码和数据指针大小恰好相同,大多数编译器都会生成正确的代码,但警告很重要,您应该使用适当的原型将function1function2定义为函数指针。

在您的情况下,这不是对您的观察结果的可能解释,但不清楚在编写{ 8, 12, 0, (void *)FUNC1, (void *)FUNC2 },时会发生什么,因为作为宏的FUNC1FUNC2可能根本不是函数表达式。

最新更新