可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have the following code snippet and I have to analyse what the output will be:
#include <stdio.h>
void f(int d);
int a = 1, b = 2, c = 3, d = 4;
int main(){
int a = 5, c = 6;
f(a);
f(b);
f(c);
printf("%d %d %d %d\n",a,b,c,d);
return 0;
}
void f(int d){
static int a = 0;
a = a + 7;
b = a + d;
c++;
d--;
printf("%d %d %d %d\n",a,b,c,d);
}
The output I've got is as follows:
7 12 4 4
15 26 5 11
21 27 6 5
5 27 6 4
This really baffled me. I noticed that in all 3 function calls the globally declared a
suffers the assignment and that in the printf()
from main()
body the a
declared in main()
is printed. However, I am not sure about the behaviour of the rest of the variables. Is this undefined behaviour or it actually makes sense?
回答1:
int a = 1, b = 2, c = 3, d = 4;
---> Global variables
int main(){
int a = 5, c = 6; ---> Shadows the global `a` and `c`
....
void f(int d){
static int a = 0; ---> local static variable visible only inside `f`
...
回答2:
This is related to C's identifier scopes. The scope of a declaration is the region of the C program over which that declaration is visible. There are six scopes:
- Top level identifiers: extends from the declaration point to the end of the source program file
- Formal parameters in a function definiton: extends to the end of the function body
- Formal parameters in function prototypes
- Block (local) identifiers: extends up to the end of the block
- Statement labels
- Preprocessor macros
What happens in your program is known as overloading of names - a situation in which the same identifier may be associated to more than one program entity at a time. There are 5 overloading classes in C (aka namespaces):
- Preprocessor macro names
- Statement labels
- Structure, union and enumeration tags
- Component names
- Other names
In C, declarations at the beginning of a block can hide declarations outside the block. For one declaration to hide another, the declared identifiers must be the same, must belong to the same overloading class, and must be declared in two distinct scopes, one of which contains the other.
With this in mind, in your code, local a
and c
hide global a
and c
in main()
, and a
in f()
hides global a
. All other references are manipulating the global variables.
回答3:
void f(int d){
**static int a = 0;**
a = a + 7;
b = a + d;
c++;
d--;
printf("%d %d %d %d\n",a,b,c,d);
}
That's right you declared global int a and global void function f
but also you have declared static variable a
Whenever function has called, function is refering a variable of function.
if you want to avoid this problem, you should make a pointer of global variable, and refering a pointed address's value global variable.
As you know static variable is keep their last value until end of program.
each function's variable is exactly going to placed in "Stack" unless allocated by malloc.
And global variable is "Heap".
I am not sure but if you disassembly your program, static value a would go to stack
and treated with PUSH and POP instruction.
回答4:
In C/C++, the identifiers in a given scope shadow the identifiers in the outer scope from the point of declaration onwards.
The following example demonstrates this:
#include <stdio.h>
const char a[] = "a";
static const char b[] = "b";
void test(const char * arg)
{
const char c[] = "c1";
printf("1-. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
const char a[] = "a1";
static const char b[] = "b1";
// arg is present in this scope, we can't redeclare it
printf("1+. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
{
const char a[] = "a2";
const char b[] = "b2";
const char arg[] = "arg2";
const char c[] = "c2";
printf("2-. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
{
static const char a[] = "a3";
const char b[] = "b3";
static char arg[] = "arg3";
static const char c[] = "c3";
printf("3. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
}
printf("2+. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
}
printf("1++. a=%s b=%s c=%s arg=%s\n", a,b,c,arg);
}
int main(void)
{
test("arg");
return 0;
}
Output:
1-. a=a b=b c=c1 arg=arg
1+. a=a1 b=b1 c=c1 arg=arg
2-. a=a2 b=b2 c=c2 arg=arg2
3. a=a3 b=b3 c=c3 arg=arg3
2+. a=a2 b=b2 c=c2 arg=arg2
1++. a=a1 b=b1 c=c1 arg=arg
回答5:
This output actually makes sense.
In C/C++, the identifiers in a given scope are given preference over the identifiers in the outer scope. In this case in the function main, variables a and c will be used as local variables and rest b and d as global variables. Similarly, in the function void f(int d)
, d is the passed parameter, a will be used as static whenever the function is called, b and c will be used as global variables.
Hence the output will be calculated.
However you have shown the incorrect output. Correct output must be :
7 12 4 4
14 26 5 11
21 27 6 5
5 27 6 4