Kapan menggunakan reinterpret_cast?


460

Saya sedikit bingung dengan penerapan reinterpret_castvs static_cast. Dari apa yang saya baca aturan umum adalah dengan menggunakan pemeran statis ketika jenis dapat ditafsirkan pada waktu kompilasi maka kata itu static. Ini adalah pemeran yang digunakan kompilator C ++ secara internal untuk pemeran implisit juga.

reinterpret_casts berlaku dalam dua skenario:

  • mengkonversi tipe integer ke tipe pointer dan sebaliknya
  • konversi satu tipe pointer ke yang lain. Ide umum yang saya dapatkan adalah ini tidak dapat diangkut dan harus dihindari.

Di mana saya sedikit bingung adalah salah satu penggunaan yang saya butuhkan, saya memanggil C ++ dari C dan kode C perlu berpegang pada objek C ++ jadi pada dasarnya ia memegang a void*. Para pemeran apa yang harus digunakan untuk mengkonversi antara tipe void *dan Class?

Saya telah melihat penggunaan keduanya static_castdan reinterpret_cast? Meskipun dari apa yang saya baca tampaknya staticlebih baik karena para pemain dapat terjadi pada waktu kompilasi? Meskipun dikatakan menggunakan reinterpret_castuntuk mengkonversi dari satu jenis pointer ke yang lain?


9
reinterpret_casttidak terjadi pada saat run time. Keduanya adalah pernyataan waktu kompilasi. Dari en.cppreference.com/w/cpp/language/reinterpret_cast : "Tidak seperti static_cast, tetapi seperti const_cast, ekspresi reinterpret_cast tidak dapat dikompilasi dengan instruksi CPU apa pun. Ini hanyalah arahan kompiler yang memerintahkan kompiler untuk memerintahkan urutan bit (representasi objek) ekspresi seolah-olah memiliki tipe new_type. "
Cris Luengo

@HeretoLearn, apakah mungkin untuk menambahkan potongan kode yang relevan dari file * .c dan * .cpp? Saya pikir itu bisa meningkatkan eksposisi pertanyaan.
OrenIshShalom

Jawaban:


443

Standar C ++ menjamin yang berikut:

static_casting pointer ke dan dari void*mempertahankan alamat. Yaitu di berikut ini a, bdan csemuanya menunjuk ke alamat yang sama:

int* a = new int();
void* b = static_cast<void*>(a);
int* c = static_cast<int*>(b);

reinterpret_casthanya menjamin bahwa jika Anda melemparkan pointer ke tipe yang berbeda, dan kemudian reinterpret_castkembali ke tipe yang asli , Anda mendapatkan nilai aslinya. Jadi sebagai berikut:

int* a = new int();
void* b = reinterpret_cast<void*>(a);
int* c = reinterpret_cast<int*>(b);

adan cmengandung nilai yang sama, tetapi nilai btidak ditentukan. (dalam praktiknya biasanya akan berisi alamat yang sama dengan adan c, tetapi itu tidak ditentukan dalam standar, dan itu mungkin tidak benar pada mesin dengan sistem memori yang lebih kompleks.)

Untuk casting ke dan dari void*, static_castharus lebih disukai.


18
Saya suka fakta bahwa 'b' tidak terdefinisi. Itu menghentikan Anda melakukan hal-hal konyol dengannya. Jika Anda melemparkan sesuatu ke jenis pointer lain Anda meminta masalah dan fakta bahwa Anda tidak dapat bergantung padanya membuat Anda lebih berhati-hati. Jika Anda menggunakan static_cast <> di atas apa gunanya 'b'?
Martin York

3
Saya pikir reinterpret_cast <> menjamin pola bit yang sama. (yang tidak sama dengan pointer yang valid ke tipe lain).
Martin York

37
nilai btidak ditentukan lagi dalam C ++ 11 saat menggunakan reinterpret_cast. Dan di C ++ 03 pemain int*untukvoid* dilarang untuk dilakukan dengan reinterpret_cast(walaupun kompiler tidak menerapkan itu dan itu tidak praktis, maka diubah untuk C ++ 11).
Johannes Schaub - litb

55
Ini sebenarnya tidak menjawab pertanyaan "kapan harus menggunakan reinterpret_cast".
einpoklum

6
@LokiAstari Saya pikir tidak ditentukan tidak menghentikan Anda dari melakukan hal-hal konyol. Itu hanya menghentikan Anda ketika Anda ingat itu tidak ditentukan. Perbedaan besar Secara pribadi saya tidak suka tidak ditentukan. Terlalu banyak yang harus diingat.
Helin Wang

158

Satu kasus ketika reinterpret_castdiperlukan adalah ketika berinteraksi dengan tipe data buram. Ini sering terjadi pada API vendor yang tidak dapat dikontrol oleh pemrogram. Berikut adalah contoh yang dibuat-buat di mana vendor menyediakan API untuk menyimpan dan mengambil data global sewenang-wenang:

// vendor.hpp
typedef struct _Opaque * VendorGlobalUserData;
void VendorSetUserData(VendorGlobalUserData p);
VendorGlobalUserData VendorGetUserData();

Untuk menggunakan API ini, programmer harus memasukkan data mereka ke VendorGlobalUserDatadan kembali lagi. static_casttidak akan berfungsi, seseorang harus menggunakan reinterpret_cast:

// main.cpp
#include "vendor.hpp"
#include <iostream>
using namespace std;

struct MyUserData {
    MyUserData() : m(42) {}
    int m;
};

int main() {
    MyUserData u;

        // store global data
    VendorGlobalUserData d1;
//  d1 = &u;                                          // compile error
//  d1 = static_cast<VendorGlobalUserData>(&u);       // compile error
    d1 = reinterpret_cast<VendorGlobalUserData>(&u);  // ok
    VendorSetUserData(d1);

        // do other stuff...

        // retrieve global data
    VendorGlobalUserData d2 = VendorGetUserData();
    MyUserData * p = 0;
//  p = d2;                                           // compile error
//  p = static_cast<MyUserData *>(d2);                // compile error
    p = reinterpret_cast<MyUserData *>(d2);           // ok

    if (p) { cout << p->m << endl; }
    return 0;
}

Di bawah ini adalah implementasi yang dibuat dari sampel API:

// vendor.cpp
static VendorGlobalUserData g = 0;
void VendorSetUserData(VendorGlobalUserData p) { g = p; }
VendorGlobalUserData VendorGetUserData() { return g; }

7
Ya, itu tentang satu-satunya penggunaan reinterpret_cast yang berarti yang dapat saya pikirkan.
jalf

8
Ini mungkin pertanyaan yang terlambat, tetapi mengapa API vendor tidak menggunakannya void*untuk itu?
Xeo

19
@Xeo Mereka tidak menggunakan void * karena mereka kehilangan (beberapa) pengecekan tipe pada waktu kompilasi.
jesup

4
Kasus penggunaan praktis dari tipe data "buram" adalah ketika Anda ingin mengekspos API ke C tetapi menulis implementasinya dalam C ++. ICU adalah contoh perpustakaan yang melakukan ini di beberapa tempat. Misalnya, dalam spoof checker API, Anda berurusan dengan pointer tipe USpoofChecker*, di mana USpoofCheckerstruct kosong. Namun, di bawah kap, setiap kali Anda melewati a USpoofChecker*, itu mengalami reinterpret_casttipe C ++ internal.
sffc

@ sffc mengapa tidak mengekspos tipe C struct kepada pengguna?
Gupta

101

Jawaban singkatnya: Jika Anda tidak tahu apareinterpret_cast kepanjangan dari , jangan gunakan itu. Jika Anda akan membutuhkannya di masa depan, Anda akan tahu.

Jawaban lengkap:

Mari kita pertimbangkan tipe angka dasar.

Ketika Anda mengonversi misalnya int(12)ke unsigned float (12.0f)prosesor Anda perlu menjalankan beberapa perhitungan karena kedua angka memiliki representasi bit yang berbeda. Ini adalah apastatic_cast singkatan.

Di sisi lain, ketika Anda memanggil reinterpret_castCPU tidak meminta perhitungan apa pun. Itu hanya memperlakukan satu set bit dalam memori seperti jika itu memiliki tipe lain. Jadi, ketika Anda masuk int*kefloat* dengan kata kunci ini, nilai baru (setelah pointer dereferecing) tidak ada hubungannya dengan nilai lama dalam arti matematika.

Contoh: Memang benar bahwareinterpret_casttidak portabel karena satu alasan - byte order (endianness). Tapi ini sering kali merupakan alasan terbaik untuk menggunakannya. Mari kita bayangkan contohnya: Anda harus membaca nomor biner 32bit dari file, dan Anda tahu itu adalah big endian. Kode Anda harus generik dan berfungsi dengan baik pada sistem big endian (mis. ARM) dan little endian (mis. X86). Jadi, Anda harus memeriksa urutan byte. Ini terkenal pada waktu kompilasi sehingga Anda dapat menulis constexprfungsi: Anda dapat menulis fungsi untuk mencapai ini:

/*constexpr*/ bool is_little_endian() {
  std::uint16_t x=0x0001;
  auto p = reinterpret_cast<std::uint8_t*>(&x);
  return *p != 0;
}

Penjelasan: representasi binerxdalam memori bisa0000'0000'0000'0001(besar) atau0000'0001'0000'0000(little endian). Setelah menafsirkan ulang-casting byte di bawahppointer bisa masing-masing0000'0000atau0000'0001. Jika Anda menggunakan pengecoran statis, itu akan selalu terjadi0000'0001 , tidak peduli apa pun endianness yang digunakan.

EDIT:

Pada versi pertama saya membuat contoh fungsi is_little_endianmenjadi constexpr. Ini mengkompilasi dengan baik pada gcc terbaru (8.3.0) tetapi standar mengatakan itu ilegal. Compiler dentang menolak untuk mengkompilasinya (yang benar).


1
Contoh yang bagus! Saya akan mengganti kependekan dari uint16_t dan unsigned char untuk uint8_t agar kurang jelas bagi manusia.
Jan Turo

@ JanTuroň benar, kami tidak dapat menganggap bahwa shortdibutuhkan 16 bit dalam memori. Dikoreksi.
jaskmar

1
Contohnya salah. reinterpret_cast tidak diizinkan dalam fungsi constexpr
Michael Veksler

1
Pertama-tama, kode ini ditolak oleh dentang terbaru (7.0.0) dan gcc (8.2.0). Sayangnya saya tidak menemukan batasan dalam bahasa formal. Yang bisa saya temukan adalah social.msdn.microsoft.com/Forums/vstudio/en-US/…
Michael

2
Lebih khusus lagi, en.cppreference.com/w/cpp/language/constant_expression (item 16) dengan jelas menyatakan bahwa reinterpret_cast tidak dapat digunakan dalam ekspresi konstan. Lihat juga github.com/cplusplus/draft/blob/master/papers/N3797.pdf (5,19 ekspresi konstan) halaman125-126 yang secara eksplisit mengesampingkan reinterpret_cast. Kemudian 7.1.5 Item penspesifikasi constexpr 5 (halaman 146) * Untuk fungsi constexpr non-templat ... jika tidak ada nilai argumen yang ada sehingga ... bisa menjadi subekspresi yang dievaluasi dari ekspresi konstanta inti (5.19 ), program ini cacat * *
Michael Veksler

20

Arti reinterpret_casttidak didefinisikan oleh standar C ++. Oleh karena itu, secara teori reinterpret_castdapat crash program Anda. Dalam praktiknya kompiler mencoba melakukan apa yang Anda harapkan, yaitu menafsirkan bit dari apa yang Anda lewati seolah-olah mereka adalah tipe yang Anda gunakan. Jika Anda tahu apa yang akan Anda gunakan dengan kompiler Anda reinterpret_cast dapat menggunakannya, tetapi mengatakan bahwa itu portabel akan berbohong.

Untuk kasus yang Anda gambarkan, dan hampir semua kasus di mana Anda dapat mempertimbangkan reinterpret_cast, Anda dapat menggunakan static_castatau beberapa alternatif lain sebagai gantinya. Di antara hal-hal lain standar ini mengatakan tentang apa yang dapat Anda harapkan dari static_cast(§5.2.9):

Nilai dari tipe “pointer to cv void” dapat secara eksplisit dikonversi ke pointer ke tipe objek. Nilai pointer tipe ke objek dikonversi ke "pointer ke cv void" dan kembali ke tipe pointer asli akan memiliki nilai aslinya.

Jadi untuk kasus penggunaan Anda, tampaknya cukup jelas bahwa komite standardisasi dimaksudkan untuk Anda gunakan static_cast.


5
Tidak cukup crash program Anda. Standar ini menawarkan beberapa jaminan tentang reinterpret_cast. Hanya saja tidak sebanyak yang sering diharapkan orang.
jalf

1
Tidak jika Anda menggunakannya dengan benar. Artinya, reinterpret_cast dari A ke B ke A sangat aman dan terdefinisi dengan baik. Tetapi nilai B tidak ditentukan, dan ya, jika Anda mengandalkan itu, hal-hal buruk bisa terjadi. Tapi gips itu sendiri cukup aman, asalkan Anda hanya menggunakannya sesuai standar. ;)
jalf

55
lol, saya curiga reinterpret_crash memang bisa merusak program Anda. Tetapi reinterpret_cast tidak akan. ;)
jalf

5
<irony> Saya mencobanya di kompiler saya, dan entah bagaimana, ia menolak untuk dikompilasi reinterpret_crash. Tidak mungkin bug kompiler akan menghentikan saya dari crash program reinterpreting saya. Saya akan melaporkan bug ASAP! </irony>
paercebal

18
@paercebaltemplate<class T, U> T reinterpret_crash(U a) { return *(T*)nullptr; }

12

Salah satu penggunaan reinterpret_cast adalah jika Anda ingin menerapkan operasi bitwise ke (IEEE 754) mengapung. Salah satu contohnya adalah trik Fast Inverse Square-Root:

https://en.wikipedia.org/wiki/Fast_inverse_square_root#Overview_of_the_code

Ini memperlakukan representasi biner dari float sebagai bilangan bulat, menggesernya ke kanan dan mengurangi dari konstanta, sehingga mengurangi separuh dan meniadakan eksponen. Setelah mengonversi kembali ke float, ia mengalami iterasi Newton-Raphson untuk membuat perkiraan ini lebih tepat:

float Q_rsqrt( float number )
{
    long i;
    float x2, y;
    const float threehalfs = 1.5F;

    x2 = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y;                       // evil floating point bit level hacking
    i  = 0x5f3759df - ( i >> 1 );               // what the deuce? 
    y  = * ( float * ) &i;
    y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
//  y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

    return y;
}

Ini awalnya ditulis dalam C, jadi menggunakan C casts, tetapi C ++ cast analog adalah reinterpret_cast.


1
error: invalid cast of an rvalue expression of type 'int64_t {aka long long int}' to type 'double&' reinterpret_cast<double&>((reinterpret_cast<int64_t&>(d) >> 1) + (1L << 61))- ideone.com/6S4ijc
Orwellophile

1
Standar mengatakan bahwa ini adalah perilaku yang tidak terdefinisi: en.cppreference.com/w/cpp/language/reinterpret_cast (di bawah "type aliasing")
Cris Luengo

@CrisLuengo Jika saya pengganti semua reinterpret_castdengan memcpy, apakah masih UB?
sandthorn

@ sandthorn: Ini adalah UB sesuai dengan standar, tetapi jika itu berfungsi untuk arsitektur Anda, jangan khawatir tentang hal itu. Trik ini OK, saya kira, untuk setiap kompiler untuk arsitektur Intel. Itu tidak dapat berfungsi sebagaimana dimaksud (atau bahkan crash) pada arsitektur lain - misalnya mungkin saja float dan longs disimpan dalam kompartemen memori yang terpisah (bukan karena saya tahu arsitektur seperti itu, itu hanya argumen ...) . memcpypasti akan membuatnya legal.
Cris Luengo


2
template <class outType, class inType>
outType safe_cast(inType pointer)
{
    void* temp = static_cast<void*>(pointer);
    return static_cast<outType>(temp);
}

Saya mencoba untuk menyimpulkan dan menulis gips sederhana yang aman menggunakan templat. Perhatikan bahwa solusi ini tidak menjamin untuk mengarahkan pointer pada suatu fungsi.


1
Apa? Kenapa mengganggu? Inilah yang reinterpret_castsudah tidak dalam situasi ini: ". Sebuah pointer objek dapat secara eksplisit dikonversi ke pointer objek dari tipe yang berbeda [72] Ketika prvalue v objek jenis pointer dikonversi ke objek jenis pointer‘pointer ke cv T ’, hasilnya adalah static_cast<cv T*>(static_cast<cv void*>(v)). " - N3797.
underscore_d

Adapun c++2003standar saya TIDAK dapat menemukan yang reinterpret_casttidakstatic_cast<cv T*>(static_cast<cv void*>(v))
Sasha Zezulinsky

1
OK, benar, tapi saya tidak peduli tentang versi dari 13 tahun yang lalu, dan sebagian besar coders juga tidak (jika mungkin) mereka dapat menghindarinya. Jawaban dan komentar harus benar-benar mencerminkan Standar terbaru yang tersedia kecuali dinyatakan sebaliknya ... IMHO. Lagi pula, saya kira Komite merasa perlu untuk menambahkan ini secara eksplisit setelah tahun 2003. (karena IIRC, itu sama di C ++ 11)
underscore_d

Sebelum C++03itu C++98. Banyak proyek menggunakan C ++ lama daripada portable C. Kadang-kadang Anda harus peduli tentang portabilitas. Misalnya Anda harus mendukung kode yang sama pada Solaris, AIX, HPUX, Windows. Dalam hal ketergantungan compiler dan portabilitas, ini rumit. Jadi contoh yang baik untuk memperkenalkan neraka portabilitas adalah dengan menggunakan reinterpret_castkode Anda
Sasha Zezulinsky

sekali lagi, jika seperti saya Anda senang membatasi diri hanya untuk platform yang bermain bagus dengan versi terbaru dan terbaik dari bahasa, keberatan Anda adalah titik diperdebatkan.
underscore_d

1

Pertama, Anda memiliki beberapa data dalam tipe tertentu seperti int di sini:

int x = 0x7fffffff://==nan in binary representation

Kemudian Anda ingin mengakses variabel yang sama dengan tipe lain seperti float: Anda dapat memutuskan di antaranya

float y = reinterpret_cast<float&>(x);

//this could only be used in cpp, looks like a function with template-parameters

atau

float y = *(float*)&(x);

//this could be used in c and cpp

SINGKAT: itu berarti memori yang sama digunakan sebagai tipe yang berbeda. Jadi Anda bisa mengonversi representasi biner dari float sebagai tipe int seperti di atas menjadi float. 0x80000000 adalah -0 misalnya (mantissa dan eksponen adalah nol tetapi tandanya, msb, adalah satu. Ini juga berfungsi untuk ganda dan panjang ganda.

MENGOPTIMALKAN: Saya pikir reinterpret_cast akan dioptimalkan dalam banyak kompiler, sementara c-casting dibuat oleh pointerarithmetic (nilai harus disalin ke memori, menyebabkan pointer tidak dapat menunjuk ke register cpu-register).

CATATAN: Dalam kedua kasus, Anda harus menyimpan nilai yang dicor dalam sebuah variabel sebelum dilemparkan! Makro ini dapat membantu:

#define asvar(x) ({decltype(x) __tmp__ = (x); __tmp__; })

Memang benar bahwa "itu berarti bahwa memori yang sama digunakan sebagai jenis yang berbeda" tetapi dibatasi untuk pasangan jenis tertentu. Dalam reinterpret_castformulir contoh Anda intuntuk float&perilaku tidak terdefinisi.
jaskmar

1

Salah satu alasan untuk digunakan reinterpret_castadalah ketika kelas dasar tidak memiliki vtable, tetapi kelas turunan tidak. Dalam hal ini, static_castdan reinterpret_castakan menghasilkan nilai pointer yang berbeda (ini akan menjadi kasus atipikal yang disebutkan oleh jalf di atas ). Sama seperti penafian, saya tidak menyatakan bahwa ini adalah bagian dari standar, tetapi penerapan beberapa kompiler yang tersebar luas.

Sebagai contoh, ambil kode di bawah ini:

#include <cstdio>

class A {
public:
    int i;
};

class B : public A {
public:
    virtual void func() {  }
};

int main()
{
    B b;
    const A* a = static_cast<A*>(&b);
    const A* ar = reinterpret_cast<A*>(&b);

    printf("&b = %p\n", &b);
    printf(" a = %p\n", a);
    printf("ar = %p\n", ar);
    printf("difference = %ld\n", (long int)(a - ar));

    return 0;
}

Yang menghasilkan sesuatu seperti:

& b = 0x7ffe10e68b38
a = 0x7ffe10e68b40
ar = 0x7ffe10e68b38
perbedaan = 2

Dalam semua kompiler yang saya coba (MSVC 2015 & 2017, clang 8.0.0, gcc 9.2, icc 19.0.1 - lihat godbolt untuk 3 terakhir ) hasil static_castberbeda dari yang reinterpret_castoleh 2 (4 untuk MSVC). Satu-satunya kompiler yang memperingatkan tentang perbedaannya adalah dentang, dengan:

17:16: peringatan: 'reinterpret_cast' dari kelas 'B *' ke markasnya di non-zero offset 'A *' berperilaku berbeda dari 'static_cast' [-Wreinterpret-base-class]
const A * ar = reinterpret_cast (& b) ;
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16:16: catatan: gunakan 'static_cast' untuk menyesuaikan pointer dengan benar saat menayangkan
const A * ar = reinterpret_cast (& b) ;
^ ~~~~~~~~~~~~~~
static_cast

Satu peringatan terakhir adalah bahwa jika kelas dasar tidak memiliki anggota data (misalnya int i;) maka dentang, gcc, dan icc mengembalikan alamat yang sama reinterpret_castdengan untuk static_cast, sedangkan MSVC masih tidak.


1

Berikut adalah varian dari program Avi Ginsburg yang dengan jelas menggambarkan properti yang reinterpret_castdisebutkan oleh Chris Luengo, flodin, dan cmdLP: bahwa kompiler memperlakukan lokasi memori menunjuk-ke ​​seolah-olah itu adalah objek dari tipe baru:

#include <iostream>
#include <string>
#include <iomanip>
using namespace std;

class A
{
public:
    int i;
};

class B : public A
{
public:
    virtual void f() {}
};

int main()
{
    string s;
    B b;
    b.i = 0;
    A* as = static_cast<A*>(&b);
    A* ar = reinterpret_cast<A*>(&b);
    B* c = reinterpret_cast<B*>(ar);

    cout << "as->i = " << hex << setfill('0')  << as->i << "\n";
    cout << "ar->i = " << ar->i << "\n";
    cout << "b.i   = " << b.i << "\n";
    cout << "c->i  = " << c->i << "\n";
    cout << "\n";
    cout << "&(as->i) = " << &(as->i) << "\n";
    cout << "&(ar->i) = " << &(ar->i) << "\n";
    cout << "&(b.i) = " << &(b.i) << "\n";
    cout << "&(c->i) = " << &(c->i) << "\n";
    cout << "\n";
    cout << "&b = " << &b << "\n";
    cout << "as = " << as << "\n";
    cout << "ar = " << ar << "\n";
    cout << "c  = " << c  << "\n";

    cout << "Press ENTER to exit.\n";
    getline(cin,s);
}

Yang menghasilkan output seperti ini:

as->i = 0
ar->i = 50ee64
b.i   = 0
c->i  = 0

&(as->i) = 00EFF978
&(ar->i) = 00EFF974
&(b.i) = 00EFF978
&(c->i) = 00EFF978

&b = 00EFF974
as = 00EFF978
ar = 00EFF974
c  = 00EFF974
Press ENTER to exit.

Dapat dilihat bahwa objek B dibangun dalam memori sebagai data spesifik-B pertama, diikuti oleh objek A tertanam. Yang static_castbenar mengembalikan alamat objek tertanam A, dan pointer yang dibuat oleh static_castdengan benar memberikan nilai dari bidang data. Pointer yang dihasilkan oleh reinterpret_castsuguhanb lokasi memori seolah-olah itu adalah objek A polos, dan jadi ketika pointer mencoba untuk mendapatkan bidang data itu mengembalikan beberapa data spesifik-B seolah-olah itu adalah isi bidang ini.

Salah satu penggunaan reinterpret_castadalah untuk mengkonversi pointer ke integer unsigned (ketika pointer dan integer unsigned berukuran sama):

int i; unsigned int u = reinterpret_cast<unsigned int>(&i);


-6

Jawaban cepat: gunakan static_castjika dikompilasi, jika tidak gunakan reinterpret_cast.


-16

Baca FAQ ! Memegang data C ++ di C bisa berisiko.

Dalam C ++, pointer ke objek dapat dikonversi menjadi void *tanpa gips. Tapi itu tidak benar sebaliknya. Anda perlu static_castmendapatkan kembali pointer asli.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.