填充作为 C 中的参数传递的固定大小的预分配字符串
Filling a pre-allocated string of fixed size passed as an argument in C
我需要以一种干净的方式从第 3 方开发人员那里获得一个固定长度的名称,(希望)不需要在他们这边进行任何分配,并且由编译器检查得很好。
我提供这样的原型:
void getName(char name[9]);
他们会编写这样的函数:
void getName(char name[9]) {
strncat(_name, "Hello World", 8);
}
然后我(在我这边)这样称呼它:
char buf[9];
*buf = '[=12=]';
getName(buf);
doSomethingWith(buf);
它可以编译并且似乎可以工作,但我不确定它是处理此问题的最佳方法。
有什么建议吗?
编辑:为澄清起见,名称字符串用作打包二进制保存文件中的标识符。它需要恰好是 8 个 ASCII 8 位字符。
我现在想知道我是否应该只接收任何字符串并在我这边截断它。我希望编译器能提供帮助,而不是进行运行时检查。
在您的示例中,名称是静态字符串。在这种情况下,该函数可能如下所示,其中不需要额外的数据副本:
const char* getName(void)
{
return "Hello World";
}
...
const char* const pName = getName();
或者:
void getName(FUNCPTR func)
{
func("Hello World");
}
其中 void func(const char* const pName)
在您身边实施。那么你也不需要allocate/copy数据。
您的第一项工作是同意 returned 字符串的数据类型。
虽然使用 char*
很诱人,但您不应该这样做,因为 char
的类型没有被标准充分定义(可以是无符号、有符号 2 的补码或有符号 1 的补码).如果你不小心,如果你混淆了你的类型,你的程序的行为可能是不安全的。
所以你应该决定一个类型并相应地使用 #DEFINE CharType
。
那么对于函数本身,不要依赖第三方来分配内存,除非你调用他们的库来释放那块内存。您的 C 运行时可能使用与他们不同的分配系统。为了解决这个常见问题,形成了一种约定:如果您为输出缓冲区传递 NULL
,那么第 3 方函数应该 return 所需缓冲区的长度。然后您自己分配所需长度的内存,并使用显式发送的已分配缓冲区的大小再次调用该函数。在那种模式下,函数 returns 分配的字符串的长度以及填充到缓冲区中的结果。
将所有这些放在一起,一个好的原型应该是
SizeType getName(CharType* buffer, SizeType length);
其中 SizeType
再次在您和第 3 方之间达成一致。从广义上讲,这就是 Windows API 的工作原理。
我需要以一种干净的方式从第 3 方开发人员那里获得一个固定长度的名称,(希望)不需要在他们这边进行任何分配,并且由编译器检查得很好。
我提供这样的原型:
void getName(char name[9]);
他们会编写这样的函数:
void getName(char name[9]) {
strncat(_name, "Hello World", 8);
}
然后我(在我这边)这样称呼它:
char buf[9];
*buf = '[=12=]';
getName(buf);
doSomethingWith(buf);
它可以编译并且似乎可以工作,但我不确定它是处理此问题的最佳方法。
有什么建议吗?
编辑:为澄清起见,名称字符串用作打包二进制保存文件中的标识符。它需要恰好是 8 个 ASCII 8 位字符。
我现在想知道我是否应该只接收任何字符串并在我这边截断它。我希望编译器能提供帮助,而不是进行运行时检查。
在您的示例中,名称是静态字符串。在这种情况下,该函数可能如下所示,其中不需要额外的数据副本:
const char* getName(void)
{
return "Hello World";
}
...
const char* const pName = getName();
或者:
void getName(FUNCPTR func)
{
func("Hello World");
}
其中 void func(const char* const pName)
在您身边实施。那么你也不需要allocate/copy数据。
您的第一项工作是同意 returned 字符串的数据类型。
虽然使用 char*
很诱人,但您不应该这样做,因为 char
的类型没有被标准充分定义(可以是无符号、有符号 2 的补码或有符号 1 的补码).如果你不小心,如果你混淆了你的类型,你的程序的行为可能是不安全的。
所以你应该决定一个类型并相应地使用 #DEFINE CharType
。
那么对于函数本身,不要依赖第三方来分配内存,除非你调用他们的库来释放那块内存。您的 C 运行时可能使用与他们不同的分配系统。为了解决这个常见问题,形成了一种约定:如果您为输出缓冲区传递 NULL
,那么第 3 方函数应该 return 所需缓冲区的长度。然后您自己分配所需长度的内存,并使用显式发送的已分配缓冲区的大小再次调用该函数。在那种模式下,函数 returns 分配的字符串的长度以及填充到缓冲区中的结果。
将所有这些放在一起,一个好的原型应该是
SizeType getName(CharType* buffer, SizeType length);
其中 SizeType
再次在您和第 3 方之间达成一致。从广义上讲,这就是 Windows API 的工作原理。