__declspec(naked) void printfive() {
int i = 5;
printf("%i\n", i);
}
由于某种原因,此代码有效,但我不明白i
的存储位置?在调用函数的框架中?它变成全球变量?如果它存储在调用者的框架中,那么编译器如何知道位移,因为您可以从具有不同帧大小和局部变量的不同函数调用printfive()
。如果它是全局的,或类似static
之类的东西,我试图去递归,我可以看到变量没有改变,它确实不是真正的本地。但很明显,没有入门代码(prolog)。好吧,我理解,没有prolog,没有框架,没有更改寄存器,但这是值,但范围会发生什么?是否在任何引用中定义了此说明符的行为?这是C ++标准的一部分吗?如果你大多在它们里面使用asm {}
(或者使用asm来调用它们并希望确保函数没有过度优化),那么这类函数很棒,但是你可以和C ++混合使用。但这有点大脑扭曲。
答案 0 :(得分:3)
我知道这个话题已经有好几年了,这是我自己的答案。
由于没有参考Microsoft文档中有关此主题的内容,因此对于那些想了解更多有关Keltar所说的需要或不需要的东西的人,here是Microsoft文档,它解释了Keltar所做的大部分事情。在这里解释。
根据Microsoft文档,应避免使用。
以下规则和限制适用于裸函数:
- 不允许使用return语句。
- 不允许使用结构化异常处理和C ++异常处理构造,因为它们必须在堆栈框架中展开。
- 出于同样的原因,禁止使用任何形式的setjmp
- 禁止使用_alloca函数。
- 为确保在序言序列之前没有局部变量的初始化代码,初始化的局部变量不 在功能范围内允许。特别是C ++的声明
功能范围内不允许使用对象。但是,可能有 嵌套作用域中的已初始化数据。- 不建议使用帧指针优化(/ Oy编译器选项),但是对于裸函数会自动取消优化。
- 您不能在函数词法范围内声明C ++类对象。但是,您可以在嵌套块中声明对象。
答案 1 :(得分:1)
来自gcc手册:
使用此属性...表示指定的函数不需要编译器生成的序言/结尾序列。程序员需要提供这些序列。可以安全地包含在裸函数中的唯一语句是没有操作数的asm语句。应避免使用所有其他语句,包括声明局部变量,if语句等。应该使用裸函数来实现汇编函数的主体,同时允许编译器为汇编器构造必需的函数声明。
它不是标准的(以及任何 __declspec
或__attribute__
)
答案 2 :(得分:0)
进入或退出函数时,编译器会添加代码以帮助传递或参数。当一个函数被声明为裸体时,会生成非参数变量赋值代码,如果要获取任何参数,则需要直接访问相关的寄存器或堆栈(取决于ABI定义的调用约定)。 / p>
在您的情况下,您没有将参数传递给函数,因此即使函数声明为裸,您的代码仍然有效。如果你想看到区别,请看看拆解器。