Why is this code compiled and linked without an error? - c++

Isn't the extern keyword supposed to simply 'blind' the compiler? Here are the codes that i can't understand why it is without an error.
struct A {
int a;
};
class B {
static A x;
public:
void f() { x.a=0; }
};
extern A B::x; // not allocated.
main() {
B z;
z.f();
}
As you already know, the static member should be instantiated manually. However, i added the extern keyword, which means it's not actually allocated. It is very weird that it compiles fine!

There is no such thing as an extern declaration for static member variables! The variable is declared extern anyway based on the definition of the class. gcc warns that you can't explicitly declare a static member variable to be extern. However, both gcc and clang compile and link the code without further ado, clearly ignoring the extern.
Of course, with the above code it is also clear that you are compiling with some non-standard mode in the first place as main() relies on the implicit int rule which was never part of C++.

Related

Declaration of function prototypes within classes in C++? [duplicate]

I have been programming in C++ for quite some time and I never thought about this until today.
Consider the following code:
struct foo
{
// compiles fine
void bar()
{
a = 1;
my_int_type b;
b = 5;
}
// Just a declaration, this fails to compile, which leads me to assume that
// even though the bar() method is declared and defined all at once, the
// compiler looks/checks-syntax-of the class interface first, and then compiles
// the respective definitions...?
void bar2(my_int_type); // COMPILE ERROR
my_int_type b; // COMPILE ERROR because it comes before the typedef declaration
typedef int my_int_type;
my_int_type a;
void bar3(my_int_type); // compiles fine
};
int main()
{
foo a;
a.bar();
return 0;
}
Is my understanding of why the errors occur (see bar2() comment above) correct/incorrect? Either way, I would appreciate an answer with a simplistic overview of how a single-pass C++ compiler would compile the code given above.
For the most part, a C++ file is parsed top-to-bottom, so entities must be declared before they are used.
In your class, bar2 and b are invalid because they both make use of my_int_type, which has not yet been declared.
One exception to the "top-to-bottom" parsing rule is member functions that are defined inside the definition of their class. When such a member function definition is parsed, it is parsed as if it appeared after the definition of the class. This is why your usage of my_int_type in bar is valid.
Effectively, this:
struct foo
{
void bar()
{
my_int_type b;
}
typedef int my_int_type;
};
is the same as:
struct foo
{
void bar();
typedef int my_int_type;
};
inline void foo::bar()
{
my_int_type b;
}
Compiler just starts to go down in a block. Any symbol which is not familiar to it will be considered as a new symbol which is not defined. This is the scheme behind the function definition or header files.
You can suppose that the compiler first makes a list of definitions so the bar() method should get compiled correctly because the definitions have provided before.
It has a lot to do with visibility. I think your confusion may come from assuming a single pass. Think of class parsing as done in two stages.
Parse class definition.
Parse method implementation.
The advantage to this is we have visibility of the entire class from within class member functions.

When is definition of class' static data member (un/-)necesary

I have a big project and work on refactoring it. Major task is rewrite of logger. New logger is (as far as I can tell) API-compatible with old one, so I believed that after changing header include directory, recompile and relink everything should work. But no. I get multiple errors of the kind undefined reference to <static_data_member>. I can't paste actual code, but it looks for example like this:
// Foo.h
class Foo {
static const int bar = 0;
int baz; // assigned in c-tor
void updateBaz() { baz = bar; }
// ....
}
static const int bar is NOT defined in Foo.cpp. It is sometimes printed by log macros. And it used to work (with old logger), now I have to define it. What change could have caused it?
Another example that that occurs with variables declared by boost:
(...)/blog_adaptor.h:50: error: undefined reference to bbost::serialization::version<CA::CReyzinSignature>::value'
So: when are definitions to static members required and when can they be omitted?
Unless the variables are declared inline (a C++17 feature), definitions of static member variables are not optional, as far as the C++ standard is concerned. Failure to provide a definition is undefined behavior.
Compilers and linkers may vary on exactly what will make them check to see if definitions exist, but that is the nature of undefined behavior.
As Nicol Bolas answered, the code in my project had undefined behavior because static data members were initialized but nowhere defined. To summarize and extend:
Static data member doesn't need to be defined when:
It is not used or is used only in discarded branches (non-instantiated templates and discarded branches of constexpr-if)
in C++17 if member is inline
also clang-tidy says that "out-of-line definition of constexpr static data member is redundant in C++17 and is deprecated", so probably static constexpr also doesn't need it
Further, following code shows why my bad project was not triggering linker error before. I don't know whether it is "not odr-use" or "Undefined Behavior that doesn't hurt you yet":
#include <boost/serialization/version.hpp>
class Klass {};
//BOOST_CLASS_VERSION(Klass, 3);
// would be expanded to:
namespace boost { namespace serialization {
template<>
struct version<Klass> {
static const int value = 3; // not defined anywhere
};
} }
int foo (int val) { // was used by old logger
return val;
}
int bar (const int &val) { // is used by new logger
return val;
}
int main () {
// return bar(boost::serialization::version<Klass>::value); // link error
return foo(boost::serialization::version<Klass>::value); // works fine
}
So there is no link error if member is used but not it's address is not queried. Passing value by reference qualifies as querying the address.

Static data member in an unnamed class C++

I read in the below link that unnamed(anonymous) class should not have static data memebers in it. Could anyone please let me know the reason for it?
https://www-01.ibm.com/support/knowledgecenter/SSLTBW_2.1.0/com.ibm.zos.v2r1.cbclx01/cplr038.htm
says the below..
You can only have one definition of a static member in a program.
Unnamed classes, classes contained within unnamed classes, and local
classes cannot have static data members.
All static member data, if they are ODR-used, must be defined outside the class/struct.
struct Foo
{
static int d;
};
int Foo::d = 0;
If the class/struct is unnamed, there is no way to define the member outside the class.
int ::d = 0;
cannot be used to define the static member of an unnamed class.
Update for C++17
If you are able to use C++17 or newer, you may use
static inline int d = 10;
That will allow a static member variable to be defined in an anonymous class/struct.
Sample code to demonstrate that a static member variable need not be defined outside the class definition:
#include <iostream>
struct foo
{
static inline int d = 10;
};
int main()
{
auto ptr = &foo::d;
std::cout << *ptr << std::endl;
}
Command to build:
g++ -std=c++17 -Wall socc.cc -o socc
Output of running the program:
10
Thanks are due to #Jean-MichaƫlCelerier for the suggestion for the update.
Are you sure that the standard actually forbids this?
As mentioned the problem arises as you need to have an actual definition of the static member. The language provides for no method to define it. There is no other problems in referring to it as we can do it from within the struct or via an instance of it.
However GCC for example will accept the following:
static struct {
static int j;
} a;
int main() {
return a.j; // Here we actually refers to the static variable
}
but it can't be linked as a.j refers to an undefined symbol (._0::j), but there's a way to get around this. By defining it in assembler or by using compiler extensions you could. For example adding the line
int j asm("_ZN3._01jE") = 42;
Will make it work. _ZN3._01jE is the real mangled name of the static variable in this case, neither the mangled or unmangled name can be used directly as a identifier in standard C++ (but it can via GCC extension or assembler).
As you must probably realize this would only work with specific compilers. Other compilers would mangle the name in other ways (or even do other things that may make the trick not work at all).
You should really question why you would like to use this trick. If you can do the work using standard methods you should most probably chose that. For example you could reduce the visibility by using anonymous namespace instead for example:
namespace {
static struct Fubar {
static int j;
} a;
Fubar::a = 0;
}
Now Fubar is not really anonymous, but it will at least be confined to the translation unit.
When C++ was standardized, unnamed classes could not have static data members, as there was no way to define/instantiate them. However, this problem has been solved with C++11, as it added the decltype operator:
struct {
static int j;
} a;
// Declare the static member of the unnamed struct:
int decltype(a)::j = 42;
int main() {
return a.j == 42 ? 0 : 1; // Use the static member
}
So, in principle, there could be unnamed classes or structs with static data members. But the C++ standard makers deliberately did not allow this syntax, as the compiler doesn't know, which name it should give to that decltype(a)::j thing for linking. So most (all?) compilers - including current versions of GCC in normal mode - refuse to compile this.
In -fpermissive mode, GCC-9 und GCC-10 accept this code and compile it fine. However, if the declaration of a is moved to a header file, that is included from different source files, they still fail at the linking stage.
So unnamed classes can only be used inside a single translation unit. To avoid polluting the global namespace, just put anything, that needs to stay local, inside an anonymous namespace. So:
namespace {
struct whatever {
static int j;
} a;
int whatever::j = 42;
}
int main() {
return a.j == 42 ? 0 : 1;
}
compiles fine, doesn't pollute global namespace, and even doesn't lead to problems, if the name whatever clashes with a name from another header file.

static member function with C language binding?

The following C++ code compiles with Visual C++ and g++:
struct S
{
static void foo();
};
extern "C"
void S::foo() {}
struct T
{
static void foo();
};
extern "C"
void T::foo() {}
auto main() -> int
{
S().foo();
T().foo();
}
Is it valid?
If it's valid, since the implementation may be in a separate translation unit, does that imply that a static member function always has the same calling convention as a C function (and if not, how does it not imply that)?
C++11 7.5/4 "Linkage specifications"
A C language linkage is ignored in determining the language linkage of
the names of class members and the function type of class member
functions.
So your example is valid in the sense that it's not malformed or an error, but the extern "C" should have no effect on S::foo() or T::foo().
A static member function has the same calling convention as a C function. But, name mangling applies. So, even if you get away with declaring your static member as extern "C", the linker would probably not find it when you try to link it against the C code that calls that function.
What you can easily do is declare a wrapper/stub that calls the static member from a plain function. Also, you can assign the static member function's address to a plain function pointer.
No it is ignored, the problem is name mangling (function naming for linkage phase). So the trick is to define a C function and use your C++ static method as a stub to call it, like this:
struct S
{
static void foo();
};
extern "C" void S_foo_impl();
void S::foo() { S_foo_impl(); }
auto main() -> int
{
S::foo();
}
Of course, S_foo_impl should be defined in a external C module.

How to declare a global variable in C++

I know one should not use global variables but I have a need for them. I have read that any variable declared outside a function is a global variable. I have done so, but in another *.cpp file, that variable could not be found. So it was not really global. Isn't it so that one has to create a header file GlobalVariabels.h and include that file to any other *cpp file that uses it?
I have read that any variable declared outside a function is a global variable. I have done so, but in another *.cpp File that variable could not be found. So it was not realy global.
According to the concept of scope, your variable is global. However, what you've read/understood is overly-simplified.
Possibility 1
Perhaps you forgot to declare the variable in the other translation unit (TU). Here's an example:
a.cpp
int x = 5; // declaration and definition of my global variable
b.cpp
// I want to use `x` here, too.
// But I need b.cpp to know that it exists, first:
extern int x; // declaration (not definition)
void foo() {
cout << x; // OK
}
Typically you'd place extern int x; in a header file that gets included into b.cpp, and also into any other TU that ends up needing to use x.
Possibility 2
Additionally, it's possible that the variable has internal linkage, meaning that it's not exposed across translation units. This will be the case by default if the variable is marked const ([C++11: 3.5/3]):
a.cpp
const int x = 5; // file-`static` by default, because `const`
b.cpp
extern const int x; // says there's a `x` that we can use somewhere...
void foo() {
cout << x; // ... but actually there isn't. So, linker error.
}
You could fix this by applying extern to the definition, too:
a.cpp
extern const int x = 5;
This whole malarky is roughly equivalent to the mess you go through making functions visible/usable across TU boundaries, but with some differences in how you go about it.
You declare the variable as extern in a common header:
//globals.h
extern int x;
And define it in an implementation file.
//globals.cpp
int x = 1337;
You can then include the header everywhere you need access to it.
I suggest you also wrap the variable inside a namespace.
In addition to other answers here, if the value is an integral constant, a public enum in a class or struct will work. A variable - constant or otherwise - at the root of a namespace is another option, or a static public member of a class or struct is a third option.
MyClass::eSomeConst (enum)
MyNamespace::nSomeValue
MyStruct::nSomeValue (static)
Declare extern int x; in file.h.
And define int x; only in one cpp file.cpp.
Not sure if this is correct in any sense but this seems to work for me.
someHeader.h
inline int someVar;
I don't have linking/multiple definition issues and it "just works"... ;- )
It's quite handy for "quick" tests... Try to avoid global vars tho, because every says so... ;- )