我有下一个成员函数:
template <typename T>
inline T Foo::Read(const DWORD addr) const // Passing by value.
{
T buffer;
ReadProcessMemory(m_processHandle, (LPVOID)addr, &buffer, sizeof(T), NULL);
return buffer;
}
如果我没记错的话,当编译器内联函数时,它将避免调用该函数,并将被调用函数的代码放入调用者函数中。
因此,在调用方函数(假设返回类型为整数)中,我想要类似以下内容:
ReadProcessMemory(m_processHandle, (LPVOID)addr, &bufferOfTheCaller, sizeof(int), NULL);
我对此有三个问题:
1)我们从函数返回的变量会发生什么?
不是在运行时执行变量 buffer 的声明吗?2)在这种情况下, ReadProcessMemory 是WinAPI中的一个巨大函数,编译器是否仍可以内联此函数?
3)将成员函数保留在类定义内,并使用关键字 inline 在类定义外进行声明有什么区别?如果要使用inline关键字,是否必须将内联函数放在同一文件.h或?
答案 0 :(得分:4)
请务必注意,inline
关键字与内联函数调用无关。它所做的一切就是只要所有定义都相同,就可以在多个翻译单元中定义函数。
inline
关键字的作用是让您在头文件中定义一个函数,该文件将包含在多个翻译单元中。这可能会给编译器提供更好的机会内联调用该函数,因为它具有在多个转换单元中可用的完整定义,但这不是命令,甚至不是您希望编译器这样做的提示。编译器将自行决定是否应该内联对任何给定函数的调用。如果确实要强制对内联函数的调用,则可以使用特定于编译器的扩展,但这不是inline
关键字的作用。
这样,我将补充一点,内联函数调用的编译器根本不会改变C ++的规则。它不是文本替换,就像预处理器宏一样。编译器将弄清楚如何将逻辑从被调用函数插入到调用方中。那时,诸如C ++变量之类的东西实际上并不存在。如果您的通话看起来像这样:
int someValue = myFoo.Read(someAddress);
然后,编译器可以轻松地将其转换为如下形式:
int someValue;
ReadProcessMemory(myFoo.m_processHandle, (LPVOID)someAddress, &someValue, sizeof(int), NULL);
由于按规则。这两个代码片段都具有相同的可观察行为,因此编译器可以在它们之间自由转换。
答案 1 :(得分:3)
从函数返回的变量会发生什么?
它将被销毁,因为返回值已被函数调用表达式丢弃。
不是在运行时执行变量缓冲区的声明吗?
声明在编译时发生。
在这种情况下,ReadProcessMemory是WinAPI中的一个巨大函数,编译器是否应该仍然可以内联此函数?
如果编译器知道函数的定义,则它可以内联扩展它。是否应该这样做还是取决于许多因素。函数的大小是一种试探法,可能会影响编译器的选择。
将成员函数定义保留在类定义内部,并使用关键字inline在类定义外部进行声明之间有什么区别?
在一种情况下,定义在类内部,而在另一种情况下,定义在类外部。没有其他区别。
如果要使用inline关键字,是否必须将内联函数放在同一文件.h或?
答案 2 :(得分:2)
如果我没记错的话,当编译器内联函数时,它将避免调用该函数,并将被调用函数的代码放入调用者函数中。
是的,但是inline
与此无关。
1)我们从函数返回的变量会发生什么?变量缓冲区的声明不是在运行时执行的吗?
无论是否进行内联,编译器都必须为buffer
保留一些空间,通常是在堆栈上。
换句话说,没有bufferOfTheCaller
。如果您的函数是内联的,则buffer
将位于调用者的堆栈框架中;否则,它将被放置在被调用者的堆栈框架中。
2)在这种情况下,ReadProcessMemory是WinAPI中的一个巨大函数,编译器是否应该仍然可以内联此函数?
ReadProcessMemory
的实现有多大无关紧要,您的代码仅对其执行函数调用,这很小。优化的编译器很可能会内联您的函数。
3)将成员函数定义在类定义内部并用关键字inline在类定义外部进行声明之间有什么区别?
没有区别。
如果要使用inline关键字,是否必须将内联函数放在同一文件.h或?
inline
关键字与内联无关。如果要将函数的定义放在头文件中,则可能需要使用inline
来防止重新定义错误。