Is the scope in C only related to compiling time, since we know that we can access any memory at runtime?

I tried to understand the exact meaning of scope in C. What I could understand was that scope was limited only by compilation time. For example, if you use a local variable from some other function. This will result in a compile time error. On the other hand, the following program works fine. This means that C has a flat memory model and can be accessed at run time. C-books bind scope and variable visibility, I found it rather confusing. I think that all these terms make sense only for compilation time. Can anyone shed light on him?

#include "stdio.h" int *ptr; int func(void) { /** abc is a local variable **/ int abc = 132; ptr = &abc; return 0; } int func1(void) { /** although scope of abc is over still I can change the value in the address of abc **/ *ptr = 200; printf("the value of abc=%d\r\n",*ptr); } int main(void) { func(); func1(); return 0; } 

Results: abc = 200

In simpler words, what is meant by area? Does it fit into the image at runtime or compile time? As we can see, we can access something at runtime. But if we do not follow the rules, we will get a compilation error. For example, a local reference to a variable in another function. The compiler will throw an error saying "variable is not defined ...".

Can I say the following about variables?

 1) Scope attribute comes under compile time. 2) Lifetime attribute comes under run-time. 3) Visibility attribute comes under compile-time 
+7
c
source share
7 answers

Yes, the C memory model allows you to easily access something so you can do something similar above and see “interesting” results.

However, what you did here is indicated as undefined behavior (UB) according to the C standard. This means that literally anything can happen; it may be what you expect, or it may not be.

Please note that you did not get access to the "local variable" because by the time you get func access again, therefore the lifetime of its local variables has expired. What you did was an area of ​​memory that “just happened” to make an interesting difference. If you called func1 from within func , then the behavior would be well defined.

A few more notes:

A scope is definitely a compilation based concept; the name field (variable, identifier, etc.) is a subset of the program code in which this name is recognized by the compiler.

This is very different from the lifetime of the variables, which does not depend on the scope in the general case, and combining the two is a common mistake. The lifetime and volume of local variables are really intertwined, but this does not apply to everything.

+8
source share

What is meant by area?

The scope of a variable is the part of the text to which you can refer to the variable. A local variable has a block area : it is visible from its declaration point to the end of the body of the closing function.
This has nothing to do with the lifetime of the variable. This is the storage time, which indicates the lifetime of the variable.

Does it fit into the image at runtime or compile time?

It enters the image at compile time and link time. When a program tries to access a local variable outside its block, the compiler will give you an error about this undeclared variable (which is local to its block).
This example will explain this better:

 #include <stdio.h> void userlocal(void); int main() { int a= 2; printf("local a in outer scope of main is %d\n",a); userlocal(); printf("local a in scope of userlocal is %d\n",b); // This will give error at compile time return 0; } void userlocal(void) { int b = 20; printf("local a in scope of userlocal is %d\n",b); } 

Exit:

 [Error] 'b' undeclared (first use in this function) 

Can I say the following about variables?

Yes you can say.

+1
source share

While theoretically this is “just UB,” in practice he is asked to actually fail. The location of abc - (in every implementation that I know of) is somewhere on the stack. Since you left the original block and then entered some other block, it is likely that something else will occupy this memory location. What are you going to overwrite.

+1
source share

As for the area, it is easiest to think that C is compiled into a series of manipulations with the register and memory, such structures as blocks, for-loops, if-statements, structs, etc., have no meaning after compilation, these are just abstractions that allow you as a programmer to maintain your judgment.

As for example and memory, this is my attempt to explain this.

As everyone says, you use specific compilers for specific implementations of the standard undefined action. To understand how this works, you can think about the program you are writing with two memories, a heap and a stack. As an example, char *foo = malloc(50); allocates memory on the heap, and char foo[] = "Foo" allocates it on the stack. A stack is a memory that remembers what you are doing and contains a long list of stack frames, each function call adds a frame, and each return pops up. A heap is another kind of memory.

To illustrate this, we have this program:

 int *ptr; int func() { int abc = 123; ptr = &abc; return 0; } int func1() { int def; printf("func1() :: *abc=%i\n", *ptr); def = 200; return 0; } int main() { func(); printf("main() :: *ptr=%i\n", *ptr); func1(); printf("main() :: *ptr=%i\n", *ptr); } 

And the following will happen on the stack ( - - undefined / unused memory, > on the left is where your program is currently running, X is the data):

 |-----| |-----| |-----| 

When we inject main() , it pushes the stack stack onto the stack:

  |-----| |-----| >|XXXXX| <- This is where all memory needed to execute main() is. 

Then you call func() , which in the memory needed to execute contains the integer 123 .

  |-----| >|XX123| <- This is the stack frame for func() |XXXXX| <- Still the stack frame for main() 

func() sets the global *ptr to the address of an integer on the stack. This means that when func() returns (and the memory is not cleared, as this will be a waste of processor cycles), the value remains

  |-----| |--123| >|XXXXX| <- main() 

and you can still reference *ptr until you call the following function

  |-----| >|XXXXX| <- This is the stack frame for func1() |XXXXX| 

Now *ptr some random value will appear ... but you can still access the memory position and change it. (If func() and func1() each defines only one local integer in its scope, it is very likely that *ptr will also point to this integer in func1() )

Bonus

I did not test the program, but I would assume that it will output something like this:

 main() :: *ptr=123 func1() :: *ptr=<some random values> main() :: *ptr=<possibly 200, could be something else> 
+1
source share

You are right that C has a flat memory model. And allows you to access any area of ​​memory. Here ptr is a global pointer to int . Thus, it points to an address where an integer can be stored and retrieved. This will result in undefined behaviour in different scenarios.

0
source share

Scope is a compile-time property and deals when a reference to a variable is valid or when it is visible, which differs from storage duration or the lifetime of an object that tells when it is valid for accessing the memory associated with the variable.

In this case, abc has an automatic storage duration, which means that it lasts for the block it is in, which in this case is a func function and tries to access the memory associated with abc outside this block undefined behavior , it may work. but results cannot be relied upon.

From the draft of the standard section C99 6.2.4 duration of storage of objects in paragraphs indicates various storage durations: static and automatic . In the explanation that a static lifetime of variables is the full execution of the program, and paragraph 5 says:

For an object that does not have an array type of variable length, its lifetime extends from entering the block with which it is connected, until the execution of this block ends one way or another. [..]

Thus, an automatic variable life is the block in which it is contained, and paragraph 2 says:

The lifetime of an object is part of the execution of the program, during which it is guaranteed to be reserved for it. The object exists, has a permanent address, 25) and saves its last stored value throughout its life. 26) If an object is referenced outside its lifetime, the behavior is undefined. The value of the pointer becomes undefined if the object it points to reaches the end of its life.

Thus, accessing an object outside its guaranteed lifetime is undefined behavior.

0
source share

It is undefined and you should not trust values. With minor changes to your code (MSVC 2013) there is a surprise.

 int func1() { /** although scope of abc is over still I can change the value in the address of abc **/ printf("the value of abc=%d\r\n", *ptr); *ptr = 200; printf("the value of abc=%d\r\n", *ptr); return 0; } int main() { func(); printf("the value of abc=%d\r\n", *ptr); func1(); } 

the output is on my computer.

value abc = 132 - value abc = 1519668 - value abc = 200

0
source share

All Articles