[英]passing reinterpret_cast pointer as void *
在以下代碼中 -
#include <iostream>
using namespace std;
struct S1{
int a; int b; int c; int d;
};
struct S{
int a; int b;
};
int main() {
S1 obj1;
obj1.a = 1;
obj1.b = 2;
obj1.c = 3;
obj1.d = 4;
cout << obj1.a << " "
<< obj1.b << " "
<< obj1.c << " "
<< obj1.d << "\n";
// more code
auto ptr = reinterpret_cast<S *>(&obj1);
cout << ptr->a << " " << ptr->b << "\n";
// more code
// someFunc(ptr, sizeof(obj1));
}
我使用的是別的地方的結構分配值結構S1的成員,然后S
指針由reinterpret_cast
荷蘭國際集團原有的S1
到S
。 這很好。
現在稍微向前,我有一個函數someFunc(const void *ptr, int len)
,它需要一個const void *
指針和要傳遞的結構的長度。 在這種情況下,應該將S1
結構傳遞給它,並且在它內部有一些memcpy
調用來復制該結構並對該副本進行處理。 那我可以這樣做嗎? --
// more code
someFunc(ptr, sizeof(obj1));
}
意思是將reinterpret_cast
ed指針傳遞給此函數以及原始S1
結構的大小,還是我必須再次reinterpret_cast
傳遞回S1
,然后再次傳遞指針。
不必再次將reinterpret_cast
為原始類型,可以為類似S1
類似類型節省一些切換案例。 注意someFunc
可以根據傳入的size
輕松地找到類型,因為那些相似類型的大小差異很大。
結構的地址是該結構的第一個字節的地址。 即使我在標准中找不到任何引用,在C ++中(就像在C中一樣)慣用的成語是將指向POD結構的指針(或多或少的C結構)轉換為指向初始子序列的指針。該類的。 當轉換為void *
,兩者將賦予相同的值。
所以用你的符號:
someFunc(ptr, sizeof(obj1));
和
someFunc(obj1, sizeof(obj1));
是完全一樣的電話。
是,
someFunc(ptr, sizeof(obj1));
很好...但是僅僅因為obj1 實際上是S1
類型的。 我對您的評論“有點懷疑”,“為我節省了一些類似S1類型的開關箱”。
我正在將值分配給結構S1的成員,然后通過將原始S1重新解釋為S來在其他地方將它們用作結構S指針。
現在稍微向前,我有一個函數someFunc(const void * ptr,int len),它需要一個const void *指針和要傳遞的結構的長度。
那我可以這樣做嗎?
您可以。 您永遠都不會。
您的代碼中應該有這樣的API的唯一原因是,如果您沒有編寫但必須使用它,無權觸摸它所駐留的代碼,和/或沒有時間預算來包裝或重寫它(這需要一個小時左右)。
使用繼承的替代代碼(避免reinterpret_cast和整個問題):
struct S { int a, b; }; // defines common behavior between structures
// this is what base classes are for
struct S1: S { int c, d; }; // inherit S
someFunc:
auto someFunc(S& sref);
S s{1, 2};
S1 s1{1, 2, 3, 4};
someFunc(s); // works
someFuncf(s1); // also works
不必再次將reinterpret_cast轉換為原始類型,可以為類似S1的類似類型節省一些切換案例。
必須在用戶類型(您的S結構)上鍵入reinterpret_cast表示您沒有將常見行為提取到通用基類/結構中。
我正在將值分配給結構S1的成員,然后通過將原始S1重新解釋為S來在其他地方將它們用作結構S指針。
這是未定義的行為。 一種可能的症狀是它“工作正常”。
S1
和S
是布局兼容的,但它們不是同一對象。 一個S1
或一個S
住在那個位置,而不是兩個都住。
訪問實際上不存在的對象是未定義的行為。
您想要的被稱為指針不可轉換。
這是合法的C和C ++:
struct S{
int a; int b;
};
struct S1{
S s;
int c; int d;
};
現在,可以將指向S1
的指針重新解釋為指向S
的指針,並且a
和b
與原始S1
的sa
和sb
相同。
在C ++中,這也可以通過繼承來完成:
struct S1:S {
int c; int d;
};
在這兩種情況下,都存在一個S1
和一個S
對象,因此您永遠不會訪問不存在的對象。
您所做的通常會起作用; 但是在C ++標准下,它是未定義的行為。
作為一個實際問題,優化器可以假設它永遠不會發生,對S
訪問不能修改S1
的狀態,反之亦然,這可能會導致程序中異常嚴重的行為。 當您升級程序以鏈接時間優化時,可能會自發出現新的極其危險的行為。
S1 obj1 { 1,2,3,4 };
static_cast<S*>(&obj1).a=99;
std::cout << obj1.a; // can legally print out 1, or anything else really
std::cout << obj1.a; // it could now print out 99. Why? Undefined behavior
一旦有了實際的指針互轉換性,C ++標准就可以保證:
S1 obj1 { 1,2,3,4 };
auto* s = reinterpret_cast<S*>(&obj1);
void* ptr = s;
Assert( static_cast<S1*>(ptr) == &obj1 );
Assert
通過。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.