一 概述
二 类型
三 语句
四 函数
五 数据
六 内存
七 代码
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
1. 变量
变量(variable)与对象(object)联系在一起。
对象是执行期间的存储区域,其内容表示值(value),以特定类型(type)进行解释。变量则是对象外在身份,用以描述对象基本信息,诸如内存地址、数据类型,以及作用域等。对象可通过类型转换或多态方式拥有不同身份。
我们可以定义(define)或声明(declare)一个变量。定义有明确内存分配行为,依照类型决定大小,或赋予初始值;声明则向编译器说明目标信息,如名字、类型和参数等。但不一定会为其分配内存,因为它或许已在某处定义过,声明只是告知该如何使用而已。显然,定义是声明的一种,反之则不然。
一个变量可以被声明多次,但只能被定义一次。
int x = 1;
单行定义多个变量时,它们的类型未必相同。
char *p, c; // char*, char static_assert(sizeof(p) == 8); static_assert(sizeof(c) == 1);
int x, y[5]; // int, int[5] int m[12], n[15][3], o[21]; // int[12], int[15][3], int[21]
并没有强制要求变量初始化,也就意味着值 “不可预知”。
int *p; printf("%d\n", *p); // Segmentation fault
int a, b = 10; // a uninitialized; b = 10
按值传递(pass-by-value),也就是说赋值、传参或返回值,总是进行拷贝。
无非是复制目标对象,还是指针自身。
int x = 1; int y = x; assert(&x != &y);
全局变量
全局变量默认可被外部访问,可用 static 修饰符限定在当前模块(源码文件)内使用。
按是否有初始化值,分配到 .data 或 .bss 段内。(自动零值),静态修饰符仅仅改变该符号作用域,并不影响内存分配方式。尽量减少可被外部访问的全局变量。
int x = 0x11; // .data static int y = 0x22; // .data int z; // .bss (zero-value) int main (void) { printf("%d, %d, %d\n", x, y, z); return EXIT_SUCCESS; }
局部变量
默认局部变量生命周期仅限当前栈帧,或某个更小的作用域。
其内存分配位置为栈帧(stack frame),强烈建议初始化。
int test() { int x = 100; ++x; return x; }
$ objdump -d -M intel ./test | grep -A9 "<test>:" 0000000000401106 <test>: 401106: f3 0f 1e fa endbr64 40110a: 55 push rbp 40110b: 48 89 e5 mov rbp,rsp 40110e: c7 45 fc 64 00 00 00 mov DWORD PTR [rbp-0x4],0x64 # x = 100 401115: 83 45 fc 01 add DWORD PTR [rbp-0x4],0x1 # ++x 401119: 8b 45 fc mov eax,DWORD PTR [rbp-0x4] # return x 40111c: 5d pop rbp 40111d: c3 ret
如添加静态修饰,则存储位置变为 .data 或 .bss,并持有最后一次值。
int test() { static int x = 100; // 初始化值保存到 .data,并未使用代码进行初始化。 ++x; return x; }
$ objdump -dS -M intel ./test | grep -A20 "<test>:" 0000000000401136 <test>: #include <stdio.h> #include <stdlib.h> int test() { 401136: f3 0f 1e fa endbr64 40113a: 55 push rbp 40113b: 48 89 e5 mov rbp,rsp static int x = 100; ++x; 40113e: 8b 05 ec 2e 00 00 mov eax,DWORD PTR [rip+0x2eec] # 404030 <x.2832> 401144: 83 c0 01 add eax,0x1 401147: 89 05 e3 2e 00 00 mov DWORD PTR [rip+0x2ee3],eax # 404030 <x.2832> return x; 40114d: 8b 05 dd 2e 00 00 mov eax,DWORD PTR [rip+0x2edd] # 404030 <x.2832> } 401153: 5d pop rbp 401154: c3 ret
$ readelf -x .data ./test Hex dump of section '.data': 0x00404020 00000000 00000000 00000000 00000000 ................ 0x00404030 64000000 d...
外部变量
使用 extern 修饰符声明在其他模块定义的变量或函数。
前置声明:使用对象(变量或函数)前,需要先声明。模块向外提供函数或全局变量,通常使用头文件进行声明。
// lib.c int X = 100;
#include <stdio.h> #include <stdlib.h> extern int X; int main (void) { printf("%d\n", X); return 0; }
$ gcc -o ./test main.c lib.c && ./test 100
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论