2013-08-14 17 views
89

Cân nhắc C++ mã sau:Làm thế nào là void * a = & pháp lý?

void* a = &a; 

Tại sao không trình biên dịch phàn nàn cho việc sử dụng một định không khai báo?

Ngoài ra, trình biên dịch xem xét biến số a là gì? Nó là một con trỏ đến một đối tượng void hoặc là nó một con trỏ đến một con trỏ void*?

+6

[Point của Tuyên bố] (http://msdn.microsoft.com/en-us/library/179x7xb9.aspx) –

+4

[Point của Tuyên bố trong C++] (http://stackoverflow.com/a/15746272/952747) – deepmax

+15

Nên đề cập đến lý do tại sao bạn muốn làm điều này - để có được một con trỏ đến đỉnh của ngăn xếp (từ đó bạn có thể fiddle với tất cả các loại của sự vật). – OrangeDog

Trả lời

95

Phạm vi khai báo biến trong C++ có thể được khá bất ngờ:

void* a =    &a; 
     ^~~~~~~~~~~~~~~~~ 
      a declared as `void*` from here on 

Do đó, &avoid** nhưng vì bất kỳ loại con trỏ là mặc nhiên chuyển đổi thành void* ...

+4

Ah và không phải UB.Mặc dù ngay từ cái nhìn đầu tiên nó có vẻ như là ... –

+0

Làm thế nào tôi có thể gán một đối tượng hữu ích cho điều này? – user2681063

+22

@ user2681063 'a = & userfulObject'? –

30

Nó tương đương với

void* a; 
a = &a; 

Do đó, a đã được công bố. Vì vậy, a nhận địa chỉ của a được viết bằng a. Vì vậy, nó là một con trỏ đến một con trỏ void. (Bạn chưa xác định bất kỳ đối tượng nào.)

+9

Về mặt kỹ thuật, bạn đã xác định một đối tượng. 'a' chính nó là một đối tượng. (Không phải tất cả các đối tượng đều có kiểu người dùng định nghĩa trong C++) – MSalters

+1

@MSalters 'đối tượng' này là gì? : D – Gusdor

+3

@Gusdor Chúng tôi chỉ có thể giả định những gì nằm ngoài khoảng trống của chân trời sự kiện. –

-1

Tốt cho con trỏ void để trỏ đến bất kỳ địa chỉ nào. Vấn đề là khi bạn dereference nó. Bạn phải bỏ nó vào kiểu mà bạn mong đợi con trỏ trỏ đến.

+0

Điều này không trả lời câu hỏi – miniBill

7

Trong void* a, a được khai báo là con trỏ không thuộc loại void mà là loại "bất kỳ" (trường hợp đặc biệt). Một địa chỉ (vị trí trong bộ nhớ) được gán cho a, như bất kỳ biến nào khác đang được khai báo, tất nhiên.

Sau đó, biểu thức &a được đánh giá để khởi tạo biến (cũng a, nhưng điều này không liên quan) vừa được khai báo. Loại &a là "con trỏ trỏ đến bất kỳ loại nào", đây là trường hợp đặc biệt của "con trỏ tới bất kỳ loại nào", hoàn toàn tương thích với loại a. Ergo, không có thông điệp trình biên dịch.

Hệ quả: không sử dụng void* nếu bạn muốn kiểm tra loại mạnh. Mọi thứ đều có thể được chuyển đổi thành nó. Chỉ ngược lại theo hướng ngược lại, ngoại trừ void* chính nó (nó sẽ là một ngoại lệ không cần thiết mà một loại không tương thích với chính nó).

Ngoài ra, AFAIR thực sự này xuất phát từ C.

Các vấn đề liên quan