0

I have one translation unit with my main() function and another TU without main. Suppose even that I only control the second one and can't touch the first one.

Now, for reasons I will not go into, I want to be able to run some code before main() runs. I know this can be done by initializing a global variable with a function call, but I want to hide this - with as little use of macros as possible (dare I say no use of macros? probably impossible, there's no proper static block in C++)

What would be an elegant, or shall we say, not-very-ugly way of doing this? To be more clear, I'm looking for something which would provide this functionality for use multiple times, not just something to get it to work once. I want it to be as close to:

// ... at global scope ...
static {
    // my code here
}

PS: This question is related, but not the same, as this question about initializing static class members. It's also motivated by the wish to clearly disprove this claim it can't be done in C++.

Note: Yes, I know about the static initialization order fiasco, no need to remind me of it... and I'm not asking for something which bypasses it. Obviously running code statically requires some prudence.

Community
  • 1
  • 1
einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • smells fishy.. why would you want to do that? – Dean Dec 18 '15 at 16:27
  • 1
    GCC has the `constructor` function attribute, which does what you are looking for: https://gcc.gnu.org/onlinedocs/gcc-4.9.2/gcc/Function-Attributes.html – Colonel Thirty Two Dec 18 '15 at 16:28
  • @Dean: Several things, but for the purpose of discussion - exhibiting the power of C++ :-) – einpoklum Dec 18 '15 at 16:30
  • What do you mean by "hide"? How exactly "hidden" it should be? If function call is out of question, how about simply defining a global variable and place code you want to execute in class constructor? global variables initilization is done before main() body is executed. – Revolver_Ocelot Dec 18 '15 at 16:30
  • 2
    Why does it have to be before `main()` runs? How would you tell the difference if it runs later? – Barmar Dec 18 '15 at 16:30
  • 1
    @Barmar: Suppose my static code carefully adds the name of a TU to some global data structure (carefully i.e. not triggering the fiasco). Now `main()` can print "we've been compiled with the following TUs:" and then all the names. Kind of neat and has other uses. – einpoklum Dec 18 '15 at 16:37
  • That just requires that it be initialized before that global variable is used, not before any other code in `main()` runs. – Barmar Dec 18 '15 at 16:38
  • @Barmar: The point here is that he wants *automatic* initalization for that global variable - without manually calling anything (from `main()` or from somewhere else). – Karoly Horvath Dec 18 '15 at 16:41
  • @KarolyHorvath I understand that he wants it to be initialized automatically. My question was about the timing requirement. It should be initialized before it gets used, but that doesn't have to be before `main()`. – Barmar Dec 18 '15 at 16:42
  • @Barmar: If it doesn't happen before `main()`, it's not fully automatic anymore. – Karoly Horvath Dec 18 '15 at 16:43
  • http://stackoverflow.com/questions/4383602/how-to-force-inclusion-of-unused-object-definitions-in-a-library – Edward Strange Dec 18 '15 at 16:59
  • Btw. for the list of TUs ("we've been compiled with the following TUs:") there are IMHO better ways of doing that on a completely different level than in the runtime (as what you asking is generating calls in the startup during runtime). This is usually done by using generators during the compilation, which either add the Git hash into the version info in the executable, or even the list of libs/cpp files/whatever you want. The advantage of that is that the listing will be complete then (consider that you forget to add the static { ... } blocks into some of the translation units). – EmDroid Dec 18 '15 at 17:19
  • @E.Maskovsky: I was just giving a most basic example. Suppose every TU generates a... I don't know, funny curses graphic image. Now my main can have a slideshow of those. The point is that you get a nice simple mechanism for doing TU-specific startup work which may or may not involve inter-TU interaction via global structures. – einpoklum Dec 18 '15 at 18:40
  • @CrazyEddie: Can you explain the context of the link you gave? If you're worried about unused variables being optimized-out, I don't think that's the case when their initialization has side-effects. – einpoklum Dec 18 '15 at 19:14

2 Answers2

5

Please enjoy the static initialization order fiasco:

int f(/* whatever args you want*/)
{
    // code to be ran before main()
    return 42;
}

static int _ignore = f(/*...*/);

Note that on occasion the code might not be called, if not used anywhere else (alias "optimized out"). One of such case is when the TU is compiled into a static library (then the unused variable and the code might not be pulled into the executable). (note of E. Maskovsky).

YSC
  • 38,212
  • 9
  • 96
  • 149
  • So, to use this, I need to define functions which are clearly visible to the rest of the code; and the same for the _ignore globals. And I have to be careful to always name them differently. I want to do much better... – einpoklum Dec 18 '15 at 16:34
  • 4
    @ein Not at all. You could put all this in a compilation unit, inside an anonymous namespace. – YSC Dec 18 '15 at 16:35
  • But it will still be visible in the code. See edit to question for an illustration of what I'm after. – einpoklum Dec 18 '15 at 16:43
  • 1
    @ein I'm sorry, I don't get it. What do you call "visible code?" If it's in an anonymous namespace on a compilation unit (not included in another one), the identifiers defined won't be visible (usable) elsewhere. – YSC Dec 18 '15 at 16:45
  • 1
    @einpoklum even with your edit the question is unclear. This answer is the way to go. You can choose which parts of the code are visible outside of the TU. – Anon Mail Dec 18 '15 at 16:50
  • 1
    Note that on occasion the code might not be called, if not used anywhere else (alias "optimized out"). One of such case is when the TU is compiled into a static library (then the unused variable and the code might not be pulled into the executable). – EmDroid Dec 18 '15 at 16:51
  • @E.Maskovsky true. This note enhances the quality of my answer, you may have edited it yourself. Anyway, I've added it. – YSC Dec 18 '15 at 16:52
  • @E.Maskovsky: IIANM, such code won't be optimized out if it has side-effects. – einpoklum Dec 18 '15 at 18:44
  • @YSC: If I do what you suggested, every TU of mine is going to be littered with arbitrary function names I invented for doing static initializations and _ignoreXXX variables. I don't want to see those - and, in fact, I don't want to write those in. I just want to write in the code of my static block, like I explained in the edit (and I'm actually not that far awar from it in my answer below). – einpoklum Dec 18 '15 at 18:45
  • It will not be truly optimized out (that's why I put it in quotes), but as said, if for example put into a static library the code will not be pulled in the executable during linking (i.e. executed at the end) if not referenced (if the static variable is not used by anything else that is called by the executable). – EmDroid Dec 19 '15 at 14:36
2

This is the best I could come up with so far. It works, but the implementation is kind of fugly.

Usage

If you write:

STATIC_BLOCK {
    std::cout << "Hello static block world!" << std::endl;
}

this code will run before your main(). However, note that writing to std::cout before main() begins is not actually such a great idea.

Notes:

  • You must surround your static block code with curly braces (no need for a trailing semicolon; thanks @KlitosKyriacou for the suggestion).
  • If you don't use curly braces, expect hard-to-figure-out error messages.
  • The relative order of execution of static code is not guaranteed in C++.

Implementation

The static block implementation involves a dummy variable. To ensure we don't collide with some other dummy variable (e.g. from another static block - or anywhere else), we need a bit of macro machinery.

#define CONCATENATE(s1, s2) s1##s2
#define EXPAND_THEN_CONCATENATE(s1, s2) CONCATENATE(s1, s2)

#define STATIC_BLOCK_IMPL2(function_name,var_name) \
static void function_name(); \
static int var_name __attribute((unused)) = (function_name(), 0) ; \
static void function_name()

#define STATIC_BLOCK_IMPL1(prefix) \  
    STATIC_BLOCK_IMPL2(CONCATENATE_FOR_STATIC_BLOCK(prefix,_fn),CONCATENATE_FOR_STATIC_BLOCK(prefix,_var))

#define STATIC_BLOCK STATIC_BLOCK_IMPL1(EXPAND_THEN_CONCATENATE(static_block_,__COUNTER__))

Notes:

  • If your compiler does not support __COUNTER__ (as it's an extension to the standard, not part of it) - you can use __LINE__, which works too. GCC and Clang support __COUNTER__.
  • __attribute__((unused)) is another compiler extension, although attributes have been coming into the language; see this discussion for example. If you drop it you'll get a warning.
  • The code is C++98 (ignoring the compiler extensions), i.e. you don't need any modern C++ constructs supported. Unfortunately it doesn't qualify as C (where initializers must be constants).

Originally inspired by Andrei Alexandrescu's SCOPE_EXIT trick.

Community
  • 1
  • 1
einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • @KlitosKyriacou: I've not done quite what you've suggested, because that would mean two static blocks would clash. But I did adapt it for an improvement and a shorter impl. Thanks! – einpoklum Dec 18 '15 at 18:37
  • Just seen your modified code and it's good as it is, no advantage in doing what I suggested any more. – Klitos Kyriacou Dec 19 '15 at 01:25