编写通用函数来检测指针数组是否包含NULL

jxh*_*jxh 6 c pointers void strict-aliasing language-lawyer

我想编写一个泛型函数来检测某个任意类型的指针数组是否包含a NULL.我最初的尝试是这样的:

bool find_null (void *ptrs, size_t num_ptrs) {
    void **array = ptrs;
    size_t i;
    for (i = 0; i < num_ptrs; ++i) {
        if (array[i] == NULL) return true;
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)

有人指出,这可能会导致严格的别名冲突,因为指针数组Foo将作为指针数组进行访问void,但未列为允许在C.2011中访问对象的允许方式之一§ 6.57.

我可以重写函数来访问指针数组unsigned char *,但我不知道如何在NULL不破坏严格别名的情况下执行检查.有人可以提供有效的技术吗?

bool find_null (void *ptrs, size_t num_ptrs) {
    unsigned char *array = ptrs;
    void *p;
    size_t i;
    for (i = 0; i < num_ptrs; ++i) {
        memcpy(&p, array + i * sizeof(p), sizeof(p));
        if (p == NULL) return true;
        /*
         * Above seems to still break strict aliasing.
         * What should be done instead?
         */
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)

目标是编写一个与类型特定函数相同的泛型函数.换句话说,以下函数的泛型版本:

bool find_null_Foo (Foo *array[], size_t num_ptrs) {
    size_t i;
    for (i = 0; i < num_ptrs; ++i) {
        if (array[i] == NULL) return true;
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)

Joh*_*ger 1

您无法使用您提供的特定界面来完成此操作,但您可以通过这种有点笨拙的方式来完成此操作:

bool find_null (const void *array, size_t num_ptrs, size_t ptr_size,
        const void *null) {
    const char (*ptr_array)[ptr_size] = array;
    size_t i;
    for (i = 0; i < num_ptrs; ++i) {
        if (!memcmp(array[i], null, ptr_size)) return true;
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)

你可以这样称呼它:

struct Foo;

#define ARRAY_SIZE 53
int main(void) {
    struct Foo *my_array[ARRAY_SIZE] = { ... };
    struct Foo * const foo_null = (struct Foo *) 0;
    if (find_null(my_array, ARRAY_SIZE, sizeof(*my_array), &foo_null)) {
        puts("It contains NULL");
    } else {
        puts("It does not contain NULL");
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,假设所讨论类型的空指针只有一种表示形式,这在许多实现中都是如此,但语言并不要求这样做。

另请注意,这实际上并不是特定于查找空指针,因此实际上您可以使用它来搜索指针数组以查找任何指针值。事实上,它甚至不是特定于指针数组的——您可以使用它来搜索任何数组中的任何值,只要字节对字节相等是一个合适的匹配标准(它不适用于结构或联合体,并且可能不适用于某些其他类型)。

此外,如果这适合您,那么您可能可以设计一个包装宏,使其更容易用于一些更常见的场景。