c语言中const 类型变量地址赋值给指针。

本文探讨了C语言中const关键字的用法及限制,包括直接赋值、通过指针修改值的情况,并解释了为何编译器会产生警告或错误。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作者:余天升
链接:https://www.zhihu.com/question/21792567/answer/19354371
来源:知乎
著作权归作者所有,转载请联系作者获得授权。

const在C语言中是表示 道义上保证变量的值不会被修改,并不能实际阻止修改,通过指针可以修改常变量的值,但是会出现一些不可知的结果。几种情况不同,我们一个一个来看。

1、直接赋值
const int a = 3;
a = 5;
// const.c:6:2: error: assignment of read-only variable ‘a’
这种情况不用多说,编译错。

2、使用指针赋值, @孙健波提到的方法,在gcc中的warning,g++中出现error,是因为代码写得不对,由非const的变成const不用显式的转换,const变为非const需要显式转换,这种情况应当使用显式的类型转换。
const int a = 3;
int* b = (int*) &a;

printf("a = %d, *b = %d\n", a, *b);
*b = 5;
printf("a = %d, *b = %d\n", a, *b);
运行结果(注:使用msvc编译的结果一致):
$ gcc const.c
$ ./a.out
a = 3, *b = 3
a = 5, *b = 5

$ g++ const.cpp
$ ./a.out
a = 3, *b = 3
a = 3, *b = 5
这里使用g++编译时,a的值之所以没有改变,是因为编译时a是常量,然后被编译器编译为立即数了。因此对使用b指针修改不会更改a的值。

值得注意的是,如果a被定义为全局常变量,使用指针修改会引发segment fault。

在函数的原型中,我们也常用const修饰指针,表示函数的实现者在道义上不会去修改这个指针所指向的空间。例如我们熟知的strcpy函数,原型如下:
char* strcpy(char* dst, const char* src);

传入的参数src类型是const char*,表示函数内部实现不会修改src所指向的空间。之所以说是道义上,是因为在内部通过上述指针强制类型转换的方式可以修改该空间的值。另外,如果我们声明了我们不会修改传入指针的所指向的空间,那么我们也不应当去修改这块空间,因为这个传入的指针可能会是一个不可写的内存,然后出现段错误。
### C语言泛型编程实现任意类型变量赋值 在C语言中,可以通过`union`和`void*`指针来实现一种简单的泛型编程机制。这种技术允许处理不同类型变量并为其赋值。以下是具体方法及其背后的原理。 #### 使用Union实现多类型支持 通过定义一个联合体(`union`),可以存储多种基本数据类型的数据[^2]。由于联合体会共享同一块内存区域,因此可以根据实际需求选择不同的字段进行访问或修改。 ```c #include <stdio.h> #include <stdint.h> typedef union { short s; char c; int i; float f; uint8_t b; uint32_t u; } GenericType; int main() { GenericType gt; // 对不同类型赋值 gt.i = 10; printf("Integer value: %d\n", gt.i); gt.f = 3.14f; printf("Float value: %.2f\n", gt.f); gt.c = 'A'; printf("Char value: %c\n", gt.c); return 0; } ``` 上述代码展示了如何利用`union`为多个内置类型提供统一接口。然而需要注意的是,在读取未写入过的成员时可能会得到不可预期的结果。 #### 利用Void Pointer传递未知类型参数 当面对更复杂的情况或者需要动态决定操作的具体类型时,则可借助于`void *`通用指针完成任务。下面的例子说明了怎样创建接受各种输入形式的函数: ```c #include <stdio.h> #include <stdlib.h> #define MAX_SIZE 1024 void assign_value(void *dest, size_t dest_size, const void *src) { if (!dest || !src || dest_size == 0) return; memcpy(dest, src, ((size_t)(dest_size)<sizeof(*src)?(size_t)(dest_size):sizeof(*src))); } int main(){ double dval=789.0; long lval=-123L; char buffer[MAX_SIZE]; memset(buffer,'\0',MAX_SIZE*sizeof(char)); assign_value(&buffer,sizeof(double),&dval); printf("Double Value Copied:%lf\n",*(double*)buffer); memset(buffer,'\0',MAX_SIZE*sizeof(char)); assign_value(&buffer,sizeof(long),&lval); printf("Long Integer Value Copied:%ld\n",*(long*)buffer); return EXIT_SUCCESS;} ``` 此段程序片段里包含了两个主要部分:一个是负责复制源地址指向的内容到目标位置去的功能函数assign_value;另一个是在main函数内部调用了该功能函数两次分别针对双精度浮点数以及长整形整数进行了测试验证[^3]。 #### 结合Const限定符增强安全性 如果希望某些特定情况下不允许再次更改已初始化完毕后的数值状态的话,那么可以在声明这些局部变量的时候加上const关键字修饰它们[^5]。这样做不仅可以防止意外篡改原始资料副本还能提高整体应用程序运行效率因为编译器能够更好地优化那些常量表达式的计算过程从而减少不必要的中间结果保存动作发生几率。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值