欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C 常量

程序员文章站 2023-08-17 17:15:55
前言 - 引言 每次都有点长, 不如来点短的. 轻松的, 当微型小说看的 ...... C++ const 表示常量(编译器语法糖 or 直接崩溃), 运行时不可改变(当然程序世界没有不可改变). 在 C 中 const 语义是不推荐变动的变量, 但不是不能改变, 更不是常量. 看论证例子: 输出结 ......

前言 - 引言

  每次都有点长, 不如来点短的. 轻松的, 当微型小说看的 ......

  c++ const 表示常量(编译器语法糖 or 直接崩溃), 运行时不可改变(当然程序世界没有不可改变). 

在 c 中 const 语义是不推荐变动的变量, 但不是不能改变, 更不是常量.  看论证例子:

#include <stdio.h>

int main(void) {
    const int pi = 1314;
    int * ptr = (int *)&pi;
    *ptr = 520;
    printf("pi = %d\n", pi);
    return 0;
}

输出结果如下: (如果是 .cc 在 cl 中输出是 1314, 在 g++ 段错误[时间 2018/09/19])

$ gcc -g -wall const.c ; ./a.out
pi = 520

 

  上面代码, 常在 "c 中没有常量" 论证中出现 (像 1, "你好", '\0' 这些是字面量,  多数会编译到代码区)

  本篇文章主题是 c 中构建常量. 总有办法 ~ 达到效果. 能够想到强加意义就是, 真不希望变量被有

心人改动. 开始之前赠送一个不错的语法, 目前时间点在最新的 cl 和 gcc 中对此不再有 warning 

#include <stdlib.h>

/* free a block allocated by `malloc', `realloc' or `calloc'. */ extern void free (void *__ptr) __throw; void buf_del(buf_t b, void * m, size_t sz) { if (b->size != sz) return free(m); ... }

return free(m); 语法源自标准手册, 在 c 中 void 也是个类型.  整体而言节约了几行代码 ~

写起来更紧凑些吧 :)

 

正文 - 思路

  基础面试常会碰到这样一个问题, c 程序中有那些存储变量的区域? (多数问程序分布区域, 挺多

的, 需要查询专业书籍, 再重温几遍高级程序员自我修养). 多数会说 普通变量在栈上, 初始化的 static

或 全局变量在初始化全局区, 未初始化 static 或 全局变量在未初始化全局区, 字符串数字字面量在代

码区. 这时候有些人会忽略 reigster 变量尝试保存在寄存器区(加分项, 自我感觉这个问题挺好, 大家都

会, super 难, 还能方便大佬引申). 同样 register 引出了我们的话题

    const register int hoge = 110;      

不妨修改验证一下 

1 #include <stdio.h>
2 
3 int main(void) {
4     const register int hoge = 110;
5     (int)hoge = 520;
6     printf("hoge = %d\n", hoge);
7     return 0;
8 }
$ gcc -g -wall register.c

register.c: in function ‘main’:
register.c:5:15: error: lvalue required as left operand of assignment
     (int)hoge = 520;

提示左值不可修改错误. ((int)hoge 已经被强转成左值).  不妨再来一个

1 int main(void) {
2     const register int hoge = 110;
3     int * ptr = (int *)&hoge;
4     *ptr = 520;
5     printf("hoge = %d\n", hoge);
6     return 0;
7 }
$ gcc -g -wall register.c
register.c: in function ‘main’:
register.c:5:5: error: address of register variable ‘hoge’ requested
     int * ptr = (int *)&hoge;

提示 register variable 变量没有地址, 无法转换错误. 

通过 register 构建 int, unsigned const 常量是没有问题. 那 float, double char * or struct nuion ...

且看下文 ~ 

   

  话说 register 申请放入寄存器, 不在五行之中. 毕竟空间有限, 这种奥妙玄幻用不了太多. 对

于 char * 如何处理呢. 有的朋友会抛出

const char * const heoo = "hello, 世界";

这种字面量表示方式出发点是 "字面量不可变". 但恰恰编译器很多, 也有很多参数配置. 有些编译

器特定配置或默认配置是可以改变字符串字面量的. 所以这种做法是不可控的, 未定义的.

  因而构造另一种修真套路, 宏(本质还是构建左值 lvalue)

#include <stdio.h>

#ifndef const_str_hoge
inline static const char * const const_str_hoge(void) { return "白龙马"; }
#define const_str_hoge const_str_hoge()
#endif

int main(void) {
    printf("const_str_hoge = %s\n", const_str_hoge);
    return 0;
}
$ gcc -g -wall chas.c ; ./a.out
const_str_hoge = 白龙马

是不是感觉大江随浪飘, 修真无岁月. 同样对于 float 也可以是这样 

#ifndef const_float_pi
inline static float const_float_pi(void) { return 3.14; }
#define const_float_pi const_float_pi()
#endif

再补充一个 struct

#include <stdio.h>

struct version {
    int major; // 主版本号
    int minor; // 副版本号
    int micro; // 子版本号
};

#ifndef const_version
inline static const struct version const_version(void) {
    return (struct version){.major = 1, .minor = 2, .micro = 3};
}
#define const_version const_version()
#endif

int main(void) {
    printf("version = { major = %d, minor = %d, micro = %d}\n", 
        const_version.major, const_version.minor, const_version.micro);
    return 0;
}
$ gcc -g -wall struct.c ; ./a.out
version = { major = 1, minor = 2, micro = 3}

单纯的运行时中是无法修改这些特殊构造出来的常量. 而且通过编译器无法编译通过,

也会让有心人放弃犯错误 :)  好的制度应该考虑让想犯错的如何难犯糊涂 ~ 

 

后记 - 展望

       错误是难免的, 欢迎交流 ~

  <<>> - https://music.163.com/#/song?id=487379098

       C 常量

上一篇: PyQt5--TextDrag

下一篇: UDP server Code