[英]Pass multidimensional array to extern “C” function as void *
我的库中有一个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 *
作为uint8_t *[]
别名,并传递一个void *
,其中需要uint8_t *[]
,这可能会导致所有类型的链接器错误。 另外,我不知道C bool
和C ++ bool
是否会在内存中转换成相同的东西(我希望如此)。
也许我应该在C中编写一个包装器,它接收void *
并将它们传递给实际的函数,这样我就不需要欺骗C ++了。
性能是一个问题,但我使用-flto
,因此任何包装器都可能在链接器中消失。
我在启用了POSIX的Linux中使用GCC( -std=gnu++17
)。
T [N] [M]将包含类型T的NxM连续对象的保证阻止了一些其他有用的优化; 在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];
}
通过用array[0][i*5]++
替换对inc_element
的调用,然后可以将其优化为array[0][0]++
。 我不认为标准的作者打算邀请编译器进行这样的“优化”,但我认为他们并不认为积极的优化者会解释未能禁止这样的邀请。
将数组指针作为const void *
传递不应该导致任何问题,但要注意bool
在C和C ++中可能有不同的表示形式。 对阵列基类型使用更明确的类型(如unsigned char
会更安全。
为指针指定此类型也有助于提高可读性,因为矩阵单元可以使用p[r * cols + c]
直接寻址。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.