Learning C++ with help of "Thinking in C++" by Bruce Eckel,stuck in exercise 32, chapter 10.
The question is how to change link order, that Mirror::test() called for object m5 return false.
Here is my code.
mirror.h:
#ifndef MIRROR_H_
#define MIRROR_H_
class Mirror {
public:
Mirror() {logic_ = true; self_ = 0;};
Mirror(Mirror *ptr) {self_ = ptr; logic_ = false;};
bool test() {
if (self_ != 0) {
return self_->test();
} else {
return logic_;
}
};
private:
bool logic_;
Mirror *self_;
};
#endif // MIRROR_H_
task
one.cpp
#include "mirror.h"
Mirror m1;
two.cpp
#include "mirror.h"
extern Mirror m1;
Mirror m2 (&m1);
three.cpp
#include "mirror.h"
extern Mirror m2;
Mirror m3 (&m2);
and so on. Finally,
five.cpp
#include "mirror.h"
#include <iostream>
extern Mirror m4;
Mirror m5 (&m4);
int main(int argc, char* argv[]) {
std::cout << m5.test() << std::endl;
}
m5.test() returns true. The task says, that I should change linking order, that m5.test() returns false. I have tried to use:
init_priority (priority)
In Standard C++, objects defined at namespace scope are guaranteed to be initialized in an order in strict accordance with that of their
definitions in a given translation unit. No guarantee is made for
initializations across translation units. However, GNU C++ allows
users to control the order of initialization of objects defined at
namespace scope with the init_priority attribute by specifying a
relative priority, a constant integral expression currently bounded
between 101 and 65535 inclusive. Lower numbers indicate a higher
priority.
but no luck.
Full exercise text:
In a header file, create a class Mirror that contains two data
members: a pointer to a Mirror object and a bool. Give it two
constructors: the default constructor initializes the bool to true and
the Mirror pointer to zero. The second constructor takes as an
argument a pointer to a Mirror object, which it assigns to the
object’s internal pointer; it sets the bool to false. Add a member
function test( ): if the object’s pointer is nonzero, it returns the
value of test( ) called through the pointer. If the pointer is zero,
it returns the bool. Now create five cpp files, each of which includes
the Mirror header. The first cpp file defines a global Mirror object
using the default constructor. The second file declares the object in
the first file as extern, and defines a global Mirror object using the
second constructor, with a pointer to the first object. Keep doing
this until you reach the last file, which will also contain a global
object definition. In that file, main( ) should call the test( )
function and report the result. If the result is true, find out how to
change the linking order for your linker and change it until the
result is false.
You'll need to change the order of the object files when passing them to the linker. This works reasonable for the toplevel code although different compilers use different approaches, i.e., it isn't portable. Also, for libraries you generally can't control the order in which the objects are included. For example, if you have
// file1.cpp
int main() {
}
// file2.cpp
#include <iostream>
static bool value = std::cout << "file2.cpp\n";
// file3.cpp
#include <iostream>
static bool value = std::cout << "file3.cpp\n";
... and you link two programs like this:
g++ -o tst1 file1.cpp file2.cpp file3.cpp
g++ -o tst2 file1.cpp file3.cpp file2.cpp
you will get different output for tst1 and tst2, e.g.:
$ ./tst1
file2.cpp
file3.cpp
$ ./tst2
file3.cpp
file2.cpp
The overall moral is: don't do it. That is: don't use global objects. If you feel you absolutely need to use global objects, encapsulate them into functions, e.g.:
Type& global_value() {
static Type value; // possibly with constructor arguments
return value;
}
This way, value is initialized the first time it is accessed and there is no way to access it while it isn't constructed, yet. If you encapsulate all objects like this, you can guarantee that they are constructed in an appropriate order (unless you have a cyclic dependency in which case it can't be made to work and you should seriously rethink your design). The above approach encapsulating objects into function is, unfortunately, not thread-safe in C++ 2003. It is thread-safe in C++ 2011, however. Still, use of global variable is generally problematic and you definitely want to minimize their use.
I was struggling with this exercise too.
I managed to write a small Python script to prepare makefile entries that link and test final executable using all possible permutation of object files:
import itertools
for perm in itertools.permutations([1, 2, 3, 4, 5]):
print '\tg++ u0{0}.o u0{1}.o u0{2}.o u0{3}.o u0{4}.o -o $# && ./main.exe'.format(*perm)
After executing my make process it turned out, that all of the possible configurations yielded true value.
This is due to the fact, that all global (i.e. static) variables are guaranteed to be initialized before entering main function.
I defined a global bool variable that holds result from a test() function before main, something like this:
#include "mirror.h"
#include <iostream>
extern Mirror m4;
Mirror m5 (&m4);
bool result = m5.test();
int main(int argc, char* argv[]) {
std::cout << result << std::endl;
}
Bingo! Some of the objects' permutations yielded false at the progam's output.
All static variables are initialized with zeroes before any of their possible constructors are called. In this exercise, the order in which constructors are called is the clue.
If any object in the depencence chain has not been initialized by constructor when a value of result variable is established, the result is false value (self_ value is 0 and logic_ value is false, so test function returns false).
When a result variable is evaluated before entering main function, there is such possibility and order of object files in a linker command has something to do with the result.
Related
I am experiencing the following issue, in my DLL project:
At the DLL side :
Inside the DLL I have declared a static vector as follows :
static std::vector<FilterProcessor::FilterInfo*> TableOfContents;
At DLL’s initialization time of static members, I am adding some entries to the above vector.
I have defined an extern “C” global function (getTocPointer()) which is returning a pointer to the vector, when it called from the client program.
extern "C" __declspec(dllexport) std::vector<FilterProcessor::FilterInfo*>* __cdecl getLibraryTOC();
At the client’s program side :
The DLL library is loaded without any problem
The address of getTocPointer() function is returned correctly to the client program, when the getProcAddress() function is called.
Indeed, when I am performing the debugging process in the DLL-side, the client program calls the above function and the execution process enters to it.
However, the vector has a zero size and, has no any contents which were added to it at initialization time. It seems it points to another vector object. . .
I can’t really understand what exactly goes wrong here.
The way of adding entries to this vector at initialization time, is the proper way?
If yes, what probably goes wrong when the client program calls the getLibraryTOC() function?
Thanks in advance
George
If that static global definition of the vector appears in a header file, then yes you do have multiple different vectors. Change the keyword static to extern to make the header file declare the vector rather than defining it, and then add exactly one definition in an implementation file.
Then, you may encounter the static initialization order fiasco. If the vector is defined in a different compilation unit than the code attempting to add entries to it, there's no guarantee that the vector object is alive yet. Attempting to use a vector whose constructor hasn't run is undefined behavior -- it might easily manifest as the constructor running afterward and setting the contents to zero length (as a default constructor should), but many other problems are possible.
You can avoid the SIOF by using a local static.
std::vector<FilterProcessor::FilterInfo*>& table_of_contents()
{
static std::vector<FilterProcessor::FilterInfo*> singleton;
return singleton;
}
In every location that would have accessed the global, including the initialization logic that fills the vector, and also your getLibraryTOC() exported function, call the accessor function instead.
That all is applicable to any C++ software having multiple compilation units. When you have a DLL, things get even more complicated, because the DLL and EXE are compiled and linked separately from each other, possibly with different settings, different compilers, or even entirely different languages. Sharing of complex objects across DLL boundaries is real trouble. If the DLL and EXE are always recompiled at the same time, it can work. But if you're trying to distribute the DLL for use by another party who writes the EXE code, the strong coupling will quickly become intolerable.
A better approach is to hide the library objects from the DLL boundary, and pass only primitive or OS-managed types across. For example:
#define DLLAPI __declspec(dllexport) __cdecl
extern "C" DLLAPI int32_t getLibraryTocCount()
{ return table_of_contents.size(); }
extern "C" DLLAPI BSTR getLibraryTocName(int index)
{ return ::SysAllocString(table_of_contents[index].name.c_str(); } // assumes std::wstring
// etc
The library I have implemented contains the following code (in a brief description) :
An Index class which implements the Table of contents of the library
A collection of audio filters named Filter01, Filter02 etc.
Index.h
struct LIB_SPECS Library_TableOfContents
{
static bool addTOCEntry(FilterInfo* Filter_Info); // add an entry to the TOC
static std::vector<FilterInfo*> TableOfContents; // TOC
};
/*-------------------------------------------------------------------
Called from the client program to return the pointer to TOC */
extern "C" LIB_SPECS std::vector<FlterInfo*>* __cdecl getLibraryTOC();
Index.cpp
/* Define / Initialize static variables */
std::vector<FilterInfo*> Library_TableOfContents::TableOfContents = {};
//=====================================================================
bool Library_TableOfContents::addTOCEntry(FilterInfo* Filter_Info)
{
Library_TableOfContents::TableOfContents.push_back(Filter_Info);
return false;
}
//======================================================================
std::vector<FilterInfo*>* getLibraryTOC()
{
return &Library_TableOfContents::TableOfContents;
}
For each Audio Filter in the library :
Filterxx.h
class LIB_SPECS Filterxx
{
public:
static struct FilterInfo
{
public:
std::string filterName;
std::string filterDescription;
// other filter info
FilterInfo(); // FilterInfo constructor
} Filter_Info;
virtual String doSomeWork(int AvatarId);
virtual void deleteFilter() = 0;
};
Filterxx.cpp
Filterxx::FilterInfo Filterxx::Filter_Info("Filterxx", “A filter description e.g. Low pass Filter ” ); //
FilterInfo::FilterInfo(std::string name, std::string description)
{
Filter_Info.filterName = name;
Filter_Info.filterDescription = description;
Library_TableOfContents::addTOCEntry(&Filter_Info);
}
// other filter functions
The getLibraryTOC() function, is called from the client program to get the table of contents in order to show it to the user.
As I said, indeed it is called by the client but, at the time of call, the table of contents seems to have a zero size.
I have some code where a static method is called, and the static std::unordered_map within the same file is not initialized. I understand the static initialization between two compile units is "undefined" and there are many SO questions on the topic; however, when I use an std::vector the issue does not occur. Also, the code can execute, but I am confused as to why these specific compile orders do not work. SO, my questions are:
There is another SO question (which I've been unable to find!) about static initialization and dynamic initialization of static variables. Is this error due to std::undored_map actually being a dynamic initialization?
is there a way to get this code to initialize the std::unordered_map as I expected? I'm actually trying to create a static library .lib or .a. When I link the static library, it generally needs to come last, and so the error occurs.
are there any workarounds for this? One option I've thought of is to create both an std::vector and an std::unordered_map. Use the std::vector while the std::unordered_map is uninitialized (via bool _map_is_initialized). Change the initialization of the std::unordered_map to be explicitly dynamic by calling a function which iterates over the values in the std::vector to produce the std::unordered_map.
Linux
g++ -std=c++1y -g -c thing.cpp
g++ -std=c++1y -g -c main.cpp
g++ -g main.o thing.o -o main
./main
This results in a Floating point exception (core dumped) error. Through gdb, I was able to figure out that hashtable_policy.h trys __num % __den; where __den==0. Also using gdb, it appears as though Thing::Things is uninitialized.
(gdb) break thing.cpp:12
(gdb) run
(gdb) print Thing::Things
No symbol "Things" in specified context.
(gdb) print thing
$1 = (Thing *) 0x618c20
Windows
cl /EHsc /Zi /c main.cpp
cl /EHsc /Zi /c thing.cpp
link /debug main.obj thing.obj
main
In my actual code, this resulted in a very clear segmentation fault; however, this example just opens a popup that says the application failed. ... I have not done better diagnostics.
Code
thing.cpp
#include<iostream>
#include "thing.hpp"
std::vector<Thing*> Before; // EDIT: added
std::unordered_map<std::string, Thing*> Thing::Things;
std::vector<Thing*> After; // EDIT: added
Thing::Thing(std::string name) : name(name) {
}
bool Thing::Register(Thing *thing) {
std::cout << "no worries, vectors initialized..." << std::endl;
Thing::Before.push_back(thing); // EDIT: added
Thing::After.push_back(thing); // EDIT: added
std::cout << "added to vectors, about to fail..." << std::endl;
Thing::Things[thing->name] = thing;
return true;
}
thing.hpp
#pragma once
#include <string>
#include <unordered_map>
class Thing {
public:
static std::vector<Thing*> Before; // EDIT: added
static std::unordered_map<std::string, Thing*> Things;
static std::vector<Thing*> After; // EDIT: added
static bool Register(Thing* thing);
std::string name;
Thing(std::string name);
};
#define ADD_THING(thing_name) \
static bool thing_name## _is_defined = Thing::Register(new Thing( #thing_name ));
main.cpp
#include "thing.hpp"
#include <iostream>
ADD_THING(obligatory);
ADD_THING(foo);
ADD_THING(bar);
int main(int argc, char* argv[]) {
std::cout << "before loop" << std::endl;
for (auto thing : Thing::Things) {
std::cout << "thing.name: " << thing.first << std::endl;
}
return 0;
}
EDIT
If the order within a given compile unit is guaranteed, why do static std::vector<Thing*> Thing::Before and static std::vector<Thing*> Thing::After get initialized, but static std::unordered_map<std::string, Thing*> Thing::Things does not?
As noted in the comments, static initialization order is not defined. Who knows the difference between vector and map. Maybe your compiler initializes classes with even number of characters in their name first.
If you're running c++11 or greater, static initialization of function local items is guaranteed to be thread safe. They will be initialized the first time control passes through the declaration statement.
// Header
class Thing {
public:
static std::unordered_map<std::string, Thing*>& Things();
static bool Register(Thing* thing);
// CPP
std::unordered_map<std::string, Thing*>& Thing::Things()
{
static std::unordered_map<std::string, Thing*> things;
return things;
}
This will initialize the first time you ask for the Things, and avoids all the potential randomness of static initialization.
Static initialization is tricky. As this answer states, the standard provides some guarantees as to the order of initialization within a single "translation unit" (normally a .cpp source file), but none whatsoever concerning what order initializations in different translation units will follow.
When you added the Before and After vectors to the code, you observed that unlike the calls to ordered_map::operator[], the calls to vector::push_back() did not crash the process and concluded that the objects were being initialized out of order within a single translation unit, contrary to the standard's guarantees. There is a hidden assumption there, namely that since push_back() did not cause a crash, the vector must therefore have been initialized. This turns out not to be the case: that method call on an uninitialized object is almost certainly corrupting memory somewhere, but won't necessarily cause a crash. A better way of checking whether or not the constructor is being called would be to run the code in a debugger, and set breakpoints on the lines which contain the objects' definitions, for instance std::vector<Thing*> Before in thing.cpp. This will show that initialization will occur as predicted in the standard.
The best option for avoiding the "fiasco", as described here, is "construct on first use". In the case of your example code, this would involve changing any direct use of Thing::Things, such as this line:
Thing::Things[thing->name] = thing;
To a method, say Thing::GetThings(), which initializes the object and returns a reference to it. lcs' answer provides an example of this, but beware: although it solves the static initialization problem, using a scoped static object may introduce an even more pernicious problem: crashes on program exit due to static deinitialization order. For that reason, allocating the object with the new keyword is preferred:
std::unordered_map<std::string, Thing*>& Thing::GetThings()
{
static std::unordered_map<std::string, Thing*>* pThings =
new std::unordered_map<std::string, Thing*>();
return *pThings;
}
That instance will of course never be delete'd, which feels an awful lot like a memory leak. But even if it weren't a pointer, de-initialization would only occur at program shutdown. So, unless the object's destructor performs some important function like flushing a file's contents to disk, the only difference that matters is the fact that using a pointer avoids the possibility of a crash on exit.
I have MCU with flash memory breaked in sections(as usual).
Linker places .struct_init, .struct_init_const, .struct_not_init sections to addresses belongs to flash memory section20. It is hardcoded in linker script.
Consider following test code:
test.h
typedef struct
{
int val1;
int val2;
} mystruct_t;
test.cpp
#include "test.h"
// each variable is placed in dedicated section
// sections are placed in flash section20
// linker exports symbols with address of eaach section
__attribute__((section(".struct_init")))
mystruct_t struct_init = {
.val1 = 1,.val2 = 2};
__attribute__((section(".struct_init_const")))
extern const mystruct_t struct_init_const = {
.val1 = 1, .val2 = 2};
__attribute__((section(".struct_not_init")))
mystruct_t struct_not_init;
main.cpp
#include <stdint.h>
// This symbols exported by linker
// contains addresses of corresponding sections
extern uintptr_t LNK_STRUCT_INIT_ADDR;
extern uintptr_t LNK_STRUCT_INIT_CONST_ADDR;
extern uintptr_t LNK_STRUCT_NOT_INIT_ADDR;
// Pointers for indirect access to data
mystruct_t* struct_init_ptr = (mystruct_t*)LNK_STRUCT_INIT_ADDR;
const mystruct_t* struct_init_const_ptr = (const mystruct_t*)LNK_STRUCT_INIT_CONST_ADDR;
mystruct_t* struct_not_init_ptr = (mystruct_t*)LNK_STRUCT_NOT_INIT_ADDR;
// Extern variables declarations for DIRECT access data
extern mystruct_t struct_init;
extern const mystruct_t struct_init_const;
extern mystruct_t struct_not_init;
// This is some variables representing config values
// They can be more complex objects(classes) with internal state and logic..
int param1_direct;
int param1_init_const_direct;
int param1_not_init_direct;
int param1_indirect;
int param2_init_const_indirect;
int param1_not_init_indirect;
int main(void)
{
// local variables init with direct access
int param1_direct_local = struct_init.val1;
int param1_init_const_direct_local = struct_init_const.val1;
int param1_not_init_direct_local = struct_not_init.val1;
// local variables init with indirect access
int param1_indirect_local = struct_init_ptr->val1;
int param2_init_const_indirect_local = struct_init_const_ptr->val1;
int param1_not_init_indirect_local = struct_not_init_ptr->val1;
//global variables init direct
param1_direct = struct_init.val1;
param1_init_const_direct = struct_init_const.val1;
param1_not_init_direct = struct_not_init.val1;
//global variables init indirect
param1_indirect = struct_init_ptr->val1;
param2_init_const_indirect = struct_init_const_ptr->val1;
param1_not_init_indirect = struct_not_init_ptr->val1;
while(1){
// use all variables we init above
// usage of variables may also occure in some functions or methods
// directly or indirectly called from this loop
}
}
I wanna be sure that initialization of param1_ variables will lead to fetch data from flash. Because data in flash section20 can be changed using bootloader(at the moment when main firmware is not running).
The question is: Can LTO(and other optimizations) throw away fetches from flash and just substitute known values because they are known at link time because of initialization.
What approach is better?
If LTO can substitute values - then initialization should be avoided?
I know volatile can help, but is it really needed in this situation?
Code exampe shows different approaches of accessing and initializing data.
not_init version seems to be the best, because compiler can't substitute anything. But it will be a good idea to have some default parameters, so i'd prefer init version if it can be used.
What approach should be chosen?
Currently i am using GCC 4.9.3 but this is general question about any C/C++ compiler.
C and C++ both feature extern variables, which lets you define constants without immediately giving away their values:
// .h
extern int const param1;
extern char const* const param2;
// ...
In general you would define them in a (single) source file, which would hide them away from anything not in this source file. This is not LTO resilient, of course, but if you can disable LTO it is an easy enough strategy.
If disabling LTO is not an option, another solution is to not define them, let LTO produce a binary, and then use a script to splice the definitions in the produced binary in the right section (the one that can be flashed).
With the value not available at LTO time, you are guaranteed that it will not be substituted.
As for the solutions you presented, while volatile is indeed a standard compliant solution, it implies that the value is not constant, which prevents caching it during run-time. Whether this is acceptable or not is for you to know, just be aware it might have a performance impact, which as you are using LTO I surmised you would like to avoid.
One of the namespaces in my program is spread between two files. One provides the "engine", the other uses the "engine" to perform various commands. All of the initializations are performed on the "engine" side, including caching parameters fetched from setup library.
So, there's engine.cpp with:
#include <stdio.h>
#include "ns.h"
namespace MyNS
{
unsigned char variable = 0;
void init()
{
variable = 5;
printf("Init: var = %d\n",variable);
}
void handler()
{
// printf("Handler: var = %d\n",variable);
}
}
The variable happens never to be used again in engine.cpp but it's extensively used in commands.cpp.
#include <stdio.h>
#include "ns.h"
namespace MyNS
{
extern unsigned char variable;
void command()
{
printf("Command: var = %d\n",variable);
}
}
After compiling and linking, I'm getting:
Init: var = 5
Command: var = 1
Now, if I uncomment the printf() in handler() I'm getting:
Engine: var = 5
Command: var = 5
Handler: var = 5
What would be the "correct" way to force GCC not to optimize it away in such a way that accessing it through extern from the other file would fetch the right value? Preferably without reducing the -O level for the rest of the application?
(for completeness case, main.h and ns.h: )
#include "ns.h"
int main(int argc, char** argv)
{
MyNS::init();
MyNS::command();
MyNS::handler();
return 0;
}
namespace MyNS
{
void init();
void command();
void handler();
}
This minimized testcase doesn't exhibit this particular behavior; it seems one needs this situation to occur in much more complex environment to happen...
eh... the solution was quite trivial.
I exchanged places of the declaration and definition of the variable.
engine.cpp:
extern unsigned char variable;
command.cpp:
unsigned char variable = 0;
That way the compiler has no doubts about need for this variable's existence while compiling commands and in engine it has to reach to the existing instance, it can't just create a temporary one on the spot.
EDIT: Now I've discovered another peculiarity. The value changes depending on where it's written to. The section of code in question is:
1: varso = SharedObject::Instance()->varso;
2: memset(det_map,0,sizeof(det_map));
3: memset(gr_map,0xFF,sizeof(gr_map));
4: memset(gr_ped,false,sizeof(gr_ped));
5: memset(&stan,0,sizeof(stan));
6: stan.SOTUstage = 1;
7: PR_SOTU = varso->NrPSOTU;
The variable occurs near a place where several arrays are initialized with memset. The variable in question is PR_SOTU (the uppercase is inherited from when it was still a macro, and since it acts along with several other macros acting in a very similar context, it's likely to stay that way).
If move the assignment from its line 7 and place it after lines 1, 2 or 3, it receives the correct value 5. Placed after line 4 it gets the value 18. Anything below, and the value is 1. I moved definition of the variable to a different place (it was the last on the list of all namespace-globals, now it's first) to exclude possibility something writes at that specific memory location, but the behavior remains.
I'm trying to initialize a global array of function pointers at compile-time, in either C or C++. Something like this:
module.h
typedef int16_t (*myfunc_t)(void);
extern myfunc_array[];
module.cpp
#include "module.h"
int16_t myfunc_1();
int16_t myfunc_2();
...
int16_t myfunc_N();
// the ordering of functions is not that important
myfunc_array[] = { myfunc_1, myfunc_2, ... , myfunc_N };
func1.cpp, func2.cpp, ... funcN.cpp (symbolic links to a single func.cpp file, so that different object files are created: func1.o, func2.o, func3.o, ... , funcN.o. NUMBER is defined using g++ -DNUMBER=N)
#include "module.h"
#define CONCAT2(x, y) x ## y
#define CONCAT(x, y) CONCAT2(x, y)
int16_t CONCAT(myfunc_, NUMBER)() { ... }
When compiled using g++ -DNUMBER=N, after preprocessing becomes:
func1.cpp
...
int16_t myfunc_1() { ... }
func2.cpp
...
int16_t myfunc_2() { ... }
and so on.
The declarations of myfunc_N() and the initialization of myfunc_array[] are not cool, since N changes often and could be between 10 to 200. I prefer not to use a script or Makefile to generate them either. The ordering of functions is not that important, i can work around that. Is there a neater/smarter way to do this?
How To Make a Low-Level Function Registry
First you create a macro to place pointers to your functions in a special section:
/* original typedef from question: */
typedef int16_t (*myfunc)(void);
#define myfunc_register(N) \
static myfunc registered_##myfunc_##N \
__attribute__((__section__(".myfunc_registry"))) = myfunc_##N
The static variable name is arbitrary (it will never be used) but it's nice to choose an expressive name. You use it by placing the registration just below your function:
myfunc_register(NUMBER);
Now when you compile your file (each time) it will have a pointer to your function in the section .myfunc_registry. This will all compile as-is but it won't do you any good without a linker script. Thanks to caf for pointing out the relatively new INSERT AFTER feature:
SECTIONS
{
.rel.rodata.myfunc_registry : {
PROVIDE(myfunc_registry_start = .);
*(.myfunc_registry)
PROVIDE(myfunc_registry_end = .);
}
}
INSERT AFTER .text;
The hardest part of this scheme is creating the entire linker script: You need to embed that snippet in the actual linker script for your host which is probably only available by building binutils by hand and examining the compile tree or via strings ld. It's a shame because I quite like linker script tricks.
Link with gcc -Wl,-Tlinkerscript.ld ... The -T option will enhance (rather than replace) the existing linker script.
Now the linker will gather all of your pointers with the section attribute together and helpfully provide a symbol pointing before and after your list:
extern myfunc myfunc_registry_start[], myfunc_registry_end[];
Now you can access your array:
/* this cannot be static because it is not know at compile time */
size_t myfunc_registry_size = (myfunc_registry_end - myfunc_registry_start);
int i;
for (i = 0; i < myfunc_registry_size); ++i)
(*myfunc_registry_start[i])();
They will not be in any particular order. You could number them by putting them in __section__(".myfunc_registry." #N) and then in the linker gathering *(.myfunc_registry.*), but the sorting would be lexographic instead of numeric.
I have tested this out with gcc 4.3.0 (although the gcc parts have been available for a long time) and ld 2.18.50 (you need a fairly recent ld for the INSERT AFTER magic).
This is very similar to the way the compiler and linker conspire to execute your global ctors, so it would be a whole lot easier to use a static C++ class constructor to register your functions and vastly more portable.
You can find examples of this in the Linux kernel, for example __initcall is very similar to this.
I was going to suggest this question is more about C, but on second thoughts, what you want is a global container of function pointers, and to register available functions into it. I believe this is called a Singleton (shudder).
You could make myfunc_array a vector, or wrap up a C equivalent, and provide a function to push myfuncs into it. Now finally, you can create a class (again you can do this in C), that takes a myfunc and pushes it into the global array. This will all occur immediately prior to main being called. Here are some code snippets to get you thinking:
// a header
extern vector<myfunc> myfunc_array;
struct _register_myfunc {
_register_myfunc(myfunc lolz0rs) {
myfunc_array.push_back(lolz0rs);
}
}
#define register_myfunc(lolz0rs) static _register_myfunc _unique_name(lolz0rs);
// a source
vector<myfunc> myfunc_array;
// another source
int16_t myfunc_1() { ... }
register_myfunc(myfunc_1);
// another source
int16_t myfunc_2() { ... }
register_myfunc(myfunc_2);
Keep in mind the following:
You can control the order the functions are registered by manipulating your link step.
The initialization of your translation unit-scoped variables occurs before main is called, i.e. the registering will be completed.
You can generate unique names using some macro magic and __COUNTER__. There may be other sneaky ways that I don't know about. See these useful questions:
Unnamed parameters in C
Unexpected predefined macro behaviour when pasting tokens
How to generate random variable names in C++ using macros?
Your solution sounds much too complicated and error prone to me.
You go over your project with a script (or probably make) to place the -D options to the compiler, anyhow. So I suppose you are keeping a list of all your functions (resp. the files defining them).
I'd use proper names for all the functions, nothing of your numbering scheme and then I would produce the file "module.cpp" with that script and initialize the table with the names.
For this you just have to keep a list of all your functions (and perhaps filenames) in one place. This could be easier be kept consistent than your actual scheme, I think.
Edit: Thinking of it even this might also be overengineering. If you have to maintain a list of your functions somewhere in any case, why not just inside the file "module.cpp"? Just include all the header files of all your functions, there, and list them in the initializer of the table.
Since you allow C++, the answer is obviously yes, with templates:
template<int N> int16_t myfunc() { /* N is a const int here */ }
myfunc_array[] = { myfunc<0>, myfunc<1>, myfunc<2> }
Now, you might wonder if you can create that variable-length initializer list with some macro. The answer is yes, but the macro's needed are ugly. So I'n not going to write them here, but point you to Boost::Preprocessor
However, do you really need such an array? Do you really need the name myfunc_array[0] for myfunc<0> ? Even if you need a runtime argument (myfunc_array[i]) there are other tricks:
inline template <int Nmax> int16_t myfunc_wrapper(int i) {
assert (i<Nmax);
return (i==Nmax) ? myfunc<Nmax> : myfunc_wrapper(i-1);
}
inline int16_t myfunc_wrapper(int i) {
return myfunc_wrapper<NUMBER>(i); // NUMBER is defined on with g++ -DNUMBER=N
}
Ok I worked out a solution based on Matt Joiner's tip:
module.h
typedef int16_t (*myfunc_t)(void);
extern myfunc_array[];
class FunctionRegistrar {
public:
FunctionRegistrar(myfunc_t fn, int fn_number) {
myfunc_array[fn_number - 1] = fn; // ensures correct ordering of functions (not that important though)
}
}
module.cpp
#include "module.h"
myfunc_array[100]; // The size needs to be #defined by the compiler, probably
func1.cpp, func2.cpp, ... funcN.cpp
#include "module.h"
static int16_t myfunc(void) { ... }
static FunctionRegistrar functionRegistrar(myfunc, NUMBER);
Thanks everyone!