C 常量

前言 - 引言程序員

  每次都有點長, 不如來點短的. 輕鬆的, 當微型小說看的 ......面試

C++ const 是常量(編譯器語法糖 or 直接崩潰), 運行時不可改變(話說程序世界沒有不可改變). ui

在 C 中 const 語義是不推薦變更的變量, 但不是不能改變, 更不是常量.  看論證例子:spa

#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])code

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

 

  上面代碼, 常在 "C 中沒有常量" 論證中出現 (像 1, "你好", '\0' 這些是字面量,  多數會編譯到代碼區)blog

  本篇文章主題是 C 中構建常量. 總有辦法 ~ 達到效果. 可以想到強加意義就是, 真不但願變量被有字符串

心人改動. 開始以前贈送一個不錯的語法, 目前時間點在最新的 cl 和 gcc 中對此再也不有 warning get

#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 也是個類型.  總體而言節約了幾行代碼 ~編譯器

寫起來更緊湊些吧 :)it

 

正文 - 思路

  基礎面試常會碰到這樣一個問題, 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

       

相關文章
相關標籤/搜索