Confusing C++ global scope issues - c++

I am taking a C++ practice test and I'm confused with a set of access scope and point of declaration related questions. Both the questions are related to each other..I know the answers..what i need is proper explanation :
What is the value of the local variable x at the end of main
int x = 5;
int main(int argc, char** argv)
{
int x = x;
return 0;
}
ans: Undefined
What is the value of y at the end of main?
const int x = 5;
int main(int argc, char** argv)
{
int x[x];
int y = sizeof(x) / sizeof(int);
return 0;
}
answer: 5

From the standard: 3.3.1 [basic.scope.pdecl]
The point of declaration for a name is immediately after its complete declarator (clause 8) and before its initializer (if any), except as noted below.
The standard even has two examples to clarify this:
int x = 12;
{ int x = x; }
Here the second x is initialized with its own (indeterminate) value.
[Note: a nonlocal name remains visible up to the point of declaration of the local name that hides it. [Example:
const int i = 2;
{ int i[i]; }
declares a local array of two integers. ]]
These two examples cover the two cases in your question.

It's controlled by when the inner x comes into existence (the start of its scope). The standard states (3.3.1 in the current standard, 3.3.2 in the upcoming one) in part (my italics):
The point of declaration for a name is immediately after its complete declarator and before its initializer.
With int x = x;, it's created at the point of the = so that when you assign x to it, that's the inner x which is being used. Since that hasn't been set to anything before, it's undefined.
With int x[x];, the inner x comes into existence at the ; so it's using the outer x as the array size.

Related

Why visual c++ (latest) and gcc 12.1 accepted hiding this init capture for lambda, while clang 14.0.0 not? (c++20)

Case 1
int main() {
int x = 100;
auto lamb_var = [y = x](){
int y = 10;
return y + 1;
};
assert (lamb_var() == 11);
return 0;
}
in https://godbolt.org/z/hPPParjnz
Both MSVC and GCC accepted shadowing the init-capture, while Clang accused y redefinition on the compound statement and throwed compiler error.
However, if we remove the init-capture and make a simple-capture, all compilers accept Shadowing:
Case 2
int main() {
int x = 100;
auto lamb_var = [x](){
int x = 10;
return x + 1;
};
assert (lamb_var() == 11);
return 0;
}
in https://godbolt.org/z/Gs4cadf5e
A simple-capture (case 2) leads to the creation of an attribute in the lambda-associated class, so shadowing should be normal.
From what I found,the expression "whose declarative region is the body of the lambda expression" of the quote below from cppreference could defend the implementation of CLANG ("redefinition"), but I'm not sure.
A capture with an initializer acts as if it declares and explicitly
captures a variable declared with type auto, whose declarative region
is the body of the lambda expression (that is, it is not in scope
within its initializer), except that: [...]
Who is right in implementation (GCC and MSVC or Clang), and how to understand this citation of cppreference?
Related questions
Lambda capture and parameter with same name - who shadows the other? (clang vs gcc)
I think that clang is correct in rejecting snippet 1 and accepting snippet 2 because in the first case the non-static data member is named y while in the second case the non-static data member is unnamed.
Case 1
Here we consider snippet 1:
int main() {
int x = 100;
auto lamb_var = [y = x](){ //the data member is "named" y
int y = 10; //error because we're defining y for second time
return y + 1;
};
assert (lamb_var() == 11);
return 0;
}
Now, from expr.prim.lambda#capture-6:
An init-capture without ellipsis behaves as if it declares and explicitly captures a variable of the form auto init-capture ; whose declarative region is the lambda-expression's compound-statement, except that:
(emphasis mine)
This seems to indicate that the non-static data member has a name which in your given example is y. Now, by writing int y = 10; we're providing a redefinition of the same named variable y in the same declarative region and hence the error.
Note that we will get the same error(as expected due to the reason explained above), if we replace [y=x] with [x=x] and int y =10; with int x = 10; as shown below:
int main() {
int x = 100;
auto lamb_var = [x = x](){ //data member "named" x
int x = 10; //this will give same error
return x + 1;
};
assert (lamb_var() == 11);
return 0;
}
Case 2
Here we consider the snippet 2:
int main() {
int x = 100;
auto lamb_var = [x](){ //data member is unnamed
int x = 10; //ok because we're defining an int variable with "name" x for the first time in this region
return x + 1;
};
assert (lamb_var() == 11);
return 0;
}
Here from expr.prim.lambda#capture-10:
For each entity captured by copy, an unnamed non-static data member is declared in the closure type. The declaration order of these members is unspecified....
(emphasis mine)
In this case, the non-static data member is unnamed and so writing int x = 10; is not a redefinition error because we're definining a variable named x for the first time in this region.

Static scoping in C/C++

In the following code, 2 is printed.
int x = 1;
int f(int y)
{
return x;
}
int main() {
x = 2;
printf("%d", f(0));
}
How is it happening if we have static scoping in C? Why isn't 1 printed?
Printing 2 in this case isn't a dynamic scoping, is it?
I thought that in static scoping it should take the nearest x to the function definition.
It does take the nearest x, but since you only have one x it doesn't really matter.
If you change the code to
int x = 1;
int f(int y)
{
return x ;
}
int main() {
int x=2;
printf("%d", f(0));
}
so you have 2 x, the global one and the local one in main you will see 1 getting printed.
Those are usually called dynamic and lexical scoping.
Lexical scoping is determined entirely at compile time, dynamic scoping at runtime.
You only have one variable named "x", so scope is irrelevant to your program.
Here's a program that would be different depending on the scoping rules:
int x = 0;
int f()
{
return x;
}
int main()
{
int x = 1;
printf("%d\n", f(x));
}
Under lexical scoping, f returns the value of the x that is lexically "nearest" - the global one.
So it would print 0;
Under dynamic scoping, f would return the value of the newest x, which is the one in main.
So it would print 1.
The scoping is moot here since you have not declared an x locally that would have otherwise shadowed the global x.
2 is printed.
x is assigned in main to 2 immediately before f is called with the parameter 0.
(Conceptually int x = 1; is ran before main is entered.)
It is the way the compiler generates the assembly/machine code.
first global variable X is stored in memory location "abc"
next main is executed: global variable X at "abc" is changed to 2
Now function f() is called:
function f returns the value of global variable X at "abc": being 2
the return value of f() is printed.
So if you wanted a different X in the main-function scope, you should have made a new object, like in the answer by nwp.

Using a variable with the same name in different spaces

This code compiles, but I have a run time error in Visual Studio:
Run-time check failure #3 - the variable 'x' is being used without being initialized...
int x = 15;
int main()
{
int x = x;
return 0;
}
I don't understand that behavior... in the error box when I click continue the program resumes and x has a corrupted content (like -8556328 instead of 15).
Why does this code work without a problem, and the int array is well declared?
const int x = 5;
int main()
{
int x[x] = {1,2,3,4};
return 0;
}
x is defined at the left of =.
so in x[x], [x] refer to the global one,
whereas in x = x;, x hides the global x and initializes from itself -> UB.
When you declare a new variable, its name becomes visible right here
int x =
// ^- there
because it is at that point the variable is fully declared, and as such; its name means something. At this point in time any other (previously declared variable) in a surrounding scope will be hidden.
There is no scope resolution operator in C, so you may not be able to use
int x = x;
in your program.
please use SRO( Scope resolution operator ::) to tell compiler which x is real x in your mind. As user defined names are mangled( Names are decorated) something like this to avoid ambiguity at it's level, these are just names used by compiler that best suits it
int x = 15;// Real name = gui_x
int main()
{
int x = x;// lui_x
return 0;
}
In this way run-time will know which version you are using but to avoid ambiguity it expects from you to use specific names. Sometimes above problem arise where you don't know that you are using already used names. For this C++ has created SRO.
Now in case of array x is address & not integer that stores something, that's why compiler didn't jumbled. You need to write
namespace abc //now all global variables are belongs to this ns abc
int x = 15;// Real name = gui_x
int main()
{
int x = abc::x;// lui_x
return 0;
}

Strange code... Can someone explain me this

Hi I am switching to C++ from C. While reading http://www.gotw.ca/publications/xc++.htm I see this code block.
const int i = 1;
const int j = 2;
struct x
{
int x;
};
namespace y
{
int i[i];
int j = j;
x x;
int y::y = x.x;
};
And I am totally confused about this specially in namespace y section.
Please explain me the behavior of this code and use of namespace. Also I read somewhere that bad use of namespace leading to violating fundamentals of inheritance. Please give me some examples of using namespace brilliantly.
This example is using some horribly obfuscated code to illustrate a point about the scope of names. From C++11 §3.3.6 [basic.scope.namespace] p1:
... A namespace member name has namespace scope. Its potential scope includes its namespace from the name’s point of declaration (3.3.2) onwards ...
point of declaration is defined in §3.3.2 [basic.scope.pdecl] p1:
The point of declaration for a name is immediately after its complete declarator (Clause 8) and before its initializer (if any), except as noted below.
So it is possible to use e.g. the name i from an outer scope in the initializer of something named i in an inner scope. The code in question:
const int i = 1;
const int j = 2;
struct x
{
int x;
};
namespace y
{
int i[i];
int j = j;
x x;
int y::y = x.x;
}
declares:
y::i as an array of 1 int that will be implicitly zeroed (since all static storage duration objects are zero-initialized if they have no explicit initializer),
y::j as an int with initial value 2,
y::x as struct of type ::x that will be implicitly zeroed, and
y::y is an invalid name. If it was simply y, it would be an int with initial value 0, since its initializer y::x.x is implicitly zero-initialized.
Here's a demo (with y::y changed to y) at Coliru.
NOTE: DO NOT EVER WRITE CODE LIKE THIS. The only time using this feature of names even borders on being acceptable is for member initializers in a class constructor. If you do this anywhere else, I will find you. And I will make you pay.
I think there is some problem with your code. The int y::y = x.x; section is wrong as there is no y previous to this and so this statement needs some correction. I am trying to give some basic info about namespace and its usage, hope it helps.
The main purpose of namespaces is to logically group functionality without the need of long names and the option for handy usage via "using". You can also use same name over different namespaces
namespace Color
{
class Add {};
class Multiply {};
};
namespace Dimension
{
class Add {};
class Multiply {};
};
So you can use the same class name Add, Multiply under two namespaces and one thing which you have to remember is that use namespaces only when required otherwise you will spam the global namespace "std" unknowingly which is not conventional.
For using namespace with inheritance you can search for articles in stack over flow and definitely you will get some. Ex: Accessing Parent Namespace in C++
int i[i]; //line 1
It creates an int array of size 1, as the index i is a constant initialized to 1
int j = j; //line 2
It declares and initilizes a variable j to 2(value of constant j) in a namespace y
x x; //line 3
It creates a structure variable x of type struct x ( Note: The structure variable x is different from the int x present inside the structure x, int x is a member of structure x
int y::y = x.x; //line 4
This is syntactically wrong, there is no need to qualify int y with namespace('y'), as it is already present in the namespaace y, So the statement should be
int y = x.x
where x.x represents accessing the data member (int x) of structure variable x created in the line 3
Namespace example Have a look on this example,it helps you to understand namespaces clearly. Refer the link for more examples [link]http://www.cplusplus.com/doc/tutorial/namespaces/
#include <iostream>
using namespace std;
namespace first
{
int x = 5;
int y = 10;
}
namespace second
{
double x = 3.1416;
double y = 2.7183;
}
int main () {
using namespace first;
cout << x << endl;
cout << y << endl;
cout << second::x << endl;
cout << second::y << endl;
return 0;
}
//Output
5
10
3.1416
2.7183
......Hope it helps you....:)

Point of declaration in C++

Why isn't the output 101 while I assigned the previous x to the new x?
int x = 101;
{
int x = x;
std::cout << x << std::endl;
}
Output (garbage):
422634
I thought the second x would be initialized to 101 but it isn't initialized.
Note: The solution in this case is int x = ::x but the question is why it happens.
Point of declaration
The point of declaration for a name is immediately after its complete
declarator and before its initializer... [C++ Standard § 3.3.2/1]
Compiler completes the declaration when it knows enough about declarator.
Above code is equal to the below one:
int x = 101;
{
int x;
x = x; <------------------// Self assignment, assigns an indeterminate value.
std::cout << x << std::endl;
}
Because, the declaration of inner x completed before = (assignment)
int x = x; <--// Now, we have the new `x` which hides the older one,
^ // so it assigns itself to itself
|
+---// Point of declaration,
// here compiler knows everything to declare `x`.
// then declares it.
On the other hand, when we declaring complex objects, the point of declaration is farther. So, the behavior is different.
For example, below code is OK
const int i = 2;
{
int i[i];
^
|
+----// Point of declaration
// compiler has to reach to "]"
// therefore before declaring `i` as an array
// there is just one `i`, the `i` of `const int i=2`
}
In above code, compiler has to know the actual size of the array to complete the declaration, so the point of declaration is ]. Therefore the i within [i] is the outer i because declaration of the i of int i[... isn't completed yet. Thus, it declares an array with 2 elements (int i[2];).
Also, this example shows the point of declaration for an enumerator
const int x = 12;
{
enum { x = x };
^
|
+---// Point of declaration
// compiler has to reach to "}" then
// there is just one `x`, the `x` of `const int x=12`
}
The enumerator x is initialized with the value of the constant x, namely 12.
There's another way to do it.
#include <iostream>
int x = 101;
int main()
{
int x = ::x;
std::cout << x << std::endl;
std::cin.get();
}
variable scope
In front of x will be overwritten.
int x = x;
This one there are two processes.
One: int x;(define variable x and allocate memory and specify the initial value : x = 0);
this moment , the front x will be hidden.
Two: x = x;(Do not find the value x);