将一个常量无误地分配给另一个常量

A constant being assigned to another constant without errors

提问人:corvelk 提问时间:1/28/2021 最后编辑:John Kugelmancorvelk 更新时间:1/28/2021 访问量:69

问:

我目前正在学习指针和按值传递的概念,我有这个 C 代码块:

void doSomething(int b){
    b = 6;
    printf("%d", b);
}
    
int a = 5;

int main(void){
    doSomething(a);
    printf("%d",a);
    return 0;
}

我应该得到在编译和执行时都没有错误的输出。通过跟踪代码,以下是我的看法:65

  • 整数被赋值 。a5
  • 由于 C 是严格按值传递的,因此 .doSomething(a) == doSomething(5)

现在在运行该行之前,我相当确定.因此,通过运行该行,程序可以有效地读取:b = 6;b == 5

5 = 6;

一个常量(因为我缺乏更好的术语)被分配给另一个常量。在 Python 中,这会因语法错误而失败,并且出现错误是有道理的。为什么它不会引发语法错误?

C 参数 变量赋 按值传递

评论

0赞 tadman 1/28/2021
你正在学习是件好事,但有一件事要尽早内化:远离全局变量。在使用的范围内声明内容。
3赞 001 1/28/2021
b不是一个常数。它是一个变量。 完全没问题。b = 6;
0赞 tadman 1/28/2021
由于 returns ,对它的所有调用都是“等价的”,如“not that it matter, because it's not anything”。doSomething()void
3赞 Martin James 1/28/2021
是的,函数参数是具有自动存储持续时间的变量 - 它们可以这样使用,例如。分配给,正如你所展示的。它们当然不是常数。
1赞 Nate Eldredge 1/28/2021
首先是第一件事。你明白为什么它是合法的,它做什么,为什么它不将一个常量分配给另一个常量吗?这实际上就是这里发生的一切。int c = 5; c = 6;

答:

1赞 tadman 1/28/2021 #1

如果你在调试器中查看,你会看到这里有两个变量在起作用,一个是代码中的全局变量,另一个是函数的本地变量。abdoSomething()

这是两个完全独立的变量。调用该函数时,请想象发生以下情况:doSomething()

stack_push(a);
call(doSomething);

编译器内部的其中执行如下操作:doSomething()

int b = stack_pop();
...

这就是“副本”的制作方式。

请注意,这个用于考虑变量的模型是一个近似值,只要达到相同的结果,优化编译器可能会做一些完全不同的事情,就像 C 规范一样。

1赞 IrAM 1/28/2021 #2

5 = 6;不一样b = 6;

b = 6;将值 6 分配给变量,具有自动存储,这是另一回事bb

5 = 6;不是一个有效的表达式,你误解了这个概念,认为两者都是一样的。
运行以下程序以查看错误:
C

void doSomething(int b){
    b = 6;
    5 = 6;
    printf("%d", b);
}
    
int a = 5;

int main(void){
    doSomething(a);
    printf("%d",a);
    return 0;
}

现在,您将收到第 3 行的错误:

错误:需要左值作为赋值
5 = 6 的左操作数;

引用左值和右值

1赞 corvelk 1/28/2021 #3

我决定把.它产生了类似于 Python 中的编译错误,Johnny Mopp 和 Martin James 的评论现在有意义了。5 = 6;main()

b确实是一个变量,而不是一个实际的常量。我的印象是,按值传递是只传递变量包含的内容,而忽略了变量的想法,认为函数只允许整数,而这只不过是一个占位符,与变量不同。bb

我的印象是,正是 ,而不是分配值的变量。b55

我目前在脑海中看到的是:

  • 整数被赋值 。a5
  • 由于 C 是严格按值传递的,因此 .doSomething(a) == doSomething(5)
  • b在调用 时分配了值。5doSomething(5)
  • b根据行分配值。6b = 6;
  • ...依此类推。

感谢大家的评论和回答!

1赞 Eric Postpischil 1/28/2021 #4

以下是 C 2018 标准在 6.5.2.2 4 中执行函数调用的方式:

在准备调用函数时,将对参数进行计算,并为每个参数分配相应参数的值...

这意味着,在函数定义中,with 被定义为一个变量(技术上是一个对象),并且,当函数被 with 或 调用时,or 的值被赋值给 ,就好像你做了 or 一样。这只是一项任务;它不会在 和 或 之间建立任何持久的连接。void doSomething(int b)bdoSomething(a)doSomething(5)a5bb = ab = 5ba5

函数内部,是一个变量,所以你当然可以执行赋值。这只需分配给变量 。bb = 66b

以下是有关参数如何成为其自身变量的更多信息。3.16 将参数定义为:

...作为函数声明或定义的一部分声明的对象,该声明或定义在进入函数时获取值,...

6.9.1 9说:

每个参数都有自动存储持续时间;它的标识符是左值...