Sự khác biệt giữa một con trỏ trỏ đến vị trí 0x0 và một con trỏ được đặt thành NULL là gì?


12

Là một con trỏ trỏ đến 0x0000 giống như một con trỏ được đặt thành NULL? Nếu giá trị NULL được xác định trong ngôn ngữ C, thì vị trí đó sẽ dịch về vị trí nào? Có phải nó giống như 0x0000. Tôi có thể tìm thêm chi tiết về các khái niệm này ở đâu?


1
Điều này đã được hỏi trên Stack Overflow - stackoverflow.com/questions/1296843/ . Tôi nghĩ rằng đó là ranh giới đối với chúng tôi, nhưng tôi sẵn sàng cung cấp cho nó lợi ích của sự nghi ngờ vào lúc này.
ChrisF

Câu trả lời:


12

Một điểm mà hầu hết các câu trả lời ở đây không giải quyết, ít nhất là không rõ ràng, đó là con trỏ null là một giá trị tồn tại trong khi thực hiện và hằng số con trỏ null là cấu trúc cú pháp tồn tại trong mã nguồn C.

Một hằng con trỏ null , là câu trả lời của Karlson khẳng định một cách chính xác, hoặc là một biểu thức hằng số nguyên với giá trị 0 (đơn giản 0là ví dụ phổ biến nhất), hoặc như một dàn diễn viên biểu thức để void*(như (void*)0).

NULLlà một macro, được định nghĩa trong <stddef.h>và một số tiêu đề tiêu chuẩn khác, mở rộng thành một định nghĩa triển khai hằng số con trỏ null . Việc mở rộng thường là 0hoặc ((void*)0)(các dấu ngoặc đơn bên ngoài là cần thiết để đáp ứng các quy tắc ngôn ngữ khác).

Vì vậy, một nghĩa đen 0, khi được sử dụng trong một ngữ cảnh đòi hỏi một biểu thức của loại con trỏ, luôn luôn ước lượng thành một null pointergiá trị con trỏ duy nhất trỏ đến không có đối tượng. Điều đó không ngụ ý bất cứ điều gì về đại diện của một con trỏ null . Con trỏ Null thường được biểu diễn dưới dạng all-bit-zero, nhưng chúng có thể được biểu diễn dưới dạng mọi thứ. Nhưng ngay cả khi một con trỏ null được biểu diễn dưới dạng 0xDEADBEEF, 0hoặc (void*)0vẫn là một con trỏ null không đổi .

Câu trả lời cho câu hỏi trên stackoverflow bao gồm điều này tốt.

Điều này ngụ ý, trong số những thứ khác, memset()hoặc calloc(), có thể đặt một vùng bộ nhớ thành all-bit-zero, sẽ không nhất thiết đặt bất kỳ con trỏ nào trong vùng đó thành con trỏ null. Họ có khả năng làm như vậy trên hầu hết các triển khai, nhưng ngôn ngữ không đảm bảo điều đó.

Tôi không biết tại sao câu hỏi này không được coi là một bản sao của câu hỏi này hoặc làm thế nào nó có chủ đề ở đây.


1
Một trong những vấn đề của tôi với thiết kế và tiến hóa của C là chữ số 0 đã tiếp tục được sử dụng như một đại diện không phản đối của một con trỏ null. Quay trở lại những ngày đầu tiên của ngôn ngữ (ví dụ trước khi xuất hiện những thứ như nguyên mẫu hàm), các con trỏ và số nguyên có thể hoán đổi cho nhau bằng cách sử dụng "0" cho một con trỏ null là đơn giản và nó sẽ "hoạt động". Tuy nhiên, khi cần phân biệt giữa số nguyên bằng 0 và con trỏ null, thì biểu diễn "0" sẽ không được dùng để thay thế cho từ khóa hoặc chuỗi toán tử.
supercat

Điều này có nghĩa là con trỏ NULL thực sự có thể trỏ đến một số vị trí khi nó được gán NULL tùy thuộc vào nền tảng? Hằng số con trỏ null có thể là một cấu trúc cú pháp nhưng chính xác thì điều gì sẽ xảy ra khi mã chạy? Giả sử cấu trúc cú pháp này đã được biên dịch trên nền tảng GNU / Linux. Giá trị con trỏ khi chúng ta gán NULL cho nó là gì? Địa chỉ này khác với địa chỉ nào khác?
Arpith

1
@Arpith: Gán NULLhoặc bất kỳ con trỏ null nào cho một đối tượng con trỏ đặt giá trị của đối tượng đó thành một con trỏ null . Ở cấp độ máy, nó cũng có thể trỏ đến một số bộ nhớ hợp lệ. Hủy bỏ hội nghị một con trỏ null có hành vi không xác định; truy cập một đoạn bộ nhớ tại địa chỉ 0x0000000là hành vi hợp lệ, theo nghĩa đen là bất cứ điều gì khác. Địa chỉ đó khác với bất kỳ địa chỉ nào khác bởi (a) so sánh bằng NULLvà (b) so sánh không bằng nhau với bất kỳ con trỏ nào với đối tượng C. Một con trỏ null là một giá trị con trỏ tùy ý được sử dụng để chỉ ra rằng nó không trỏ đến bất cứ thứ gì.
Keith Thompson

1
Ở cấp độ máy, nó có thể trỏ đến một số bộ nhớ hợp lệ, nhưng trong hầu hết các môi trường C, nó sẽ trỏ đến bộ nhớ không hợp lệ để mọi nỗ lực sử dụng con trỏ sẽ dẫn đến bẫy / lỗi / ngoại lệ phần cứng. Nó thường chỉ trên các nền tảng phần cứng đơn giản nhất --- những nền tảng không hỗ trợ quản lý bộ nhớ --- trong đó con trỏ NULL trỏ đến một vị trí bộ nhớ hợp lệ.
Solomon chậm

7

Mọi nền tảng ngoài kia đều miễn phí để định nghĩa NULL khi nó vừa ý.

Theo Tiêu chuẩn C, nếu bạn gán 0 cho một con trỏ, nó sẽ được chuyển đổi thành giá trị NULL (cho nền tảng đó.) Tuy nhiên, nếu bạn lấy một con trỏ NULL và chuyển nó thành int, không có gì đảm bảo rằng bạn sẽ nhận được 0 trên mọi nền tảng ngoài kia. Tuy nhiên, thực tế là trên hầu hết các nền tảng, nó sẽ bằng không.

Thông tin về những thứ mà bạn có thể tìm thấy trong C Language Specification . Một nguồn, sự đáng tin cậy mà tôi không thể đảm bảo, đó là: http://www.winapi.co.kr/pds/doc/ISO-C-FDIS.1999-04.pdf


2
Nếu họ chọn tách ra khỏi tiêu chuẩn, họ có thể tự do xác định lại NULL pointer constant. Theo như tôi biết thì không có trình biên dịch nào ngoài đó làm được điều đó.
Karlson

Có trình biên dịch nào ngoài đó không triển khai NULL thành 0 không? Và NULL có được đảm bảo để đánh giá sai?
ugoren

NULL được đảm bảo để đánh giá sai theo tiêu chuẩn. Tôi không biết có trình biên dịch nào (nền tảng, thực tế) không triển khai NULL là 0 hay không và tôi thực sự nghi ngờ về điều đó, nhưng tiêu chuẩn không cấm nó, vì vậy ai biết được.
Mike Nakis

Có sự nhầm lẫn giữa biểu diễn "hằng con trỏ null" trừu tượng (như được đề cập trong thông số kỹ thuật) trong bộ nhớ, có thể là do nhà sản xuất nền tảng làm hài lòng và định nghĩa của NULLmacro, phải mở rộng sang 0C ++ và 0hoặc (void *)0trong C, bởi vì đó là "hằng con trỏ null" thực sự.
Jan Hudec

Mặc dù về lý thuyết, NULL có thể được định nghĩa là bất cứ điều gì, tuy nhiên có một đảm bảo theo tiêu chuẩn rằng một hằng số int có giá trị 0 được đánh dấu cho một con trỏ sẽ dẫn đến một con trỏ null (ISO 9899: 1999 6.3.2.3/3). Macro NULL của stddef.h phải là một con trỏ null (7.17 / 3), do đó, nó sẽ rất nặng nề cho trình biên dịch không thực hiện NULL là 0 hoặc (void *) 0.

1

Nó được định nghĩa trong ngôn ngữ C bởi vì không có địa chỉ máy nào khác mà nó tương đương. Nếu có, chúng ta sẽ không cần một sự trừu tượng từ nó! Mặc dù trên hầu hết các nền tảng, NULL cuối cùng có thể được triển khai dưới dạng 0 hoặc loại khác, nhưng thật sai lầm khi cho rằng điều này là phổ biến vì vậy, nếu bạn quan tâm đến tính di động.


Đó là những tiêu chuẩn dành cho open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
Karlson

0

Theo phần Tài liệu tiêu chuẩn C6.3.2.3 :

Một biểu thức hằng số nguyên có giá trị 0 hoặc một biểu thức được tạo thành kiểu void *, được gọi là hằng số con trỏ null.55) Nếu hằng số con trỏ null được chuyển đổi thành loại con trỏ, con trỏ kết quả, được gọi là con trỏ null, là đảm bảo so sánh không bằng một con trỏ với bất kỳ đối tượng hoặc chức năng nào.

Cho đến nay tôi đã không thấy một trình biên dịch đã phá vỡ điều này.


@ PéterTörök Bạn nói đúng đó là một ông trùm. :)
Karlson

1
Có, nhưng lưu ý rằng nó không nói bất cứ điều gì về con trỏ thực sự có giá trị số là 0. Nó có thể không, mặc dù trên hầu hết các nền tảng.
Jan Hudec
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.