I have this code:
// 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 ;
}
I want to inline create_uid()
, while keeping the _next_uid
variable global to the program so the variable is unique.
My questions are:
- Can I do this?
- Is the
inline
statement require_next_uid
to be visible outside the compilation unit?
Note: This doesn't seems to answer those questions clearly.
CodePudding user response:
Edited after clarifiation of the question.
If you want only a single _next_uid
, then simply put the following into your header file:
inline int create_uid()
{
static int _next_uid = 0;
return _next_uid ;
}
CodePudding user response:
Short answer. No. The following code
// my.h
static int _next_uid = 0;
inline int create_uid() {
return _next_uid ;
}
will probably compile, but will result in undefined behaviour if used in more than one translation units. This is because the _next_uid
variables are different entities in different translation units. Thus the definitions of create_uid()
are also different. However:
If an inline function [...] with external linkage is defined differently in different translation units, the behavior is undefined. [1]
What you can do instead is either use a local scope static variable in the function, like @DanielLangr showed in one of the other answers [1]. This has the disadvantage, that that variable cannot be accessed outside of the function. Alternatively as @wohlstad mentioned in one of the comments, you can use a C 17 inline variable:
// my.h
inline int _next_uid = 0;
inline int create_uid() {
return _next_uid ;
}
Note that this does not define a static variable. Using static
and inline
will have the same effect as just using static
[3], which results in the undefined behaviour I mentioned above.
Inlining a function means per definition, that all the variables it uses must be reachable from the translation unit where it is inlined. This cannot work with a unique static (thus not visible to other TUs) variable.
[1]: https://en.cppreference.com/w/cpp/language/inline
[2]: https://stackoverflow.com/a/72124623/17862371
[3]: https://stackoverflow.com/a/58101307/17862371
CodePudding user response:
Summary:
It doesn't work if you put implementation of inline next_id()
to a single c
file, which means the function is in a single compile unit. So main
cannot find inline next_id()
, you'll get the error undefined reference
.
It can be compiled if you declare inline next_id()
in a shared header file, in which case each compile unit will properly find inline next_id()
.
In my case, only one instance of this global variable will appear in virtual address space .DATA
segment of the process. The output number is continuous.
Example:
Makefile 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
main.cpp 12:
#include <cstdio>
#include "share.hpp"
#include "second.hpp"
int main(){
printf("[main] %d\n", next_id());
consume_id();
printf("[main] %d\n", next_id());
consume_id();
printf("[main] %d\n", next_id());
return 0;
}
second.hpp 1:
void consume_id();
second.cpp 7:
#include <cstdio>
#include "share.hpp"
void consume_id(){
printf("[scnd] %d\n", next_id());
}
share.hpp 4:
#pragma once
int next_id();
share.cpp 7:
static int _next_id = 0;
int next_id()
{
return _next_id ;
}
Result output:
[main] 0
[scnd] 1
[main] 2
[scnd] 3
[main] 4
But if it is changed to:
share.cpp 4:
inline int next_id()
{
return _next_id ;
}
undefined reference to `next_id()'
If changed to
share.hpp 7:
#pragma once
static int _next_id = 0;
inline int next_id()
{
return _next_id ;
}
Works
EDIT:
It seems to be an undefined behavior
I'm using `gcc version 11.2.0 (Ubuntu 11.2.0-19ubuntu1)
IN MY CASE
You will have copies of static int _next_id
but only in the object file. In memory there is only one.
objdump -d main > main.s
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),