ODR@functions(+classes)

OneDefinitionRule is more strict on global variables (which have static duration). You can’t have 2 global variables sharing the same name. Devil is in the details:

As explained in various posts, you declare the same global variable in a header file that’s included in various compilation units, but you allocate storage in exactly one compilation unit. Under a temporary suspension of disbelief, let’s say there are 2 allocated storage for the same global var, how would you update this variable?

With free function f1(), ODR is more relaxed. http://www.drdobbs.com/cpp/blundering-into-the-one-definition-rule/240166489 explains the Lessor ODR vs Greater ODR. My focus today is the Greater ODR therein. The same function can be included via a header file into multiple compilation units and goes into multiple binaries. Two copies of this function are usually identical definitions. If they actually have different definitions, compiler/linker can’t easily notice and are not required to verify, so no build error (!) but you could hit strange run time errors.

Java linker is simpler and never cause any problem so I never look into it.

c++variables: ! always objects

Every variable that holds data is an object. Objects are created either with static duration (by defining rather than declaring the variable), with automatic duration (declaration alone) or with dynamic duration via new/malloc().

That’s the short version. Here’s the long version:

– stack variables (including function parameters) – each stack object has a name (multiple possible?) i.e. the host variable, like a door plate on the memory location. When you clone a stack variable you get a cloned object. (Advanced — You could create a reference to the stack object, when you pass the host variable by-reference into a function. You should never return a stack variable by reference)

– heap objects – have no name no “host variable” no door plate. They only have addresses. The address could be saved in a “pointer object”, which is a can of worm. (In many cases, the address is passed around without any pointer object)

– non-local static objects — are more tricky. The variable(i.e. name) is there after you declare it, but it is a door plate without a door. It only becomes a door plate on a storage location when you allocate storage i.e. create the object by “defining” the host variable. There’s a one-definition-rule for static objects, so most of the time you first declare the variable without defining it, then you define it elsewhere. See https://bintanvictor.wordpress.com/2017/05/30/declared-but-undefined-variable-in-c/

C++error: declared but undefined variable

I sometimes declare a static field in a header, but fail to define it (i.e. give it storage). It compiles fine and may even link successfully. When you run the executable, you may hit

error loading library /home/nysemkt_integrated_parser.so: undefined symbol: _ZN14arcabookparser6Parser19m_srcDescriptionTknE

Note this is a shared library.
Note the field name is mangled. You can un-mangle it using c++filt:

c++filt _ZN14arcabookparser6Parser19m_srcDescriptionTknE arcabookparser::Parser::m_srcDescriptionTkn

According to Deepak, the binary files only has mangled names. The linker and all subsequent programs deal exclusively with mangled names.

If you don’t use this field, the undefined variable actually will not bother you! I think the compiler just ignores it.

c++class field defined]header, but global vars obey ODR

Let’s put function declaration/definition aside — simpler.

Let’s put aside local static/non-static variables — different story.

Let’s put aside function parameters. They are like local variables.

The word “static” is heavily overloaded and confusing. I will try to avoid it as far as possible.

The tricky/confusing categories are

  • category: static field. Most complex and better discussed in a dedicated post — See https://bintanvictor.wordpress.com/2017/02/07/c-static-field-init-basic-rules/
  • category: file-scope var — i.e. those non-local vars with “static” modifier
  • category: global var declaration — using “extern”
    • definition of the same var — without “extern” or “static”
  • category: non-static class field, same as the classic C struct field <– the main topic in the post. This one is not about declaration/definition of a variable with storage. Instead, this is defining a type!

I assume you can tell a variable declaration vs a variable definition. Our intuition is usually right.

The Aha — [2] pointed out — A struct field listing is merely describing what constitutes a struct type, without actually declaring the existence of any variables, anything to be constructed in memory, anything addressable. Therefore, this listing is more like a integer variable declaration than a definition!

Q: So when is the memory allocated for this field?
A: when you allocate memory for an instance of this struct. The instance then becomes an object in memory. The field also becomes a sub-object.

Main purpose to keep struct definition in header — compiler need to calculate size of the struct. Completely different purpose from function or object declarations in headers. Scott Meyers discussed this in-depth along with class fwd declaration and pimpl.

See also

global^file-scope variables]c++

(Seldom quizzed…) This topic is all about lingo..

The word “static” is heavily overloaded and confusing. I will try to avoid it as far as possible.

Any object declared outside a block has “static duration” which means (see MSDN) “allocated at compile time not run time”

“Global” means extern linkage i.e. visible from other files. You globalize a variable by removing “static” modifier if any.

http://stackoverflow.com/questions/14349877/static-global-variables-in-c explains the 2+1 variations of non-local object

  • a single “static” variable in a *.cpp file. The “static” makes this variable visible only to this file.
  • an extern variable. I used this many times. Basically in one *.cpp it’s declared without “static” or extern. In other *.cpp files, it’s declared extern without a initial value.
    • I also tested a simple alternative — put definition in a header, and extern declaration in another header.
  • wrong way — if you (use a shared header to) declare the same variable “static” in 2 *.cpp files, then each file gets a distinct file-scope variable of the same name. Nonsense.

“File-scope” means internal linkage i.e. visible only within the file. You make a variable file-scope by adding “static”.

https://msdn.microsoft.com/en-us/library/s1sb61xd.aspx

http://en.wikipedia.org/wiki/Global_variable#C_and_C.2B.2B says “Note that not specifying static is the same as specifying extern: the default is external linkage” but I doubt it.

I guess there are 3 forms :

  • static int — file-scope, probably not related to “extern”
  • extern int — global declaration of a var already Defined in a single file somewhere else
  • int (without any modifier) — the single definition of a global var

c++ static field init – basic rules

See also post on extern…

These rules are mostly based on [[c++primer]], about static Field, not local statics or file-scope static variables.

Rule 1 (the “Once” rule) — init must appear AND execute exactly once for each static field.

In my Ticker Plant xtap experience, the static field definition crucially sets aside storage for the static field. The initial value is often unused.

Corollary: avoid doing init in header files, which is often included multiple times.

Rule 2 (the “Twice” rule) — static field Must be DECLARED in the class definition block, and also DEFINED outside. No exception. Therefore, the same variable is “specified” exactly twice [1]. However, the run time would “see” the declaration multiple times if it’s included in multiple places.

Corollary: always illegal to init a static field at both declaration and definition.

[1] Note ‘static’ keyword should be at declaration not definition. Ditto for static methods. See P117 [[essential c++]]

Integer constant fields are special, and can be initialized in 2 ways
* at declaration. However, you MUST still (Rule2) define without initialization. Such a definition is rather non-intuitive and inconsistent with other definitions.
* at definition, outside the class. In this case, declaration would NOT initialize — Rule 1

Rule 3: For all other static fields, init MUST be at-definition, outside the class.

Therefore, it’s simpler to follow Rule 3 for all static fields including integer constants, though other people’s code are beyond my control.

 

c++ uninitialized "static" objects ^ stackVar

By “static” I mean global variables or local static variables. These are Objects with addresses, not mere symbols in source code. Note Some static objects are _implicitly_ static — P221 effC++.

Rule 1: uninitialized local and class fields of primitive types (char, float…) aren’t automatically initialized. See [[programming]] by Stroustrup.

Rule 2: uninitialized statics are automatically initialized to 0 bits at a very early stage of program loading. See
http://stackoverflow.com/questions/2091499/why-global-and-static-variables-are-initialized-to-their-default-values

Rule 3: all class instances are “initialized”, either explicitly, or implicitly via default ctor. Beware. Reconsider Rule 1 — is a field of primitive type of the class initialized? I don’t think so. Therefore, “initialized” means a ctor is called on the new-born instance, but not all fields therein are necessarily initialized. I’d say the ctor can simply ignore a primitive-typed field.

Uninitialized static Objects (stored in BSS segment) don’t take up space in object file. Also, by grouping all the symbols that are not explicitly initialized together, they can be easily zeroed out at once. See
http://stackoverflow.com/questions/9535250/why-is-the-bss-segment-required

Any static Object explicitly initialized by programmer is considered an “initialized” static object and doesn’t go into BSS.

P136 [[understanding and using c pointers]] uses a real example to confirm that a pointer field in a C struct is uninitialized. C has no ctor!

P261 [[programming]] by Stroustrup has a half-pager summary
* globals are default-initialized
* locals and fields are truly uninitialized …
** … unless the data type is a custom class having a default ctor. In that case, you can safely declare the variable without initialization, and content will be a pre-set value.

func^var in header files

Many authors describe a single set of rules for func declaraion vs variable declaration in header files. However, for some beginners, it might make more sense to assume the rules are largely independent and unrelated between func vs var.

Note I will use “include file” and “header file” interchangeably.

The word “static” is heavily overloaded and confusing. I will try to avoid it as far as possible.

(Perhaps because function in header files are implicit global) We are more familiar with the rules on functions
– Rule: each some.cpp file that uses a shared func1() must have func1 “declared”. Best done via include file.
– Rule: across all the .cpp files, there must be exactly 1 definition of func1, otherwise linker complains. Consequently, this must go into a non-include file and seen once only by the linker.

——global variables——-
Let’s start with a big Backgrounder (because it’s rather confusing) — Let’s ignore fields of classes/structs and just focus on classic C variables. The most common and most simple variables are local to a function — function-scope static/non-static variables. The other variables are essentially static-duration variables[1]. A simple type of non-local variable is a file-scope but unshared variable. It can be used across functions within that single file, but here we are interested in global shared variables. I think there are various categories but as hinted in the rather authoritative [[essential c++]] P53, most common is a file-scope static var. The way to globalize such a variable var2 is

Rule: use extern in an include file, so every .cpp file will “see” this extern declaration of var2
Rule: in exactly one .cpp file, define var2 without “extern” or “static”

[1] Someone said online “A local variable is a variable that is declared inside a function. A global variable is a variable that is declared outside all functions“. Scott Meyers discussed “non-local static variable”.

—— static field eg sf2 ——-
See also post on static Field init, and P115 [[essentil c++]]
Usually must be defined exactly once outside class Declaration (which is part of include files). Somewhat similar to shared global variables.

Rule — each some.cpp file that uses this field must have it “declared”. Best done via include file.
Rule — across all the .cpp files, there must be exactly 1 definition of this field. Consequently, this must go into a non-include file and seen once only by the compiler. The field name should be prefixed with the class name, but with the “static” keyword.
Rule — NO “extern” please.
Rule — (special) — const static Integral field can be initialized (not “defined”) in the declaration. See
http://stackoverflow.com/questions/370283/why-cant-i-have-a-non-integral-static-const-member-in-a-class. But watch out for http://stackoverflow.com/questions/3025997/c-defining-static-const-integer-members-in-class-definition