简体   繁体   English

将多维数组传递给extern“C”函数为void *

[英]Pass multidimensional array to extern “C” function as void *

I have a C function in my library that works with multidimensional arrays nicely: 我的库中有一个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));

And I have a unsigned char * that I receive from a class defined in openCV. 我有一个unsigned char * ,我从openCV中定义的class中收到。 That pointer represents a bidimensional data, but it isn't, and I have to use it with pointer arithmetics ( unsigned char *img_pix = img->data + i*img->step + j; ), which I don't especially like. 该指针代表一个二维数据,但它不是,我必须使用它与指针算术( unsigned char *img_pix = img->data + i*img->step + j; ),我并不特别喜欢。

I create an array of bool of the same size of the image (this is a real array, so I can use array notation) to store the results of the function. 我创建了一个与图像大小相同的bool数组(这是一个真正的数组,因此我可以使用数组表示法)来存储函数的结果。

I could write an almost exact copy of alx_local_maxima_u8() that uses just a pointer and pointer arithmetics, but I'd like to be able to re-use it if I can. 我可以写一个几乎完全复制的alx_local_maxima_u8() ,只使用一个指针和指针算术,但我希望能够重新使用它,如果可以的话。

Is it safe to write a prototype that uses a void * in this way just to fool C++?: 以这种方式编写使用void *的原型来愚弄C ++是否安全?

extern "C"
{
[[gnu::nonnull]]
void    alx_local_maxima_u8 (ptrdiff_t rows, ptrdiff_t cols,
                             const void *arr_in,
                             void *arr_out);
}

In theory void * can hold any pointer which is what C will receive, and C will not access any data that doesn't belong to those pointers, so the only problems I see are aliasing a unsigned char * as a uint8_t *[] , and passing a void * where a uint8_t *[] is expected, which may cause all kind of linker errors. 理论上, void *可以保存任何C将接收的指针,C不会访问任何不属于这些指针的数据,所以我看到的唯一问题是将unsigned char *作为uint8_t *[]别名,并传递一个void * ,其中需要uint8_t *[] ,这可能会导致所有类型的链接器错误。 Also, I don't know if C bool and C++ bool will translate into the same thing in memory (I hope so). 另外,我不知道C bool和C ++ bool是否会在内存中转换成相同的东西(我希望如此)。

Maybe I should write a wrapper in C which receives void * and passes them to the actual function, so that I don't need to fool C++. 也许我应该在C中编写一个包装器,它接收void *并将它们传递给实际的函数,这样我就不需要欺骗C ++了。

Performance IS a concern, but I use -flto , so any wrappers will probably vanish in the linker. 性能是一个问题,但我使用-flto ,因此任何包装器都可能在链接器中消失。

I use GCC ( -std=gnu++17 ) in Linux with POSIX enabled. 我在启用了POSIX的Linux中使用GCC( -std=gnu++17 )。

The guarantee that a T[N][M] will contain NxM consecutive objects of type T impedes some otherwise-useful optimizations; T [N] [M]将包含类型T的NxM连续对象的保证阻止了一些其他有用的优化; the primary usefulness of that guarantee in pre-standard versions of C was that it allowed code to treat storage as a single-dimensional array in some contexts, but a multi-dimensional array in others. 在C的预标准版本中,该保证的主要用途是它允许代码在某些上下文中将存储视为一维数组,而在其他情况下则将多维数组视为多维数组。 Unfortunately, the Standards fails to recognize any distinction between the pointers formed by the decay of an inner array versus a pointer formed by casting an outer array to the inner-element type either directly or through void* , even though they impose limitations on the former which would impede the usefulness of the latter. 遗憾的是,标准未能认识到内部数组衰减形成的指针与通过直接或通过void*将外部数组转换为内部元素类型而形成的指针之间的任何区别,即使它们对前者施加限制这将阻碍后者的有用性。

On any typical platform, in the absence of whole-program optimization, the ABI would treat a pointer to an element of a multi-dimensional array as equivalent to a pointer to an element of a single-dimensional array with the same total number of elements, making it safe to treat the latter as the former. 在任何典型的平台上,在没有整个程序优化的情况下,ABI会将指向多维数组元素的指针视为指向具有相同总元素数的一维数组元素的指针。 ,将后者视为前者是安全的。 I don't believe there is anything in the C or C++ Standard, however, that would forbid an implementation from "optimizing" something like: 我不相信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];
}

by replacing the call to inc_element with array[0][i*5]++ , which could in turn be optimized to array[0][0]++ . 通过用array[0][i*5]++替换对inc_element的调用,然后可以将其优化为array[0][0]++ I don't think the authors of the Standard intended to invite compilers to make such "optimizations", but I don't think they thought aggressive optimizers would interpret a failure to prohibit such things as an invitation. 我不认为标准的作者打算邀请编译器进行这样的“优化”,但我认为他们并不认为积极的优化者会解释未能禁止这样的邀请。

Passing the array pointer as a const void * should not cause any problem, but be aware that bool may have a different representation in C and C++. 将数组指针作为const void *传递不应该导致任何问题,但要注意bool在C和C ++中可能有不同的表示形式。 It would be safer to use a more explicit type such as unsigned char for the array base type. 对阵列基类型使用更明确的类型(如unsigned char会更安全。

Specifying this type for the pointer would also help readability, as matrix cells could be addressed directly using p[r * cols + c] . 为指针指定此类型也有助于提高可读性,因为矩阵单元可以使用p[r * cols + c]直接寻址。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM