简体   繁体   English

C语言编程。 为什么函数指针会破坏优化

[英]C programming. Why do function pointers destroy optimization

I've had a love/hate relationship with C programming with function pointers. 我对使用函数指针的C编程有一种爱与恨的关系。 I mainly work with microcontrollers where flash space is limited, so obviously I take a strong interest in using optimizations. 我主要使用闪存空间有限的微控制器,因此显然我对使用优化非常感兴趣。 One the one hand, function pointers make my life SO easy as I can write a hardware-portable software module in which the user can provide function callbacks for doing hardware-dependent things (ex: User callback to write byte to a serial port). 一方面,函数指针使我的生活变得如此轻松,因为我可以编写一个硬件可移植的软件模块,在该模块中,用户可以提供函数回调来执行与硬件有关的事情(例如:用户回调以将字节写入串行端口)。 In this way, I can write code that is 95% platform independent and then it's a quick job to port to new hardware. 这样,我可以编写95%与平台无关的代码,然后移植到新硬件是一项快速的工作。

On the other hand, I have noticed that a lot of compilers throw optimizations out the window when they see any use of function pointers. 另一方面,我注意到许多编译器在看到任何使用函数指针的情况下都会抛弃优化。 For example, I wrote a fairly generic function that accepts an enumerated type as an argument and then has a giant switch/case statement for each enumerated type selection to configure registers and such, depending on which enumerated type the user passed into the function.I'm calling this function once with a constant literal, IE something that should never change. 例如,我编写了一个相当通用的函数,该函数接受枚举类型作为参数,然后对于每个枚举类型选择都有一个巨大的switch / case语句来配置寄存器等,具体取决于用户传递给函数的枚举类型。会使用常量文字(即永远不变的东西)调用此函数一次。 The built binary seems to be including op codes to handle every single switch/case selection, even though all but one of the case selections should be deemed "dead code." 内置的二进制文件似乎包含处理每个开关/案例选择的操作码,即使除了案例选择之一以外的所有案例都应视为“死代码”。 I played with the different optimization settings, but to get the smallest binary I had to completely comment out every "case" block except the one I needed, and this reduced by flash utilization by about 1k bytes. 我使用了不同的优化设置,但是要获得最小的二进制文件,我必须完全注释掉除所需的每个“ case”块之外的内容,这将使闪存利用率降低约1k字节。 If I don't use function pointers, it has no problem optimizing this code. 如果我不使用函数指针,则优化此代码没有问题。

The strange part is that I have never utilized a function pointer in my code with that function's prototype. 奇怪的是,我从未在函数原型中使用代码中的函数指针。 And for the function pointer prototypes I had used, the pointer was established once at startup to a static function and then never again (another constant literal assignment). 对于我曾经使用过的函数指针原型,指针在启动时就建立了一个静态函数,然后再也没有建立(另一个常量文字赋值)。 I know I could probably accomplish the same design goals using #defines all over the place, but it irks me that the tools can't interpret what is possible/impossible based on my code. 我知道我可以在整个地方使用#defines来实现相同的设计目标,但是令我感到困扰的是,这些工具无法根据我的代码解释什么是可能/不可能。

I can see the case where you have a function pointer, and some dynamic thing that you can't predict for executes the function (ie a person types into a terminal and you don't know in advanced what the arguments will be). 我可以看到这样的情况:您有一个函数指针,而某些无法预测的动态事物会执行该函数(即,一个人键入一个终端,并且您不知道高级参数是什么)。

Is there any good reason why compilers struggle to optimize when function pointers are used, even in a predictable way? 是否有充分的理由说明编译器在使用函数指针时仍难以进行优化,即使是以可预测的方式进行优化也是如此?

Without seeing your code, I can't draw any definitive conclusions, but here is what I know from my own experience. 没有看到您的代码,我无法得出任何明确的结论,但这是我从自己的经验中学到的。

Even if the function is static and only called once, the pointers are being initalised at runtime. 即使函数是静态的并且仅被调用一次,指针也会在运行时被初始化。 The compiler can't optimise away function pointers whose addresses are not known until runtime. 编译器无法优化其地址直到运行时才知道的函数指针。

It also can't optimise away function pointers when the functions exist in other translation units; 当函数存在于其他翻译单元中时,它也无法优化离开函数指针; it doesn't know where functions are if they're outside the translation unit, only that they've been declared; 它不知道函数在翻译单元之外是什么,只是它们已经被声明了。 it's the linker's job to handle that. 这是链接器的工作。 I believe it should be theoretically possible for LTO to handle this, but I'm not sure if any implementations do so. 我认为LTO在理论上应该可以处理此问题,但是我不确定是否有任何实现方法可以做到这一点。

However, some compilers can optimise function pointers (MSVC comes to mind) if it knows where all the addresses are, and if the function pointers are initalised at compile-time. 但是,如果某些编译器知道所有地址在哪里,并且在编译时是否初始化了函数指针,则可以优化函数指针(想到的是MSVC)。

The basic problem is separate compilation -- when you have a language (such as C) where different source files are compiled separately and later linked together by a separate linker, the compiler optimizer doesn't know about anything that is in other compilation units when it runs (those compilation units might not even have been written yet!), so it has no way of knowing that the pointer is not modified and/or the function is not called with any other argument. 基本问题是单独的编译-当您使用一种语言(例如C)来对不同的源文件进行单独编译,然后通过单独的链接器链接在一起时,编译器优化器将不了解其他编译单元中的任何内容。它会运行(那些编译单元甚至可能尚未编写!),因此它无法知道指针未修改和/或未使用任何其他参数调用该函数。

One possible solution to this is link-time optimization -- if your development suite supports it. 一种可能的解决方案是链接时间优化-如果您的开发套件支持的话。

Another is forcing everything into one compilation unit and making everything static so that the compiler knows no other compilation unit can refer to it. 另一个是将所有内容强制放入一个编译单元,并使所有内容static以便编译器知道其他编译单元无法引用它。 This may allow the optimizer to do a better job. 这可以使优化器做得更好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM