extern "C" 静态数组函数参数

joh*_*den 6 c c++ c99 c11

我想与我从 C++ 程序编写的 C 库交互。C 库是使用现代 C 编写的,并使用static数组说明符来显示数组的最小长度,或者指针不能为NULL

当我尝试编写与extern "C"使用此功能的函数接口的程序时,我收到以下消息:

错误:静态数组大小是 C99 特性,在 C++ 中不允许

不能与这个 C 库接口吗?我是否必须修改 C 库,或者是否有替代方案?

这是导致错误的示例程序:

// foo.h

#ifndef FOO_H
#define FOO_H

void foo(int i[static 1]);

#endif //FOO_H
Run Code Online (Sandbox Code Playgroud)
// foo.c
#include <stdio.h>

void foo(int i[static 1]) {
    printf("%i", i[0]);
}
Run Code Online (Sandbox Code Playgroud)
// main.cpp

extern "C"
{
    void foo(int i[static 1]);
}

int main() {
    int i[] = {1};
    foo(i);
}
Run Code Online (Sandbox Code Playgroud)

Joh*_*eau 6

extern "C"向 C++ 编译器指示不应修改函数名称。由于您链接的是外部库,因此期望外部库有一个名为foo. staticC99 和数组大小中的关键字告诉编译器“这个数组将至少是这个大小”,这可能允许编译器进行某些优化(我不知道这些可能是什么优化,但考虑到它可能会循环展开到N = 4您声明的位置void foo(int i[static 5]);如果您传递的数组不是至少这个大小,那么您可能会过得很糟糕。

直接的解决方案只是我们需要告诉 C++ 编译器:

  1. 有一个函数叫 foo
  2. 它接受int *一个参数
extern "C"
{
    void foo(int i[]);
}
Run Code Online (Sandbox Code Playgroud)

但是对于在 C++ 程序中使用它的任何人,我们都会丢失该函数必须至少为 N 大小的信息(这就是static数组大小中的关键字的含义)。除了可能通过某种类型的模板化包装函数之外,我想不出一种强制编译时检查的好方法:

#include <cstddef>

extern "C"
{
    void foo(int i[]);
}

template <std::size_t N>
void c_foo(int i[N])
{
    static_assert(N >= 5);
    foo(i);
}

int main(int argc, char** argv)
{
    int a[5] = {1, 2, 3, 4, 5};
    int b[4] = {1, 2, 3, 4};

    c_foo<5>(a); // this will be fine
    c_foo<4>(b); // this will raise a compile-time error
}


Run Code Online (Sandbox Code Playgroud)

为了更加安全,我会将您的c_foo函数的函数原型和任何“安全”extern "C"原型放在一个c_library_interface.h文件中,并将您的c_foo函数和任何“不安全”extern "C"原型的函数定义放在另一个c_library_interface_unsafe.cpp文件中。这样,只要您不在主 C++ 文件中包含不安全文件,您就应该只能static通过模板与数组大小函数进行交互,模板将进行一些大小检查。