变量值如何存储在 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;初始化时,valuex变量中当前为复制y变量。

任何对 xy 的值的后续更改都不会影响另一个的值(除非执行从一个到另一个的显式重新分配)。

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会是1z无所谓所以它甚至可能被删除。 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 您不能使用引用,因为您没有引用变量。那是一个表达式

在某些语言中,像这样的赋值在数学意义上更多地被处理,如在 yalways x + 2 取决于任何值 x 在那一刻。 Functional programming languages 倾向于采用此模型,但具体细节差异很大。

您可能要断言的是“变量在 imperative programming languages 中是这样工作的吗?”答案是通常是。