Which subclause of C++ standard prohibits redeclaration / redefinition in a same block? - c++

I'm reading Standard for Programming Language C++ and I cannot find a subclause prohibiting code like follows, which will obviously not compile:
/* Code A */
int main() {
int i;
int i;
}
while this one will compile:
/* Code B */
int main() {
int i;
{ int i; }
}
I've found something related, but I failed to find a matching one:
[basic.def.odr#1]: No translation unit shall contain more than one definition of any variable...
If it's this subclause, I cannot find a subclause explaining why the 2 i's are not the same variable in Code B but are the same variable in Code A;
[basic.scope.block#1]:A name declared in a block ([stmt.block]) is local to that block; it has block scope. Its potential scope begins at its point of declaration ([basic.scope.pdecl]) and ends at the end of its block. A variable declared at block scope is a local variable.
In fact I tried to look for something like or more general than "A name of variable with a block scope cannot be redeclared within its potential scope, excluding nested blocks" like [temp.local#6], but I failed:
[temp.local#6]: The name of a template-parameter shall not be redeclared within its scope (including nested scopes). ...
So can some give me some help? Thanks!

You are looking for [basic.scope.scope]/5
Two declarations potentially conflict if they correspond and cause their shared name to denote different entities ([basic.link]). The program is ill-formed if, in any scope, a name is bound to two declarations that potentially conflict and one precedes the other ([basic.lookup]).
emphasis mine

Related

Is it undefined behavior to redeclare a variable within enclosed scope?

#include <iostream>
using namespace std;
int main() {
int i = 0;
if(true) {
int i = 5;
cout << i << '\n';
}
return 0;
}
Tried running the above code on Ideone to see if its legal. The results perplex me:
We have a compilation error (1), (2)
Or this code prints 5 as expected (1)
Or it prints nothing (1), (2)
As you can see from my links this same code behaves radically differently each time it is compiled on Ideone! This smells like undefined behavior (UB).
OK C++ is known for its unintuitive behaviors BUT! - I admit its just my intuition but I wouldn't expect even C++ to make redeclaring a variable in an inner scope UB! Id expect either shadowing or mandatory compilation error.
Is my code really UB according to the C++ standard, or is it just a peculiarity of Ideone and/or gcc? If its UB, is it UB because I redeclared i or for some other reason I'm failing to notice now?
Is it UB to redeclare a variable within enclosed scope?
No, it is not.
The compiler error you are seeing is most likely caused by the fact that the outer i is declared but not used.
Otherwise, your code is just fine.
It works fine for me at https://ideone.com/AwVJqZ as well as my desktop.
There is no undefined behavior, the standard allows name hiding, it is covered in [basic.scope.hiding]:
A declaration of a name in a nested declarative region hides a declaration of the same name in an enclosing declarative region; see [basic.scope.declarative] and [basic.lookup.unqual].
and [basic.scope.declarative] says:
Every name is introduced in some portion of program text called a declarative region, which is the largest part of the program in which that name is valid, that is, in which that name may be used as an unqualified name to refer to the same entity.
In general, each particular name is valid only within some possibly discontiguous portion of program text called its scope.
To determine the scope of a declaration, it is sometimes convenient to refer to the potential scope of a declaration.
The scope of a declaration is the same as its potential scope unless the potential scope contains another declaration of the same name.
In that case, the potential scope of the declaration in the inner (contained) declarative region is excluded from the scope of the declaration in the outer (containing) declarative region.
and gives the following example:
[ Example: In
int j = 24;
int main() {
int i = j, j;
j = 42;
}
the identifier j is declared twice as a name (and used twice). The
declarative region of the first j includes the entire example. The
potential scope of the first j begins immediately after that j and
extends to the end of the program, but its (actual) scope excludes the
text between the , and the }. The declarative region of the second
declaration of j (the j immediately before the semicolon) includes all
the text between { and }, but its potential scope excludes the
declaration of i. The scope of the second declaration of j is the same
as its potential scope. — end example  ]
Why you see such variable results from IDEone, I don't know. It does not provide a lot of knobs for figuring out what is going on. Wandbox is one of several alternatives that provide a lot of knobs and does not exhibit the same variability for this case.

Where is name lookup rule defined that finds the most immediate declaration of a name?

int i;
void f()
{
int i{};
{
int a = i; // local or global 'i'?
}
}
My question is not which i gets chosen, as it's clear that it's the local one, but rather, where in the standard that is specified.
The closest rule I could find is [basic.lookup.unqual]p6, which says:
In the definition of a function that is a member of namespace N, a name used after the function's declarator-id shall be declared before its use in the block in which it is used or in one of its enclosing blocks ([stmt.block]) or shall be declared before its use in namespace N or, if N is a nested namespace, shall be declared before its use in one of N's enclosing namespaces.
But there it just says that the name has to be declared sometime before the use; it's not what I'm looking for. The example in the same paragraph makes everything clearer as it says what scopes are searched in what order, but it's an example and as such not nominative.
Every other paragraph in [basic.lookup.unqual] doesn't apply to non-member functions. So my question is where in the standard is this specified?
In [basic.scope.declarative] we have:
Every name is introduced in some portion of program text called a declarative region, which is the largest part of the program in which that name is valid, that is, in which that name may be used as an unqualified name to refer to the same entity.
In general, each particular name is valid only within some possibly discontiguous portion of program text called its scope.
To determine the scope of a declaration, it is sometimes convenient to refer to the potential scope of a declaration.
The scope of a declaration is the same as its potential scope unless the potential scope contains another declaration of the same name.
In that case, the potential scope of the declaration in the inner (contained) declarative region is excluded from the scope of the declaration in the outer (containing) declarative region.
[ Example: In
int j = 24;
int main() {
int i = j, j;
j = 42;
}
the identifier j is declared twice as a name (and used twice).
The declarative region of the first j includes the entire example.
The potential scope of the first j begins immediately after that j and extends to the end of the program, but its (actual) scope excludes the text between the , and the }.
The declarative region of the second declaration of j (the j immediately before the semicolon) includes all the text between { and }, but its potential scope excludes the declaration of i.
The scope of the second declaration of j is the same as its potential scope.
— end example ]
(Emphasis mine.)
In your
int a = i;
example, i must refer to the local i because the global i is literally not in scope here.
As it says at the beginning of [basic.lookup.unqual]:
In all the cases listed in [basic.lookup.unqual], the scopes are searched for a declaration in the order listed in each of the respective categories [...]
But it doesn't matter which search order we choose if only one declaration is in scope in the first place.

What is the definition of definition

What does definition mean in the c++ standard's context? Several definitions of the same name are accepted in the different scopes:
int a=1;
int main()
{
int a=1;
}
It is unclear what actually ODR does mean.
What you are referring to here does not come under ODR since the scope of the variable has changed.
A name (other than a statement label) has block scope if it's
declared within a function definition (including that function's
parameter list) or in a brace-enclosed block within that function. Its
scope begins right after its declaration and runs to the end of the
block immediately enclosing that declaration.
You can read the rest of the article here: http://www.drdobbs.com/cpp/scope-regions-in-c/240002006

Declaring two global variables of same name in C

I have declared two global variables of same name in C.
It should give error as we cannot declare same name variables in same storage class.
I have checked it in C++ — it gives a compile time error, but not in C. Why?
Following is the code:
int a;
int a = 25;
int main()
{
return 0;
}
Check it out at : Code Written at Ideone
I think this probably is the reason
Declaration and Definition in C
But this is not the case in C++. I think in C++, whether the variable is declared at global scope or auto scope the declaration and definition is happening at the same time.
Could anyone throw some more light on it.
Now when I define the variable two times giving it value two times it gives me error
(instead of one declaration and one definition).
Code at : Two definitions now
int a;
int a;
int a;
int a = 25;
int main()
{
return 0;
}
In C, multiple global variables are "merged" into one. So you have indeed just one global variable, declared multiple times. This goes back to a time when extern wasn't needed (or possibly didn't exist - not quite sure) in C.
In other words, this is valid in C for historical reasons so that we can still compile code written before there was a ANSI standard for C.
Although, to allow the code to be used in C++, I would suggest avoiding it.
This is what the classic text "The C Programming Language" by Dennis Ritchie and Brain Kernighan says:
An external declaration for an object is a definition if it has an initializer.
An external object declaration that does not have an initializer, and does not contain the extern specifier, is a tentative definition.
If a definition for an object appears in a translation unit, any tentative definitions are treated merely as redundant declarations.
If no definition for the object appears in the translation unit, all its tentative definitions become a single definition with initializer 0.
So for example:
extern int a =123; // this declaration is a definition as a is initialized to 123
int a; //this is a tentative definition
int a;
int a;
int a;
/*all the above the three tentative declarations are redundant*/
int a;
int a;
int a;
Futher in the code if no where do something as a=100 where we consider a corresponding to this global scope variable and not any other local variable with the same name and type, then ultimately, the global variable a shall be initialized to 0

Does the declaration or definition determine the scope of a variable in C++?

Which determines the scope of a variable, the declaration or definition?
The documentation that I read says that the declaration determines the scope, but my own test said the contrary:
I get "undefined reference to i" error with the linker:
#include <iostream> // Stream declarations
using namespace std;
extern int i; //declaration
int prueba();
int main() {
int i; //Definition
i=6;
prueba();
} ///:~
int prueba(){
cout << i; //cannot access to the scope of i;
}
Declaration. You can declare something external, and it's visible in that file, no matter where it was defined. Similarly, a function is visible anywhere it's declared.
Other than externs and functions though, I can't think of a way to declare a variable that doesn't also define it...
EDIT: OTOH, static (global) variables, the scope is determined by the definition, which is ALSO the declaration.
EDIT 2: Basically I think my point is that you can't really have a definition that isn't ALSO a declaration. so, the only interesting cases are where the declaration isn't also a definition, and that's basically extern with a global in another file, and function declarations...
Both determine the scope - it's just that they determine the scope of subtly different things.
The definition of an object in C/C++ determines at which scope the actual object is visible in and determines the 'largest scope' of visibility for an object or function.
The declaration determines at which scope a particular 'instance' of the name is visible in.
For example, a global variable is defined at global scope (of course) and is potentially visible at global scope or a tighter scope. But the following declaration of the global variable, g_var, is only visible within function foo():
void foo(void)
{
extern int g_var; // the variable g_var has global scope, but this
// declaration has function-level scope
printf( "g_var is: %d\n", g_var);
}
Brian Postow's point that this distinction really only applies to global variables and functions is a a good one to keep in mind.
It enters scope at the ... declarator of the definition. so
int x=3;
{
int x=x; // x is initialized to itself, uninitialized.
}
The iso c++ spec is unfortunately not freely available, so I can't quote chapter and verse.
The definition determines the scope.
From the online version of the C standard:
6.1.2.3 A label name is the only kind of identifier that has function scope.
It can be used (in a goto statement)
anywhere in the function in which it
appears, and is declared implicitly by
its syntactic appearance (followed by
a : and a statement).
6.2.1.4 Every other identifier has scope determined by the placement of
its declaration (in a declarator or
type specifier). If the declarator or
type specifier that declares the
identifier appears outside of any
block or list of parameters, the
identifier has file scope, which
terminates at the end of the
translation unit. If the declarator or
type specifier that declares the
identifier appears inside a block or
within the list of parameter
declarations in a function definition,
the identifier has block scope, which
terminates at the end of the
associated block. If the declarator or
type specifier that declares the
identifier appears within the list of
parameter declarations in a function
prototype (not part of a function
definition), the identifier has
function prototype scope, which
terminates at the end of the function
declarator. If an identifier
designates two different entities in
the same name space, the scopes might
overlap. If so, the scope of one
entity (the inner scope) will be a
strict subset of the scope of the
other entity (the outer scope). Within
the inner scope, the identifier
designates the entity declared in the
inner scope; the entity declared in
the outer scope is hidden (and not
visible) within the inner scope.
Emphasis mine.