Related
1.
int Add (int a, int b = 3);
int Add (int a, int b)
{
}
2.
int Add (int a, int b);
int Add (int a, int b = 3)
{
}
Both work; which is the standard way and why?
If you put the declaration in a header file, and the definition in a separate .cpp file, and #include the header from a different .cpp file, you will be able to see the difference.
Specifically, suppose:
lib.h
int Add(int a, int b);
lib.cpp
int Add(int a, int b = 3) {
...
}
test.cpp
#include "lib.h"
int main() {
Add(4);
}
The compilation of test.cpp will not see the default parameter declaration, and will fail with an error.
For this reason, the default parameter definition is usually specified in the function declaration:
lib.h
int Add(int a, int b = 3);
In C++ the requirements imposed on default arguments with regard to their location in parameter list are as follows:
Default argument for a given parameter has to be specified no more than once. Specifying it more than once (even with the same default value) is illegal.
Parameters with default arguments have to form a contiguous group at the end of the parameter list.
Now, keeping that in mind, in C++ you are allowed to "grow" the set of parameters that have default arguments from one declaration of the function to the next, as long as the above requirements are continuously satisfied.
For example, you can declare a function with no default arguments
void foo(int a, int b);
In order to call that function after such declaration you'll have to specify both arguments explicitly.
Later (further down) in the same translation unit, you can re-declare it again, but this time with one default argument
void foo(int a, int b = 5);
and from this point on you can call it with just one explicit argument.
Further down you can re-declare it yet again adding one more default argument
void foo(int a = 1, int b);
and from this point on you can call it with no explicit arguments.
The full example might look as follows
void foo(int a, int b);
int main()
{
foo(2, 3);
void foo(int a, int b = 5); // redeclare
foo(8); // OK, calls `foo(8, 5)`
void foo(int a = 1, int b); // redeclare again
foo(); // OK, calls `foo(1, 5)`
}
void foo(int a, int b)
{
// ...
}
As for the code in your question, both variants are perfectly valid, but they mean different things. The first variant declares a default argument for the second parameter right away. The second variant initially declares your function with no default arguments and then adds one for the second parameter.
The net effect of both of your declarations (i.e. the way it is seen by the code that follows the second declaration) is exactly the same: the function has default argument for its second parameter. However, if you manage to squeeze some code between the first and the second declarations, these two variants will behave differently. In the second variant the function has no default arguments between the declarations, so you'll have to specify both arguments explicitly.
The first way would be preferred to the second.
This is because the header file will show that the parameter is optional and what its default value will be. Additionally, this will ensure that the default value will be the same, no matter the implementation of the corresponding .cpp file.
In the second way, there is no guarantee of a default value for the second parameter. The default value could change, depending on how the corresponding .cpp file is implemented.
Default arguments must be specified with the first occurrence of the function name—typically, in the function prototype. If the function prototype is omitted because the function definition also serves as the prototype, then the default arguments should be specified in the function header.
On thing to remember here is that the default param must be the last param in the function definition.
Following code will not compile:
void fun(int first, int second = 10, int third);
Following code will compile:
void fun(int first, int second, int third = 10);
As shown highlighted in attached snapshot,starting line of main function,i know that it is starting point of main function but what is the proper term for it?can we call it function declaration line?
I don't know about C, but here are some snippets from the C++23 draft:
dcl.fct.def/3
Example 1: A simple example of a complete function definition is
int max(int a, int b, int c) {
int m = (a > b) ? a : b;
return (m > c) ? m : c;
}
Here int is the decl-specifier-seq; max(int a, int b, int c) is the declarator; { /* ... */ } is the function-body. — end example]
So, in int main() we get that int is the decl-specifier-seq and main() is the declarator.
We also have another example (sorry for only finding examples) dcl.fct/9:
[Example 5: The declaration
int fseek(FILE*, long, int);
declares a function taking three arguments of the specified types, and returning int ([dcl.type]). — end example]
(while not formal), I deduce that the combination of the decl-specifier-seq and the declarator makes the int main() part a declaration.
This line
int main()
in the function definition (that is at the same time a function declaration) is called the function declarator that has the return type (type specifier) int.
That is this code snippet in whole
int main()
{
//...
}
is a function declaration that introduce the identifier main in the file scope.
Pay attention to that according to the C Standard the function declarator of main that does not accept arguments shall be declared like
int main( void )
There are two terms in C and C++ that share a common usage, and unfortunately often gets confused with each other. The terms are declaration and definition.
A declaration is telling the compiler that something (a "name") exists, somewhere in the program. A definition is the implementation of the thing that was declared.
For functions, you can have a declaration and definition at the same time.
For example lets say your program have a function named foo, taking one int argument and returning a int value. It can be declared as:
int foo(int arg);
This declaration of the function is also known as declaring the prototype of the function. You need to have this declaration before you call the function, or the compiler won't know that it exist. After the declaration it's possible to call the function, the compiler don't need to see the full implementation of the function, only the declaration.
Then we have the definition, where we implement the function:
int foo(int arg)
{
return arg * 2;
}
Now lets take another function bar which takes no arguments and returns no value. It has no previous declaration, only a definition:
void bar(void)
{
// Does something here...
}
But because there's no existing declaration before the definition, the definition is also is the declaration.
Also note that there is a big difference between C and C++ when it comes to function declarations.
In C a function taking no arguments must use the argument type void. Not specifying any arguments:
void some_function();
actually declares the function some_function as taking an indeterminate number of arguments of indeterminate type. The C compiler will then fill in the missing arguments details when the first call is made, or when it finds another declaration (or definition) that specifies the arguments.
In C++ such a declaration declares the function as taking no arguments.
This is only one difference between C and C++, and the reason why many of us here don't like questions being tabbed with both languages, or the term "C/C++".
In simple terms, function declaration means are just declaring the function name, its arguments and its return type.
e.g.
int foo(int x, int y); ==> Function declaration ends with semicolon ;
Function definition means you are actually defining the functionality.
e.g.
int foo(int x, int y){
return x+y;
} ==> Function definition enclosed within curly braces { }
And the given main() function is function definition.
In general terms, for conventional purpose may be you can call the first line of a function definition as "function header".
And the entire code within the curly braces { } of the function definition as "function body".
The meaning of both eludes me.
A declaration introduces an identifier and describes its type, be it a type, object, or function. A declaration is what the compiler needs to accept references to that identifier. These are declarations:
extern int bar;
extern int g(int, int);
double f(int, double); // extern can be omitted for function declarations
class foo; // no extern allowed for type declarations
A definition actually instantiates/implements this identifier. It's what the linker needs in order to link references to those entities. These are definitions corresponding to the above declarations:
int bar;
int g(int lhs, int rhs) {return lhs*rhs;}
double f(int i, double d) {return i+d;}
class foo {};
A definition can be used in the place of a declaration.
An identifier can be declared as often as you want. Thus, the following is legal in C and C++:
double f(int, double);
double f(int, double);
extern double f(int, double); // the same as the two above
extern double f(int, double);
However, it must be defined exactly once. If you forget to define something that's been declared and referenced somewhere, then the linker doesn't know what to link references to and complains about a missing symbols. If you define something more than once, then the linker doesn't know which of the definitions to link references to and complains about duplicated symbols.
Since the debate what is a class declaration vs. a class definition in C++ keeps coming up (in answers and comments to other questions) , I'll paste a quote from the C++ standard here.
At 3.1/2, C++03 says:
A declaration is a definition unless it [...] is a class name declaration [...].
3.1/3 then gives a few examples. Amongst them:
[Example: [...]
struct S { int a; int b; }; // defines S, S::a, and S::b [...]
struct S; // declares S
—end example
To sum it up: The C++ standard considers struct x; to be a declaration and struct x {}; a definition. (In other words, "forward declaration" a misnomer, since there are no other forms of class declarations in C++.)
Thanks to litb (Johannes Schaub) who dug out the actual chapter and verse in one of his answers.
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 (emphasis mine) that a declaration is a definition unless...
... it declares a function without specifying the function’s body:
void sqrt(double); // declares sqrt
... it declares a static member within a class definition:
struct X
{
int a; // defines a
static int b; // declares b
};
... it declares a class name:
class Y;
... it contains the extern keyword without an initializer or function body:
extern const int i = 0; // defines i
extern int j; // declares j
extern "C"
{
void foo(); // declares foo
}
... or is a typedef or using statement.
typedef long LONG_32; // declares LONG_32
using namespace std; // declares std
Now for the big reason why it's important to understand the difference between a declaration and definition: the One Definition Rule. From section 3.2.1 of the C++ standard:
No translation unit shall contain more than one definition of any variable, function, class type, enumeration type, or template.
Declaration: "Somewhere, there exists a foo."
Definition: "...and here it is!"
There are interesting edge cases in C++ (some of them in C too). Consider
T t;
That can be a definition or a declaration, depending on what type T is:
typedef void T();
T t; // declaration of function "t"
struct X {
T t; // declaration of function "t".
};
typedef int T;
T t; // definition of object "t".
In C++, when using templates, there is another edge case.
template <typename T>
struct X {
static int member; // declaration
};
template<typename T>
int X<T>::member; // definition
template<>
int X<bool>::member; // declaration!
The last declaration was not a definition. It's the declaration of an explicit specialization of the static member of X<bool>. It tells the compiler: "If it comes to instantiating X<bool>::member, then don't instantiate the definition of the member from the primary template, but use the definition found elsewhere". To make it a definition, you have to supply an initializer
template<>
int X<bool>::member = 1; // definition, belongs into a .cpp file.
Declaration
Declarations tell the compiler that a
program element or name exists. A
declaration introduces one or more
names into a program. Declarations can
occur more than once in a program.
Therefore, classes, structures,
enumerated types, and other
user-defined types can be declared for
each compilation unit.
Definition
Definitions specify what code or data
the name describes. A name must be
declared before it can be used.
From the C99 standard, 6.7(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;
for an enumeration constant or typedef name, is the (only) declaration of the
identifier.
From the C++ standard, 3.1(2):
A declaration is a definition unless it declares a function without specifying the function's body, it contains the extern specifier or a linkage-specification and neither an initializer nor a function-body, it declares a static data member in a class declaration, it is a class name declaration, or it is a typedef declaration, a using-declaration, or a using-directive.
Then there are some examples.
So interestingly (or not, but I'm slightly surprised by it), typedef int myint; is a definition in C99, but only a declaration in C++.
From wiki.answers.com:
The term declaration means (in C) that you are telling the compiler about type, size and in case of function declaration, type and size of its parameters of any variable, or user defined type or function in your program. No space is reserved in memory for any variable in case of declaration. However compiler knows how much space to reserve in case a variable of this type is created.
for example, following are all declarations:
extern int a;
struct _tagExample { int a; int b; };
int myFunc (int a, int b);
Definition on the other hand means that in additions to all the things that declaration does, space is also reserved in memory. You can say "DEFINITION = DECLARATION + SPACE RESERVATION" following are examples of definition:
int a;
int b = 0;
int myFunc (int a, int b) { return a + b; }
struct _tagExample example;
see Answers.
C++11 Update
Since I don't see an answer pertinent to C++11 here's one.
A declaration is a definition unless it declares a/n:
opaque enum - enum X : int;
template parameter - T in template<typename T> class MyArray;
parameter declaration - x and y in int add(int x, int y);
alias declaration - using IntVector = std::vector<int>;
static assert declaration - static_assert(sizeof(int) == 4, "Yikes!")
attribute declaration (implementation-defined)
empty declaration ;
Additional clauses inherited from C++03 by the above list:
function declaration - add in int add(int x, int y);
extern specifier containing declaration or a linkage specifier - extern int a; or extern "C" { ... };
static data member in a class - x in class C { static int x; };
class/struct declaration - struct Point;
typedef declaration - typedef int Int;
using declaration - using std::cout;
using directive - using namespace NS;
A template-declaration is a declaration. A template-declaration is also a definition if its declaration defines a function, a class, or a static data member.
Examples from the standard which differentiates between declaration and definition that I found helpful in understanding the nuances between them:
// except one all these are definitions
int a; // defines a
extern const int c = 1; // defines c
int f(int x) { return x + a; } // defines f and defines x
struct S { int a; int b; }; // defines S, S::a, and S::b
struct X { // defines X
int x; // defines non-static data member x
static int y; // DECLARES static data member y
X(): x(0) { } // defines a constructor of X
};
int X::y = 1; // defines X::y
enum { up , down }; // defines up and down
namespace N { int d; } // defines N and N::d
namespace N1 = N; // defines N1
X anX; // defines anX
// all these are declarations
extern int a; // declares a
extern const int c; // declares c
int f(int); // declares f
struct S; // declares S
typedef int Int; // declares Int
extern X anotherX; // declares anotherX
using N::d; // declares N::d
// specific to C++11 - these are not from the standard
enum X : int; // declares X with int as the underlying type
using IntVector = std::vector<int>; // declares IntVector as an alias to std::vector<int>
static_assert(X::y == 1, "Oops!"); // declares a static_assert which can render the program ill-formed or have no effect like an empty declaration, depending on the result of expr
template <class T> class C; // declares template class C
; // declares nothing
Definition :
extern int a; // Declaration
int a; // Definition
a = 10 // Initialization
int b = 10; // Definition & Initialization
Definition associates the variable with a type and allocates memory, whereas declaration just specifies the type but doesn't allocate memory. Declaration is more useful when you want to refer the variable before definition.
*Don't confuse definition with initialization. Both are different, initialization gives value to the variable. See the above example.
Following are some examples of definition.
int a;
float b;
double c;
Now function declaration :
int fun(int a,int b);
Note the semicolon at the end of function so it says it is only a declaration. Compiler knows that somewhere in the program that function will be defined with that prototype. Now if the compiler gets a function call something like this
int b=fun(x,y,z);
Compiler will throw an error saying that there is no such function. Because it doesn't has any prototype for that function.
Note the difference between two programs.
Program 1
#include <stdio.h>
void print(int a)
{
printf("%d",a);
}
main()
{
print(5);
}
In this, print function is declared and defined as well. Since function call is coming after the definition. Now see the next program.
Program 2
#include <stdio.h>
void print(int a); // In this case this is essential
main()
{
print(5);
}
void print(int a)
{
printf("%d",a);
}
It is essential because function call precedes definition so compiler must know whether there is any such function. So we declare the function which will inform the compiler.
Definition :
This part of defining a function is called Definition. It says what to do inside the function.
void print(int a)
{
printf("%d",a);
}
To understand the nouns, let's focus on the verbs first.
declare -
to announce officially; proclaim
define -
to show or describe (someone or something) clearly and completely
So, when you declare something, you just tell what it is.
// declaration
int sum(int, int);
This line declares a C function called sum that takes two arguments of type int and returns an int. However, you can't use it yet.
When you provide how it actually works, that's the definition of it.
// definition
int sum(int x, int y)
{
return x + y;
}
definition means actual function written & declaration means simple declare function
for e.g.
void myfunction(); //this is simple declaration
and
void myfunction()
{
some statement;
}
this is definition of function myfunction
Rule of thumb:
A declaration tells the compiler how to interpret the variable's data in memory. This is needed for every access.
A definition reserves the memory to make the variable existing. This has to happen exactly once before first access.
To understand the difference between declaration and definition we need to see the assembly code:
uint8_t ui8 = 5; | movb $0x5,-0x45(%rbp)
int i = 5; | movl $0x5,-0x3c(%rbp)
uint32_t ui32 = 5; | movl $0x5,-0x38(%rbp)
uint64_t ui64 = 5; | movq $0x5,-0x10(%rbp)
double doub = 5; | movsd 0x328(%rip),%xmm0 # 0x400a20
movsd %xmm0,-0x8(%rbp)
and this is only definition:
ui8 = 5; | movb $0x5,-0x45(%rbp)
i = 5; | movl $0x5,-0x3c(%rbp)
ui32 = 5; | movl $0x5,-0x38(%rbp)
ui64 = 5; | movq $0x5,-0x10(%rbp)
doub = 5; | movsd 0x328(%rip),%xmm0 # 0x400a20
movsd %xmm0,-0x8(%rbp)
As you can see nothing change.
Declaration is different from definition because it gives information used only by the compiler. For example uint8_t tell the compiler to use asm function movb.
See that:
uint def; | no instructions
printf("some stuff..."); | [...] callq 0x400450 <printf#plt>
def=5; | movb $0x5,-0x45(%rbp)
Declaration haven't an equivalent instruction because it is no something to be executed.
Furthermore declaration tells the compiler the scope of the variable.
We can say that declaration is an information used by the compiler to establish the correct use of the variable and for how long some memory belongs to certain variable.
Find similar answers here: Technical Interview Questions in C.
A declaration provides a name to the program; a definition provides a unique description of an entity (e.g. type, instance, and function) within the program. Declarations can be repeated in a given scope, it introduces a name in a given scope.
A declaration is a definition unless:
Declaration declares a function without specifying its body,
Declaration contains an extern specifier and no initializer or function body,
Declaration is the declaration of a static class data member without a class definition,
Declaration is a class name definition,
A definition is a declaration unless:
Definition defines a static class data member,
Definition defines a non-inline member function.
Declaration says "this thing exists somewhere"
int sampleFunc(); // function
extern int car; // variable
Definition says "this thing exists here; make memory for it"
int sampleFunc() {} // function
int car; // variable
Initialization is optional at the point of definition for objects, and says "here is the initial value for this thing":
int car = 0; // variable
Couldnt you state in the most general terms possible, that a declaration is an identifier in which no storage is allocated and a definition actually allocates storage from a declared identifier?
One interesting thought - a template cannot allocate storage until the class or function is linked with the type information. So is the template identifier a declaration or definition? It should be a declaration since no storage is allocated, and you are simply 'prototyping' the template class or function.
A declaration presents a symbol name to the compiler. A definition is a declaration that allocates space for the symbol.
int f(int x); // function declaration (I know f exists)
int f(int x) { return 2*x; } // declaration and definition
This is going to sound really cheesy, but it's the best way I've been able to keep the terms straight in my head:
Declaration: Picture Thomas Jefferson giving a speech... "I HEREBY DECLARE THAT THIS FOO EXISTS IN THIS SOURCE CODE!!!"
Definition: picture a dictionary, you are looking up Foo and what it actually means.
According to the GNU C library manual (http://www.gnu.org/software/libc/manual/html_node/Header-Files.html)
In C, a declaration merely provides information that a function or variable exists and gives its type. For a function declaration, information about the types of its arguments might be provided as well. The purpose of declarations is to allow the compiler to correctly process references to the declared variables and functions. A definition, on the other hand, actually allocates storage for a variable or says what a function does.
Adding definition and declaration examples from the C++ standard document(from the section 3.1 Declarations and definitions)
Definitions:
int a; // defines a
extern const int c = 1; // defines c
int f(int x) { return x+a; } // defines f and defines x
struct S { int a; int b; }; // defines S, S::a, and S::b
struct X { // defines X
int x; // defines non-static data member x
static int y; // DECLARES static data member y
X(): x(0) { } // defines a constructor of X
};
int X::y = 1; // defines X::y
enum { up, down }; // defines up and down
namespace N { int d; } // defines N and N::d
namespace N1 = N; // defines N1
X anX; // defines anX
Declarations:
extern int a; // declares a
extern const int c; // declares c
int f(int); // declares f
struct S; // declares S
typedef int Int; // declares Int
extern X anotherX; // declares anotherX
using N::d; // declares d
The concept of Declaration and Definition will form a pitfall when you are using the extern storage class because your definition will be in some other location and you are declaring the variable in your local code file (page). One difference between C and C++ is that in C you the declarations are done normally at the beginning of a function or code page. In C++ it's not like that. You can declare at a place of your choice.
My favorite example is "int Num = 5" here your variable is 1. defined as int 2. declared as Num and 3. instantiated with a value of five. We
Define the type of an object, which may be built-in or a class or struct.
Declare the name of an object, so anything with a name has been declared which includes Variables, Funtions, etc.
A class or struct allows you to change how objects will be defined when it is later used. For example
One may declare a heterogeneous variable or array which are not specifically defined.
Using an offset in C++ you may define an object which does not have a declared name.
When we learn programming these two terms are often confused because we often do both at the same time.
Stages of an executable generation:
(1) pre-processor -> (2) translator/compiler -> (3) linker
In stage 2 (translator/compiler), declaration statements in our code tell to the compiler that these things we are going to use in future and you can find definition later, meaning is :
translator make sure that : what is what ? means declaration
and (3) stage (linker) needs definition to bind the things
Linker make sure that : where is what ? means definition
There are some very clear definitions sprinkled throughout K&R (2nd edition); it helps to put them in one place and read them as one:
"Definition" refers to the place where the variable is created or assigned storage; "declaration" refers to the places where the nature of the variable is stated but no storage is allocated. [p. 33]
...
It is important to distinguish between the declaration of an external variable and its definition. A declaration announces the properties of a variable (primarily its type); a definition also causes storage to be set aside.
If the lines
int sp;
double val[MAXVAL]
appear outside of any function, they define the external variables sp and val, cause storage to be set aside, and also serve as the declaration for the rest of that source file.
On the other hand, the lines
extern int sp;
extern double val[];
declare for the rest of the source file that sp is an int and that val is a double array (whose size is determined elsewhere), but they do not create the variables or reserve storage for them.
There must be only one definition of an external variable among all the files that make up the source program. ... Array sizes must be specified with the definition, but are optional with an extern declaration. [pp. 80-81]
...
Declarations specify the interpretation given to each identifier; they do not necessarily reserve storage associated with the identifier. Declarations that reserve storage are called definitions. [p. 210]
The declaration is when a primitive or object reference variable or method is created without assigning value or object.
int a;
final int a;
The definition means assigning the value or object respectively
int a =10;
Initialization means allocating memory for a respective variable or object.
Declaration of a variable is for informing to the compiler the following information: name of the variable, type of value it holds and the initial value if any it takes. i.e., declaration gives details about the properties of a variable. Whereas, Definition of a variable says where the variable gets stored. i.e., memory for the variable is allocated during the definition of the variable.
Declaration means give name and type to a variable (in case of variable declaration), eg:
int i;
or give name,return type and parameter(s) type to a function without body(in case of function declaration), eg:
int max(int, int);
whereas definition means assign value to a variable (in case of variable definition), eg:
i = 20;
or provide/add body(functionality) to a function is called function definition, eg:
int max(int a, int b)
{
if(a>b) return a;
return b;
}
many time declaration and definition can be done together as:
int i=20;
and:
int max(int a, int b)
{
if(a>b) return a;
return b;
}
In above cases we define and declare variable i and function max().
For example, let's consider the static storage class specifier. Here are a few examples of both valid and ill-formed uses of this storage class specifier:
static int a; // valid
int static b; // valid
static int* c; // valid
int static* d; // valid
int* static e; // ill-formed
static int const* f; // valid
int static const* g; // valid
int const static* h; // valid
int const* static i; // ill-formed
typedef int* pointer;
static pointer j; // valid
pointer static k; // valid
(The declarations marked "valid" were accepted by Visual C++ 2012, g++ 4.7.2, and Clang++ 3.1. The declarations marked "ill-formed" were rejected by all of those compilers.)
This seems odd because the storage class specifier applies to the declared variable. It is the declared variable that is static, not the type of the declared variable. Why are e and i ill-formed, but k is well-formed?
What are the rules that govern valid placement of storage class specifiers? While I've used static in this example, the question applies to all storage class specifiers. Preferably, a complete answer should cite relevant sections of the C++11 language standard and explain them.
In summary, anywhere in the declaration specifier (See section 7.1 in the ISO/IEC 14882-2012), ie before the *. Qualifiers after the * are associated with the pointer declarator, not the type specifier, and static doesn't make sense within the context of a pointer declarator.
Consider the following cases:
You can declare a normal int and a pointer to an int in the same declaration list, like this:
int a, *b;
this is because the type specifier is int, then you have two declarations using that type specifier int, a, and a pointer declarator *a which declares a pointer to int. Now consider:
int a, static b; // error
int a, *static b; // error
int a, static *b; // error
which should look wrong (as they are), and the reason (as defined in sections 7.1 and 8.1) is because C and C++ require that your storage specifiers go with your type specifier, not in your declarator.
So now it should be clear that that the following is also wrong, since the above three are also wrong:
int *static a; // error
Your last example,
typedef int* pointer;
static pointer j; // valid
pointer static k; // valid
are both valid and both equivalent because the pointer type is defined as a type specifier and you can put your type specifier and storage specifeir in any order. Note that they are both equivalent and would be equivalent to saying
static int *j;
static int *k;
or
int static *j;
int static *k;
Per 7.1, the [simplified] structure of C++ declaration is
decl-specifier-seq init-declarator-list;
Per 7.1/1, storage class specifiers belong in the initial "common" part decl-specifier-seq.
Per 8/1, init-declarator-list is a sequence of declarators.
Per 8/4, the * part of pointer declaration is a part of an individual declarator in that sequence. This immediately means that everything that follows a * is a part of that individual declarator. This is why some of your storage class specifier placements are invalid. Declarator syntax does not allow inclusion of storage class specifiers.
The rationale is rather obvious: since storage class specifiers are supposed to apply to all declarators in the whole declaration, they are placed into the "common" part of the declaration.
I'd say that a more interesting (and somewhat related) situation takes place with specifiers that can be present in both decl-specifier-seq and individual declarators, like const specifier. For example, in the following declaration
int const *a, *b;
does const apply to all declarators or only to the first one? The grammar dictates the former interpretation: that const applies to all declarators, i.e. it is a part of the decl-specifier-seq.
If you employ the "Golden Rule" (which also doesn't apply only to pointers) it follows naturally, intuitively, and it avoids a lot of mistakes and pitfalls when declaring variables in C/C++. The "Golden Rule" should not be violated (there are rare exceptions, like const applied to array typedefs, which propagates const to the base type, and references, that came with C++).
K&R, Appendix A, Section 8.4, Meaning of Declarators states:
Each declarator is taken to be an assertion that when a construction of the same form as the declarator appears in an expression, it yields an object of the indicated type and storage class.
To declare a variable in C/C++ you should really think of the expression you should apply to it to get the base type.
1) There should be a variable name
2) Then comes the expression as valid* out of the declaration statement, applied to the variable name
3) Then comes the remaining information and properties of declaration like base type and storage
Storage is not a characteristic you can always confer to the outcome of expressions, contrary to constness for example. It makes sense only at declaration. So storage must come somewhere else that's not in 2.
int * const *pp;
/*valid*/
int * static *pp;
/*invalid, this clearly shows how storage makes no sense for 2 and so breaks */
/*the golden rule. */
/*It's not a piece of information that goes well in the middle of a expression.*/
/*Neither it's a constraint the way const is, it just tells the storage of */
/*what's being declared. */
I think K&R wanted us to use inverted reasoning when declaring variables, it's frequently not the common habit. When used, it avoids most of complex declaration mistakes and difficulties.
*valid is not in a strict sense, as some variations occur, like x[], x[size, not indexing], constness, etc... So 2 is a expression that maps well (for the declaration usage), "same form", one that reflects variable's use, but not strictly.
Golden Rule Bonus for the Uninitiated
#include <iostream>
int (&f())[3] {
static int m[3] = {1, 2, 3};
return m;
}
int main() {
for(int i = 0; i < sizeof(f()) / sizeof(f()[0]); ++i)
std::cout << f()[i] << std::endl;
return 0;
}
In the context of declarations, & is not an operation to get an address, it just tells what's a reference.
f(): f is a function
&return: its return is a reference
reference[3]: the reference is to an array of 3 elements
int array[i]: an element is an int
So you have a function that returns a reference to an array of 3 integers, and as we have the proper compile time information of the array size, we can check it with sizeof anytime =)
Final golden tip, for anything that can be placed before the type, when in multiple declarations, it's to be applied to all the variables at once, and so can't be applied individually.
This const can't be put before int:
int * const p;
So the following is valid:
int * const p1, * const p2;
This one can:
int const *p; // or const int *p;
So the following is invalid:
int const *p1, const *p2;
The exchangeable const is to be applied for all:
int const *p1, *p2; // or const int *p1, *p2;
Declaration Conventions
Because of that, I always put everything that can't be put before the type, closer to the variable (int *a, int &b), and anything that can be put before, I put before (volatile int c).
There's much more on this topic at http://nosubstance.me/post/constant-bikeshedding/.
1.
int Add (int a, int b = 3);
int Add (int a, int b)
{
}
2.
int Add (int a, int b);
int Add (int a, int b = 3)
{
}
Both work; which is the standard way and why?
If you put the declaration in a header file, and the definition in a separate .cpp file, and #include the header from a different .cpp file, you will be able to see the difference.
Specifically, suppose:
lib.h
int Add(int a, int b);
lib.cpp
int Add(int a, int b = 3) {
...
}
test.cpp
#include "lib.h"
int main() {
Add(4);
}
The compilation of test.cpp will not see the default parameter declaration, and will fail with an error.
For this reason, the default parameter definition is usually specified in the function declaration:
lib.h
int Add(int a, int b = 3);
In C++ the requirements imposed on default arguments with regard to their location in parameter list are as follows:
Default argument for a given parameter has to be specified no more than once. Specifying it more than once (even with the same default value) is illegal.
Parameters with default arguments have to form a contiguous group at the end of the parameter list.
Now, keeping that in mind, in C++ you are allowed to "grow" the set of parameters that have default arguments from one declaration of the function to the next, as long as the above requirements are continuously satisfied.
For example, you can declare a function with no default arguments
void foo(int a, int b);
In order to call that function after such declaration you'll have to specify both arguments explicitly.
Later (further down) in the same translation unit, you can re-declare it again, but this time with one default argument
void foo(int a, int b = 5);
and from this point on you can call it with just one explicit argument.
Further down you can re-declare it yet again adding one more default argument
void foo(int a = 1, int b);
and from this point on you can call it with no explicit arguments.
The full example might look as follows
void foo(int a, int b);
int main()
{
foo(2, 3);
void foo(int a, int b = 5); // redeclare
foo(8); // OK, calls `foo(8, 5)`
void foo(int a = 1, int b); // redeclare again
foo(); // OK, calls `foo(1, 5)`
}
void foo(int a, int b)
{
// ...
}
As for the code in your question, both variants are perfectly valid, but they mean different things. The first variant declares a default argument for the second parameter right away. The second variant initially declares your function with no default arguments and then adds one for the second parameter.
The net effect of both of your declarations (i.e. the way it is seen by the code that follows the second declaration) is exactly the same: the function has default argument for its second parameter. However, if you manage to squeeze some code between the first and the second declarations, these two variants will behave differently. In the second variant the function has no default arguments between the declarations, so you'll have to specify both arguments explicitly.
The first way would be preferred to the second.
This is because the header file will show that the parameter is optional and what its default value will be. Additionally, this will ensure that the default value will be the same, no matter the implementation of the corresponding .cpp file.
In the second way, there is no guarantee of a default value for the second parameter. The default value could change, depending on how the corresponding .cpp file is implemented.
Default arguments must be specified with the first occurrence of the function name—typically, in the function prototype. If the function prototype is omitted because the function definition also serves as the prototype, then the default arguments should be specified in the function header.
On thing to remember here is that the default param must be the last param in the function definition.
Following code will not compile:
void fun(int first, int second = 10, int third);
Following code will compile:
void fun(int first, int second, int third = 10);