kmemdup_nul() 和 Linux 中的 kstrndup() 有什么区别?

What is the difference between kmemdup_nul() and kstrndup() in Linux?

它们是相似的功能,但它们之间的确切区别是什么? Linux 文档指出:

Note: Use kmemdup_nul() instead if the size is known exactly.

这两个函数都通过kmalloc() 分配所需的内存,然后在分配的缓冲区末尾放置一个NUL 终止符。两者之间唯一的区别是 kstrndup() 首先调用 strnlen() 来计算字符串的长度,从而计算出所需的大小,从而扫描字符串。

您可以将 kmemdup_nul() 视为 kstrndup() 的优化版本。如果您已经知道字符串的长度,则可以避免初始扫描,只需使用 kmemdup_nul() 将长度作为参数传递。这样可以节省时间,因为不需要扫描字符串,这也是您看到该注释的原因。

此外,如果字符串比max短,kstrndup()会保存space,所以如果你不知道字符串的长度,即使kmemdup_nul() 也可以,您可能想调用 kstrndup() 来潜在地保存 space.

从代码中可以清楚的看出,这两个函数唯一的区别就是对strnlen()的调用。这是源代码,来自 mm/util.c:

/**
 * kstrndup - allocate space for and copy an existing string
 * @s: the string to duplicate
 * @max: read at most @max chars from @s
 * @gfp: the GFP mask used in the kmalloc() call when allocating memory
 *
 * Note: Use kmemdup_nul() instead if the size is known exactly.
 *
 * Return: newly allocated copy of @s or %NULL in case of error
 */
char *kstrndup(const char *s, size_t max, gfp_t gfp)
{
    size_t len;
    char *buf;

    if (!s)
        return NULL;

    len = strnlen(s, max);
    buf = kmalloc_track_caller(len+1, gfp);
    if (buf) {
        memcpy(buf, s, len);
        buf[len] = '[=10=]';
    }
    return buf;
}
EXPORT_SYMBOL(kstrndup);

/**
 * kmemdup_nul - Create a NUL-terminated string from unterminated data
 * @s: The data to stringify
 * @len: The size of the data
 * @gfp: the GFP mask used in the kmalloc() call when allocating memory
 *
 * Return: newly allocated copy of @s with NUL-termination or %NULL in
 * case of error
 */
char *kmemdup_nul(const char *s, size_t len, gfp_t gfp)
{
    char *buf;

    if (!s)
        return NULL;

    buf = kmalloc_track_caller(len + 1, gfp);
    if (buf) {
        memcpy(buf, s, len);
        buf[len] = '[=10=]';
    }
    return buf;
}
EXPORT_SYMBOL(kmemdup_nul);