redis源碼學習-編程技巧

#宏的用法

#define VERSION "6.0.1"
#define DATETIME "datetime"

//將變量 s 以字符串的形式輸出
#define xstr(s) __str(s)
#define __str(s) #s

//使用宏拼接字符串
#define ECHO_STR ("jemalloc-" xstr(hello) "." xstr(world) "." xstr(version))
//printf ("%s\n", ECHO_STR); 將輸出 jemalloc-hello.world.version

//同時,還可以使用如下方式拼接字符串
char* buf = VERSION DATETIME;
printf ("%s\n", buf); //將輸出buf的值爲 6.0.1datetime

上述代碼中,爲什麼需要使用兩個嵌套宏函數來完成字符串是輸出呢,看如下例子就能知道結果:

printf ("%s\n", xstr (VERSION)); //輸出 "6.0.1"
printf ("%s\n", _str(VERSION));  //輸出 VERSION

後者不會對參數進行宏替換,直接當做字符串輸出,前者纔對參數進行宏替換

#零長數組和變長數組
##零長數組
在 GNU c 中允許零長數組,在 c++ 和 ANSI C 中都不允許使用,如下所示:

typedef struct sds {
	unsigned int len;
	unsigned int free;
	char buf[0];
};

此結構體中包含一個長度爲零的數組,但是它的使用必須滿足一定的條件。

  • 結構體中至少有一個其他類型的成員,否則會報錯 “error: flexible array member in otherwise empty struct
  • 必須放在結構體的成員中的最後一個位置,否則會報錯 “error: flexible array member not at end of struct

查看該結構體的大小發現,長度爲 0 的數組長度爲 0, sizeof (sds) == 8

在 ISO C99 中,使用變長數組也可以實現同樣的功能。
##變長數組

typedef struct sds {
	unsigned int len;
	unsigned int free;
	char buf[];
}sds;
sds mSds = {5, 10, {'h', 'e', 'l', 'l', 'o'}};	//此結構體的變量只能在函數體外部定義和初始化,否則會報錯
//error: non-static initialization of a flexible array member
//error: (near initialization for 'mSds')

通過 sizeof 查看大小

sizoef (sds) : 8
sizeof (mSds): 8

變長數組是不完全數據類型,不能使用 sizeof 獲取它的大小。

這種C99中伸縮數組(flexible array),是對結構體功能的擴展。在結構體的原型申明時,可以申明一個沒有指定數組長度的數組,在使用是,通過malloc動態決定結構體變量的數組大小。

在 C 中申明一個數組

int arr[NUM];

NUM的值一般是一個常量,且是不變的,但是在邊長數組的長度可以在運行時指定。如下所示:

int i;
scanf ("%d", &i);
int arr[i];

上述的數組長度就是在運行時決定的,這種類型的數組就稱之爲變長數組。

可參考文檔

https://gcc.gnu.org/onlinedocs/gcc-4.6.2/gcc/C-Extensions.html#C-Extensions

sds * pSds = (sds*)malloc (sizeof (sds) + length + 1);
pSds->len = length;
pSds->free = 0;
memcpy (pSds->buf, str, length);
pSds->buf[length] = '\0';

在 redis 源碼中,sdsnew 函數每此創建一個結構體後,都是返回的 pSds->buf 進行處理,這樣,結構體往後偏移了 sizeof(struct sds)個字節(即 8 個字節),所以每次在對 buf 處理的時候,先轉成 sds 結構體時,都需要往前偏移 8 個字節,得到 len 和 free。

void sdslen (void * s) 
{
	struct sds * sh = (void *)(s - (sizeof (struct sds)));
	return sh->len;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章