相关疑难解决方法(0)

没有"静态"或"外部"的"内联"在C99中是否有用?

当我尝试构建此代码时

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 inlineextern inline代替just inline,或者如果我使用-O(因此函数实际内联),则错误消失.

这种行为似乎在C99标准第6.7.4(6)段中定义:

如果转换单元中函数的所有文件范围声明都包含inline函数说明符extern,则该转换单元中的定义是内联定义.内联定义不提供函数的外部定义,也不禁止另一个转换单元中的外部定义.内联定义提供了外部定义的替代,翻译器可以使用该定义在同一翻译单元中实现对该功能的任何调用.未指定对函数的调用是使用内联定义还是使用外部定义.

如果我理解了这一切,inline那么如果还有一个具有相同名称的外部函数,那么具有上例中定义的函数的编译单元只会一致地编译,而且我永远不知道我自己的函数或外部函数是否被调用.

这种行为不是完全愚蠢吗?在inline没有staticextern在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所有关于编译器优化都需要在调用的站点上看到函数的定义.这只能通过将标题放在标题中来实现,当然,标题中的定义在编译器每次看到它时都不能发出代码.但由于编译器不是强制实际内联函数,因此必须在某处存在外部定义.

c inline c99

91
推荐指数
2
解决办法
3万
查看次数

是否可以强制函数不被内联?

我想强制一个小函数不被编译为内联函数,即使它非常简单.我认为这对于调试目的很有用.有没有关键字可以做到这一点?

c++ visual-c++

48
推荐指数
5
解决办法
3万
查看次数

GCC内联汇编中的标签

在我正在进行的GCC内联汇编实验中,我遇到了一个关于标签和内联代码的新问题.

考虑以下简单的跳转:

__asm__
(
    "jmp out;"
    "out:;"
    :
    :
);
Run Code Online (Sandbox Code Playgroud)

除了跳转到out标签外,这没有任何作用.这样,这段代码编译得很好.但是如果你把它放在一个函数中,然后用优化标志进行编译,编译器就会抱怨:"错误:符号'out'已经被定义了".

似乎正在发生的事情是编译器每次内联函数时都会重复此汇编代码.这会导致标签out重复,从而导致多个out标签.

那么,我该如何解决这个问题呢?在内联装配中是否真的不可能使用标签?关于GCC内联汇编的教程提到:

因此,您可以将汇编放入CPP宏和内联C函数中,因此任何人都可以将其用作任何C函数/宏.内联函数非常类似于宏,但有时使用起来更干净.请注意,在所有这些情况下,代码将被复制,因此只应在该asm代码中定义本地标签(1:样式).

我试图找到有关这些"本地标签"的更多信息,但似乎无法找到与内联汇编有关的任何内容.看起来教程是说本地标签是一个数字后面跟冒号(比如1:),所以我尝试使用这样的标签.有趣的是,代码已编译,但在运行时它只是触发了分段错误.嗯...

那么任何建议,提示,答案......?

c c++ assembly gcc inline-assembly

38
推荐指数
2
解决办法
3万
查看次数

无法评估功能 - 可能内联

我写了一个与此类似的函数:

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**

如何从内联函数中打印值?

c++ gdb

17
推荐指数
2
解决办法
1万
查看次数

函数参数不会在该函数的出口处销毁

我很确定,应该在相应函数的出口处调用函数参数的析构函数.考虑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)

c++

14
推荐指数
2
解决办法
1083
查看次数

避免gcc功能序幕开销?

我最近遇到了很多函数,其中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:我应该首先提到:这些函数不能内联.他们有外部联系,他们是图书馆代码.允许它们在应用程序中内联将导致各种问题.

c x86 gcc code-generation

12
推荐指数
1
解决办法
2157
查看次数

gcc -finline-functions行为?

我正在使用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)

c++ gcc inline

6
推荐指数
1
解决办法
2615
查看次数

防止gcc内联函数

是否可以阻止gcc编译器内联特定函数.如果是这样,怎么样?

不要告诉我降低优化级别.我想要所有的优化,但标记一个特定的函数不被编译器内联,就像变量的情况下的volatile一样.

我想要这样做的原因是因为我的函数使用内联汇编定义的标签,gcc在内联函数时会搞砸,因为内联会导致gcc创建该标签的多个实例.

c linux x86 gcc

6
推荐指数
2
解决办法
4041
查看次数

我可以将模板函数设置为 noinline 或者强制它出现在分析器中吗?

我试图perf在 Ubuntu 20.04 上进行配置,但问题是许多函数没有出现在其中(可能是因为它们是内联的),或者只出现它们的地址(没有名称等)。我正在使用 CMake 的RelWithDebInfo构建。但有一些模板函数我不知道如何将其引入分析器结果中。我认为noinline如果这在 C++ 中对于模板函数是合法的,那么标记它们可能会有所帮助,但这会破坏代码库并且需要针对每个函数完成。有什么建议如何noinline同时实现所有功能吗?

c++ profiling cmake debug-information perf

6
推荐指数
1
解决办法
736
查看次数

没有内联函数的没有.cpp文件的c ++类?

我已经问了一个类似的问题,但这个问题有点不同

我不想为每个简单的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文件中使用日志类而不需要链接器投诉.

即使我使用这种方法会将成员函数变成内联吗?

c++ linker templates c++11

3
推荐指数
2
解决办法
269
查看次数

禁用一个函数的返回值优化

struct X {
  void * a;
  void * b;
};

X foo( void * u, void * v);
Run Code Online (Sandbox Code Playgroud)
  • foo()在汇编程序(i386)中实现
  • 类型X的返回值的地址作为隐藏参数传递给foo()

  • 如果使用-O0编译测试代码,则代码按预期工作

  • 如果用-O3编译分段错误发生(返回值被优化掉)
  • 如果使用-O3 -fno-elide-constructors编译,代码将再次按预期工作

如何强制编译器不为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)

c++ assembly return-value-optimization rvo nrvo

2
推荐指数
1
解决办法
771
查看次数

在Linux中通过perf添加动态跟踪点以获取未列出的功能

我试图用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

错误:无法添加事件.

c trace linux-kernel perf

1
推荐指数
1
解决办法
227
查看次数