3 ms·
No no no no no. This is a C++ problem. As much as you want to blame this particular problem on C, C handles this the right way. Let's try to write the equiva
by bb88 9y ago
No no no no no. This is a C++ problem. As much as you want to blame this particular problem on C, C handles this the right way.
Let's try to write the equivalent of this error in C:
int myfunc() {
return 5;
}
static int x;
static int y = 4;
static int z = myfunc();
int main()
{};
Compiling that in gcc gives me:
main.c:8:16: error: initializer element is not constant
static int z = myfunc();
^~~~~~
And it makes sense, C just wants to do a memcpy() to initialize the static variables. In C++, the only way the class is initialized is if the ctor is run. And that means running the ctor before main().
Edited to add:
You're correct that 5.1.2 does not specify memcpy() as a form of initialization. But see my reply below about C11 and static storage classes.
- kuschku 9y agoThe same issue always occurs where you have static constructors that are not constant. That's why it gives you a compiler warning, and why your IDE marks it in yellow. The same issue occurs in any language with static constructors, including Java.
- pjmlp 9y agoNow try that with other C compilers as well, or without using static. Also add common C extensions into the soup like constructor function attributes. Finally ISO/IEC 9899:2011, section 5.1.2. "All objects with static storage duration shall be initialized (set to their initial values) before program startup. The manner and timing of such initialization are otherwise unspecified. Program termination returns control to the execution environment." Don't mix what your compiler does, with what the standard requires. Doing so only leads to unportable programs and misunderstandings.
- bb88 9y agoThe C11 standard is clear here on syntax for a static initializer. Read section 6.7.9, constraint 4: All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals. It's syntax, not initialization. And that makes sense. However the memory is initialized before runtime could be via memcpy() it could be loaded as part of the executable and then mapped dynamically at runtime. That's what 5.1.2 is saying. What 6.7.9 constraint 4 is saying, is that static variables can only be constant expressions.
- pjmlp 9y agoYes, but global variables are not necessarily static.
- bb88 9y agoI think you're missing the point entirely here. C++ has to run code before main if a ctor is in a class that's static. There's no other way to initialize that static object. C prevents this by requiring static storage to be initialized with constants.
- pjmlp 9y agoFair enough.
- caf 9y agoAll variables declared at file scope have static storage duration in C.
- pjmlp 9y agoI was talking about using static keyword.
- caf 9y agoYes, but what's important here is the storage duration, which the static keyword doesn't affect at file scope (it just affects the symbol scope).
- jmaygarden 9y agoUse of static in the context of that C snippet is deprecated in C++. One is supposed to use an unnamed namespace instead. namespace { int myfunc() { return 5; } int x; int y = 4; int z = myfunc(); }; int main() {} In my opinion, his point is still valid.
- 72deluxe 9y agoHow is this an actual problem in the real world?
- jmaygarden 9y agoIf one isn’t careful, you end up with interdependency between static initializers. Since the order of static initialization is undefined, you get fun bugs like your program crashing because a minor change caused the objects to link in a different order. For example, the dreaded singleton using a static variable inside a function: Singleton& get_singleton() { static Singleton instance; return instance; } Having a couple of those referenced in static initializers is a recipe for disaster. It’s a bad practice, but people unfortunately do it all the time. Those that do this are equally unequipped to realize why their program suddenly started crashing after an innocuous change.
- jensa1948 9y agoPeople who use singletons deserve no better...
- kllrnohj 9y agoIf you think C code doesn't run before main() you're very naive. Just try this: #include <stdio.h> static volatile int* x; static int y = 42; void __attribute__((constructor)) foo() { printf("[foo] x = %p\n", x); } int main() { x = &y; printf("[main] x = %p\n", x); return 0; } And before you complain about that being a compiler extension yes, it is, but it's also not rare, either, and you're probably using C libraries that do this.
- bb88 9y agoIt's a compiler "hack" for shared libraries, because there is no other way to run initialization for elf objects. [1] The C standard doesn't allow it. And gcc forces you to be explicit about it. [1]: https://www.geeksforgeeks.org/__attribute__constructor-__attribute__destructor-syntaxes-c/ https://www.geeksforgeeks.org/__attribute__constructor-__att...
- fnord123 9y ago>And before you complain about that being a compiler extension yes, it is, but it's also not rare, either, and you're probably using C libraries that do this. e.g. All Linux kernel modules use this for initialising static structs for interfacing with the kernel.