Last active
March 20, 2019 12:19
-
-
Save eyalroz/79bf2c24c0c241f50d11 to your computer and use it in GitHub Desktop.
A static block implementation in almost-C C++
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* static_block.h | |
* | |
* An implementation of a Java-style static block, in C++ (and potentially a | |
* GCC/clang extension to avoid warnings). Almost, but not quite, valid C. | |
* Partially inspired by Andrei Alexandrescu's Scope Guard and | |
* discussions on stackoverflow.com | |
* | |
* By Eyal Rozenberg <[email protected]> | |
* | |
* Licensed under the Apache License v2.0: | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
*/ | |
#pragma once | |
#ifndef STATIC_BLOCK_H_ | |
#define STATIC_BLOCK_H_ | |
#ifndef UNIQUE_IDENTIFIER | |
// We could define a CONCATENATE() generally, but let's | |
// not interfere with macro names from elsewhere | |
#define CONCATENATE_FOR_STATIC_BLOCK(s1, s2) s1##s2 | |
// Ditto | |
#define EXPAND_THEN_CONCATENATE_FOR_STATIC_BLOCK(s1, s2) CONCATENATE_FOR_STATIC_BLOCK(s1, s2) | |
/** | |
* This macro expands into a different identifier in every expansion. | |
* Note that you _can_ clash with an invocation of UNIQUE_IDENTIFIER | |
* by manually using the same identifier elsewhere; or by carefully | |
* choosing another prefix etc. | |
*/ | |
#ifdef __COUNTER__ | |
#define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE_FOR_STATIC_BLOCK(prefix, __COUNTER__) | |
#else | |
#define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE_FOR_STATIC_BLOCK(prefix, __LINE__) | |
#endif /* COUNTER */ | |
#endif /* UNIQUE_IDENTIFIER */ | |
/** | |
* Following is a mechanism for executing code statically. | |
* | |
* @note Caveats: | |
* - Your static block must be surround by curly braces. | |
* - No need for a semicolon after the block (but it won't hurt). | |
* - Do not put static blocks in files, as it might get compiled multiple | |
* times ane execute multiple times. | |
* - A STATIC_BLOCK can only be used in file scope - not within any other block etc. | |
* - Templated static blocks will probably not work. Avoid them. | |
* - No other funny business, this is fragile. | |
* - This does not having any threading issues (AFAICT) - as it has no static | |
* initialization order issue. Of course, you have to _keep_ it safe with | |
* your static code. | |
* - Execution of the code is guaranteed to occur before main() executes, | |
* but the relative order of statics being initialized is unknown/unclear. So, | |
* do not call any method of an instance of a class which you expect to have been | |
* constructed; it may not have been. Instead, you can use a static getInstance() method | |
* (look this idiom up on the web, it's safe). | |
* - Variables defined within the static block are not global; they will | |
* go out of scope as soon as its execution concludes. | |
* | |
* Usage example: | |
* | |
* static_block { | |
* do_stuff(); | |
* printf("in the static block!\n"); | |
* } | |
* | |
*/ | |
#define static_block STATIC_BLOCK_IMPL1(UNIQUE_IDENTIFIER(_static_block_)) | |
#define STATIC_BLOCK_IMPL1(prefix) \ | |
STATIC_BLOCK_IMPL2(CONCATENATE_FOR_STATIC_BLOCK(prefix,_fn),CONCATENATE_FOR_STATIC_BLOCK(prefix,_var)) | |
#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() | |
#endif /* STATIC_BLOCK_H_ */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I try it . It seems like I can't use it in *.c file . It is ok in cpp file.