C语言取地址操作符触发的对编程语言数据传输/读写哲思
2015-04-14 青岛 张俊浩
2025-11 北京 修正之前混淆读写认知,同时用更贴近底层硬件但又简单美的方式表述
今天在论坛贴吧看到关于C语言操作符/取地址符"&"的问题,因为之前自己学C语言时也遇到这个问题,触发了许多关于编程语言、计算机底层硬件机制的思考,就整理一下思路回帖,也顺便整理成一篇博客~
问题如下:
int a;
scanf("%d",&a);
我们老师讲,&是取地址符,但是我就奇怪,为什么叫取地址?地址不是形容一个事物在哪吗?
我们明明是想知道a是多少,而不是说它在哪,我输个10,a就是10了呀。
额,个人感觉C语言是门很"硬"的语言,因为它相对其他高级语言更接近硬件底层,而相对于机器指令汇编又跳出了繁琐的底层处理器指令编程。
无法理解"&"或者说"地址"、"取地址",是因为你站在高级(自然语言)语言的层面,而不是机器本身。任何变量都是数据,数据就会在硬件机器上有他的存储空间,存储空间有对应的位置,来方便我们操作这个存储空间,比如存储设备,内存,内存空间,内存地址。
这里我们定义了变量a,比如int a; 实际上是预留了一个存储空间,存储空间有相应的位置/地址,我们用符号"a"来指代,我们编译高级语言的时候,编译器会把我们所以对变量a的操作,转化为对相应存储空间的操作。
对一块存储空间本质上有两种操作:读、写,或者称输出、输入。读写操作本质对应着数据传输的过程:从源到目的,源=》目地。
"=" vs "f"
1.简单的数据传输过程:操作符"="
高级语言中用操作符"="表示数据的读写、传输过程,是数据的从一个存储空间向另一个存储空间传输的过程,或者说数据从源存储空间读出,写入目的存储空间。我们一般用操作符"="表示数据传输的过程,表示读出写入操作。操作符"="操作的对象:右侧为数据源,读操作的操作对象,一般称为右值,左侧为数据目的存储空间,写操作的操作对象,一般称为左值。
比如:
1.1 a = 1; //内存地址的指代符号a在操作符"="的左侧,a称为左值,是写操作的目地地址,表示是往目的地址a的存储空间写数据;这里源数据是一个立即数,立即数一般存储在指令中;本条代码指令做的数据传输/读写操作:把从指令中解码后的立即数"1"写入目的地址a对应的存储空间;
1.2 b = a; //内存地址的指代符号a在操作符=的右侧,a称为右值,是读操作的数据源;内存地址的指代符号b在操作符=的左侧,b称为左值,是写操作的目的地址;这条代码指令做的数据传输/读写操作:从源地址a所对应的存储空间读出数据,写入目的地址b所对应的存储空间。
2. 复杂的数据处理、传输过程:封装成函数::f
数据往往不只是简单的传输,从源地址存储空间读取/获得的输入数据,一般需要做一定处理之后,再写入/输出目的存储空间。
这些复杂/多样/具体的数据传输、处理过程就不能用简单的数据传输符号"="来表示,计算机编程语言把这个过程封装为f/函数/方法/算法/算子:函数接收数据,处理数据,输出处理后的数据。
或者数学式更简洁的表述:
y = f(x)
x::读::输入数据 =》f::函数::算法::处理数据 =》y::写::输出数据
或者伪代码式表述:
输出 函数 (输入) {
算法具体实现:处理数据
}
2.1 函数做读出/输入操作时
把要传输的数据的源地址传递给函数即可,函数会从源地址读取数据,传递给函数处理。变量名即地址,如果想从变量名所指代的地址空间读数据传入函数,直接传变量名即可。
以printf为例:
printf("%d", a); //prinf函数的作用是从源地址/输入地址存储空间读取数据,然后往标准输出stdout输出,函数传入的数据(除了格式化字符串)是一个源存储空间的地址;变量名a即地址,从变量名a所指代的地址空间读取数据传入函数,所以直接传变量名即可。
2.2 函数做写入/输出操作时
2.2.1 y = f(x):y即函数f返回数据要写入的地址
2.2.2 或者把要写入的地址传给函数f
以本篇博客最开始讨论的函数scanf为例,关于C语言地址、取地址运算符"&"
scanf("%d",&a):
scanf函数的作用是把从标准输入stdin获得的数据格式化后写入一个目的存储空间,函数传入的数据(除了格式化字符串)是一个目地存储空间的地址;
&a作为scanf函数的输入数据,&a是什么?&a其实就是符号a所指代的内存地址,"&"操作符是为了获得存储空间地址a,把存储空间地址a传给scanf函数,让scanf函数往地址a所指向目的存储空间写数据;如果不加操作符号 "&",就会把存储空间a(这里把存储空间与存储存储空间地址简化等同)存储的数值,误当成要写入内存地址,传给scanf函数,造成的后果是scanf函数试图把从标准输获得数据往错误的地址对应的存储空间写,而非地址a指向的存储空间,近一步会触发内存越界、段错误,即便不发生错误,也非我们想要的数据正确写入的地址。
当然如果想了解=、函数数据的传递更底层的细节,需要具体到代码、硬件视角的话,需要了解栈帧,寄存器,需要了解编译过程,需要看编译后的汇编代码,ELF、机器指令,处理器硬件架构设计,梁晓晖译《汇编语言:基于Linux环境》、马朝晖译《汇编语言程序设计》、《程序员的自我修养》是不错的自我修养进阶。
本文解释了C语言中取地址运算符“&”的概念及其使用场景,详细介绍了变量存储空间与取地址符的关系,帮助读者理解输入输出操作。
4961

被折叠的 条评论
为什么被折叠?



