2010-03-24 35 views
14

Tiêu chuẩn nói rằng dereferencing con trỏ null dẫn đến hành vi không xác định. Nhưng "con trỏ rỗng" là gì? Trong mã sau đây, những gì chúng tôi gọi là "con trỏ null":Điều nào trong số này sẽ tạo ra một con trỏ rỗng?

struct X 
{ 
    static X* get() { return reinterpret_cast<X*>(1); } 
    void f() { } 
}; 

int main() 
{ 
    X* x = 0; 
    (*x).f(); // the null pointer? (1) 

    x = X::get(); 
    (*x).f(); // the null pointer? (2) 

    x = reinterpret_cast<X*>(X::get() - X::get()); 
    (*x).f(); // the null pointer? (3) 

    (*(X*)0).f(); // I think that this the only null pointer here (4) 
} 

Tôi nghĩ rằng dereferencing của con trỏ null chỉ diễn ra trong trường hợp cuối cùng. Tôi có đúng không? Có sự khác biệt giữa thời gian biên dịch null con trỏ và thời gian chạy theo C + + Standard?

+0

Đó không phải là bài tập về nhà. Tiêu chuẩn C++ nói không nhiều về dereferencing các con trỏ null. Tôi chỉ muốn biết. –

+0

Phần đầu tiên của câu trả lời của tôi ở đây nói về dereferencing null con trỏ: http://stackoverflow.com/questions/2474018/when-does-invoking-a-member-function-on-a-null-instance-result-in- undefined-behav (Tôi thích câu hỏi đó.) – GManNickG

Trả lời

12

Chỉ chữ cái đầu tiên và cuối cùng là các con trỏ rỗng. Những người khác là kết quả của reinterpret_cast và do đó hoạt động trên thực hiện xác định giá trị con trỏ. Cho dù hành vi là không xác định cho họ phụ thuộc vào việc có một đối tượng tại địa chỉ bạn đúc.

+0

Sự khác biệt giữa dereferencing con trỏ null và một số con trỏ không hợp lệ là gì? –

+0

@Johannes: chúng là các con trỏ rỗng, nhưng chúng sẽ tạo ra một kết xuất lõi? Ban đầu tôi nghĩ như vậy, nhưng sau một vài suy nghĩ tôi không chắc lắm. Xem câu trả lời của tôi ở trên. –

+2

@Scott Smith: Việc triển khai được xác định. Đặc biệt trên các nền tảng không có khái niệm về "lõi" tức là bất kỳ thứ gì ngoài UNIX. –

12

Biểu thức hằng số nguyên ước lượng bằng 0 là hợp lệ như một con trỏ rỗng, vì vậy trường hợp đầu tiên cũng là dereferencing một con trỏ rỗng.

Một con trỏ được đặt thành 0 thông qua tính toán số học không nhất thiết là một con trỏ rỗng. Trong hầu hết các triển khai, nó sẽ hoạt động giống như một con trỏ rỗng, nhưng điều này không được đảm bảo bởi tiêu chuẩn.

+1

"Chuyển đổi một biểu thức hằng số không đổi (5.19) với giá trị 0 luôn mang lại một con trỏ rỗng (4.10), nhưng chuyển đổi các biểu thức khác xảy ra có giá trị 0 không cần tạo ra con trỏ rỗng" (5.2.10/5 note 64). –

+1

@James Ahh! 0! = NULL với giá trị rất lớn là 0! – Earlz

+1

@Earlz: Nhưng 0! là 1! – GManNickG

0
X* x = 0; 
(*x).f(); // the null pointer? (1) 

Tôi nghĩ rằng đây đủ điều kiện như dereference, mặc dù f() không bao giờ thực sự sử dụng con trỏ this, và không có phương pháp ảo trong X. Phản xạ của tôi là để nói rằng đây là một vụ tai nạn, nhưng bây giờ tôi nghĩ về nó, tôi không chắc chắn như vậy.

x = X::get(); 
(*x).f(); // the null pointer? (2) 

Có thể là con trỏ không hợp lệ. không chắc chắn liệu nó có sụp đổ hay không (xem phần trên để biết lý do).

x = reinterpret_cast<X*>(X::get() - X::get()); 
(*x).f(); // the null pointer? (3) 

Biểu thức có X::get() - X::get() biên dịch không? Tôi không nghĩ rằng nó là hợp pháp để trừ một con trỏ từ một con trỏ khác như thế.

EDIT: D'oh! Tất nhiên là hợp pháp. Tôi đang nghĩ gì vậy? Rõ ràng, tôi là một maroon.

+0

Trong mối quan tâm đến việc gọi một hàm phi tĩnh trên một cá thể rỗng: Nó dẫn đến hành vi không xác định. Vì vậy, tất cả các cược được tắt, rõ ràng. Điều đó nói rằng, trong thực tế miễn là không có nhu cầu cho con trỏ 'this' (không có chức năng ảo, không có thành viên, vv), sau đó nó sẽ không sụp đổ, vì nó không bao giờ được sử dụng. – GManNickG

+0

trừ con trỏ là rất phổ biến - và nó sẽ trả về sự khác biệt giữa hai con trỏ. Tuy nhiên vì đây không phải là trong cùng một mảng thì bạn là đúng - kết quả không xác định. (nhưng nó có thể biên dịch) – pm100

+0

@Scott Smith, tôi vừa biên dịch trong GNU C++ và được thực hiện mà không có lỗi. Tại sao bạn nghĩ rằng trừ con trỏ là bất hợp pháp? Suy nghĩ đầu tiên của tôi là mã trong câu hỏi OP sẽ sụp đổ trong (2). –

7

C++ Chuẩn (2003) 4,10

4,10 Pointer chuyển đổi

1 Một con trỏ hằng null là một không thể thiếu biểu thức hằng số (5,19) rvalue kiểu integer mà đánh giá không. Một hằng số con trỏ null có thể được chuyển đổi thành kiểu con trỏ; kết quả là giá trị con trỏ null là loại đó và có thể phân biệt với mọi giá trị khác của con trỏ đến đối tượng hoặc con trỏ tới loại hàm. Hai giá trị con trỏ của cùng một loại phải là so sánh bằng nhau. Việc chuyển đổi hằng số con trỏ null là thành con trỏ thành loại đủ điều kiện cv là một chuyển đổi đơn lẻ và không phải là chuỗi chuyển đổi con trỏ theo sau là chuyển đổi bằng cấp (4.4).

5.2.10 diễn giải lại đúc

Note 64) Chuyển đổi một hằng số biểu hiện không thể thiếu (5,19) với giá trị zero luôn mang lại một con trỏ null (4.10), nhưng chuyển đổi biểu thức khác điều đó xảy ra có giá trị không cần không mang lại một con trỏ null.

1) X* x = 0; (*x).f(); Có. 0 là biểu thức hằng số không đổi và được chuyển đổi thành hằng số con trỏ null. Sau đó, hằng số con trỏ null có thể được chuyển đổi thành giá trị con trỏ null.

2) x = X::get(); không, xem ghi chú 64 trong 5.2.10

3) x = reinterpret_cast<X*>(X::get() - X::get()); không, xem ghi chú 64 trong 5.2.10

4) ((X) 0) .f() ; Vâng. 0 (biểu thức hằng số không đổi) -> hằng số con trỏ null -> giá trị con trỏ null.

+0

Đối với chú thích trong 5.2.10, cũng chú ý báo cáo lỗi trong http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#463 –

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