今天无意间看到这样一段代码,因为还是第一次看到,这是glibc库里的代码,写出来分享一下:
#ifndef ERR_MAP
# define ERR_MAP(n) n
#endif
const char *const _sys_errlist_internal[] ={
#define _S(n, str) [ERR_MAP(n)] = str,
#include <errlist.h>
#undef _S};
这里很明显定义了一个指针数组,也就是首先 _sys_errlist_internal 是一个数组,并且这个数组里元素都是指针,所以它是一个指针数组毫无疑问。这里比较奇怪的是初始化方式,即 [n] = str。一般我们指针数组是这样初始化的:
const char *const errlist_internal[] =
{"Operation not premitted","No such file or directry","I/O error"
};
而像这样的初始化方式也是合法的,可能 C 语言所有类型的数组都支持这样初始化:
const char *const errlist_internal[] =
{[0] = "Operation not premitted",[2] = "No such file or directry",[5] = "I/O error"
};
因为没有指定数组大小,所以这样初始化数组大小是多少呢?从 C 语言数组类型知识点我们应该能猜出来,数组大小应该是 6,即包含 6 个元素。
#include <stdio.h>
#include <stdlib.h>const char *const errlist_internal[] =
{[0] = "Operation not premitted",[2] = "No such file or directry",[5] = "I/O error"
};int main()
{size_t num = sizeof(errlist_internal)/sizeof(errlist_internal[0]);printf("number of list is %lu\n", num);size_t i = 0;for(; i < num; i++){printf("errlist_internal[%lu] = %s\n", i, errlist_internal[i]);}return 0;
}
所以这种初始化方式应该是指定元素的初始化方式,未初始化到的元素是空的(指针类型时是null,其他类型未验证)。 所以像 glibc 库里这个代码,预编译出来应该类似这样的:
#include <stdio.h>
#include <stdlib.h>#ifndef ERR_MAP
# define ERR_MAP(n) n
#endif
const char *const _sys_errlist_internal[] ={
#define _S(n, str) [ERR_MAP(n)] = str,
#include "errlist.h"
#undef _S};int main()
{size_t num = sizeof(_sys_errlist_internal)/sizeof(_sys_errlist_internal[0]);printf("number of list is %lu\n", num);size_t i = 0;for(; i < num; i++){printf("_sys_errlist_internal[%lu] = %s\n", i, _sys_errlist_internal[i]);}return 0;
}
errlist.h
_S(1, "Operation not permitted")
_S(2, "No such file or directory")
预编译出来是这样的:
在 errlist.h 头文件里使用了宏定义,然后完成对指针数组的初始化。