Confused about declaration, definition [duplicate] - c++

This question already has answers here:
Variable declaration vs definition
(3 answers)
What is the difference between a definition and a declaration?
(27 answers)
Closed 5 years ago.
In the book C++ Primer, it states:
A variable definition consists of a type specifier, followed by a list of one or more variable names separated by commas, and ends with a semicolon.
Each name in the list has the type defined by the type specifier.
A definition may (optionally) provide an initial value for one or more of the name it defines.
Now my confusion is that, I've always thought that for built-in types like int, double, float, etc. If I don't explicitly initialize the variable, then that's simply a declaration. For example:
int a; //i thought that this would just be a declaration
int a = 45; //while built-in types with explicit initialization would be a
//definition
Especially, since default initialization states that:
The value of an uninitialized variable of a built-in type is undefined.
(when inside a function)
Yet the book says:
int a; //is a definition (both a declaration and definition)
int b; //is a definition. yet the variable b is undefined.
So now i'm kind of confused as to what constitutes a declaration and what
constitutes a definition? if having and not having an explicit initialization is not the determining factor.
I know the difference between a declaration and definition when it comes to functions/class. That to use a function/class in more than one file requires declarations that are separate from the function's definition.
Where we define the function in only one file (header file). And that other files that use that function/class must declare (not define) when using that class/function.
In addition, I know that:
A declaration specifies the type and name of a variable and makes a name known to the program.
While, a definition creates the associated entity and allocates storage for that particular variable.
But still, i'm a bit puzzled about when something is a definition vs a declaration when it comes built-in types. Basically all built in types with or without an initializer is both a declaration and a definition?
Example:
int x;
double y;
char z;
float g;

int a; is both a declaration (the variable can be used) and a definition (it has its own memory) but if it is an automatic variable, it is not initialized.
extern int a; is a mere declaration and is not a definition.

From here:
Most of the time, when you declare a variable, you are also providing
the definition. What does it mean to define a variable, exactly? It
means you are telling the compiler where to create the storage for
that variable. For example, if you write:
int x;
int main()
{
x = 3;
}
The line int x; both declares and defines the variable; it effectively
says, "create a variable named x, of type int. Also, the storage for
the variable is that it is a global variable defined in the object
file associated with this source file
this is a part from site more relevant to your question
please refer to the link for further your misconception will be hopefully cleared
http://www.cprogramming.com/declare_vs_define.html

Related

Declaration with multiple declarators - Definition?

Is the following declaration also a definition?
int f(), i = 1;
If we would rewrite it like this only the second declaration would be a definition:
int f();
int i = 1;
The c++ standard seems to apply the term definition to entire declarations, but to me it seems like it should be applied to parts of declarations.
Each declarator is individually considered to define or merely declare its identifier.
f() is only declared. There should be a definition somewhere else.
i is defined. A subsequent declaration would need to use extern to avoid being a redefinition.
§3.1 Declarations and definitions in the C++14 standard says,
A declaration is a definition unless it declares a function without specifying the function’s body, it contains the extern specifier or…
The paragraph goes on and on with quite a few rules and exceptions. It may perhaps be a defect in the standard that it fails to mention declarators there, despite discussing features that do not immediately appertain to entire declarations.
We also have §8/3,
Each init-declarator in a declaration is analyzed separately as if it was in a declaration by itself.
This could be interpreted to override the "contagious" formulation of rules in §3.1/2.
Both of them are equivalent statements. In both cases, it is declaration for the function f() and declaration + definition for the variable i.
This declaration
int f(), i = 1;
contains two declarations and one definition. That is it declares a function and it declares and at the same time defines an object.
A function definition is a function declaration that includes its body. However in the declaration above the function does not includes its body. So it is only a declaration of function f with unknown number of parameters if it is a C declaration or without parameters if it is a C++ declaration..
As for variable i then this declaration is at the same time a definition of the variable because a memory is reserved for the corresponding object of type int and moreover the reserved memory is initialized by integer constant 1.
From the C Standard (6.7 Declarations)
5 A declaration specifies the interpretation and attributes of a set
of identifiers. A definition of an identifier is a declaration for
that identifier that:
— for an object, causes storage to be reserved for that object;
— for a function, includes the function body

What is the difference between declaration and definition of a variable in C++? [duplicate]

This question already has answers here:
What is the difference between a definition and a declaration?
(27 answers)
Closed 7 years ago.
My question stems from studying Effective C++ by Scott Meyers.
In Item II of that book, following is written :
To limit the scope of a constant to a class, you must make it a member and, to ensure there's at most one copy of the constant, you must make it a static member.
That is correctly written. Then immediately the following example is given :
class GamePlayer {
private:
static const int NumTurns = 5;
int scores[NumTurns];
....
};
Then the following is written pertaining to the above example :
What you see above is a declaration and not a definition of NumTurns.
My First question is : What is the meaning of this statement ?
Immediately after that the following is mentioned :
Usually C++ requires that you provide a definition for anything you use, but class specific constants that are static and of integral type (e.g - integers, chars, bools) are an exception. As long as you don't take their address, you can declare them and use them without providing a definition. If you do take the address of a class constant, or if your compiler incorrectly insists on a definition even if you don't take the address, you provide a separate definition like this :
const int GamePlayer::Numturns; //definition of NumTurns
Why now it is a definition and not a declaration ?
I understand the difference in the context of a function but do not understand it in the context of a regular variable. Also, can someone expand on what the author means by
... if you do take the address of a class constant, or if your ..
part of the above quoted paragraph ?
P.S : I am a relatively newbie in C++.
Just as with functions, variables can have 'purely declarative' declarations, and actual definitions. You're confused because you probably didn't encounter many pure variable declarations before.
int i; // Definition
extern int i, j; // (Re)declares i, and declares j
extern int j = 0; // Defines j (confusing, eh?)
As you're used to with functions, definitions are declarations, but not all declarations are definitions. §3.1/2 reads
A declaration is a definition unless […] it declares a static data
member in a class definition (9.2, 9.4),
Thus in-class static data member declarations are never defining the variables they declare. However, sometimes, a variables definition doesn't have to be present. That is the case when you can use its value directly without necessitating the variables run-time existence.
In technical terms, as long as a static data member (or any entity, for that matter) is not 'odr-used', it doesn't have to be defined. Odr-use for all entities is defined in §3.2/3:
A variable x whose name appears as a potentially-evaluated expression
ex is odr-used by ex unless applying the lvalue-to-rvalue conversion
(4.1) to x yields a constant expression (5.20) that does not invoke
any non-trivial functions and, if x is an object, ex is an element of
the set of potential results of an expression e, where either the
lvalue-to-rvalue conversion (4.1) is applied to e, or e is a
discarded-value expression (Clause 5).
This looks complicated, and it was simpler in earlier versions of the standard. However, it roughly says that the variable is not odr-used by some expression when that expression "immediately" accesses the variables value, and this access yields a constant expression. Meyers example of "taking its address" is only one of many for odr-use.
For some class A and its static data member i,
class A {
static const int i = 57; // Declaration, not definition
};
const int A::i; // Definition in namespace scope. Not required per se.
It is stated here that:
Static const integral data members initialized in the class interface are not addressable variables. They are mere symbolic names for their associated values. Since they are not variables, it is not possible to determine their addresses. Note that this is not a compilation problem, but a linking problem. The static const variable that is initialized in the class interface does not exist as an addressable entity.
What "addressable entity" refers here is "instance" of static const data type. No instance, no address, i.e its only a declaration.
Note that static variables that are explicitly defined in a source file can be linked correctly, though.
class X
{
public:
static int const s_x = 34;
static int const s_y;
};
int const X::s_y = 12;
int main()
{
int const *ip = &X::s_x; // compiles, but fails to link
ip = &X::s_y; // compiles and links correctly
}
... if you do take the address of a class constant, or if your .. part of the above quoted paragraph ?
It means if such a member is odr-used, a definition at namespace scope is still required, but it should not have an initializer.
struct X {
const static int n = 1;
};
const int* p = &X::n; // X::n is odr-used
const int X::n; // ... so a definition is necessary
Why now it is a definition and not a declaration ?
Because this statement causes the compiler to generate an address for the static variable.
Also, can someone expand on what the author means by "if you do take
the address of a class constant":
When you make a pointer point to a variable you take its address.
A short answer is: a declaration says "this thing exists somewhere", and a definition causes the space to be allocated. In your case, you've declared it to be static and const. The compiler may be smart enough to notice that if you only ever use it as a value, it can simply replace that usage with the literal 5. It doesn't need to actually make space for a variable somewhere and fill it with the 5, it can use the 5 directly at compile-time. However, if you take the address of it, the compiler can no longer make that assumption and now needs to put that 5 into somewhere addressable. The compiler needs it to exist in one translation unit (roughly: one cpp file. See also the One Definition Rule.), so now you have to explicitly declare it somewhere.

static variable in the class declaration or definition?

I am new to C++.
I have a class like this:
class CodeTest
{
private:
static const int TOTAL=100;
};
Is TOTAL a declaration or a definition?
When I was reading Scott Meyer's book, it was mentioned that in the implementation file we need to define something like:
const int CodeTest::TOTAL;
Why is this required?
The declaration in an implementation file outside of the header is required because otherwise every translation unit that includes this header would define its own object (that is, its own storage for the variable).
This would violate the One Definition Rule. A consequence would be e.g. that if the variable was changed in one translation unit, this change would be invisible to other translation units. Now, this isn’t that relevant since the variable is constant. However, taking its address would also yield different pointers in different translation units.
Since this stirred up some controversy, I looked in the standard, and #Nawaz is right, I was wrong.
9.4.2/2
If a static data member is of const integral type [...]. The member
shall still be defined in a namespace scope if it is used in the
program and the namespace scope definition shall not contain an
initializer.
So what you have there is a declaration, and the variable is initialized to a value. Outside the class you must define the variable, but not assign a value to it.
The part with const integral type only applies to this particular case - i.e. you can initialize said type inside the class, but all static data members must be defined outside.
To answer the question:
Regardless of whether the definition is or isn't required outside the class (depending on whether you use the member or not), whatever is inside the class (initialized or not) is just a declaration.
First part of the question:
This line: static const int TOTAL=100; is a declaration followed by an initialisation.
TOTAL is an identifier.
Second part of the question
const int CodeTest::TOTAL is required to initialize the variable.
static const int TOTAL=100; // is a declaration followed by an initialisation.
From the C++ standard section 3.1:
A declaration introduces names into a translation unit or redeclares names introduced by previous declarations. A declaration specifies the interpretation and attributes of these names.
The next paragraph states that a declaration is a definition unless...... it declares a static member within a class definition:
struct X
{
int a; // defines a
static int b; // declares b
};
You can read more about definition and declaration here: SO: What is the difference between a definition and a declaration?

Why can you initialize a static const variable inline but not a plain static (C++)

If I were to do this
class Gone
{
public:
static const int a = 3;
}
it works but if do
class Gone
{
public:
static int a = 3;
}
it gives a compile error. Now I know why the second one doesn't work, I just don't know why the first one does.
Thanks in advance.
This trick works only for constant compile-time expressions. Consider the following simple example:
#include <iostream>
class Foo {
public:
static const int bar = 0;
};
int main()
{
std::cout << Foo::bar << endl;
}
It works just fine, because compiler knows that Foo::bar is 0 and never changes. Thus, it optimizes the whole thing away.
However, the whole thing breaks once you take the address of that variable like this:
int main()
{
std::cout << Foo::bar << " (" << &Foo::bar << ")" << std::endl;
}
Linker sends you to fix the program because compile-time constants don't have addresses.
Now, the second case in your example doesn't work simply because a non-constant variable cannot be a constant compile-time expression. Thus, you have to define it somewhere and cannot assign any values in initialization.
C++11, by the way, has constexpr. You can check Generalized constant expressions wiki (or C++11 standard :-)) for more info.
Also, be careful - with some toolchains you will never be able to link program as listed in your first example when optimizations are turned off, even if you never take an address of those variables. I think there is a BOOST_STATIC_CONSTANT macro in Boost to work around this problem (not sure if it works though because I reckon seeing linkage failures with some old gcc even with that macro).
The static const int declaration is legal because you're declaring a constant, not a variable. a doesn't exist as a variable - the compiler is free to optimize it out, replacing it with the declared value 3 anywhere a reference to Gone::a appears. C++ allows the static initialization in this restricted case where it's an integer constant.
You can find more details, including an ISO C++ standard citation here.
Initialization of variables has to be done at the point of definition, not the point of declaration in the general case. Inside the class brackets you only have a declaration and you need to provide a definition in a single translation unit*:
// can be in multiple translation units (i.e. a header included in different .cpp's)
struct test {
static int x; // declaration
static double d; // declaration
};
// in a single translation unit in your program (i.e. a single .cpp file)
int test::x = 5; // definition, can have initialization
double test::d = 5.0; // definition
That being said, there is an exception for static integral constants (and only integral constants) where you can provide the value of the constant in the declaration. The reason for the exception is that it can be used as a compile-time constant (i.e. to define the size of an array), and that is only possible if the compiler sees the value of the constant in all translation units where it is needed.
struct test {
static const int x = 5; // declaration with initialization
};
const int test::x; // definition, cannot have initialization
Going back to the original question:
Why is it not allowed for non-const integers?
because initialization happens in the definition and not declaration.
Why is it allowed for integral constants?
so that it can be used as a compile-time constant in all translation units
* The actual rules require the definition whenever the member attribute is used in the program. Now the definition of used is a bit tricky in C++03 as it might not be all that intuitive, for example the use of that constant as an rvalue does not constitute use according to the standard. In C++11 the term used has been replaced with odr-used in an attempt to avoid confusion.
A static const is defined in the class definition since everybody that uses the code need to know the value at compile time, not link time. An ordinary static is actually only declared in the class definition, but defined once, in one translation unit.
I seem to recall that originally (ARM) it was not allowed, and we used to use enum to define constants in class declarations.
The const case was explicitly introduced so as to support availability of the value in headers for use in constant expressions, such as array sizes.
I think (and please comment if I have this wrong) that strictly you still need to define the value:
const int Gone::a;
to comply with the One Definition Rule. However, in practice, you might find that the compiler optimises away the need for an address for Gone::a and you get away without it.
If you take:
const int* b = &Gone::a;
then you might find you do need the definition.
See the standard, $9.4.2:
ISO 1998:
"4 If a static data member is of const integral or const enumeration
type, its declaration in the class definition can specify a
constantinitializer which shall be an integral constant expression
(5.19). In that case, the member can appear in integral constant
expressions within its scope. The member shall still be defined in a
namespace scope if it is used in the program and the namespace scope
definition shall not contain an initializer."
Draft for c++11:
"3 If a static data member is of const effective literal type, its
declaration in the class definition can specify a constant-initializer
brace-or-equal-initializer with an initializer-clause that is an
integral constant expression. A static data member of effective
literal type can be declared in the class definition with the
constexpr specifier; if so, its declaration shall specify a
constant-initializer brace-or-equal-initializer with an
initializerclause that is an integral constant expression. In both
these cases, the member may appear in integral constant expressions.
The member shall still be defined in a namespace scope if it is used
in the program and the namespace scope definition shall not contain an
initializer."
I am not sure entirely what this covers, but I think it means that we can now use the same idiom for floating point and possibly string literals.

Why does declaring a "static const" member in a header file cause linker errors?

I have a class declaration(.h file) like so:
struct MyClass {
static const uint32_t SIZE = sizeof(MyType);
};
When linking my program together, I get linker errors for MyClass::SIZE. nm confirms that the symbol is undefined. http://forums.devshed.com/c-programming-42/linker-errors-undefined-reference-to-static-member-data-193010.html seems to address my problem, indicating that "class static objects must also be declared outside any function or class just like normal globals."
I have two questions:
Is this explanation valid for my case? If so, can you explain in a little more detail why this is true?
What's the best way to fix it? I'd like to keep this member's initialization entirely in the .h file.
Your problem may have nothing to do with someone taking the address of your variable. It could simply be the compiler opting not to use the variable as a constant expression even though it could. For example:
f(int const&);
struct X { enum { enum_val = 42 }; static int const static_mem = 42; };
f(5);
f(X::enum_val);
f(X::static_mem);
In the first two cases the compiler is required to use the input as a constant expression and the const& can be initialized with such. The last case however is different. Even though your intent is probably to use static_mem as a constant expression, and its completely legitimate to do so, the compiler is free to do otherwise and some will actually create a reference to the variable itself. This is "use" of the variable and thus you're required to have a definition of that variable somewhere in the program.
There's two ways to fix this issue:
1) Add a definition to your program.
2) Use enum instead:
struct X
{
enum { static_mem = ? };
};
The first solution is necessary if you ever do intend that taking the address of your variable be possible. Chances are though that you did not or you would have created that definition already. The later solution forces the compiler to use X::static_mem as a constant expression since enum members don't actually exist as objects in the program. Based on your last statement in your question, I'm betting this is the solution you really want.
The standard requires a definition for a static member integral constant only if its address is taken, otherwise the declaration with an initializer (what you have) is enough. That linker error message should mention which object/function takes an address of MyClass::SIZE.
Quoting myself from No definition available for static const member with initializer?
And from 9.4.2/4:
If a static data member is of const
integral or const enumeration type,
its declaration in the class
definition can specify a
constant initializer which shall be an
integral constant expression (5.19).
In that case, the member can appear in
integral constant expressions within
its scope. The member shall still be
defined in a namespace scope if it is
used in the program and the namespace
scope definition shall not contain an
initializer.
From these references we can infer ("...shall still be defined..." in 9.4.2/4) that if it's not defined then the program isn't well-formed.
#David Rodríguez - dribeas points out that you must be taking the address of the static member in your program somewhere. If you can avoid taking the address then there's no need for the definition in the implementation file (alternately you aren't taking the address and have a buggy compiler). Otherwise you must have the definition.
If you've to do this:
//.h file
struct MyClass
{
static const uint32_t SIZE = sizeof(MyType); //this is declaration!
};
//.cpp file
const uint32_t MyClass::SIZE; //this is definition - necessary!
Most likely, but without any error messages, it's hard to say.
Use a static const int. You can initialize it in the header, and you don't need to declare it in the cpp.