1. 程式人生 > >由淺至深->C語言中union和enum關鍵字的經典問題分析

由淺至深->C語言中union和enum關鍵字的經典問題分析

引言:由淺至深系列的第二篇文章,繼續體悟語言中的一些細節!

文章嚮導
union的自我介紹
union與系統大小端
enum列舉的引入
真正意義上的常量?

正文

一、union的自我介紹

  union(聯合/共用體)在語法描述上與struct有相似之處,是一種能在同一儲存空間記憶體儲不同型別資料的資料型別,換句話說,它主要被用於儲存某種既沒有規律、事先也未知順序的混合型別資料。

二、union與系統大小端

1.不可不知的union特性

  為了更好地理解union使用上的特性,將其與struct進行一番對比:

struct A
{
    int
i; char c; }; union B { int i; char c; } printf("%d\n", sizeof(struct A)); //輸出5 printf("%d\n", sizeof(union B)); //輸出4

  上述並不是一份嚴格意義上的程式,但我們可從中得出一個結論:與struct不同,union只分配最大成員空間,且所有成員共享這一空間。既然是共享同一份空間,也就是可理解為共用同一個記憶體首地址,同時共用體中的成員都可以對這份空間進行操作,操作也是共同生效。關於操作共同生效這一點的體悟,將在接下來的系統大小端中詳細論述。

2.探祕系統大小端

  在引出系統大小端這個問題前,我們不妨思考下述這樣一個情景:

union C
{
    int i;
    char c;
}
union C c;
c.i = 1;
printf("%d\n", c.c); //輸出值為多少?

  或許有讀者會認為顯然結果為1嘛,但令人遺憾的是這個答案並不是那麼的令人滿意,why? 因為這個輸出值取決於系統的大小端模式,所以為了見到union的真正面貌,首先得打倒他的嘍囉“大小端”呢!

  • 小端模式:低地址儲存低位資料
  • 大端模式:低地址儲存高位資料

顯然,小端模式更符合人們直觀的思維對應關係,有點懵?看看下面的圖吧:
這裡寫圖片描述
  上述程式片段中,已將c.i賦值為1,它在記憶體空間中的儲存方式就如上圖描述的兩種情形。若為小端模式:因c.c為char型,則取到是該空間中的第一個位元組資料,故輸出為1;若為大端模式:同理可得,輸出為0。

3.實用程式(如何檢測系統大小端)

#include <stdio.h>

/* 檢查處理器大小端
 * 若為大端模式,返回0
 * 若為小端模式,返回1
*/
int checkCPU()
{
    union w
    {
        int a;
        char b;
    }c;
    c.a = 1;
    return (c.b == 1); //判斷c.b是否與1相等,小端模式下低地址中存放的是0x01,而大端模式下高地址存放的是0x01 
}

int main()
{
    printf("%d\n", checkCPU());

    return 0;
}

  本程式就是基於系統大小端的原理進行編寫,讀者可好好體悟一番。

三、enum列舉的引入

  enum是C語言的一種自定義型別,可用它建立一個新“型別”並指定其具有的值。將列舉引入的目的實際是為了提高程式的可讀性,舉個栗子:

enum color
{
    RED;
    BLUE = 2;
    GREEN;
};

int main
{
    int c = GREEN;
    printf("%d\n", c); //輸出3
    c = RED;
    printf("%d\n", c); //輸出0

    return 0;
}

上面這個例子雖然簡單,可卻向我們闡明瞭幾分道理:

  • enum變數的型別實際上為int型
  • 列舉中第一個定義的值預設為0(手動指定除外)
  • 預設情況下後續定義的值為在前一個的基礎上+1

四、真正意義上的常量?

  C語言中常量這個問題經常會在筆試/面試題中提及,或許首先映入你的腦海中會是const、define這兩個關鍵字,如果是,今天不妨重新認識它—enum !

  • 首先,我const鄭重宣告,C語言中我沒法定義一個常量,很抱歉迷惑了一些初學者!如果你想得到一個只讀變數,我很樂意。
  • emm,我define是可以定義一種稱之為巨集常量的東西,但我的本質是字面量(並不佔用記憶體空間),僅僅是在預編譯期進行文字替換而已。
  • 今天我就把話撂在這兒:我enum可以定義C語言中真正意義上的常量!不信?非要我露一手你才信服:
#include<stdio.h>
enum  //無名列舉,用於定義常量
{
    SIZE = 10
};

void InitArray(int array[])
{
    int i = 0;
    for(i=0; i<SIZE; i++)  //here!
    {
        array[i] = i+1;
    }   
}

void PrintArray(int array[])
{
    int i = 0;
    for(i=0; i<SIZE; i++) //here!
    {
        printf("%d\n",array[i]);
    }
}

int main()
{
    int array[SIZE]={0}; //here!

    InitArray(array);
    PrintArray(array);

    return 0;
}

  嗯,希望我說明白了。Farewell,my friend!

參閱資料
C Primer Plus
狄泰軟體學院-C語言進階剖析教程

相關推薦

->C言中unionenum關鍵字經典問題分析

引言:由淺至深系列的第二篇文章,繼續體悟語言中的一些細節! 文章嚮導 union的自我介紹 union與系統大小端 enum列舉的引入 真正意義上的常量? 正文 一、union的自我介紹   union(聯合/共用體)在語

關於c言中mallocremalloc函式的分析

首先申明,這是本人第一次寫部落格,其目的僅僅是為了加強自己對知識點的掌握,為到達在本子上記筆記的效果 進入正題。對於malloc,它的作用就是為了動態分配空間,像c++中的new一樣。這裡就不說他們兩的區別了。malloc函式有這樣幾個特點。 1.分配的空間地址是連續的,

C言中char*char[]用法區別分析

本文例項分析了C語言中char* 和 char []的區別。分享給大家供大家參考之用。具體分析如下: 一般來說,很多人會覺得這兩個定義效果一樣,其實差別很大。以下是個人的一些看法,有不正確的地方望指正。 本質上來說,char *s定義了一個char型的指標,它只知道所指向的

】redis 現實發布訂閱的幾種方式

前言 提到訊息佇列,最熟悉無疑是 rabbitmq,它基本是業界標準的解決方案。本文詳細介紹 redis 多種現實輕訂閱方法,作者認為非常有趣並加以總結,希望對有需要的朋友學習 redis 功能有一定的帶入作用。 方法一:SUBSCRIBE + PUBLISH //程式1:使用程式碼現實訂閱端 var s

【MySQL經典案例分析】關於資料行溢位的探討

本文由雲+社群發表 一、從常見的報錯說起 ​ 故事的開頭我們先來看一個常見的sql報錯資訊: ​ 相信對於這類報錯大家一定遇到過很多次了,特別對於OMG這種已內容生產為主要工作核心的BG,在內容線的儲存中,資料大一定是個繞不開的話題。這裡的資料“大”,遠不止儲存空間佔用多,其中也包括了單個

【MySQL經典案例分析】關於數據行溢出的探討

發布 解決 del set cloud 這樣的 自己 表結構 innodb 本文由雲+社區發表 一、從常見的報錯說起 ? 故事的開頭我們先來看一個常見的sql報錯信息: ? 相信對於這類報錯大家一定遇到過很多次了,特別對於OMG這種已內容生產為主要工作核心的BG,在內

c言中fscanffprintf

寫的權限 set per efi errno fclose pri form price 很多時候我們需要寫入數據到文件中時都覺得很困擾,因為格式亂七八槽的,可讀性太差了,於是我們就想有沒有什麽函數可以格式化的從文件中輸入和輸出呢,還真有。下面我將講解一下fscanf和fp

C言中typedefsizeof的註意事項

isp sizeof spa 註意 list數據 對象 audio 應該 user typedef的作用是給一個數據類型起一個別名。 typedef struct LIST { int data; }SeqList; SeqList 就相當於struct LIS

c言中external,static關鍵字用法

static用法: 在C中,static主要定義全域性靜態變數、定義區域性靜態變數、定義靜態函式。 1、定義全域性靜態變數:在全域性變數前面加上關鍵字static,該全域性變數變成了全域性靜態變數。全域性靜態變數有以下特點。 a.在全域性區分配記憶體。 b.如果沒有初始化,其預設值為

(C言中printf函式讀取的具體分析)

(C語言中printf函式讀取的具體分析) 不多說,直接上。printf函式將傳入的資料傳送到記憶體堆區(緩衝區),然後再根據前面的(格式說明符一個個讀取,這樣會造成錯誤) #include<stdio.h> #include<limits.h> #incl

C言中 malloc free

from:http://blog.sina.com.cn/s/blog_af1a77fa0102xceb.html 一、malloc()和free()的基本概念以及基本用法: 1、函式原型及說明: void *malloc(long NumBytes):該函式分配了NumBytes個位元

c言中staticauto的區別

1、static變數存放在靜態儲存區,在程式整個執行期間都不釋放;而auto變數存放在動態儲存區,隨著生命週期的結束而立即釋放。 2、static變數只賦值一次,以後就不用賦值;而auto變數在函式每呼叫一次都要賦初值

關於C言中“x++”“++x”的問題

關於一個變數在不同環境下自增自減的問題。 #include<stdio.h> int main() { int x = 8; int y = 0; y = (++x) + (x++) + (++x); printf("%d\n",y);

C言中printfscanf函式基本的引數型別輸出形式

printf函式的引數型別和輸出形式 字元 引數型別 輸出形式 d,i int 十進位制數 o int 無符號八進位制數(不含前導0) x,X int 無符號十六進位制數(沒有前

C言中“指標”“指標變數”的區別是什麼

比較嚴格的說法是這樣的:系統為每一個記憶體單元分配一個地址值,C/C++把這個地址值稱為“指標”。如有int i=5;,存放變數i的記憶體單元的編號(地址)&i被稱為指標。“指標變數”則是存放前述“地址值”的變數,也可以表述為,“指標變數”是存放變數所佔記憶體空間“

C言中i++++i的區別

C語言中i++和++i的區別 C語言中++i和i++是有區別的!快速理解的話就是用一句話概括: 1、i++是先賦值再運算+1; 2、++i是先運算+1再賦值; i++和++i都是c語言裡的自增,但是它們自增的順序不同。++i表示,i自增1後再參與其它運算,而i++ 則是i參與運算後,i的

C言中char * char []的區別

問題引入: 在實習過程中發現了一個以前一直預設的錯誤,同樣char *c = "abc"和char c[]="abc",前者改變其內容程式是會崩潰的,而後者完全正確。 程式演示: #include <iostream> usingnamespa

C言中的32個關鍵字及部分講解

說起c語言中的關鍵字,大家印象最深的可能就是int,double等定義一個數據變數時所使用的關鍵字了。但是除了這些資料型別的關鍵字還有哪些呢?for?while?沒錯,這些確實都是,但是並沒有一個系統的總結。本文筆者就將就c語言學習中所遇到的共計32個關鍵字進行整理。請善用搜

C言中constC++中const關鍵字的區別

# include "iostream" using namespace std; struct Teacher {     char name[30];     int age; }; void operatorTeacher(Teacher *pT) {   

C言中typedefdefine的區別

    正確思考typedef和巨集文字替換直接的區別關鍵在於就是把typedef看成一種徹底的“封裝”型別——在宣告它之後不能在裡面增加別的東西。它和巨集的區別主要體現在兩個方面。    一、可以用其他型別說明符對巨集型別名進行擴充套件,但對typedef所定義的型別名卻不