C 如何以更好的方式编写这些字符数组?

C 如何以更好的方式编写这些字符数组?,c,arrays,C,Arrays,现在我有一个字符数组,我用它来存储字体数据: const char * const FONT[] = { "\x48" "a44448", //0 "\x27" "m\x48" "m\x40", //1 "\x06" "a46425" "m\x00" "m\x80", //2 "\x06" "a46425" "a42425", //3 "\x83" "m\x03" "m\x68" "m\x60", //4 "\x88" "m\x08" "m\x0

现在我有一个字符数组,我用它来存储字体数据:

const char * const FONT[] = {
    "\x48" "a44448", //0
    "\x27" "m\x48" "m\x40", //1
    "\x06" "a46425" "m\x00" "m\x80", //2 
    "\x06" "a46425" "a42425", //3
    "\x83" "m\x03" "m\x68" "m\x60", //4
    "\x88" "m\x08" "m\x04" "m\x44" "a42424" "m\x00", //5
    "\x02" "a42428" "a84842", //6
    "\x08" "m\x88" "m\x20", //7
    "\x44" "A46428" "a42428", //8
    "\x86" "a46428" "m\x60", //9
    ...
有没有一种方法可以以更可读的方式编写,但仍然在编译时计算它? 例如,类似于:

#define start(x,y) //somehow create '\x<x><y>'. start(3,4) -> '\x34'
#define arc(x,y,rx,ry,a) //evaluate to {'a','<x>','<y>','<rx>','<ry>','<a>'}. arc(1,2,3,4,5) -> {'a','1','2','3','4','5'}

const char * const FONT[] = {
    start(4,8) arc(4,4, 4,4, 8) "", //somehow concatenate them
    ...
#define start(x,y) //somehow create '\x<x><y>'. start(3,4) -> '\x34'
#define arc(x,y,rx,ry,a) //evaluate to {'a','<x>','<y>','<rx>','<ry>','<a>'}. arc(1,2,3,4,5) -> {'a','1','2','3','4','5'}

const char * const FONT[] = {
    start(4,8) arc(4,4, 4,4, 8) "", //somehow concatenate them
    ...
但这是可行的:

const char X[] = {'\x48','a','4','4','4','4','8','\0'};
const char * const FONT[] = {
    X,
...
const char X[] = {'\x48','a','4','4','4','4','8','\0'};
const char * const FONT[] = {
    X,
...

一个更好的方法是,即使对于可打印字符,也要用十六进制表示法来写。但考虑到不同的长度,这仍然是一个混乱


在运行时从文件中加载字体,或者从文件中将其链接为二进制blob,怎么样?要使二进制数据在源代码中看起来很好,实际上并没有一种好方法。

更好的方法是,即使对于可打印字符,也要用十六进制表示法来编写。但考虑到不同的长度,这仍然是一个混乱


在运行时从文件中加载字体,或者从文件中将其链接为二进制blob,怎么样?实际上,没有一种好方法可以使二进制数据在源代码中看起来很好。

这组宏应该满足您的需要:

#define str(s) #s
#define start(px,py) str(\x##px##py)
#define arc(x,y,rx,ry,pa) str(a##x##y##rx##ry##pa)

const char * const FONT[] = {
    start(4,8) arc(4,4, 4,4, 8),
}
这利用了(也称为字符串化和串联运算符)

并产生以下预编译器输出:

const char * const FONT[] = {
    "\x48" "a44448",
}

这组宏应该执行您想要的操作:

#define str(s) #s
#define start(px,py) str(\x##px##py)
#define arc(x,y,rx,ry,pa) str(a##x##y##rx##ry##pa)

const char * const FONT[] = {
    start(4,8) arc(4,4, 4,4, 8),
}
这利用了(也称为字符串化和串联运算符)

并产生以下预编译器输出:

const char * const FONT[] = {
    "\x48" "a44448",
}

你几乎明白了原因。声明指针数组是因为有大小不同的行。所以在
const char*const FONT[]中{…
FONT
是一个
const
数组,指向
const char
s数组的指针。一个literal字符串是一个const char数组,因此它将衰减为一个指针,用于初始化
FONT
。如果首先声明一个char数组并使用它的名称,事情也会进行得很顺利,因为这里的数组指向指针

但是在C
{'\x48'、'a'、'4'、'4'、'4'、'4'、'8'、'\0'}中,
本身并不是一个数组,而只是一个只能用于初始化字符数组的初始化列表。例如:

char arr_ok[] = { '1', '2', '3', '\0' }; // correct initialization of a char[4]
char *ptr_ko = { '1', '2', '3', '\0' };  // wrong initialization of a char* (should not compile)
// Stringify the argument (without expansion)
#define STRINGIFY(x) #x

// Expand the argument and stringify the result
#define STRINGIFY_EXPANSION(x) STRINGIFY(x)

// Assumes that the arguments should not themselves be expanded
#define MAKE_HEX(x, y) \ ## x ## y

#define start(x,y) STRINGIFY_EXPANSION(MAKE_HEX(x,y))
这意味着初始化列表不是数组,不能衰减为指针


对于二维阵列,情况会有所不同:

char arr2D[][9] = { { '1', '2', '3' }, { '4', '5', '6' }, { '7', '8', '9'} };

这一行分别用'1'、'2'、'3'、'4'、'5'、'6'和'7'、'8'、'9'初始化3个子数组。但它不能用于指针数组。

你几乎知道了原因。你声明了指针数组,因为你有不同大小的行。因此在
const char*const FONT[]中{…
FONT
是一个
const
数组,指向
const char
s数组的指针。一个literal字符串是一个const char数组,因此它将衰减为一个指针,用于初始化
FONT
。如果首先声明一个char数组并使用它的名称,事情也会进行得很顺利,因为这里的数组指向指针

但是在C
{'\x48'、'a'、'4'、'4'、'4'、'4'、'8'、'\0'}中,
本身并不是一个数组,而只是一个只能用于初始化字符数组的初始化列表。例如:

char arr_ok[] = { '1', '2', '3', '\0' }; // correct initialization of a char[4]
char *ptr_ko = { '1', '2', '3', '\0' };  // wrong initialization of a char* (should not compile)
// Stringify the argument (without expansion)
#define STRINGIFY(x) #x

// Expand the argument and stringify the result
#define STRINGIFY_EXPANSION(x) STRINGIFY(x)

// Assumes that the arguments should not themselves be expanded
#define MAKE_HEX(x, y) \ ## x ## y

#define start(x,y) STRINGIFY_EXPANSION(MAKE_HEX(x,y))
这意味着初始化列表不是数组,不能衰减为指针


对于二维阵列,情况会有所不同:

char arr2D[][9] = { { '1', '2', '3' }, { '4', '5', '6' }, { '7', '8', '9'} };
此行分别使用'1','2','3','4','5','6和'7','8','9'初始化3个子数组。但它不能用于指针数组

有没有一种方法可以用更易读的方式来写这篇文章,但仍然有它 在编译时计算?例如:

#define start(x,y) //somehow create '\x<x><y>'. start(3,4) -> '\x34'
#define arc(x,y,rx,ry,a) //evaluate to {'a','<x>','<y>','<rx>','<ry>','<a>'}. arc(1,2,3,4,5) -> {'a','1','2','3','4','5'}

const char * const FONT[] = {
    start(4,8) arc(4,4, 4,4, 8) "", //somehow concatenate them
    ...
#define start(x,y) //somehow create '\x<x><y>'. start(3,4) -> '\x34'
#define arc(x,y,rx,ry,a) //evaluate to {'a','<x>','<y>','<rx>','<ry>','<a>'}. arc(1,2,3,4,5) -> {'a','1','2','3','4','5'}

const char * const FONT[] = {
    start(4,8) arc(4,4, 4,4, 8) "", //somehow concatenate them
    ...
类似地,您可以将
arc()
宏实现为

// No macro expansion wanted here, neither at this level nor before stringifying
#define arc(x,y,rx,ry,a) STRINGIFY(x ## y ## rx ## ry ## a)
(从技术上讲,这会创建一个字符串文字标记,它意味着一个空终止符,而不是您描述的未终止的
char
数组,但这正是您真正想要的。)

另外,为什么我可以使用字符串文字而不是字符数组文字:(这是 (不起作用)

但这是可行的:

const char X[] = {'\x48','a','4','4','4','4','8','\0'};
const char * const FONT[] = {
    X,
...
const char X[] = {'\x48','a','4','4','4','4','8','\0'};
const char * const FONT[] = {
    X,
...
很大程度上是因为这些不是数组文字。它们是普通的初始值设定项。初始值设定项提供用于初始化所声明对象的一系列值;当该对象是复合对象(如数组或结构)时,其初始值设定项中显示的多个值为其部分或全部成员提供初始值ur数组
FONT
的类型为
char*
,这些指针是初始值设定项提供的值。此外,它们没有更深层次的结构,因此不需要嵌套大括号

数组文字可能如下所示:

(const char[]) {'\x48','a','4','4','4','4','8','\0'}
而且,由于数组在初始化器中也会衰减为指针,就像它们在其他地方一样,因此确实可以使用数组文字来初始化指针数组:

const char * const FONT[] = {
    (const char[]) {'\x48','a','4','4','4','4','8','\0'},
    // ...
};
有没有一种方法可以用更易读的方式来写这篇文章,但仍然有它 在编译时计算?例如:

#define start(x,y) //somehow create '\x<x><y>'. start(3,4) -> '\x34'
#define arc(x,y,rx,ry,a) //evaluate to {'a','<x>','<y>','<rx>','<ry>','<a>'}. arc(1,2,3,4,5) -> {'a','1','2','3','4','5'}

const char * const FONT[] = {
    start(4,8) arc(4,4, 4,4, 8) "", //somehow concatenate them
    ...
#define start(x,y) //somehow create '\x<x><y>'. start(3,4) -> '\x34'
#define arc(x,y,rx,ry,a) //evaluate to {'a','<x>','<y>','<rx>','<ry>','<a>'}. arc(1,2,3,4,5) -> {'a','1','2','3','4','5'}

const char * const FONT[] = {
    start(4,8) arc(4,4, 4,4, 8) "", //somehow concatenate them
    ...
类似地,您可以将
arc()
宏实现为

// No macro expansion wanted here, neither at this level nor before stringifying
#define arc(x,y,rx,ry,a) STRINGIFY(x ## y ## rx ## ry ## a)
(从技术上讲,这会创建一个字符串文字标记,它意味着一个空终止符,而不是您描述的未终止的
char
数组,但这正是您真正想要的。)

另外,为什么我可以使用字符串文字而不是字符数组文字:(这是 (不起作用)

但这是可行的:

const char X[] = {'\x48','a','4','4','4','4','8','\0'};
const char * const FONT[] = {
    X,
...
const char X[] = {'\x48','a','4','4','4','4','8','\0'};
const char * const FONT[] = {
    X,
...
很大程度上是因为这些不是数组文字。它们是普通的初始值设定项。初始值设定项提供用于初始化所声明对象的一系列值;当该对象是复合对象(如数组或结构)时,其初始值设定项中显示的多个值为其部分或全部成员提供初始值ur数组
FONT
的类型为
char*
,这些指针是初始值设定项提供的值。此外,它们没有更深层次的结构,因此不需要嵌套大括号

数组文字可能如下所示:

(const char[]) {'\x48','a','4','4','4','4','8','\0'}
而且,由于数组在初始化器中也会衰减为指针,就像它们在其他地方一样,因此确实可以使用数组文字来初始化指针数组:

const char * const FONT[] = {
    (const char[]) {'\x48','a','4','4','4','4','8','\0'},
    // ...
};
(这不起作用)是因为您想要
char