为什么允许指向内联函数的指针?

8 浏览
0 Comments

为什么允许指向内联函数的指针?

我有两个问题:

1)为什么C++中允许使用内联函数的指针?

我了解到内联函数的代码只会在函数调用语句中被复制,内联函数没有编译时的内存分配。那么为什么可以存在指向内联函数的指针,考虑到内联函数没有固定的内存地址呢?

2)考虑下面的代码:

inline void func()    
{
    int n=0;
    cout<<(&n);
} 

每次调用func()时,它不应该打印n的地址的不同值吗?

(因为我认为每次复制内联函数代码时,局部变量必须重新分配内存空间(而对于普通函数来说,是重新初始化))

我是一个初学者,我问这个问题是为了加强我的概念。如果我有任何错误,请纠正我。

0
0 Comments

为什么允许指向内联函数的指针?

在现代用法中,`inline`关键字与内联几乎没有任何关系 - 现代编译器自由地在你的背后内联(或不内联)函数,这些函数是优化技术的一部分。C++中的代码转换(包括内联)是在“as-if”规则下进行的,这基本上意味着编译器可以根据需要对代码进行转换,只要执行结果“as-if”原始代码按照编写的方式执行。这个规则推动了C++中的优化。

话虽如此,一旦函数的地址被取出,它就需要存在(即地址需要有效)。这可能意味着它不再内联,但仍然可能被内联(优化器将应用适当的分析)。

那么,为什么允许指向内联函数的指针存在,因为内联函数没有固定的内存地址呢?

不,这只是一个提示,与链接相关,与实际的内联无关。这推动了当前主要的用法,即在头文件中定义函数。

如果`func()`被调用多次,它不应该打印出不同的`n`的地址吗?

可能会打印出不同的值,`n`是一个局部变量,基于函数执行时的堆栈位置。也就是说,函数是内联的,它与链接相关,链接器将在翻译单元之间合并这些函数。

正如在评论中指出的:

如果示例更改为`static int n`,那么对该函数的每次调用都必须打印出一个常量值(在程序的单个运行中,当然是)...无论代码是否被内联。

这再次是链接要求对局部变量`n`的影响。它可能被内联,也可能生成一个非内联版本。调用来自程序的不同部分的`func`可能会给出不同的`&n`的值。这个地址与“堆栈”的位置有关,而不是函数的地址。

如果示例更改为`static int n`,那么对该函数的每次调用都必须打印出一个常量值(在程序的单个运行中,当然是)...无论代码是否被内联。

0
0 Comments

为什么C++允许指向内联函数的指针?

内联函数就像其他任何函数一样,指向它们是可以的,内联函数在这方面并不特殊。

我读到过内联函数的代码只是被复制到调用语句中,而且在编译时不会分配内存。

你(以及你可能读到的材料)混淆了两个相关但名称相似的概念。

内联函数在使用它的所有翻译单元中都定义,而非内联函数仅在一个翻译单元中根据一次定义规则定义。这就是内联函数声明的含义;它放松了一次定义规则,并且还要求在使用它的所有翻译单元中定义它(如果不放松一次定义规则,则这是不可能的)。

内联扩展(或内联)是一种优化,通过将被调用的函数复制到调用者的框架中,避免了函数调用。无论函数是否被声明为内联,函数调用都可以扩展内联。而被声明为内联的函数不一定被内联展开。

然而,如果函数在翻译单元中没有定义(除非链接时优化执行扩展),则无法在该翻译单元中将函数内联展开。因此,内联声明允许的在所有调用它的翻译单元中定义函数的要求,也使得通过允许在调用它的所有翻译单元中定义函数来实现函数的内联展开。但是,这种优化并不保证。

内联展开确实会导致局部变量位于调用者的框架中,是的。但是,如果调用来自不同的框架,它们的位置将不同,而不管是否进行了展开。

通常会生成任何已经内联展开的函数的常规非展开版本。如果取函数的地址,它将指向该非展开函数。如果编译器可以证明对函数的所有调用都是内联的,编译器可能选择根本不提供非展开版本。这要求函数具有内部链接,并且取函数地址通常使得这种证明非常困难或不可能。

对于对我来说新颖、有用且简洁的真正含义的内联特性的表述,我给你+1:它"放松了一次定义规则"。这对于C来说比C++更加适用,因为C不要求所有相同函数的内联定义是相同的。

好吧,现在我有点困惑了。根据你在我以前的一个问题上的回答(实际上,我一直把它保持在一个标签页中,因为我觉得我还没有完全理解它):“不管是内联的还是不内联的,C都不允许在贡献到同一个程序或库的翻译单元中有同名的多个外部定义。”所以听起来你在说内联在C中并没有放松一次定义规则。但是根据你上面的评论,听起来你又在说它放松了一次定义规则……?

对于C来说是这样的,没有不一致。C++和C在函数的“外部定义”和具有外部链接的函数的定义之间有一个微妙而令人困惑的区别。区别在于函数是否在同一翻译单元中被声明为内联。如果是的话,那么定义就不是外部定义,因此不能将其链接到其他翻译单元的调用中,并且不会与函数的其他定义冲突,即使函数具有外部链接。

感谢你的澄清。在你的最后一句话中,当你说“即使函数具有外部链接”时,一个函数具有外部函数的定义,但它的定义是内联的(因此不是内部定义),这到底意味着什么?这是否只意味着符号存在于(即在)多个翻译单元中,并且至少有一个外部定义,但存在一个存在非外部定义(内联定义)的翻译单元?

额,而不是“因此不是外部定义”。

对于C来说,是的,就是这样。然而,在C++中,如果有一个具有外部链接的内联函数定义,那么在程序中不应该有同名函数的外部定义,尽管可能会有其他内联定义。C++还要求所有相同函数的内联定义是相同的。

编译器可以并且通常会避免在一个翻译单元中发出具有大于内部链接的函数的外部副本,如果它们可以证明其地址在该翻译单元中不被使用。如果其他翻译单元需要该副本,它将发出它 - 作为模糊符号,以防多个翻译单元发出它。

为什么C++允许指向内联函数的指针?

内联函数就像其他任何函数一样,指向它们是可以的,内联函数在这方面并不特殊。

我读到过内联函数的代码只是被复制到调用语句中,而且在编译时不会分配内存。

你(以及你可能读到的材料)混淆了两个相关但名称相似的概念。

内联函数在使用它的所有翻译单元中都定义,而非内联函数仅在一个翻译单元中根据一次定义规则定义。这就是内联函数声明的含义;它放松了一次定义规则,并且还要求在使用它的所有翻译单元中定义它(如果不放松一次定义规则,则这是不可能的)。

内联扩展(或内联)是一种优化,通过将被调用的函数复制到调用者的框架中,避免了函数调用。无论函数是否被声明为内联,函数调用都可以扩展内联。而被声明为内联的函数不一定被内联展开。

然而,如果函数在翻译单元中没有定义(除非链接时优化执行扩展),则无法在该翻译单元中将函数内联展开。因此,内联声明允许的在所有调用它的翻译单元中定义函数的要求,也使得通过允许在调用它的所有翻译单元中定义函数来实现函数的内联展开。但是,这种优化并不保证。

内联展开确实会导致局部变量位于调用者的框架中,是的。但是,如果调用来自不同的框架,它们的位置将不同,而不管是否进行了展开。

通常会生成任何已经内联展开的函数的常规非展开版本。如果取函数的地址,它将指向该非展开函数。如果编译器可以证明对函数的所有调用都是内联的,编译器可能选择根本不提供非展开版本。这要求函数具有内部链接,并且取函数地址通常使得这种证明非常困难或不可能。

对于对我来说新颖、有用且简洁的真正含义的内联特性的表述,我给你+1:它"放松了一次定义规则"。这对于C来说比C++更加适用,因为C不要求所有相同函数的内联定义是相同的。

好吧,现在我有点困惑了。根据你在我以前的一个问题上的回答(实际上,我一直把它保持在一个标签页中,因为我觉得我还没有完全理解它):“不管是内联的还是不内联的,C都不允许在贡献到同一个程序或库的翻译单元中有同名的多个外部定义。”所以听起来你在说内联在C中并没有放松一次定义规则。但是根据你上面的评论,听起来你又在说它放松了一次定义规则……?

对于C来说是这样的,没有不一致。C++和C在函数的“外部定义”和具有外部链接的函数的定义之间有一个微妙而令人困惑的区别。区别在于函数是否在同一翻译单元中被声明为内联。如果是的话,那么定义就不是外部定义,因此不能将其链接到其他翻译单元的调用中,并且不会与函数的其他定义冲突,即使函数具有外部链接。

感谢你的澄清。在你的最后一句话中,当你说“即使函数具有外部链接”时,一个函数具有外部函数的定义,但它的定义是内联的(因此不是内部定义),这到底意味着什么?这是否只意味着符号存在于(即在)多个翻译单元中,并且至少有一个外部定义,但存在一个存在非外部定义(内联定义)的翻译单元?

额,而不是“因此不是外部定义”。

对于C来说,是的,就是这样。然而,在C++中,如果有一个具有外部链接的内联函数定义,那么在程序中不应该有同名函数的外部定义,尽管可能会有其他内联定义。C++还要求所有相同函数的内联定义是相同的。

编译器可以并且通常会避免在一个翻译单元中发出具有大于内部链接的函数的外部副本,如果它们可以证明其地址在该翻译单元中不被使用。如果其他翻译单元需要该副本,它将发出它 - 作为模糊符号,以防多个翻译单元发出它。

0
0 Comments

为什么允许指向内联函数的指针?

现在使用inline的主要原因是允许在头文件中使用函数体。在函数中使用inline关键字告诉链接器,跨多个翻译单元的所有函数实例可以合并; 在多个单元中包含非内联函数的头文件会导致未定义行为,因为违反了一定义规则。

C++17还添加了内联变量,其具有相同的属性,即变量可以在头文件中定义,并且所有定义都由链接器合并,而不会导致一定义规则的违反。

你所说的“代码被复制到调用函数中”的问题被称为内联,与inline关键字无关。编译器将根据优化设置决定是否对非内联函数和内联函数执行此操作。

0