gpt4 book ai didi

c++ - Visual C++ ~ 不内联简单的 const 函数指针调用

转载 作者:可可西里 更新时间:2023-11-01 16:42:39 25 4
gpt4 key购买 nike

亲爱的 StackOverflowers,

我得到了一段在 Microsoft Visual Studio C++ 2012 上编译的简单代码:

int add(int x, int y)
{
return x + y;
}

typedef int (*func_t)(int, int);

class A
{
public:
const static func_t FP;
};

const func_t A::FP = &add;

int main()
{
int x = 3;
int y = 2;
int z = A::FP(x, y);
return 0;
}

编译器生成如下代码:

int main()
{
000000013FBA2430 sub rsp,28h
int x = 3;
int y = 2;
int z = A::FP(x, y);
000000013FBA2434 mov edx,2
000000013FBA2439 lea ecx,[rdx+1]
000000013FBA243C call qword ptr [A::FP (013FBA45C0h)]
return 0;
000000013FBA2442 xor eax,eax
}

我在“完全优化”(/Obx 标志)和“任何合适的”内联函数扩展上编译了它。 (/Ob2 标志)

我想知道为什么编译器不特别内联这个调用,因为它是常量。你们有没有人知道为什么它没有内联,以及是否可以让编译器内联它?

基督徒

编辑:我现在正在运行一些测试,MSVC 也无法内联函数指针:

-我将 const 指针移出类并使其成为全局指针。

-我将 const 指针移出类并将其置于 main 中。

-我将指针设置为非常量并将其移入本地。

-当我将返回类型设置为 void 并且不给它任何参数时

我开始相信 Microsoft Visual Studio 根本无法内联函数指针...

最佳答案

问题不在于内联,编译器一有机会就会这样做。问题是 Visual C++ 似乎没有意识到指针变量实际上是一个编译时常量。

测试用例:

// function_pointer_resolution.cpp : Defines the entry point for the console application.
//

extern void show_int( int );

extern "C" typedef int binary_int_func( int, int );

extern "C" binary_int_func sum;
extern "C" binary_int_func* const sum_ptr = sum;

inline int call( binary_int_func* binary, int a, int b ) { return (*binary)(a, b); }

template< binary_int_func* binary >
inline int callt( int a, int b ) { return (*binary)(a, b); }

int main( void )
{
show_int( sum(1, 2) );
show_int( call(&sum, 3, 4) );
show_int( callt<&sum>(5, 6) );
show_int( (*sum_ptr)(1, 7) );
show_int( call(sum_ptr, 3, 8) );
// show_int( callt<sum_ptr>(5, 9) );
return 0;
}

// sum.cpp
extern "C" int sum( int x, int y )
{
return x + y;
}

// show_int.cpp
#include <iostream>

void show_int( int n )
{
std::cout << n << std::endl;
}

函数被分成多个编译单元,以便更好地控制内联。具体来说,我不想内联 show_int,因为它会使汇编代码变得困惑。

第一个问题是有效代码(注释行)被 Visual C++ 拒绝。 G++ has no problem with it ,但 Visual C++ 提示“预期的编译时常量表达式”。这实际上是对所有 future 行为的良好预测。

启用优化和正常编译语义(无跨模块内联),编译器生成:

_main   PROC                        ; COMDAT

; 18 : show_int( sum(1, 2) );

push 2
push 1
call _sum
push eax
call ?show_int@@YAXH@Z ; show_int

; 19 : show_int( call(&sum, 3, 4) );

push 4
push 3
call _sum
push eax
call ?show_int@@YAXH@Z ; show_int

; 20 : show_int( callt<&sum>(5, 6) );

push 6
push 5
call _sum
push eax
call ?show_int@@YAXH@Z ; show_int

; 21 : show_int( (*sum_ptr)(1, 7) );

push 7
push 1
call DWORD PTR _sum_ptr
push eax
call ?show_int@@YAXH@Z ; show_int

; 22 : show_int( call(sum_ptr, 3, 8) );

push 8
push 3
call DWORD PTR _sum_ptr
push eax
call ?show_int@@YAXH@Z ; show_int
add esp, 60 ; 0000003cH

; 23 : //show_int( callt<sum_ptr>(5, 9) );
; 24 : return 0;

xor eax, eax

; 25 : }

ret 0
_main ENDP

使用 sum_ptr 和不使用 sum_ptr 之间已经存在巨大差异。使用 sum_ptr 的语句生成间接函数调用 call DWORD PTR _sum_ptr 而所有其他语句生成直接函数调用 call _sum,即使源代码使用函数指针。

如果我们现在通过使用 /GL 编译 function_pointer_resolution.cpp 和 sum.cpp 并使用 /LTCG 链接来启用内联,我们会发现编译器会内联所有直接调用。间接调用保持原样。

_main   PROC                        ; COMDAT

; 18 : show_int( sum(1, 2) );

push 3
call ?show_int@@YAXH@Z ; show_int

; 19 : show_int( call(&sum, 3, 4) );

push 7
call ?show_int@@YAXH@Z ; show_int

; 20 : show_int( callt<&sum>(5, 6) );

push 11 ; 0000000bH
call ?show_int@@YAXH@Z ; show_int

; 21 : show_int( (*sum_ptr)(1, 7) );

push 7
push 1
call DWORD PTR _sum_ptr
push eax
call ?show_int@@YAXH@Z ; show_int

; 22 : show_int( call(sum_ptr, 3, 8) );

push 8
push 3
call DWORD PTR _sum_ptr
push eax
call ?show_int@@YAXH@Z ; show_int
add esp, 36 ; 00000024H

; 23 : //show_int( callt<sum_ptr>(5, 9) );
; 24 : return 0;

xor eax, eax

; 25 : }

ret 0
_main ENDP

底线:是的,编译器会通过编译时常量函数指针进行内联调用,只要该函数指针不是从变量中读取即可。函数指针的使用得到优化:

call(&sum, 3, 4);

但这并没有:

(*sum_ptr)(1, 7);

所有测试都使用 Visual C++ 2010 Service Pack 1 运行,为 x86 编译,在 x64 上托管。

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86

关于c++ - Visual C++ ~ 不内联简单的 const 函数指针调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16462800/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com