簡體   English   中英

將reinterpret_cast指針傳遞為void *

[英]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荷蘭國際集團原有的S1S 這很好。

現在稍微向前,我有一個函數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指針。

這是未定義的行為。 一種可能的症狀是它“工作正常”。

S1S是布局兼容的,但它們不是同一對象。 一個S1或一個S住在那個位置,而不是兩個都住。

訪問實際上不存在的對象是未定義的行為。

您想要的被稱為指針不可轉換。

這是合法的C和C ++:

struct S{
  int a; int b;
};
struct S1{
  S s;
  int c; int d;
};

現在,可以將指向S1的指針重新解釋為指向S的指針,並且ab與原始S1sasb相同。

在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM