变量值如何存储在 C 中?
How are variable values stored in C?
假设我有以下 C 代码:
int x= 4;
int y = x;
printf("x:%d,y:%d\n",x,y);
X 现在引用存储“4”的内存位置并打印为 4。y 引用 x 所以它也将打印 4。那么为什么当我更改 x 的值时,例如 x=6;
, y 也不会改变吗?我一定是误会了什么。所有语言都一样吗?
我在任何地方都找不到问题的答案(可能是因为措辞不当)。
你的理解完全错误。
当您写入 int x = 4;
时,x
表示堆栈上的实际内存位置,然后用值 4
填充。 x
不可撤销地与那段内存相关联 - 当 x
超出范围时,内存也会消失。
当你再写int y = x;
时,y
代表了一块实际的内存。它不会'refer'到x
,而是x
的内容被复制到y
.
Is it the same for all languages?
不,不同的语言可以而且确实具有完全不同的语义。然而,C 的做法通常称为 value semantics.
y
从不引用 x
。赋值运算符 =
复制值。 x
只是 4
类型的 int
值。 int y = x
正在将 x 的当前值赋给 y,并在此过程中复制它。
为了像您描述的那样运行,y
需要是一个指向 int int *
的指针,并且它会被分配 x
的地址,就像这样:
#include <stdio.h>
int main(int argc, char *argv[]) {
int x = 4;
int *y = &x;
printf("before: x: %d, y: %d\n", x, *y);
x = 123; // modify x
printf("after: x: %d, y: %d\n", x, *y);
}
X now references the memory location where the '4' is stored
不,4 没有存储在任何地方,它是 mov
的参数。 x
有自己的存储位置,其中包含一个整数值,在本例中为 4。
y references x
不,y
也有自己的存储整数的内存位置,在本例中也是 4。
So why is it that when I change the value of x, eg x=6;, y doesn't get changed
它们都是不同的内存位置,更改一个不会影响另一个。
y references x so it will also print 4.
这是你的基本误解。 y
变量是 不是 引用;它是 int
类型的变量,与 x
没有任何 隐式 连接。在进行int y = x;
初始化时,value在x
变量中当前为复制到y
变量。
任何对 x
或 y
的值的后续更改都不会影响另一个的值(除非执行从一个到另一个的显式重新分配)。
Is it the same for all languages?
好吧,我什至不会尝试回答“所有语言!”但是,在某些方面 'close' 到 C 的语言是 C++。对于您显示的代码,C 和 C++ 的行为(以及上面的解释)是相同的。但是,在 C++ 中,您可以定义一个变量作为引用!
只需在其声明中添加 &
字符即可使 y
成为 引用变量 ;这样做时,更改 x
也会更改 y
的显示值。尝试编译以下代码(确保使用 C++ 编译器)并按原样测试它并使用注释掉的行:
#include <iostream>
int main()
{
int x = 4;
// int y = x; // Using this line, the value of "y" won't change...
int& y = x; // ... but adding the "&" makes "y" a REFERENCE.
printf("x:%d,y:%d\n", x, y); // x:4,y:4
x = 6;
printf("x:%d,y:%d\n", x, y); // x:6,y:6 (with the "&") or x:6,y:4 (without the "&")
return 0;
}
对于这两个变量
int x= 4;
int y = x;
编译器分配自己的内存范围,其大小对应于类型 int
的对象的大小,变量 x
的值即存储在内存范围中的值分配给变量 x
用于初始化变量 y
即它的内存范围。
所以如果你写的例子
x = 6;
然后整数常量6
被存储在分配给变量x
的内存区中。变量 y
将保持不变。
如果要谈论引用,那么在 C 中指针提供对实体(函数或对象)的引用。
如果你会写例如
int *px = &x;
然后指针 px
提供对变量 x
的引用。
所以在通过引用将对象传递给函数的机制中使用了指针。考虑以下演示程序。
#include <stdio.h>
void f( int *px )
{
*px = 10;
}
int main(void)
{
int x = 1;
printf( "Before calling f() x = %d\n", x );
f( &x );
printf( "After calling f() x = %d\n", x );
return 0;
}
程序输出为
Before calling f() x = 1
After calling f() x = 10
在程序中,main 中声明的变量 x
通过指向它的指针通过引用传递给函数 f
。
并非所有语言都一样。 C 风格的语言(如 C++ 等)是否也一样?通常,是的。
重要的是,x
不引用“内存位置”。它只是表示一个具有特定值的对象(用 C 语言来说,意思是“您可以更改和传递的东西”)。编译时 x
可能会存储在内存中、寄存器中,或者被优化并完全消除。
例如:
int x = 1;
int y = x + 1;
int z = 4;
printf("x:%d,y:%d\n",x,y);
这里y
会是2
,可以在编译时确定,x
会是1
,z
无所谓所以它甚至可能被删除。 y
不是基于 x
计算的,它是基于代码的 静态分析 计算的,编译器正确地断言它只能是 [=15] =],所以 x
因子被优化掉了。
当您更改 y
时,您正在更改一个单独的东西,它对 x
没有影响,除非您 明确地 进行该分配。
在像 C++ 这样存在引用的语言中,情况并非如此,因为它们就像变量别名:
int& y = x; // Same as `x`, where `y` is just another name for same
请注意,这也是有限制的,例如 int y = x + 2
您不能使用引用,因为您没有引用变量。那是一个表达式。
在某些语言中,像这样的赋值在数学意义上更多地被处理,如在 y
中 always x + 2
取决于任何值 x
在那一刻。 Functional programming languages 倾向于采用此模型,但具体细节差异很大。
您可能要断言的是“变量在 imperative programming languages 中是这样工作的吗?”答案是通常是。
假设我有以下 C 代码:
int x= 4;
int y = x;
printf("x:%d,y:%d\n",x,y);
X 现在引用存储“4”的内存位置并打印为 4。y 引用 x 所以它也将打印 4。那么为什么当我更改 x 的值时,例如 x=6;
, y 也不会改变吗?我一定是误会了什么。所有语言都一样吗?
我在任何地方都找不到问题的答案(可能是因为措辞不当)。
你的理解完全错误。
当您写入 int x = 4;
时,x
表示堆栈上的实际内存位置,然后用值 4
填充。 x
不可撤销地与那段内存相关联 - 当 x
超出范围时,内存也会消失。
当你再写int y = x;
时,y
代表了一块实际的内存。它不会'refer'到x
,而是x
的内容被复制到y
.
Is it the same for all languages?
不,不同的语言可以而且确实具有完全不同的语义。然而,C 的做法通常称为 value semantics.
y
从不引用 x
。赋值运算符 =
复制值。 x
只是 4
类型的 int
值。 int y = x
正在将 x 的当前值赋给 y,并在此过程中复制它。
为了像您描述的那样运行,y
需要是一个指向 int int *
的指针,并且它会被分配 x
的地址,就像这样:
#include <stdio.h>
int main(int argc, char *argv[]) {
int x = 4;
int *y = &x;
printf("before: x: %d, y: %d\n", x, *y);
x = 123; // modify x
printf("after: x: %d, y: %d\n", x, *y);
}
X now references the memory location where the '4' is stored
不,4 没有存储在任何地方,它是 mov
的参数。 x
有自己的存储位置,其中包含一个整数值,在本例中为 4。
y references x
不,y
也有自己的存储整数的内存位置,在本例中也是 4。
So why is it that when I change the value of x, eg x=6;, y doesn't get changed
它们都是不同的内存位置,更改一个不会影响另一个。
y references x so it will also print 4.
这是你的基本误解。 y
变量是 不是 引用;它是 int
类型的变量,与 x
没有任何 隐式 连接。在进行int y = x;
初始化时,value在x
变量中当前为复制到y
变量。
任何对 x
或 y
的值的后续更改都不会影响另一个的值(除非执行从一个到另一个的显式重新分配)。
Is it the same for all languages?
好吧,我什至不会尝试回答“所有语言!”但是,在某些方面 'close' 到 C 的语言是 C++。对于您显示的代码,C 和 C++ 的行为(以及上面的解释)是相同的。但是,在 C++ 中,您可以定义一个变量作为引用!
只需在其声明中添加 &
字符即可使 y
成为 引用变量 ;这样做时,更改 x
也会更改 y
的显示值。尝试编译以下代码(确保使用 C++ 编译器)并按原样测试它并使用注释掉的行:
#include <iostream>
int main()
{
int x = 4;
// int y = x; // Using this line, the value of "y" won't change...
int& y = x; // ... but adding the "&" makes "y" a REFERENCE.
printf("x:%d,y:%d\n", x, y); // x:4,y:4
x = 6;
printf("x:%d,y:%d\n", x, y); // x:6,y:6 (with the "&") or x:6,y:4 (without the "&")
return 0;
}
对于这两个变量
int x= 4;
int y = x;
编译器分配自己的内存范围,其大小对应于类型 int
的对象的大小,变量 x
的值即存储在内存范围中的值分配给变量 x
用于初始化变量 y
即它的内存范围。
所以如果你写的例子
x = 6;
然后整数常量6
被存储在分配给变量x
的内存区中。变量 y
将保持不变。
如果要谈论引用,那么在 C 中指针提供对实体(函数或对象)的引用。
如果你会写例如
int *px = &x;
然后指针 px
提供对变量 x
的引用。
所以在通过引用将对象传递给函数的机制中使用了指针。考虑以下演示程序。
#include <stdio.h>
void f( int *px )
{
*px = 10;
}
int main(void)
{
int x = 1;
printf( "Before calling f() x = %d\n", x );
f( &x );
printf( "After calling f() x = %d\n", x );
return 0;
}
程序输出为
Before calling f() x = 1
After calling f() x = 10
在程序中,main 中声明的变量 x
通过指向它的指针通过引用传递给函数 f
。
并非所有语言都一样。 C 风格的语言(如 C++ 等)是否也一样?通常,是的。
重要的是,x
不引用“内存位置”。它只是表示一个具有特定值的对象(用 C 语言来说,意思是“您可以更改和传递的东西”)。编译时 x
可能会存储在内存中、寄存器中,或者被优化并完全消除。
例如:
int x = 1;
int y = x + 1;
int z = 4;
printf("x:%d,y:%d\n",x,y);
这里y
会是2
,可以在编译时确定,x
会是1
,z
无所谓所以它甚至可能被删除。 y
不是基于 x
计算的,它是基于代码的 静态分析 计算的,编译器正确地断言它只能是 [=15] =],所以 x
因子被优化掉了。
当您更改 y
时,您正在更改一个单独的东西,它对 x
没有影响,除非您 明确地 进行该分配。
在像 C++ 这样存在引用的语言中,情况并非如此,因为它们就像变量别名:
int& y = x; // Same as `x`, where `y` is just another name for same
请注意,这也是有限制的,例如 int y = x + 2
您不能使用引用,因为您没有引用变量。那是一个表达式。
在某些语言中,像这样的赋值在数学意义上更多地被处理,如在 y
中 always x + 2
取决于任何值 x
在那一刻。 Functional programming languages 倾向于采用此模型,但具体细节差异很大。
您可能要断言的是“变量在 imperative programming languages 中是这样工作的吗?”答案是通常是。