禁用GCC中字符串的NUL终止

禁用GCC中字符串的NUL终止,c,gcc,null-terminated,C,Gcc,Null Terminated,是否可以全局禁用GCC中以NUL结尾的字符串 我使用自己的字符串库,我完全不需要最后的NUL字符,因为它已经在结构内部存储了适当的长度 然而,如果我想附加10个字符串,这将意味着在堆栈上不必要地分配10个字节。对于宽字符串,情况更糟:对于x86,浪费了40个字节;对于x86_64,80字节 我定义了一个宏,将堆栈分配的字符串添加到我的结构中: #define AppendString(ppDest, pSource) \ AppendSubString(ppDest, (*ppDest)-&

是否可以全局禁用GCC中以NUL结尾的字符串

我使用自己的字符串库,我完全不需要最后的NUL字符,因为它已经在结构内部存储了适当的长度

然而,如果我想附加10个字符串,这将意味着在堆栈上不必要地分配10个字节。对于宽字符串,情况更糟:对于x86,浪费了40个字节;对于x86_64,80字节

我定义了一个宏,将堆栈分配的字符串添加到我的结构中:

#define AppendString(ppDest, pSource) \
  AppendSubString(ppDest, (*ppDest)->len + 1, pSource, 0, sizeof(pSource) - 1)

使用
sizeof(…)-1
效果很好,但我想知道是否可以取消NUL终止以节省几个字节?

这非常糟糕,但您可以明确指定每个字符数组常量的长度:

char my_constant[6] = "foobar";
assert(sizeof my_constant == 6);

wchar_t wide_constant[6] = L"foobar";
assert(sizeof wide_constant == 6*sizeof(wchar_t));

我知道您只处理程序中声明的字符串:

 ....
 char str1[10];
 char str2[12];
 ....
而不是使用
malloc()
和friends分配的文本缓冲区,否则
sizeof
对您没有帮助

无论如何,在最后删除\0时,我会三思而后行:您将失去与C标准库函数的兼容性


除非您要为库重写任何单个字符串函数(例如sprintf),否则您确定要这样做吗?

我记不起细节,但当我这样做时

char my_constant[5]
它可能会保留8个字节,因为有些机器无法处理字的中间部分


几乎总是最好将这类事情留给编译器,让它为您处理优化,除非有非常好的理由这样做。

事实上,这只是在您的内存非常低的情况下。否则我不建议这样做

似乎做你们正在谈论的事情最恰当的方式是:

  • 以以下形式准备一些最小的“列表”文件:
string1\u常量\u名称“str1” string2\u常量\u名称“str2” ...
  • 要构造处理文件并生成声明的实用程序,请执行以下操作:
常量字符字符串1_常量[4]=“str1”; 当然,我不建议手动执行此操作,否则在任何字符串更改后都会遇到麻烦

由于固定的自动生成数组,现在您有了两个未终止的字符串,并且每个变量都有sizeof()。这个解决方案似乎可以接受

好处是易于本地化,可以添加一些级别的检查以降低此解决方案的风险,并节省R/O数据段


缺点是需要在每个模块中包含所有此类字符串常量(包括以保持sizeof()已知)。因此,只有当链接器合并了这样的符号(有些没有)时,这才有意义。

如果没有使用标准库函数中处理字符串的任何,则可以忽略NUL终止字节

strlen()
、无
fgets()
、无
atoi()
、无
strtoul()
、无
fopen()
、无
printf()
转换说明符……

用所需的空间声明“不完全是C字符串”

struct NotQuiteCString { /* ... */ };

struct NotQuiteCString variable;
variable.data = malloc(5);
data[0] = 'H'; /* ... */ data[4] = 'o'; /* "hello" */

这些不是类似于Pascal风格的字符串或Hollerith字符串吗?我认为这只有在您确实希望字符串数据保留空值时才有用,在空值中,您实际上是在任意内存中运行,而不是“字符串”本身。

这个问题使用了错误的假设-它假设存储长度(例如,隐式地将其作为数字传递给函数)不会产生任何开销,但事实并非如此

虽然可以通过不存储0字节(或wchar)来节省空间,但大小必须存储在某个位置,并且示例提示它作为常量参数传递给某个函数,这几乎肯定会在代码中占用更多空间。如果同一字符串被多次使用,则开销是每次使用,而不是每次字符串


使用strlen来确定字符串长度而不是内联的包装器几乎肯定会节省更多空间。

空字符串该怎么办?你打算如何处理它们?我很确定80字节对你的程序来说不会是个问题。特别是在x86上。祝你好运,用自己的版本替换C中的字符串函数。以及传递以nul结尾的字符串的所有函数。以及获得足够的性能。请您再解释一下您的问题,这样您就不会因为试图在字符串开头分配两个字节来保存一个字节而受到指责了。事实上,这显然是过早的优化。即使许多语言解释器定义自己的字符串类型,但在许多情况下,它们仍然包含0字节,因为与偶数长度字段/malloc开销相比,它可以忽略不计。以Charles Babbage的名义,您为什么要这样节省空间?除非你正在处理一些你没有提到的非常奇怪的问题,否则你不需要这样做,而且你会给你自己造成比你解决的问题多得多的问题。你可以把它变成一个宏:
#define NEW_STRING(var,val)char var[sizeof(val)-1]=val,如果你自己的字符串类型被定义为
{length;pointer}
那么您最好使用length=0和pointer=NULL——访问指针无论如何都是无效的,因为没有可读取的字符。@intgr:对于您的代码,我得到了:“错误:从非宽字符串初始化的宽字符数组”@SinanÜnür:即使是空字符串也是NUL终止的。这意味着sizeof()-1按预期结果为0。在我的情况下,AppendSubString()将立即停止,并且不会添加任何内容。@Matt B:我知道这一点,但实际上它并不能解决我的问题。AppendString()宏在我的代码中的用法如下:AppendString(&string,“Hello World”);如您所见,我没有为此使用任何变量。@timn:Oops,我是 const char string1_constant[4] = "str1";
struct NotQuiteCString { /* ... */ };

struct NotQuiteCString variable;
variable.data = malloc(5);
data[0] = 'H'; /* ... */ data[4] = 'o'; /* "hello" */