c++ - 将多维数组作为 void * 传递给外部“C”函数
问题描述
我的库中有一个 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 *
我从class
openCV 中定义的接收到的。该指针表示二维数据,但它不是,我必须将它与指针算术 ( unsigned char *img_pix = img->data + i*img->step + j;
) 一起使用,我不是特别喜欢。
我创建了一个bool
与图像大小相同的数组(这是一个真正的数组,所以我可以使用数组表示法)来存储函数的结果。
我可以编写一个几乎完全相同的副本,alx_local_maxima_u8()
它只使用一个指针和指针算术,但如果可以的话,我希望能够重新使用它。
编写一个void *
以这种方式使用 a 的原型来愚弄 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 不会访问任何不属于这些指针的数据,所以我看到的唯一问题是将 a 别名unsigned char *
为 a ,并在预期a 的地方uint8_t *[]
传递 a可能会导致各种链接器错误。另外,我不知道 C和 C++是否会在内存中转换成相同的东西(我希望如此)。void *
uint8_t *[]
bool
bool
也许我应该用 C 编写一个包装器来接收void *
它们并将它们传递给实际的函数,这样我就不需要欺骗 C++。
性能是一个问题,但我使用-flto
,所以任何包装器都可能在链接器中消失。
我在启用 POSIX 的 Linux 中使用 GCC ( -std=gnu++17
)。
解决方案
保证 T[N][M] 将包含 NxM 类型 T 的连续对象阻碍了一些其他有用的优化;在 C 的预标准版本中,该保证的主要用途是它允许代码在某些情况下将存储视为一维数组,但在其他情况下是多维数组。不幸的是,标准未能识别由内部数组衰减形成的指针与通过直接或通过将外部数组转换为内部元素类型形成的指针之间的任何区别void*
,即使它们对前者施加了限制,这将阻碍后者的用处。
在任何典型的平台上,在没有全程序优化的情况下,ABI 会将指向多维数组元素的指针等同于指向具有相同元素总数的单维数组元素的指针,使得将后者视为前者是安全的。但是,我不相信 C 或 C++ 标准中有任何内容会禁止实现“优化”,例如:
// In first compilation unit
void inc_element(void*p, int r, int c, int stride)
{
int *ip = (int*)p;
ip[r*stride+c]++;
}
// In second compilation unit
int array[5][5];
void inc_element(void*p, int r, int c, int stride);
int test(int i)
{
if (array[1][0])
inc_element(array, i, 0, 5);
return array[1][0];
}
通过将调用替换为inc_element
,array[0][i*5]++
这又可以优化为array[0][0]++
. 我不认为该标准的作者打算邀请编译器进行此类“优化”,但我认为他们认为积极的优化器不会将未能禁止此类事情解释为邀请。
推荐阅读
- go - 如何计算包含数据的单元格
- linux - 将环境变量值导入文件 Shell 脚本
- python - 在 python 字典中查找重复次数最多的值
- azure-devops - 错误:Azure DevOps Artifact Feed 设置错误的包依赖项
- eclipse - 在 Eclipse 中,如何在默认文本编辑器中更改没有文件扩展名的纯文本文件的前景色和背景色?
- javascript - 如何在 .env 文件中分配变量?
- r - 我们可以在闪亮的情况下观察渲染表的输出吗
- python - 批量删除消息数组
- vue.js - Chart.js 中不显示注释
- postgresql - posgresql 从一列中选择两个不同的数据作为两列