Home > Enterprise >  Can I inline a function which uses a static variable?
Can I inline a function which uses a static variable?

Time:05-05

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:

  1. Can I do this?
  2. 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),           
  • Related