当我尝试构建此代码时
inline void f() {}
int main()
{
f();
}
Run Code Online (Sandbox Code Playgroud)
使用命令行
gcc -std=c99 -o a a.c
Run Code Online (Sandbox Code Playgroud)
我收到链接器错误(未定义引用f).如果我使用static inline或extern inline代替just inline,或者如果我使用-O(因此函数实际内联),则错误消失.
这种行为似乎在C99标准第6.7.4(6)段中定义:
如果转换单元中函数的所有文件范围声明都包含
inline函数说明符extern,则该转换单元中的定义是内联定义.内联定义不提供函数的外部定义,也不禁止另一个转换单元中的外部定义.内联定义提供了外部定义的替代,翻译器可以使用该定义在同一翻译单元中实现对该功能的任何调用.未指定对函数的调用是使用内联定义还是使用外部定义.
如果我理解了这一切,inline那么如果还有一个具有相同名称的外部函数,那么具有上例中定义的函数的编译单元只会一致地编译,而且我永远不知道我自己的函数或外部函数是否被调用.
这种行为不是完全愚蠢吗?在inline没有static或extern在C99中定义函数是否有用?我错过了什么吗?
当然我错过了什么,行为并不愚蠢.:)
正如Nemo所解释的那样,我们的想法是定义函数
inline void f() {}
Run Code Online (Sandbox Code Playgroud)
在头文件中只有一个声明
extern inline void f();
Run Code Online (Sandbox Code Playgroud)
在相应的.c文件中.只有extern声明才会触发生成外部可见的二进制代码.确实没有inline在.c文件中使用 - 它只在标题中有用.
正如Jonathan的回答中引用的C99委员会的基本原理所阐述的那样,inline所有关于编译器优化都需要在调用的站点上看到函数的定义.这只能通过将标题放在标题中来实现,当然,标题中的定义在编译器每次看到它时都不能发出代码.但由于编译器不是强制实际内联函数,因此必须在某处存在外部定义.
我想强制一个小函数不被编译为内联函数,即使它非常简单.我认为这对于调试目的很有用.有没有关键字可以做到这一点?
在我正在进行的GCC内联汇编实验中,我遇到了一个关于标签和内联代码的新问题.
考虑以下简单的跳转:
__asm__
(
"jmp out;"
"out:;"
:
:
);
Run Code Online (Sandbox Code Playgroud)
除了跳转到out标签外,这没有任何作用.这样,这段代码编译得很好.但是如果你把它放在一个函数中,然后用优化标志进行编译,编译器就会抱怨:"错误:符号'out'已经被定义了".
似乎正在发生的事情是编译器每次内联函数时都会重复此汇编代码.这会导致标签out重复,从而导致多个out标签.
那么,我该如何解决这个问题呢?在内联装配中是否真的不可能使用标签?关于GCC内联汇编的本教程提到:
因此,您可以将汇编放入CPP宏和内联C函数中,因此任何人都可以将其用作任何C函数/宏.内联函数非常类似于宏,但有时使用起来更干净.请注意,在所有这些情况下,代码将被复制,因此只应在该asm代码中定义本地标签(1:样式).
我试图找到有关这些"本地标签"的更多信息,但似乎无法找到与内联汇编有关的任何内容.看起来教程是说本地标签是一个数字后面跟冒号(比如1:),所以我尝试使用这样的标签.有趣的是,代码已编译,但在运行时它只是触发了分段错误.嗯...
那么任何建议,提示,答案......?
我写了一个与此类似的函数:
class abc {
private :
int m_var ;
public :
int func() { return m_var ; }
};
Run Code Online (Sandbox Code Playgroud)
当我尝试打印func()使用abc对象指针时gdb,它给出错误:
**Cannot evaluate function -- may be inlined**
如何从内联函数中打印值?
我很确定,应该在相应函数的出口处调用函数参数的析构函数.考虑5.2.2p4的C++ 11标准:
[...]参数的生命周期在定义它的函数返回时结束.[...]
但是,让我们试试这段代码:
#include <iostream>
using namespace std;
struct Logger {
Logger(int) { cout << "Construct " << this << '\n'; }
Logger(const Logger&) { cout << "Copy construct " << this << '\n'; }
~Logger() { cout << "Destruct " << this << '\n'; }
};
int f(Logger)
{
cout << "Inside f\n";
return 0;
}
int main()
{
f(f(f(10)));
}
Run Code Online (Sandbox Code Playgroud)
用gcc或clang编译后,输出如下:
Construct 0x7fffa42d97ff
Inside f
Construct 0x7fffa42d97fe
Inside f
Construct 0x7fffa42d97fd
Inside f
Destruct 0x7fffa42d97fd
Destruct 0x7fffa42d97fe …Run Code Online (Sandbox Code Playgroud) 我最近遇到了很多函数,其中gcc在x86上生成了非常糟糕的代码.他们都符合以下模式:
if (some_condition) {
/* do something really simple and return */
} else {
/* something complex that needs lots of registers */
}
Run Code Online (Sandbox Code Playgroud)
将简单的情况看作是一个非常小的东西,一半或更多的工作花在推动和弹出不会被修改的寄存器上.如果我手动编写asm,我会在复杂的情况下保存并恢复已保存的跨调用寄存器,并且在简单的情况下完全避免触及堆栈指针.
有没有什么方法可以让gcc变得更聪明并且自己做到这一点?最好使用命令行选项,而不是源代码中的丑陋黑客...
编辑:为了使它具体化,这里有一些非常接近我正在处理的一些函数:
if (buf->pos < buf->end) {
return *buf->pos++;
} else {
/* fill buffer */
}
Run Code Online (Sandbox Code Playgroud)
另一个:
if (!initialized) {
/* complex initialization procedure */
}
return &initialized_object;
Run Code Online (Sandbox Code Playgroud)
另一个:
if (mutex->type == SIMPLE) {
return atomic_swap(&mutex->lock, 1);
} else {
/* deal with ownership, etc. */
}
Run Code Online (Sandbox Code Playgroud)
编辑2:我应该首先提到:这些函数不能内联.他们有外部联系,他们是图书馆代码.允许它们在应用程序中内联将导致各种问题.
我正在使用gcc和-finline-functions优化发布版本.为了对抗代码膨胀,因为我在嵌入式系统上工作,我想说不要内联特定的功能.这样做的显而易见的方法是通过函数属性即属性(noinline).问题是,当我打开作为-O3开关一部分的全局-finline-functions优化时,这似乎不起作用.
它也与它被模板化有关,因为同一函数的非模板化版本没有内联,这是预期的.
有没有人知道如何在这个全局开关打开时控制内联?
这是代码:
#include <cstdlib>
#include <iostream>
using namespace std;
class Base
{
public:
template<typename _Type_>
static _Type_ fooT( _Type_ x, _Type_ y ) __attribute__ (( noinline ));
};
template<typename _Type_>
_Type_ Base::fooT( _Type_ x, _Type_ y )
{
asm("");
return x + y;
}
int main(int argc, char *argv[])
{
int test = Base::fooT( 1, 2 );
printf( "test = %d\n", test );
system("PAUSE");
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud) 是否可以阻止gcc编译器内联特定函数.如果是这样,怎么样?
不要告诉我降低优化级别.我想要所有的优化,但标记一个特定的函数不被编译器内联,就像变量的情况下的volatile一样.
我想要这样做的原因是因为我的函数使用内联汇编定义的标签,gcc在内联函数时会搞砸,因为内联会导致gcc创建该标签的多个实例.
我试图perf在 Ubuntu 20.04 上进行配置,但问题是许多函数没有出现在其中(可能是因为它们是内联的),或者只出现它们的地址(没有名称等)。我正在使用 CMake 的RelWithDebInfo构建。但有一些模板函数我不知道如何将其引入分析器结果中。我认为noinline如果这在 C++ 中对于模板函数是合法的,那么标记它们可能会有所帮助,但这会破坏代码库并且需要针对每个函数完成。有什么建议如何noinline同时实现所有功能吗?
我已经问了一个类似的问题,但这个问题有点不同
我不想为每个简单的c ++类编写.cpp文件.
当我在单个.hpp文件中编写类定义和声明时,链接器会抱怨成员函数的多个定义,这些函数没有在类的主体内部实现或者使用内联键盘定义.
例如,这将起作用,但成员函数将变为内联:
// log.hpp file
#pragma once
#include<iostream>
class log {
private:
static int m_cnt = 0;
public:
void log();
};
inline void log::log() {
std::cout << ++m_cnt << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
所以我使用模板来摆脱链接器投诉,并希望成员函数不会内联(是吗?):
// log.hpp file
#pragma once
#include<iostream>
template<typename T>
class log_t {
private:
static int m_cnt = 0;
public:
void log();
};
template<typename T>
void log_t<T>::log() {
std::cout << ++m_cnt << std::endl;
}
// some random type (int)
typedef log_t<int> log;
Run Code Online (Sandbox Code Playgroud)
然后我可以简单地在多个.cpp文件中使用日志类而不需要链接器投诉.
即使我使用这种方法会将成员函数变成内联吗?
struct X {
void * a;
void * b;
};
X foo( void * u, void * v);
Run Code Online (Sandbox Code Playgroud)
类型X的返回值的地址作为隐藏参数传递给foo()
如果使用-O0编译测试代码,则代码按预期工作
如何强制编译器不为foo()添加RVO(又名强制-fno-elide-constructors)?
Update1:代码必须适用于任意编译器(至少gcc,clang,msvc),示例代码:
void * vp = bar();
X x = foo( vp, 0);
x = foo( x.a, 0);
x = foo( x.a, 0);
Run Code Online (Sandbox Code Playgroud)
Update2:问题是,编译器优化了x的实例
X x = foo( vp, 0);
x = foo( x.a, 0);
x = foo( x.a, 0)
Run Code Online (Sandbox Code Playgroud)
要么
X x1 = foo( vp, 0);
X x2 = foo( x1.a, 0);
X …Run Code Online (Sandbox Code Playgroud) 我试图用zap_pte_rangemm/memory.c 跟踪函数perf.但功能没有列在perf probe -F.那么有没有办法动态追踪这个功能?即明确添加跟踪点并重新编译内核?
perf probe -a zap_pte_range
Run Code Online (Sandbox Code Playgroud)
得到:
没有找到构建ID为33b15ec444475ee7806331034772f61666fa6719的[kernel.kallsyms],继续没有符号
无法在内核中找到符号zap_pte_range
错误:无法添加事件.