[programming] 在 C 语言中有什么比较优雅的方法定义不可变变量?

Rust/zig 等现代语言里面都引入了不可变语法,很方便。那么,如果我用C语言时,也想要某个变量或 struct field 保持不变,该怎么做呢?我知道有 const 、宏替换(可能不可取)。除此之外,还有什么哪些办法?敬请各位道友赐教,谢谢。

另,如果能讲讲 const 的本质就更好了。

下述代码是我之前的笔记,仅供参考。

#include <stdio.h>
// const int a = 10; // 全局const变量,编译器会将其放在text段,其值不能更改,否则会Segmentation fault

int main()
{
	const int a = 10; // 函数中的const变量在栈上,其值可以更改
	int* b = (int*)&a;
	*b = 20;
	printf("a:%d\n",a);
	
	return 0;
}

结论:我认为const关键字仅起到提醒作用,提醒你不要改变这个变量的值。const修饰变量的值到底能不能变,需要看变量所处位置[当然,根本原因在于编译器]。

嗯。这么说,const 不能保证值不变。谢谢。

Rust 的不可变应该是为了计算生命周期吧,感觉面向过程的语言,有没有不可变没有那么重要。

已初始化的全局变量在程序镜像的data段而不是text段吧

对于全局常量有的编译器会把数据放到 .rodata 段中,有的会放到 .text 段中。比如 gcc 10 中数据是这么存放的。

格式化字符串会放到rodata,但我没见过初始化了的全局变量放text的

和编译器有关,有的编译器会

什么编译器会,能举个例子吗

好久不搞 c 语言了,具体哪些忘记了。把全局常量放到 text 段的编译器挺多的,应该能查查

没有这样的编译器,否则就不符合elf spec了

没说不能放到 .text 段中吧。不过一些老的编译器处理的也确实不规范,有的甚至把字面值放到 .data 段中。。 image

为什么没说呢,elf spec说了.text里是放可执行指令的,全局变量不算可执行指令吧

这个要说怎么看了,我记得最早的时候是不太区分 .text .rodata .rodata1 .dynsym 等段的,统一都叫做 TEXT 段或 CODE 段,和 DATA 段做区分,具体的区分开数据和指令或其他符号是后来弄的,所以一些编译器产生的目标文件在 .text 段中直接包含了除了指令之外的其他数据和符号。 const 数据放到 .text 段中是因为在一些嵌入式环境中,.text 段的数据是提供只读保护的其他段的数据保证不了。

但也有例外有些比较老的编译器有把只读数据或字面值放到 .data 段的,这样的话就有可能能修改字面值,比如把 3 改成 4…

ELF 又不会给每次运行之前给你反汇编了研究到底是指令还是数据,只要是不会被执行到的位置塞什么都可以。

像 ARM 这样汇编器是会把常量放 text segment 最后面的。