在C语言中,单个缓冲区中有多个以空字符结尾的字符串。

4
需要创建一个格式为以下内容的字符串,并将其放置在单个缓冲区[1000]中。请注意,\x00是空终止符。
@/foo\x00ACTION=add\x00SUBSYSTEM=block\x00DEVPATH=/devices/platform/goldfish_mmc.0\x00MAJOR=command\x00MINOR=1\x00DEVTYPE=harder\x00PARTN=1

实际上,我需要将以下以空字符结尾的字符串打包到单个缓冲区中。

@/foo  
ACTION=add  
SUBSYSTEM=block  
DEVPATH=/devices/platform/goldfish_mmc.0  
MAJOR=command  
MINOR=1  
DEVTYPE=harder  
PARTN=1  

我该如何做到这一点?

1
char buffer[1000] = "@/foo\000ACTION=add\000SUBSYSTEM=block\000` ... etc pp." - Ctx
1
"foo\x00ACTION" 不起作用,因为在这里 \x00AC 被视为单个字符(A 和 C 也是十六进制数字),如果这让你感到困惑。 - Ctx
1
你可以使用\0代替\x00,这样就避免了\x00AC被视为宽字符的问题。事实上,\0是指定“NUL”的首选C方式。 - Ahmed Masud
1
你是如何获取这个字符串列表的?问这个问题的原因是,根据它们来自哪里,可能有更快的方法来做到这一点。 - Ahmed Masud
1
@AhmedMasud 我更喜欢使用\000,因为当你有两个字符串 "abc" "123" 时,"abc\0123" 的结果并非预期。 - Ctx
1
@Ctx 可能是最好的 :-) 因为八进制将避免任何“widechar”问题。 - Ahmed Masud
3个回答

3

您需要逐个复制每个字符串,记录上一次复制的位置,并从该位置后面开始下一个字符串的复制。

char *p = buffer;
strcpy(p, "@/foo");
p += strlen(p) + 1;
strcpy(p, "ACTION=add");
p += strlen(p) + 1;
...

3
您可以使用%c在使用sprintf函数时打印数字零,如下所示:
char *a[] = {"quick", "brown", "fox", "jumps"};
int n = 0;
char buf[100];
for (int i = 0 ; i != 4 ; i++) {
    n += sprintf(buf+n, "%s%c", a[i], 0);
}

Demo


或者稍微简单一点,n += sprintf(buf+n, "%s%c", a[i], 0); - Ctx
@Ctx 你说得对,谢谢!我不确定 printf 的返回值是否包括尾随的零,而不将其解释为空终止符。 - Sergey Kalinichenko

3

您可以使用包含显式嵌入的NUL字符的字符串来初始化缓冲区:

char buffer[1000] =
  "@/foo\0"
  "ACTION=add\0"
  "SUBSYSTEM=block\0"  
  "DEVPATH=/devices/platform/goldfish_mmc.0\0"
  "MAJOR=command\0"
  "MINOR=1\0"
  "DEVTYPE=harder\0"  
  "PARTN=1";

或者您可以使用memcpy显式地复制它:

char str[] =
  "@/foo\0"
  "ACTION=add\0"
  "SUBSYSTEM=block\0"  
  "DEVPATH=/devices/platform/goldfish_mmc.0\0"
  "MAJOR=command\0"
  "MINOR=1\0"
  "DEVTYPE=harder\0"  
  "PARTN=1";
char buffer[1000];

memcpy(buffer, str, sizeof(str));

在这里,编译器将连接相邻的字符串常量,但只有最后一个字符串会得到隐式的NUL; 所有其他字符串都有显式的NUL。此外,将像"\01"这样的字符串分解为"\0" "1"可以防止编译器将"\01"视为单个字符字符串{ 0x01, 0x00 }(带有隐式尾随NUL),而是将其视为两个字符的字符串{ 0x00, 0x31, 0x00 }(也带有隐式尾随NUL),这正是预期的结果。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接