填充作为 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 的工作原理。