在C中有效地“包装”常量字符串

时间:2013-02-08 04:48:51

标签: c

我目前正在用C编写一个解析器,在设计它时我需要的一件事是一个可变字符串“class”(一组函数对表示实例的不透明结构进行操作),我称之为{{ 1}}。字符串类的实例只不过是包含my_string的结构体以及一些元数据。

然而,出现了一个问题,即使用常量字符串。例如,我有几个返回char *指针的方法,但有时我想返回一个常量字符串。考虑这个人为的伪代码:

my_string *

...在某些情况下,我想要获取预构建的my_string *element_get_data(my_element *el) { if (element_has_character_data(el)) return element_get_character_data(el); /* returns a (my_string *) */ else return my_string_constant("#data"); /* ditto */ } 实例,但在其他情况下,我想只返回包含在my_string结构中的字符串“#data”。

此代码的问题在于,每次调用my_string时,它都会创建一个新的(堆分配的)my_string实例。 C常量字符串具有良好的语义,因为它们在程序的DATA部分中被静态分配,因此每次遇到常量字符串时,该字符串的地址始终相同。

因此,让几个不同的element_get_data(...)个实例都指向完全相同的my_string似乎很愚蠢。什么是重复删除这种方法的有效方法?我应该保留char *映射的哈希表吗?或者有没有办法对C常量字符串使用类似的语义?在Mac上,Core Foundation设法使用const char * -> my_string *宏执行此操作。

对我来说理想的解决方案将以某种方式制作一个像CFSTR(...)这样的宏,它在程序的DATA部分存储一个my_string_constant(...)结构,所以它也可以不变。这样的事情有可能吗?

1 个答案:

答案 0 :(得分:1)

当我写这个问题时(或者说,在我完成后几乎立即),我以GNUStep's implementation of Core Foundation's CFSTR() macro的形式找到了我的问题的答案。我的类似实现如下所示:

#define MY_STR(str) ({\
    static struct { const char *buffer; my_bool shouldFree; my_bool mutable; my_bool constant; } s = {NULL, MY_FALSE, MY_FALSE, MY_TRUE};\
    s.buffer = str;\
    (my_string *)&s;\
})

这样做的原因是因为代码块在编译期间被内联,这意味着它创建了一个相对于本地范围的静态分配的结构。因此,如果(例如)多次调用包含MY_STR("Hello, world!")的函数,则将始终返回相同的静态分配结构,从而产生我们期望的行为。

这个概念可以很容易地扩展到字符串以外的东西,允许您轻松创建自己的静态分配对象类型。整齐!