GCC优化标志:它“修复”代码

rnmwe5a2  于 2022-11-13  发布在  其他
关注(0)|答案(2)|浏览(169)

基本上,我有一段代码将函数指针转换为对象指针类型。

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 },
};

FUNC 1FUNC 2...是定义所有返回类型为void的函数的宏。

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

return handlerList[i].function1

用什么方法可以定义一个函数指针数组并调用它而不需要将函数指针转换为对象指针?

EDIT:已添加编译标志

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

e7arh2l6

e7arh2l61#

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

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

    return 0;
}

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

w1jd8yoj

w1jd8yoj2#

C标准没有定义函数指针和数据指针之间的转换的原因是它们可能有不同的表示形式,包括不同的大小。如果代码指针和数据指针在目标体系结构上碰巧有相同的大小,大多数编译器将生成正确的代码,但是警告是重要的,您应该使用适当的原型将function1function2定义为函数指针。
在您的例子中,这可能不是您观察到的结果的解释,但不清楚当您编写{ 8, 12, 0, (void *)FUNC1, (void *)FUNC2 },时会发生什么,因为FUNC1FUNC2作为宏,可能根本不是函数表达式。

相关问题