2

I have a static C library that I want to port to C++, in the C library I got some global variables that store some common data used by the functions for example:

// global variable in the C library
int global_number_of_cpu_cores;

init_global_vars()
{
    global_number_of_cpu_cores = get_info();
}
    
void lib_function()
{
    // use global_number_of_cpu_cores
}

when using the library, it must be first initialized by the init function but in C++, the object's constructors are executed before the main function, so I cannot code:

class class_lib
{
    class_lib()
    {
         // use global_number_of_cpu_cores but this is uninitialized!
    }
}

Also, you can initialize global variables with functions:

int program_var = lib_function(); // lib_function uses global_number_of_cpu_cores but this is unintialized!

what is a decent/elegant way to solve this when designing a C++ library? how do well-designed C++ libraries like Boost, Qt, etc solve this? any idea?

AntonioSk
  • 528
  • 3
  • 20
DaveJol2
  • 97
  • 5
  • 2
    Look at [Solving the Static Initialization Order Fiasco (SIOF) with C++20](https://www.modernescpp.com/index.php/c-20-static-initialization-order-fiasco) – Jarod42 Sep 20 '22 at 10:45
  • Probably the first step with "porting" a C library to C++ - before exploiting any C++-specific features - will be to simply compile with a C++ compiler (maybe, after adorning some functions/types with `extern "C"`). Types in a C library will not have constructors and, if a C++ compiler generates any (for `struct` types) they will either have no effect or give the same effect as in C. If any issues with order of initialisation of globals arise when building as C++ then they probably existed but didn't show up in testing of the C version. – Peter Sep 20 '22 at 11:37

1 Answers1

0

What you can do - simply create a C wrapper interface for C++ I.e. something like following:

In header file, e.g. foo.h

#ifndef __FOO_H_INCLUDED__
#define __FOO_H_INCLUDED__

#ifdef __cplusplus
extern "C" {
#endif

void print_logical_cpus()

#ifdef __cplusplus
}
#endif / * extern "C"  */

#endif / * __FOO_H_INCLUDED__  */

in the implementation file e.g. foo.cpp

#include "foo.h"
#include <cstdio>
#include <thread>

struct GlobalSettings {
 GlobalSettings():
   logical_cpus(std::thread::hardware_concurrency())
 {}
  std::size_t logical_cpus;
};

static GlobalSettings __gsettings;

extern "C" {

  void print_logical_cpus()
  {
      std::printf("Logical cpus %z", __gsettings.logical_cpus);
  }

}

If you still need to port on raw C, there are compiler specific tricks to run functions before and after main. GCC uses attribute((constructor)) and attribute((destructor))) MS VC++ uses __declspec(allocate(".CRT$XLC"))

Victor Gubin
  • 2,782
  • 10
  • 24