我可以内联使用静态变量的函数吗?



我有这个代码:

// my.h
#ifndef MY_HEADER
#define MY_HEADER
int create_uid();
#endif
// my.cpp
#include "my.h"
static int _next_uid = 0;
int create_uid()
{
return _next_uid++;
}

我想内联create_uid(),同时将_next_uid变量保留为程序的全局变量,以便变量是唯一的。

我的问题是:

  1. 我可以这样做吗?
  2. inline语句是否要求_next_uid在编译单元外部可见?

注意:这似乎没有清楚地回答这些问题。

澄清问题后编辑。

如果您只需要一个_next_uid,那么只需将以下内容放入头文件中:

inline int create_uid()
{
static int _next_uid = 0;
return _next_uid++;
}

简短的回答。不。以下代码

// my.h
static int _next_uid = 0;
inline int create_uid() {
return _next_uid++;
}

可能会编译,但如果在多个翻译单元中使用,将导致未定义的行为。这是因为_next_uid变量是不同翻译单元中的不同实体。因此,create_uid()的定义也不同。然而:

如果具有外部链接的内联函数 [...] 在不同的翻译单元中定义不同,则行为是未定义的。[1]

相反,您可以做的是在函数中使用局部范围静态变量,就像其他答案之一 [1] 中显示的@DanielLangr。这样做的缺点是无法在函数外部访问该变量。或者,正如其中一个注释中@wohlstad提到的,您可以使用 C++17 内联变量:

// my.h
inline int _next_uid = 0;
inline int create_uid() {
return _next_uid++;
}

请注意,这不会定义静态变量。使用staticinline将具有与仅使用static[3] 相同的效果,这会导致我上面提到的未定义的行为。

内联函数意味着根据定义,它使用的所有变量都必须可以从内联的翻译单元访问。这不能与唯一的静态(因此对其他 TU 不可见)变量一起使用。

[1]: https://en.cppreference.com/w/cpp/language/inline
[2]: https://stackoverflow.com/a/72124623/17862371
[3]: https://stackoverflow.com/a/58101307/17862371

总结:

如果将inline next_id()的实现放在单个c文件中,则不起作用,这意味着该函数位于单个编译单元中。所以main找不到inline next_id(),你会得到错误undefined reference

如果在共享头文件中声明inline next_id(),则可以编译它,在这种情况下,每个编译单元将正确找到inline next_id()

就我而言,此全局变量只有一个实例将出现在进程段.DATA虚拟地址空间中。输出编号是连续的。

例:

生成文件8:

all:
c++ -c main.cpp
c++ -c second.cpp
c++ -c share.cpp
c++ main.o second.o share.o -o main
clean:
rm -f main.o second.o share.o main

主.cpp12:

#include <cstdio>
#include "share.hpp"
#include "second.hpp"
int main(){
printf("[main] %dn", next_id());
consume_id();
printf("[main] %dn", next_id());
consume_id();
printf("[main] %dn", next_id());
return 0;
}

第二.hpp1:

void consume_id();

第二.cpp7:

#include <cstdio>
#include "share.hpp"
void consume_id(){
printf("[scnd] %dn", next_id());
}

分享.hpp4:

#pragma once
int next_id();

分享.cpp7:


static int _next_id = 0;
int next_id()
{
return _next_id++;
}

结果输出:

[main] 0
[scnd] 1
[main] 2
[scnd] 3
[main] 4

但如果改为:

分享.cpp4:

inline int next_id()
{
return _next_id++;
}

对"next_id()"的未定义引用

如果更改为

分享.hpp7:

#pragma once
static int _next_id = 0;
inline int next_id()
{
return _next_id++;
}

工程

编辑

这似乎是一种未定义的行为

我正在使用'gcc版本11.2.0(Ubuntu 11.2.0-19ubuntu1)

就我而言

您将拥有static int _next_id的副本,但仅在目标文件中。内存中只有一个。

objdump -d main > main.s

143:

00000000000011b3 <_Z7next_idv>:
11b3:   f3 0f 1e fa             endbr64 
11b7:   55                      push   %rbp
11b8:   48 89 e5                mov    %rsp,%rbp
11bb:   8b 05 53 2e 00 00       mov    0x2e53(%rip),%eax        # 4014 <_ZL8_next_id>
11c1:   8d 50 01                lea    0x1(%rax),%edx
11c4:   89 15 4a 2e 00 00       mov    %edx,0x2e4a(%rip)        # 4014 <_ZL8_next_id>
11ca:   5d                      pop    %rbp
11cb:   c3                      ret    

这里的函数_Z7next_idv只在内存中出现 1 次。

147:

11bb:   8b 05 53 2e 00 00       mov    0x2e53(%rip),%eax        # 4014 <_ZL8_next_id>

_next_id的标签是_ZL8_next_id的,也只在内存中出现1次。

最新更新