【发布时间】:2019-07-11 17:02:43
【问题描述】:
我的库中有一个可以很好地处理多维数组的 C 函数:
void alx_local_maxima_u8 (ptrdiff_t rows, ptrdiff_t cols,
const uint8_t arr_in[static restrict rows][static cols],
bool arr_out[static restrict rows][static cols])
__attribute__((nonnull));
我有一个 unsigned char *,我从 openCV 中定义的 class 收到。该指针表示二维数据,但它不是,我必须将它与指针算术(unsigned char *img_pix = img->data + i*img->step + j;)一起使用,我不是特别喜欢。
我创建了一个与图像大小相同的bool数组(这是一个真正的数组,所以我可以使用数组表示法)来存储函数的结果。
我可以编写一个几乎完全相同的 alx_local_maxima_u8() 副本,它只使用一个指针和指针算法,但如果可以的话,我希望能够重复使用它。
以这种方式编写使用void * 的原型来欺骗C++ 是否安全?:
extern "C"
{
[[gnu::nonnull]]
void alx_local_maxima_u8 (ptrdiff_t rows, ptrdiff_t cols,
const void *arr_in,
void *arr_out);
}
理论上void * 可以保存C 将接收的任何指针,C 不会访问任何不属于这些指针的数据,所以我看到的唯一问题是将unsigned char * 别名为@ 987654331@,并传递一个void *,其中应该是uint8_t *[],这可能会导致各种链接器错误。另外,我不知道 C bool 和 C++ bool 是否会在内存中转换成相同的东西(我希望如此)。
也许我应该用 C 编写一个包装器,它接收 void * 并将它们传递给实际的函数,这样我就不需要欺骗 C++。
性能是一个问题,但我使用-flto,所以任何包装器都可能会在链接器中消失。
我在启用 POSIX 的 Linux 中使用 GCC (-std=gnu++17)。
【问题讨论】:
-
为什么不直接使用可移植的兼容定义?
-
理论上
x[m][n]和x[m*n]在任何一种语言中都是不兼容且不可互换的,即使布局相同。然而,在实践中,编译器不太可能做任何险恶的事情,因为数据来自不受其控制的模块并且它不知道其“真实”类型。因此,它必须假设您没有对类型撒谎。当然,随着编译器变得越来越智能,一切皆有可能。 -
@Mgetz 如果我在 C 中使用简单的指针(就像 openCV 编码它的 2D 图像一样),我将失去在 C 中使用数组表示法的能力,这只是一个不。如果你知道一个不会强制修改函数定义的原型,这在两种语言中都有效,并且不会依赖于 UB,请告诉我,因为我是 C++ 的新手,不要知道我能用它做什么。
-
@n.m.这就是我担心的。理论上编译器不应该知道内容,所以它不能做很多坏事,但是当我使用
-flto时,我担心链接器将能够做那些事情。并且链接器可以访问所有这些信息。 -
GNU 链接器在 GCC 中间表示上运行,称为 GIMPLE,据我所知,它与语言无关。语法类似于 C,但这没有任何意义。我认为链接器不会使用严格的 C 或 C++ 别名规则,因为并非所有语言都有这样的规则(但您最好让开发人员确定)。当然,有一天这一切都可能改变。
标签: c++ c arrays pointers strict-aliasing