- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
亲爱的 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/
标记为家庭作业,因为这是我写的期中问题,但我不明白答案。我被要求在以下语句中解释每个 const 的用途: const char const * const GetName() const { ret
const int* const fun(const int* const& p) const; 我试图弄清楚这个给定函数原型(prototype)的输入参数。我在这两个之间争论,不确定哪个是正确的。
下面的代码用于在同时存在 const 和非 const getter 时减少代码重复。它从非 const 创建 const 版本。我搜索了一下,很多人说我应该从 const 创建非 const 版本。
据我所知,TypeScript 查看了 const string变量作为一个不可变的类型变量,只有那个值,没有其他可能的值。一直以为加as const那是多余的。 为什么我在示例的第二部分得到以下内容
我有一个具有以下签名的方法: size_t advanceToNextRuleEntryRelatedIndex( size_t index, size_t nStrings, char const
首先,有什么区别: (1) const char* (2) char const* (3) const char const* 我相当确定我完全理解这一点,但我希望有人能具体地给我一个句子,这样它就会
这里是新手! 我正在阅读一段代码,我看到作者经常写一个成员函数作为 const int func (const scalar& a) const // etc 你看这里有三个const,现在我明白了中
我总是搞乱如何正确使用 const int*、const int * const 和 int const *。是否有一套规则来定义你可以做什么和不能做什么? 我想知道在赋值、传递给函数等方面所有该做和
我见过人们将 const 用作函数参数的代码。使用 const* 与 const * const 有什么好处?这可能是一个非常基本的问题,但如果有人能解释一下,我将不胜感激。 Bool IsThisN
我总是搞乱如何正确使用 const int*、const int * const 和 int const *。是否有一套规则来定义你可以做什么和不能做什么? 我想知道在赋值、传递给函数等方面所有该做和
这个问题在这里已经有了答案: What is the difference between const int*, const int * const, and int const *? (23 个
如果引用的对象不是 const 对象,那么引用“const”关键字的目的是什么? r1 和 r2 的作用(如下)有什么不同吗? int i = 42; // non const object cons
friend 让我解释原因 const const const const const int const i = 0; 是有效的语法。我拒绝对这个话题有任何想法。虽然我很好奇它是否只是语法问题? 编
我总是搞砸如何正确使用 const int*、const int * const 和 int const *。是否有一套规则来定义你能做什么和不能做什么? 我想知道在分配、传递给函数等方面的所有注意事
常量在 const char* push(const char * const &&_data); 表示无法更改引用的内容。为什么我不能将 const char* 传递给 push? 最佳答案 您的代
我有一个关于在函数参数中涉及指针的最佳实践以及它们是否应该指定为 *const 的问题或 const *const .我知道对于 const 的使用或过度使用存在不同的意见。 ,但至少有一些用途是捕捉
我目前正在为我的类(class)写一个作业,它应该充当一个非常基本的外壳。我快完成了,但是我遇到了 execvp 和我的参数字符数组的问题。这是我的代码的一小段。 //Split the left c
所以,我知道了char const *、char * const 和char const * const 之间的区别。那些是: char* the_string : I can change the
我正在运行一些示例程序以重新熟悉 C++,我遇到了以下问题。首先,这里是示例代码: void print_string(const char * the_string) { cout << t
我正在为系统中的编译错误而苦苦挣扎,这是代码 struct Strless : public binary_function { public : bool operator()(cons
我是一名优秀的程序员,十分优秀!