在C中,代码
char *c = "Hello world!";
存储Hello world!\0
在rodata中,并c
使用指向它的指针进行初始化。除了字符串以外,我该如何做呢?
具体来说,我正在尝试定义自己的字符串类型
typedef struct {
size_t Length;
char Data[];
} PascalString;
然后想要某种宏,以便我可以说
const PascalString *c2 = PASCAL_STRING_CONSTANT("Hello world!");
并且具有相同的行为,即\x0c\0\0\0Hello world!
存储在rodata中并c2
使用指向它的指针进行初始化。
我尝试使用
#define PASCAL_STRING_CONSTANT(c_string_constant) \
&((const PascalString) { \
.Length=sizeof(c_string_constant)-1, \
.Data=(c_string_constant), \
})
正如这些 问题中所建议的那样,但是它不起作用,因为它Data
是一个灵活的数组:我得到了错误error: non-static initialization of a flexible array member
(对于gcc,clang给出了类似的错误)。
这在C中可能吗?如果是这样,PASCAL_STRING_CONSTANT
宏将是什么样?
澄清
对于C字符串,以下代码块永远不会将字符串存储在堆栈中:
#include <inttypes.h>
#include <stdio.h>
int main(void) {
const char *c = "Hello world!";
printf("test %s", c);
return 0;
}
正如我们通过查看Assembly所看到的,第5行编译为仅将指针加载到寄存器中。
我希望能够使用pascal字符串获得相同的行为,并且可以使用GNU扩展。以下代码也永远不会将pascal字符串存储在堆栈中:
#include <inttypes.h>
#include <stdio.h>
typedef struct {
size_t Length;
char Data[];
} PascalString;
#define PASCAL_STRING_CONSTANT(c_string_constant) ({\
static const PascalString _tmpstr = { \
.Length=sizeof(c_string_constant)-1, \
.Data=c_string_constant, \
}; \
&_tmpstr; \
})
int main(void) {
const PascalString *c2 = PASCAL_STRING_CONSTANT("Hello world!");
printf("test %.*s", c2->Length, c2->Data);
return 0;
}
查看其生成的程序集,第18行也只是加载了一个指针。
但是,我发现在ANSI C中执行此操作的最佳代码会生成将整个字符串复制到堆栈中的代码:
#include <inttypes.h>
#include <stdio.h>
typedef struct {
size_t Length;
char Data[];
} PascalString;
#define PASCAL_STRING_CONSTANT(initial_value) \
(const PascalString *)&(const struct { \
uint32_t Length; \
char Data[sizeof(initial_value)]; \
}){ \
.Length = sizeof(initial_value)-1, \
.Data = initial_value, \
}
int main(void) {
const PascalString *c2 = PASCAL_STRING_CONSTANT("Hello world!");
printf("test %.*s", c2->Length, c2->Data);
return 0;
}
在为此代码生成的程序集中,第19行将整个结构复制到堆栈上,然后生成一个指向它的指针。
我正在寻找生成与我的第二个示例相同的程序集的ANSI C代码,或者解释为什么ANSI C无法做到这一点。
尽管这不是标准的,但可以使用statment-expressions GNU扩展来完成。
#define PASCAL_STRING_CONSTANT(c_string_constant) ({\
static const PascalString _tmpstr = { \
.Length=sizeof(c_string_constant)-1, \
.Data=c_string_constant, \
}; \
&_tmpstr; \
})
通过扩展,您可以在一个块中包含多个语句作为表达式,该表达式通过将块括在中来求值最后一条语句的值({ ... })
。因此,我们可以将我们PascalString
的static const
值声明为一个值,然后返回指向它的指针。
为了完整起见,如果我们要修改它,我们也可以创建一个堆栈缓冲区:
#define PASCAL_STRING_STACKBUF(initial_value, capacity) \
(PascalString *)&(struct { \
uint32_t Length; \
char Data[capacity]; \
}){ \
.Length = sizeof(initial_value)-1, \
.Data = initial_value, \
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句