Câu hỏi Bất kỳ ví dụ thực sự của reinterpret_cast thay đổi một giá trị con trỏ?


Theo tiêu chuẩn C ++, reinterpret_cast của một con trỏ T* với một số loại con trỏ khác Q*  có thể thay đổi hoặc không thay đổi giá trị con trỏ tùy thuộc vào việc triển khai.

Tôi rất quan tâm - nó có bất kỳ ví dụ thực sự của một thực hiện C ++ nơi đúc một con trỏ đến một số loại con trỏ khác với reinterpret_cast thay đổi con trỏ? Điều gì và tại sao lại thay đổi ở đó?


10
2017-07-21 11:38


gốc


ý của bạn là "thay đổi giá trị" con trỏ trỏ tới? - akira
@akira: không, thay đổi giá trị của con trỏ - sharptooth
bạn có ý nghĩa như: T* t = 0x13; Q* q = 0x42; t = reintrepret_cast<Q*>(q); sản lượng t != 0x42? - akira
@akire: Tôi đoán là có. Tôi không chắc chắn bản thân mình, đó là lý do tại sao tôi hỏi. Bạn có thể quan tâm đến việc đọc câu trả lời cho câu hỏi được liên kết - họ đã truyền cảm hứng cho tôi để đặt câu hỏi này. - sharptooth
vì vậy bạn không chắc chắn về những gì bạn đang yêu cầu? :) Tôi nghĩ rằng các câu trả lời đã xóa là kết quả của câu hỏi hơi không rõ ràng. vâng, câu hỏi được liên kết là thú vị. - akira


Các câu trả lời:


Lưu ý rằng khi tiêu chuẩn nói rằng nó có thể hoặc không thể làm điều gì đó, nó không có nghĩa là có bất kỳ thực hiện hiện tại nào có hành vi đó, chỉ có chúng có thể.

Cái gần nhất mà tôi có thể nghĩ đến là một kiến ​​trúc mà sự sắp xếp kiểu được yêu cầu bởi phần cứng và việc triển khai thực hiện quyết định sửa căn chỉnh nếu cần. Cái gì đó như:

aligned8 var;
aligned1 *p = reinterpret_cast<aligned1*>(&var);
aligned1 *q = p + 1; // assuming aligned 1 size is not multiple of 8
aligned8 *a = reinterpret_cast<aligned8*>(q); // [1]

Có thể có một yêu cầu cho a là một con trỏ hợp lệ, nó phải giải quyết một vị trí bộ nhớ nhiều là 8, trong khi đối số q với các yêu cầu căn chỉnh ít hơn có thể trỏ đến bất kỳ địa chỉ bộ nhớ nào.


6
2017-07-21 12:28





class A1 { int a1; };
class A2 { int a2; };

class B: public A1, public A2 { };

#define DBG(val)  cout << #val << ": " << val << endl

// test code
B b;
DBG(&b);                                           // prints 0x42

void *p_blank = &b;
DBG(p_blank);                                      // prints 0x42
A2 *p_a2 = &b; 
DBG(p_a2);                                         // prints 0x46
void *p_reinterpreted = reinterpret_cast<A2*>(&b);
DBG(p_reinterpreted);                              // prints 0x42
A2 *p_reinterpreted2 = reinterpret_cast<A2*>(&b);
DBG(p_reinterpreted2);                             // prints 0x42

A2 *p_a2 = &b có nghĩa cho tôi con trỏ tới đối tượng A2 trong đối tượng B. reinterpret_cast<A2*>(&b) có nghĩa cho tôi con trỏ đến b và coi nó như con trỏ A2. Kết quả của reinterpret_cast này có kiểu 'pointer to A2', do đó nó không tạo ra cảnh báo khi gán cho biến void * (hoặc biến A2 *).


2
2017-07-21 12:46



A2* p_a2 = &b; làm tôi ngạc nhiên... - akira
Trong ví dụ của bạn reinterpret_cast không thay đổi giá trị chút nào ... bạn đang tắt Tôi sợ. - Matthieu M.
Trong A2 *p_a2 = &b; bạn sử dụng chuyển đổi ngầm định tương đương với static_cast, không phải reinterpret_cast. - sharptooth
Có vẻ như tôi không hiểu câu hỏi một cách chính xác. Tôi hiểu rằng bạn tìm kiếm một trường hợp mà reinterpret_cast <> trả về một giá trị khác với một toán tử 'address of' trống. Tôi không tìm thấy một mệnh đề trong tiêu chuẩn C ++ cho phép reinterpret_cast <T *> khác với reinterpret_cast <F *>. - nusi
@akira: Khi bạn tạo một upcast ngầm (hoặc static_cast) đến một con trỏ cơ sở, con trỏ được trả về là địa chỉ của lớp con của cơ sở đó trong đối tượng. Khi bạn làm điều đó với căn cứ đầu tiên, các địa chỉ trùng với nhau. Nếu có nhiều thừa kế, upcasting cho tất cả nhưng cơ sở đầu tiên (giả định rằng lớp cơ sở đầu tiên không rỗng) sẽ tạo ra con trỏ được bù đắp. Trong ví dụ cụ thể này, A1 lớp học chính xác 4 byte. - David Rodríguez - dribeas


Nguồn rắc rối có khả năng nhất là trên một máy vectơ nơi các phép toán vô hướng được xác định theo các vectơ, và một con trỏ vô hướng bao gồm một con trỏ tới vectơ với một chỉ mục vào vectơ. Trong lịch sử, kiến ​​trúc Cray ban đầu giống như thế này và nó gây đau đầu. Ngày nay bạn có thể thấy thứ gì đó như thế trên GPU, nhưng tôi không thể chỉ ra thứ gì đó cụ thể trên đỉnh đầu của tôi.

Hiệu ứng có khả năng nhất là cắt ngắn khi kiểu con trỏ đích thiếu bit để chỉ định phần chỉ mục. C ++ 11 cho một cái gật đầu theo hướng này bằng cách cho phép bất kỳ kiểu con trỏ nào reinterpret_casted miễn là chúng có yêu cầu liên kết giống nhau. Các bit "zeroed" bằng cách căn chỉnh nghiêm ngặt được phép không tồn tại.

Một con trỏ đối tượng có thể được chuyển đổi một cách rõ ràng thành một con trỏ đối tượng của   một loại khác. Khi một giá trị v của loại “con trỏ đến T1” là   chuyển đổi thành loại “con trỏ đến cv T2”, kết quả là static_cast<cv T2*>(static_cast<cv void*>(v)) nếu cả T1 và T2 đều là bố cục chuẩn   các loại (3.9) và các yêu cầu căn chỉnh của T2 không chặt chẽ hơn   của T1, hoặc nếu một trong hai loại bị vô hiệu. Chuyển đổi giá trị của loại   "Con trỏ đến T1" đến loại "con trỏ đến T2" (trong đó T1 và T2 là   loại đối tượng và nơi yêu cầu căn chỉnh của T2 không   chặt chẽ hơn so với T1) và quay trở lại loại ban đầu của nó mang lại   giá trị con trỏ ban đầu. Kết quả của bất kỳ con trỏ nào khác   chuyển đổi không được chỉ định.


1
2017-11-09 04:53





Tôi không nghĩ rằng câu hỏi là có ý nghĩa khác nhau cho C + + so với C con trỏ phôi. Từ câu trả lời này Tôi chỉ trích dẫn một trong các ví dụ:

Loạt MV Eclipse từ Data General có ba định dạng con trỏ được hỗ trợ kiến ​​trúc (từ, byte và con trỏ bit), hai trong số đó được sử dụng bởi trình biên dịch C: con trỏ byte cho char*void*và con trỏ từ cho mọi thứ khác

Điều đó gợi ý một reinterpret_cast<Word_Aligned_Type*>(char*) có thể mất đi ý nghĩa của nhân vật / byte trong từ đang được chỉ ra, làm cho hoạt động không thể đảo ngược.


1
2018-03-04 07:29





Reinterpret_cast sẽ không bao giờ trả về một địa chỉ khác - cần phải sao chép địa chỉ chính xác.

Trong trường hợp thừa kế nhiều, như David Rodriguez nói, lấy địa chỉ của một trong các căn cứ có thể trả lại một địa chỉ có một khoản bù đắp cho địa chỉ của căn cứ đầu tiên. Reinterpret_cast sẽ trả về địa chỉ offset đó, nhưng nếu bạn coi nó là địa chỉ upcast, địa ngục sẽ xảy ra.

Để upcasting, static_cast có thể trả về một địa chỉ khác với địa chỉ đã cho. Nếu địa chỉ bạn có là một trong các cơ sở, và địa chỉ đó đang được bù đắp cho địa chỉ cơ sở đầu tiên, static_cast sẽ trả về một địa chỉ hợp lệ cho đối tượng upcasted, bằng với địa chỉ của base đầu tiên và do đó không bằng nhau để con trỏ được truyền.

Để làm cho nó ngắn gọn: reinterpret_cast cung cấp cho bạn cùng một địa chỉ, luôn luôn. Static_cast và dynamic_cast có thể trả về một địa chỉ khác, ví dụ: trong một số trường hợp liên quan đến đa kế thừa.

Sự khác biệt giữa static_cast và dynamic_cast là static_cast không kiểm tra xem con trỏ bạn cung cấp cho nó có phải là đối tượng phù hợp cho dàn diễn viên hay không, do đó hãy chắc chắn rằng trước khi gọi nó.


0
2017-11-09 04:01



Một câu lệnh liên quan đến "bắt buộc" phải được sao lưu bằng một nguồn. Tất cả những gì tôi thấy là bạn được phép chuyển đổi thành con trỏ của loại căn chỉnh ít liên kết chặt chẽ hơn và sau đó trở lạivà "Kết quả của bất kỳ chuyển đổi con trỏ nào khác không được chỉ định." (5.2.10 / 7) - Potatoswatter
Ừm, tôi đã bỏ lỡ hoàn toàn các vấn đề liên kết, tôi có thể thấy nó sẽ thay đổi địa chỉ như thế nào. Cảm ơn vì sự đúng đắn của bạn. - Alex