[英]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.