Tại sao địa chỉ số 0 được sử dụng cho con trỏ null?


121

Trong C (hoặc C ++ cho vấn đề đó), con trỏ là đặc biệt nếu chúng có giá trị bằng 0: Tôi được khuyến khích đặt con trỏ về 0 sau khi giải phóng bộ nhớ của chúng, vì nó có nghĩa là giải phóng con trỏ một lần nữa không nguy hiểm; khi tôi gọi malloc, nó trả về một con trỏ có giá trị bằng không nếu nó không thể lấy cho tôi bộ nhớ; Tôi sử dụng if (p != 0)mọi lúc để đảm bảo các con trỏ đã chuyển là hợp lệ, v.v.

Nhưng vì địa chỉ bộ nhớ bắt đầu từ 0, không phải 0 chỉ là một địa chỉ hợp lệ như bất kỳ địa chỉ nào khác? Làm thế nào 0 có thể được sử dụng để xử lý con trỏ null nếu trường hợp đó xảy ra? Tại sao số âm không phải là số rỗng?


Biên tập:

Một loạt các câu trả lời hay. Tôi sẽ tóm tắt những gì đã được nói trong các câu trả lời được thể hiện như tâm trí của tôi diễn giải nó và hy vọng rằng cộng đồng sẽ sửa chữa cho tôi nếu tôi hiểu sai.

  • Giống như mọi thứ khác trong lập trình, đó là một sự trừu tượng. Chỉ là một hằng số, không thực sự liên quan đến địa chỉ 0. C ++ 0x nhấn mạnh điều này bằng cách thêm từ khóa nullptr.

  • Nó thậm chí không phải là một sự trừu tượng hóa địa chỉ, nó là hằng số được chỉ định bởi tiêu chuẩn C và trình biên dịch có thể dịch nó sang một số khác miễn là nó đảm bảo rằng nó không bao giờ bằng địa chỉ "thực" và bằng các con trỏ null khác nếu 0 không phải là giá trị tốt nhất để sử dụng cho nền tảng.

  • Trong trường hợp nó không phải là một sự trừu tượng, đó là trường hợp của những ngày đầu, địa chỉ 0 được hệ thống sử dụng và giới hạn đối với lập trình viên.

  • Tôi thừa nhận rằng đề xuất số âm của tôi hơi hoang đường. Sử dụng một số nguyên có dấu cho các địa chỉ sẽ hơi lãng phí nếu điều đó có nghĩa là ngoài con trỏ null (-1 hoặc bất kỳ), không gian giá trị được chia đều giữa các số nguyên dương tạo ra các địa chỉ hợp lệ và các số âm chỉ bị lãng phí.

  • Nếu bất kỳ số nào luôn có thể biểu diễn bằng kiểu dữ liệu, thì đó là 0. (Có lẽ cũng là 1. Tôi nghĩ về số nguyên một bit sẽ là 0 hoặc 1 nếu không có dấu, hoặc chỉ là bit có dấu nếu có dấu hoặc số nguyên hai bit sẽ là [-2, 1]. Nhưng sau đó bạn chỉ có thể chọn 0 là null và 1 là byte duy nhất có thể truy cập trong bộ nhớ.)

Vẫn có một cái gì đó chưa được giải quyết trong tâm trí của tôi. Câu hỏi Stack Overflow Con trỏ đến một địa chỉ cố định cụ thể cho tôi biết rằng ngay cả khi 0 cho con trỏ null là một sự trừu tượng, các giá trị con trỏ khác không nhất thiết phải như vậy. Điều này dẫn đến việc tôi đăng một câu hỏi Stack Overflow khác, Tôi có bao giờ muốn truy cập địa chỉ số không? .


11
Bạn có thể dễ dàng thay đổi if (p != 0)để if (p)mà là một thành ngữ phổ biến trong C và C ++, mặc dù bạn sẽ phải thoát khỏi thói quen nếu bạn mất Java.
Paul Tomblin

14
Xóa nội dung nào đó hai lần có nghĩa là mã của bạn sai. Tôi khuyên bạn không nên đặt con trỏ thành null sau khi bạn có thể gặp sự cố và khắc phục sự cố chứ không phải ngăn chặn nó. Trong mọi trường hợp, bạn mắc sai lầm khi giả sử một địa chỉ là một số nguyên. Điều này không nhất thiết phải đúng và 0 chỉ đại diện cho một số giá trị con trỏ thực tế dành riêng cho việc triển khai. "Địa chỉ phủ định" không có ý nghĩa, về mặt khái niệm.
GManNickG

6
@GMan: Thậm chí có thể là một ý tưởng hay khi đặt con trỏ đến một địa chỉ sẽ buộc phải gặp sự cố, chẳng hạn như 0xDEADBEEF.
Billy ONeal

5
Câu hỏi sẽ không bao giờ chết!

8
@Noah: Điểm được đặt thành null -> ẩn lỗi lập trình, không đặt thành null -> tìm lỗi lập trình. Tôi không biết về bạn, nhưng tôi muốn mã của mình chính xác.
GManNickG

Câu trả lời:


65

2 điểm:

  • chỉ có giá trị không đổi 0 trong mã nguồn là con trỏ null - việc triển khai trình biên dịch có thể sử dụng bất kỳ giá trị nào nó muốn hoặc cần trong mã đang chạy. Một số nền tảng có giá trị con trỏ đặc biệt 'không hợp lệ' mà việc triển khai có thể sử dụng làm con trỏ null. Câu hỏi thường gặp về C có một câu hỏi, "Nghiêm túc đấy, có bất kỳ máy thực tế nào thực sự sử dụng con trỏ nonzero null, hoặc các đại diện khác nhau cho con trỏ đến các loại khác nhau không?" , điều đó chỉ ra một số nền tảng đã sử dụng thuộc tính 0 này là con trỏ null trong nguồn C trong khi được biểu diễn khác nhau trong thời gian chạy. Tiêu chuẩn C ++ có một lưu ý làm rõ rằng việc chuyển đổi "một biểu thức hằng số tích phân với giá trị 0 luôn tạo ra một con trỏ rỗng,

  • một giá trị âm có thể được nền tảng sử dụng như một địa chỉ - tiêu chuẩn C chỉ đơn giản là phải chọn một cái gì đó để sử dụng để chỉ ra một con trỏ null và số không được chọn. Thành thật mà nói, tôi không chắc liệu các giá trị sentinel khác có được xem xét hay không.

Các yêu cầu duy nhất đối với con trỏ null là:

  • nó đảm bảo so sánh bất bình đẳng giữa một con trỏ với một đối tượng thực tế
  • bất kỳ hai con trỏ null nào sẽ so sánh bằng nhau (C ++ tinh chỉnh điều này để điều này chỉ cần giữ cho các con trỏ cùng kiểu)

12
+1 Tôi nghi ngờ 0 được chọn chỉ vì lý do lịch sử. (0 là địa chỉ bắt đầu và không hợp lệ, hầu hết thời gian.) Tất nhiên nói chung giả định như vậy không phải lúc nào cũng đúng, nhưng 0 hoạt động khá tốt.
GManNickG

8
Không gian cũng có thể là một yếu tố góp phần. Trong những ngày mà C mới được phát triển, trí nhớ đắt hơn rất nhiều so với bây giờ. Số 0 có thể được tính toán thuận tiện bằng cách sử dụng lệnh XOR hoặc không cần tải giá trị tức thời. Tùy thuộc vào kiến ​​trúc, điều này có thể tiết kiệm không gian.
Sparky

6
@GMan - Bạn nói đúng. Trên các CPU đời đầu, địa chỉ bộ nhớ số 0 là đặc biệt và có chức năng bảo vệ phần cứng chống lại quyền truy cập từ phần mềm đang chạy (trong một số trường hợp, đó là điểm bắt đầu của vectơ đặt lại và việc sửa đổi nó có thể ngăn không cho CPU đặt lại hoặc khởi động). Các lập trình viên đã sử dụng biện pháp bảo vệ phần cứng này như một hình thức phát hiện lỗi trong phần mềm của họ, cho phép logic giải mã địa chỉ của CPU kiểm tra các con trỏ chưa được khởi tạo hoặc không hợp lệ thay vì phải sử dụng lệnh CPU để thực hiện. Quy ước vẫn tồn tại cho đến ngày nay, mặc dù mục đích của địa chỉ số 0 có thể đã thay đổi.
bta

10
Trình biên dịch Minix 16 bit được sử dụng 0xFFFF cho NULL.
Joshua

3
Trong nhiều hệ thống nhúng, 0 là một địa chỉ hợp lệ. Giá trị -1 (tất cả các bit một) cũng là một địa chỉ hợp lệ. Kiểm tra cho ROM rất khó tính khi dữ liệu bắt đầu ở địa chỉ 0. :-(
Thomas Matthews

31

Trước đây, không gian địa chỉ bắt đầu từ 0 luôn là ROM, được sử dụng cho một số hệ điều hành hoặc các quy trình xử lý ngắt mức thấp, ngày nay, vì mọi thứ đều là ảo (bao gồm cả không gian địa chỉ), hệ điều hành có thể ánh xạ bất kỳ phân bổ nào đến bất kỳ địa chỉ nào, vì vậy nó có thể cụ thể KHÔNG phân bổ bất cứ thứ gì tại địa chỉ 0.


6
Đó là khá nhiều là nó. Đó là theo quy ước lịch sử và các phần bổ trợ đầu tiên được sử dụng cho các trình xử lý ngắt, do đó không sử dụng được cho các chương trình bình thường. Ngoài ra, 0 là "trống", có thể được hiểu là không có giá trị / không có con trỏ.
TomTom

15

IIRC, giá trị "con trỏ null" không được đảm bảo bằng 0. Trình biên dịch dịch 0 thành bất kỳ giá trị "null" nào phù hợp với hệ thống (trong thực tế có thể luôn luôn là 0, nhưng không nhất thiết). Bản dịch tương tự được áp dụng bất cứ khi nào bạn so sánh một con trỏ với số không. Bởi vì bạn chỉ có thể so sánh các con trỏ với nhau và với giá trị-0 đặc biệt này, nó ngăn lập trình viên biết bất cứ điều gì về biểu diễn bộ nhớ của hệ thống. Về lý do tại sao họ chọn 0 thay vì 42 hoặc somes như vậy, tôi sẽ đoán đó là vì hầu hết các lập trình viên bắt đầu đếm ở 0 :) (Ngoài ra, trên hầu hết các hệ thống, 0 là địa chỉ bộ nhớ đầu tiên và họ muốn nó thuận tiện, vì trong thực tế các bản dịch như tôi đang mô tả hiếm khi thực sự diễn ra; ngôn ngữ chỉ cho phép chúng).


5
@Justin: Bạn hiểu nhầm rồi. Hằng số 0 luôn là con trỏ null. Những gì @meador đang nói là có thể con trỏ null (được biểu thị bằng hằng số 0) không tương ứng với địa chỉ số không. Trên một số nền tảng, việc tạo một con trỏ null ( int* p = 0) có thể tạo một con trỏ chứa giá trị 0xdeadbeefhoặc bất kỳ giá trị nào khác mà nó thích. 0 là một con trỏ null, nhưng một con trỏ null không nhất thiết phải là một con trỏ tới địa chỉ zero. :)
jalf

Con trỏ NULL là một giá trị dành riêng và tùy thuộc vào trình biên dịch có thể là bất kỳ mẫu bit nào. Con trỏ NULL không có nghĩa là nó trỏ đến địa chỉ 0.
Sharjeel Aziz

3
Nhưng @Jalf, hằng số 0 không phải lúc nào cũng là con trỏ rỗng. Đó là những gì chúng tôi viết khi chúng tôi muốn trình biên dịch điền vào con trỏ null thực tế của nền tảng cho chúng tôi. Thực tế mà nói, các con trỏ null thường không tương ứng với các địa chỉ không, tuy nhiên, và tôi giải thích câu hỏi của Joel như hỏi tại sao đó là. Rốt cuộc, có một byte bộ nhớ hợp lệ tại địa chỉ đó, vậy tại sao không sử dụng địa chỉ không tồn tại của một byte không tồn tại thay vì xóa một byte hợp lệ khỏi trò chơi? (Tôi đang viết những gì tôi tưởng tượng Joel đang nghĩ, không phải là câu hỏi mà tôi đang tự hỏi bản thân.)
Rob Kennedy

@Rob: Đại loại. Tôi biết ý của bạn và bạn đúng, nhưng tôi cũng vậy :) Số nguyên không đổi 0 đại diện cho con trỏ null ở cấp mã nguồn. So sánh một con trỏ null với 0 cho kết quả đúng. Việc gán 0 cho một con trỏ sẽ đặt con trỏ đó thành null. 0 con trỏ null. Nhưng biểu diễn thực tế trong bộ nhớ của một con trỏ null có thể khác với mẫu bit 0. (Dù sao, bình luận của tôi là phản hồi cho bình luận hiện đã bị xóa của @ Justin, không phải cho câu hỏi của @ Joel. :)
jalf

@jalf @Rob Bạn cần một số điều khoản để làm rõ, tôi nghĩ. :) Từ §4.10 / 1: " Hằng số con trỏ null là một hằng số tích phân giá trị của kiểu số nguyên có giá trị bằng 0. Một hằng số con trỏ rỗng có thể được chuyển đổi thành một kiểu con trỏ; kết quả là giá trị con trỏ null của kiểu đó và có thể phân biệt được với mọi giá trị khác của con trỏ tới đối tượng hoặc con trỏ tới kiểu hàm. "
GManNickG

15

Bạn phải hiểu sai ý nghĩa của hằng số 0 trong ngữ cảnh con trỏ.

Cả trong C và trong C ++ con trỏ đều không thể "có giá trị bằng không". Con trỏ không phải là đối tượng số học. Chúng không có giá trị số như "không" hoặc "âm" hoặc bất kỳ thứ gì có tính chất đó. Vì vậy, tuyên bố của bạn về "con trỏ ... có giá trị bằng không" đơn giản là vô nghĩa.

Trong C & C ++, con trỏ có thể có giá trị con trỏ null dành riêng . Biểu diễn thực tế của giá trị con trỏ null không liên quan gì đến bất kỳ "số không" nào. Nó hoàn toàn có thể là bất cứ thứ gì thích hợp cho một nền tảng nhất định. Đúng là trên hầu hết các giá trị null-pointer của plaforms được biểu diễn vật lý bằng một giá trị địa chỉ bằng không thực tế. Tuy nhiên, nếu trên một số nền tảng, địa chỉ 0 thực sự được sử dụng cho một số mục đích (tức là bạn có thể cần tạo các đối tượng ở địa chỉ 0), giá trị con trỏ null trên nền tảng đó rất có thể sẽ khác. Ví dụ, nó có thể được biểu diễn dưới dạng 0xFFFFFFFFgiá trị địa chỉ hoặc 0xBAADBAADgiá trị địa chỉ.

Tuy nhiên, bất kể giá trị con trỏ null được thể hiện như thế nào trên một nền tảng nhất định, trong mã của bạn, bạn vẫn sẽ tiếp tục chỉ định con trỏ null theo hằng số 0. Để gán giá trị con trỏ null cho một con trỏ đã cho, bạn sẽ tiếp tục sử dụng các biểu thức như p = 0. Trình biên dịch có trách nhiệm nhận ra những gì bạn muốn và dịch nó thành biểu diễn giá trị con trỏ null thích hợp, tức là dịch nó thành mã sẽ đưa giá trị địa chỉ của 0xFFFFFFFFvào con trỏ pchẳng hạn.

Nói tóm lại, việc bạn sử dụng 0trong mã sorce để tạo ra các giá trị con trỏ null không có nghĩa là giá trị con trỏ null bằng cách nào đó được gắn với địa chỉ 0. Cái 0mà bạn sử dụng trong mã nguồn của mình chỉ là "đường cú pháp" hoàn toàn không liên quan đến địa chỉ vật lý thực tế mà giá trị con trỏ null đang "trỏ" tới.


3
<quote> Con trỏ không phải là đối tượng số học </quote> Số học con trỏ được định nghĩa khá tốt trong C và C ++. Một phần của yêu cầu là cả hai con trỏ đều trỏ trong cùng một tổ hợp. Con trỏ null không trỏ đến bất kỳ tổng hợp nào nên việc sử dụng nó trong các biểu thức số học con trỏ là bất hợp pháp. Ví dụ, nó không được đảm bảo rằng (p1 - nullptr) - (p2 - nullptr) == (p1 - p2).
Ben Voigt

5
@Ben Voigt: Đặc tả ngôn ngữ xác định khái niệm về kiểu số học . Tất cả những gì tôi đang nói là các kiểu con trỏ không thuộc về loại kiểu số học. Số học con trỏ là một câu chuyện khác và hoàn toàn không liên quan, một sự trùng hợp ngôn ngữ đơn thuần.
AnT

1
Làm thế nào ai đó đọc các đối tượng số học phải biết nó có nghĩa là "theo nghĩa của các loại số học" chứ không phải "theo nghĩa của toán tử số học" (một số trong số đó có thể sử dụng được trên con trỏ) hoặc "theo nghĩa của số học con trỏ". Đối với sự trùng hợp về ngôn ngữ, đối tượng số học có nhiều chữ cái chung với số học con trỏ hơn là các loại số học . Đồng thời, tiêu chuẩn nói về giá trị con trỏ . Áp phích ban đầu có thể có nghĩa là biểu diễn số nguyên của một con trỏ chứ không phải giá trị con trỏNULLrõ ràng không cần phải được biểu diễn bằng 0.
Ben Voigt

Ví dụ, thuật ngữ đối tượng vô hướng trong thuật ngữ C / C ++ chỉ là cách viết tắt của các đối tượng thuộc loại vô hướng (giống như đối tượng POD = đối tượng của loại POD ). Tôi đã sử dụng thuật ngữ đối tượng số học theo cùng một cách, có nghĩa là các đối tượng thuộc loại số học . Tôi mong "ai đó" hiểu nó theo cách đó. Ai đó không phải lúc nào cũng có thể yêu cầu làm rõ.
AnT

1
tôi đã làm việc trên một hệ thống nơi (như xa như phần cứng được quan tâm) null là 0xffffffff và 0 là một địa chỉ hoàn toàn hợp lệ
pm100

8

Nhưng vì địa chỉ bộ nhớ bắt đầu từ 0, không phải 0 chỉ là một địa chỉ hợp lệ như bất kỳ địa chỉ nào khác?

Trên một số / nhiều / tất cả các hệ điều hành, địa chỉ bộ nhớ 0 là đặc biệt theo một cách nào đó. Ví dụ: nó thường được ánh xạ tới bộ nhớ không hợp lệ / không tồn tại, điều này gây ra ngoại lệ nếu bạn cố gắng truy cập nó.

Tại sao số âm không phải là số rỗng?

Tôi nghĩ rằng các giá trị con trỏ thường được coi là số không có dấu: nếu không, ví dụ: con trỏ 32 bit sẽ chỉ có thể xử lý bộ nhớ 2 GB thay vì 4 GB.


4
Tôi đã viết mã trên một thiết bị có địa chỉ số 0 là địa chỉ hợp lệ và không có bảo vệ bộ nhớ. Con trỏ rỗng cũng là tất cả-bit-0; nếu bạn vô tình viết tới một con trỏ null thì bạn đã làm hỏng cài đặt hệ điều hành ở địa chỉ số không; sự vui nhộn thường không xảy ra sau đó.
MM

1
Có: trên CPU x86 không có chế độ bảo vệ, ví dụ, địa chỉ 0 là bảng vectơ ngắt .
ChrisW

@ChrisW: Trên chế độ không được bảo vệ x86, địa chỉ số không cụ thể là vectơ ngắt chia cho không, mà một số chương trình có thể có lý do hoàn toàn chính đáng để viết.
supercat

Ngay cả trên các nền tảng mà bộ nhớ có thể sử dụng sẽ bắt đầu ở địa chỉ vật lý, số không, việc triển khai C có thể dễ dàng sử dụng địa chỉ số không để giữ một đối tượng có địa chỉ không bao giờ được lấy, hoặc đơn giản là không sử dụng từ đầu tiên của bộ nhớ. Trên hầu hết các nền tảng, so sánh với không lưu một chỉ dẫn so với so sánh với bất kỳ thứ gì-khác, vì vậy thậm chí lãng phí từ lưu trữ đầu tiên sẽ rẻ hơn so với sử dụng địa chỉ khác 0 cho null. Lưu ý rằng không có yêu cầu nào rằng địa chỉ của những thứ không có trong Tiêu chuẩn C (ví dụ: cổng I / O hoặc vectơ ngắt) so sánh không bằng với null, cũng không phải ...
supercat

... trình xử lý hệ thống null-pointer truy cập bất kỳ khác với bất kỳ quy trình nào khác, vì vậy all-bits-zero nói chung là một địa chỉ tốt cho "null" ngay cả trên các hệ thống mà quyền truy cập đến vị trí vật lý bằng không sẽ hữu ích và có ý nghĩa.
supercat

5

Tôi đoán rằng giá trị ma thuật 0 được chọn để xác định một con trỏ không hợp lệ vì nó có thể được kiểm tra với ít hướng dẫn hơn. Một số ngôn ngữ máy tự động đặt cờ số không và dấu hiệu theo dữ liệu khi tải thanh ghi để bạn có thể kiểm tra con trỏ null với một lần tải đơn giản sau đó và các lệnh rẽ nhánh mà không cần thực hiện một lệnh so sánh riêng biệt.

(Tuy nhiên, hầu hết ISA chỉ đặt cờ trên các lệnh ALU chứ không phải tải. Và thường thì bạn không tạo ra con trỏ thông qua tính toán, ngoại trừ trong trình biên dịch khi phân tích cú pháp nguồn C. Nhưng ít nhất bạn không cần một hằng số chiều rộng con trỏ tùy ý để so sánh với.)

Trên Commodore Pet, Vic20 và C64 là những máy đầu tiên tôi làm việc, RAM bắt đầu ở vị trí 0 nên việc đọc và ghi bằng con trỏ null là hoàn toàn hợp lệ nếu bạn thực sự muốn.


3

Tôi nghĩ đó chỉ là một quy ước. Phải có một số giá trị để đánh dấu một con trỏ không hợp lệ.

Bạn chỉ mất một byte không gian địa chỉ, điều đó hiếm khi là một vấn đề.

Không có con trỏ tiêu cực. Con trỏ luôn không có dấu. Ngoài ra, nếu chúng có thể phủ định, quy ước của bạn có nghĩa là bạn mất một nửa không gian địa chỉ.


Lưu ý: bạn không thực sự mất không gian địa chỉ; bạn có thể có được một con trỏ đến địa chỉ 0 bằng cách thực hiện: char *p = (char *)1; --p;. Vì hành vi trên con trỏ null không được xác định theo tiêu chuẩn, hệ thống này có thể pthực sự đọc và ghi địa chỉ 0, tăng dần để cung cấp địa chỉ 1, v.v.
MM

@MattMcNabb: Việc triển khai trong đó địa chỉ 0 là địa chỉ phần cứng hợp lệ có thể xác định hoàn toàn hợp pháp hành vi char x = ((char*)0);đọc địa chỉ 0 và lưu trữ giá trị đó vào x. Mã như vậy sẽ mang lại Hành vi không xác định trên bất kỳ triển khai nào không xác định hành vi của nó, nhưng thực tế là một tiêu chuẩn cho biết một cái gì đó là Hành vi không xác định thì không có cách nào cấm việc triển khai cung cấp thông số kỹ thuật của riêng chúng cho những gì nó sẽ làm.
supercat

@supercat ITYM *(char *)0. Điều đó đúng, nhưng theo gợi ý của tôi, việc triển khai không cần xác định hành vi của *(char *)0hoặc của bất kỳ hoạt động con trỏ null nào khác.
MM

1
@MattMcNabb: Hành vi của char *p = (char*)1; --p;sẽ chỉ được xác định theo tiêu chuẩn nếu trình tự đó đã được thực hiện sau khi một con trỏ đến thứ gì đó khác với byte đầu tiên của một đối tượng đã được truyền tới một intptr_tvà kết quả của việc ép kiểu đó đã xảy ra để mang lại giá trị 1 , và trong trường hợp cụ thể đó, kết quả của --psẽ mang lại một con trỏ đến byte trước byte mà giá trị con trỏ, khi được truyền tới intptr_t, đã mang lại 1.
supercat

3

Mặc dù C sử dụng 0 để biểu diễn con trỏ null, hãy nhớ rằng giá trị của chính con trỏ có thể không phải là số không. Tuy nhiên, hầu hết các lập trình viên sẽ chỉ sử dụng các hệ thống mà trên thực tế, con trỏ null là 0.

Nhưng tại sao lại bằng không? Đó là một địa chỉ mà mọi hệ thống đều chia sẻ. Và đôi khi các địa chỉ thấp được dành riêng cho các mục đích của hệ điều hành, do đó giá trị hoạt động tốt như không giới hạn cho các chương trình ứng dụng. Việc gán giá trị nguyên một cách ngẫu nhiên cho một con trỏ có khả năng kết thúc bằng 0 như bất kỳ thứ gì khác.


3
Lý do có nhiều khả năng hơn đằng sau tất cả những điều này là: rất rẻ khi phân phối bộ nhớ được khởi tạo trước bằng 0 và thuận tiện để các giá trị trong bộ nhớ đó đại diện cho một cái gì đó có ý nghĩa như số nguyên 0, dấu phẩy động 0.0 và con trỏ null. Dữ liệu tĩnh trong C được khởi tạo thành zero / null không phải chiếm bất kỳ khoảng trống nào trong tệp thực thi và được ánh xạ tới một khối không điền khi được tải. Số không cũng có thể được đối xử đặc biệt trong ngôn ngữ máy: so sánh số 0 dễ dàng như "rẽ nhánh nếu bằng 0", v.v. MIPS thậm chí còn có một thanh ghi giả chỉ là một hằng số 0.
Kaz

2

Trước đây, bộ nhớ thấp của một ứng dụng đã bị chiếm bởi tài nguyên hệ thống. Chính trong những ngày đó, số không đã trở thành giá trị null mặc định.

Mặc dù điều này không nhất thiết đúng với các hệ thống hiện đại, nhưng vẫn là một ý tưởng tồi nếu bạn đặt giá trị con trỏ cho bất kỳ thứ gì ngoại trừ những gì cấp phát bộ nhớ đã giao cho bạn.


2

Về lập luận về việc không đặt con trỏ thành null sau khi xóa nó để sau này xóa "lỗi lộ" ...

Nếu bạn thực sự, thực sự lo lắng về điều này thì một cách tiếp cận tốt hơn, một phương pháp được đảm bảo hoạt động, là tận dụng khẳng định ():


...
assert(ptr && "You're deleting this pointer twice, look for a bug?");
delete ptr;
ptr = 0;
...

Điều này yêu cầu một số lần nhập thêm và một lần kiểm tra thêm trong quá trình gỡ lỗi các bản dựng, nhưng nó chắc chắn cung cấp cho bạn những gì bạn muốn: thông báo khi ptr bị xóa 'hai lần'. Giải pháp thay thế được đưa ra trong cuộc thảo luận bình luận, không đặt con trỏ thành null vì vậy bạn sẽ gặp sự cố, đơn giản là không đảm bảo thành công. Tệ hơn nữa, không giống như ở trên, nó có thể gây ra sự cố (hoặc tệ hơn nhiều!) Cho người dùng nếu một trong những "lỗi" này lọt vào kệ. Cuối cùng, phiên bản này cho phép bạn tiếp tục chạy chương trình để xem điều gì thực sự xảy ra.

Tôi nhận ra rằng điều này không trả lời cho câu hỏi được hỏi, nhưng tôi lo lắng rằng ai đó đọc các nhận xét có thể đi đến kết luận rằng KHÔNG đặt con trỏ về 0 nếu có thể họ được gửi đến miễn phí () hoặc xóa hai lần. Trong một vài trường hợp có thể, KHÔNG BAO GIỜ là một phương pháp hay để sử dụng Hành vi không xác định làm công cụ gỡ lỗi. Không ai từng phải truy tìm một lỗi cuối cùng gây ra bởi việc xóa một con trỏ không hợp lệ sẽ đề xuất điều này. Những loại lỗi này mất hàng giờ để tìm kiếm và gần như luôn ảnh hưởng đến chương trình theo một cách hoàn toàn bất ngờ mà khó có thể theo dõi lại vấn đề ban đầu.


2

Một lý do quan trọng tại sao nhiều hệ điều hành sử dụng tất cả các bit-không cho biểu diễn con trỏ null, là điều này có nghĩa là memset(struct_with_pointers, 0, sizeof struct_with_pointers)và tương tự sẽ đặt tất cả các con trỏ bên trong struct_with_pointersthành con trỏ null. Điều này không được đảm bảo bởi tiêu chuẩn C, nhưng rất nhiều chương trình giả định như vậy.


1

Trong một trong những máy DEC cũ (tôi nghĩ là PDP-8), bộ nhớ C runtime sẽ bảo vệ trang đầu tiên của bộ nhớ để mọi nỗ lực truy cập bộ nhớ trong khối đó sẽ gây ra một ngoại lệ được đưa ra.


PDP-8 không có trình biên dịch C. PDP-11 không có bảo vệ bộ nhớ và VAX nổi tiếng vì đã âm thầm trả lại các tham chiếu con trỏ 0 về NULL. Tôi không chắc máy này đề cập đến.
fuz

1

Việc lựa chọn giá trị sentinel là tùy ý và điều này trên thực tế đang được giải quyết bởi phiên bản tiếp theo của C ++ (được gọi không chính thức là "C ++ 0x", rất có thể sẽ được biết đến trong tương lai với tên ISO C ++ 2011) với sự ra đời của từ khóa nullptrđể đại diện cho một con trỏ có giá trị rỗng. Trong C ++, giá trị 0 có thể được sử dụng làm biểu thức khởi tạo cho bất kỳ POD nào và cho bất kỳ đối tượng nào có phương thức khởi tạo mặc định và nó có ý nghĩa đặc biệt là gán giá trị sentinel trong trường hợp khởi tạo con trỏ. Đối với lý do tại sao một giá trị âm không được chọn, các địa chỉ thường nằm trong khoảng từ 0 đến 2 N-1 cho một số giá trị N. Nói cách khác, các địa chỉ thường được coi là các giá trị không dấu. Nếu giá trị lớn nhất được sử dụng làm giá trị sentinel, thì nó sẽ phải thay đổi giữa các hệ thống tùy thuộc vào kích thước của bộ nhớ trong khi 0 luôn là một địa chỉ có thể biểu diễn. Nó cũng được sử dụng vì lý do lịch sử, vì địa chỉ bộ nhớ 0 thường không sử dụng được trong các chương trình và ngày nay hầu hết các hệ điều hành đều có các phần của hạt nhân được tải vào (các) trang dưới của bộ nhớ và các trang như vậy thường được bảo vệ theo cách mà nếu bị chạm vào (được tham chiếu) bởi một chương trình (lưu hạt nhân) sẽ gây ra lỗi.


1

Nó phải có một số giá trị. Rõ ràng là bạn không muốn dẫm lên các giá trị mà người dùng có thể muốn sử dụng một cách hợp pháp. Tôi sẽ suy đoán rằng vì thời gian chạy C cung cấp phân đoạn BSS cho dữ liệu được khởi tạo bằng 0, nó có ý nghĩa nhất định khi diễn giải số 0 là giá trị con trỏ chưa được khởi tạo.


0

Hiếm khi một hệ điều hành nào cho phép bạn ghi tới địa chỉ 0. Việc gắn những thứ dành riêng cho hệ điều hành xuống bộ nhớ thấp là điều thường thấy; cụ thể là IDT, bảng trang, v.v. (Các bảng phải nằm trong RAM và việc dán chúng ở dưới cùng sẽ dễ dàng hơn là thử và xác định vị trí trên cùng của RAM.) Và không có hệ điều hành nào phù hợp với bạn. chỉnh sửa bảng hệ thống willy-nilly.

Điều này có thể không nằm trong tâm trí của K&R khi họ tạo ra C, nhưng nó (cùng với thực tế là 0 == null khá dễ nhớ) khiến 0 trở thành một lựa chọn phổ biến.


Điều này không đúng trong chế độ được bảo vệ và trên thực tế, trên một số cấu hình Linux nhất định, bạn có thể ghi vào địa chỉ ảo 0.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

0

Giá trị 0là một giá trị đặc biệt có nhiều nghĩa khác nhau trong các biểu thức cụ thể. Trong trường hợp con trỏ, như đã được chỉ ra nhiều lần, nó được sử dụng có lẽ vì vào thời điểm đó, cách nói tiện lợi nhất là "chèn giá trị sentinel mặc định ở đây". Là một biểu thức hằng, nó không có cùng ý nghĩa với bitwise zero (tức là tất cả các bit được đặt thành 0) trong ngữ cảnh của một biểu thức con trỏ. Trong C ++, có một số kiểu không có biểu diễn bitwise 0 NULLchẳng hạn như thành viên con trỏ và con trỏ tới hàm thành viên.

Rất may, C ++ 0x có một từ khóa mới cho "biểu hiện đó có nghĩa là một con trỏ không hợp lệ biết rằng không còn đồ để Bitwise zero cho các biểu thức không thể thiếu": nullptr. Mặc dù có một số hệ thống mà bạn có thể nhắm mục tiêu bằng C ++ cho phép tham chiếu đến địa chỉ 0 mà không bị chặn, vì vậy lập trình viên hãy cẩn thận.


0

Đã có rất nhiều câu trả lời hay trong chủ đề này; Có thể có nhiều lý do khác nhau để thích giá trị 0cho con trỏ null, nhưng tôi sẽ thêm hai lý do nữa:

  • Trong C ++, không khởi tạo con trỏ sẽ đặt nó thành null.
  • Trên nhiều bộ xử lý, việc đặt giá trị bằng 0 hoặc kiểm tra giá trị bằng / không bằng 0 sẽ hiệu quả hơn bất kỳ hằng số nào khác.

0

Điều này phụ thuộc vào việc triển khai con trỏ trong C / C ++. Không có lý do cụ thể nào tại sao NULL lại tương đương trong các phép gán cho một con trỏ.


-1

Có những lý do lịch sử cho điều này, nhưng cũng có những lý do tối ưu hóa cho nó.

Thông thường hệ điều hành cung cấp một quy trình với các trang bộ nhớ được khởi tạo bằng 0. Nếu một chương trình muốn giải thích một phần của trang bộ nhớ đó là một con trỏ thì nó là 0, vì vậy, chương trình đủ dễ dàng để xác định rằng con trỏ đó là không được khởi tạo. (điều này không hoạt động tốt khi áp dụng cho các trang flash chưa được khởi tạo)

Một lý do khác là trên nhiều bộ xử lý, rất dễ dàng để kiểm tra sự tương đương của một giá trị về 0. Đôi khi việc so sánh miễn phí được thực hiện mà không cần bất kỳ hướng dẫn bổ sung nào và thường có thể được thực hiện mà không cần cung cấp giá trị 0 trong một thanh ghi khác hoặc dưới dạng một chữ trong luồng hướng dẫn để so sánh với.

Các phép so sánh giá rẻ cho hầu hết các bộ xử lý là dấu nhỏ hơn 0 và bằng 0. (dấu lớn hơn 0 và không bằng 0 được ngụ ý bởi cả hai điều này)

Vì 1 giá trị trong số tất cả các giá trị có thể cần được bảo lưu dưới dạng xấu hoặc chưa được khởi tạo nên bạn cũng có thể đặt nó trở thành giá trị có thử nghiệm rẻ nhất về mức độ tương đương với giá trị xấu. Điều này cũng đúng với các chuỗi ký tự được kết thúc bằng '\ 0'.

Nếu bạn cố gắng sử dụng lớn hơn hoặc nhỏ hơn 0 cho mục đích này thì bạn sẽ cắt giảm một nửa phạm vi địa chỉ của mình.


-2

Hằng số 0được sử dụng thay NULLvì C đã được thực hiện bởi một số hàng nghìn tỷ tiền sử của năm trước, NULL, NIL, ZIP, hoặc NADDAsẽ có tất cả có ý nghĩa nhiều hơn 0.

Nhưng vì địa chỉ bộ nhớ bắt đầu từ 0, không phải 0 chỉ là một địa chỉ hợp lệ như bất kỳ địa chỉ nào khác?

Thật. Mặc dù rất nhiều hệ điều hành không cho phép bạn ánh xạ bất kỳ thứ gì ở địa chỉ 0, ngay cả trong không gian địa chỉ ảo (mọi người nhận ra rằng C là một ngôn ngữ không an toàn và phản ánh rằng lỗi không tham chiếu con trỏ null rất phổ biến, quyết định "sửa" chúng bằng cách không cho phép không gian người dùng mã ánh xạ đến trang 0; Vì vậy, nếu bạn gọi một lệnh gọi lại nhưng con trỏ gọi lại là NULL, bạn sẽ không thực thi một số mã tùy ý).

Làm thế nào 0 có thể được sử dụng để xử lý con trỏ null nếu trường hợp đó xảy ra?

Bởi vì 0được sử dụng để so sánh với một con trỏ sẽ được thay thế bằng một số giá trị thực thi cụ thể , đó là giá trị trả về của malloc khi malloc bị lỗi.

Tại sao số âm không phải là số rỗng?

Điều này sẽ còn khó hiểu hơn.


Quan điểm của bạn về "thượng cổ", v.v. có lẽ nằm ở gốc rễ của nó, mặc dù tôi nghĩ rằng các chi tiết cụ thể là khác nhau. Các dạng sớm nhất của những gì phát triển thành C được thiết kế để chạy trên một kiến ​​trúc cụ thể, nơi intmột con trỏ không chỉ có cùng kích thước như một con trỏ - trong nhiều ngữ cảnh int, con trỏ và một con trỏ có thể được sử dụng thay thế cho nhau. Nếu một quy trình mong đợi một con trỏ và một con trỏ được truyền vào số nguyên 57, quy trình sẽ sử dụng địa chỉ có cùng mẫu bit với số 57. Trên các máy cụ thể đó, mẫu bit để biểu thị một con trỏ null là 0, do đó, chuyển một int 0 sẽ chuyển một con trỏ null.
supercat

Kể từ thời điểm đó, C đã phát triển để nó có thể được sử dụng để viết chương trình cho nhiều loại máy khác với các cách biểu diễn số và con trỏ khác nhau. Trong khi các hằng số khác 0 hiếm khi được sử dụng làm con trỏ, hằng số 0 được sử dụng rộng rãi để biểu diễn con trỏ rỗng. Để không cho phép việc sử dụng như vậy sẽ làm hỏng mã hiện có, vì vậy các trình biên dịch được mong đợi sẽ dịch một số 0 thành bất kỳ thứ gì mà việc triển khai sử dụng để biểu diễn một con trỏ null.
supercat

-4

( Vui lòng đọc đoạn này trước khi đọc bài viết.Tôi yêu cầu bất cứ ai quan tâm đến việc đọc bài đăng này nên cố gắng đọc nó một cách cẩn thận, và tất nhiên đừng phản đối nó cho đến khi bạn hiểu nó hoàn toàn, cảm ơn. )

Bây giờ nó là wiki cộng đồng, vì vậy nếu ai đó không đồng ý với bất kỳ khái niệm nào, vui lòng sửa đổi nó, với lời giải thích rõ ràng và chi tiết về những gì sai và tại sao, và nếu có thể, vui lòng trích dẫn nguồn hoặc cung cấp bằng chứng có thể được sao chép lại.

Câu trả lời

Dưới đây là một số lý do khác có thể là yếu tố cơ bản cho NULL == 0

  1. Thực tế là số 0 là sai, vì vậy người ta có thể làm trực tiếp if(!my_ptr)thay vì if(my_ptr==NULL).
  2. Thực tế là các số nguyên toàn cục chưa được khởi tạo được khởi tạo theo mặc định cho tất cả các số không và như vậy một con trỏ của tất cả các số không sẽ được coi là chưa được khởi tạo.

Ở đây tôi muốn nói một lời về các câu trả lời khác

Không phải vì đường tổng hợp

Nói rằng NULL bằng 0 vì theo cú pháp, không có ý nghĩa quá nhiều, nếu vậy tại sao không sử dụng chỉ số 0 của một mảng để giữ độ dài của nó?

Trên thực tế, C là ngôn ngữ gần giống với cách triển khai bên trong nhất, có hợp lý khi nói rằng C chọn số 0 chỉ vì đường cú pháp không? Họ muốn cung cấp từ khóa null (như nhiều ngôn ngữ khác) hơn là ánh xạ từ 0 đến NULL!

Như vậy cho đến ngày nay nó có thể chỉ là đường cú pháp, rõ ràng là ý định ban đầu của các nhà phát triển ngôn ngữ C không phải là đường cú pháp, như tôi sẽ trình bày thêm.

1) Đặc điểm kỹ thuật

Tuy nhiên, mặc dù đúng là đặc điểm kỹ thuật C nói từ hằng số 0 dưới dạng con trỏ null (phần 6.3.2.3), và cũng xác định NULL được thực thi được xác định (phần 7.19 trong đặc tả C11 và 7.17 trong đặc tả C99), Thực tế vẫn là trong cuốn sách "Ngôn ngữ lập trình C" được viết bởi những người phát minh ra C, điều sau đây được nêu trong phần 5.4:

C đảm bảo rằng số 0 không bao giờ là địa chỉ hợp lệ cho dữ liệu, vì vậy giá trị trả về bằng 0 có thể được sử dụng để báo hiệu một sự kiện bất thường, trong trường hợp này là không có khoảng trắng.

Con trỏ và số nguyên không thể hoán đổi cho nhau, Số không là ngoại lệ duy nhất: hằng số 0 có thể được gán cho một con trỏ và một con trỏ có thể được so sánh với hằng số 0. Hằng số ký hiệu NULL thường được sử dụng thay cho số 0, như một phép ghi nhớ để chỉ rõ hơn rằng đây là một giá trị đặc biệt cho một con trỏ. NULL được định nghĩa trong. Chúng tôi sẽ sử dụng NULL kể từ đó.

Như người ta có thể thấy (từ các từ "địa chỉ số không") ít nhất ý định ban đầu của các tác giả của C là địa chỉ số không, chứ không phải hằng số 0, hơn nữa từ đoạn trích này xuất hiện lý do tại sao đặc tả nói từ hằng số 0 có lẽ không phải để loại trừ một biểu thức có giá trị bằng 0, nhưng thay vào đó, bao gồm hằng số nguyên 0 để trở thành hằng số nguyên duy nhất được phép sử dụng trong ngữ cảnh con trỏ mà không cần ép kiểu.

2) Tóm tắt

Mặc dù đặc điểm kỹ thuật không nói rõ ràng rằng địa chỉ số 0 có thể được xử lý khác với hằng số 0, nhưng nó không nói rằng không, và thực tế là khi xử lý hằng số con trỏ null, nó không khẳng định nó được triển khai được định nghĩa như nó làm bởi NULL hằng số được định nghĩa , thay vào đó khẳng định nó bằng 0, cho thấy rằng có thể có sự khác biệt giữa hằng số 0 và địa chỉ số không.

(Tuy nhiên nếu đây là trường hợp, tôi chỉ tự hỏi tại sao NULL được định nghĩa bởi vì trong trường hợp này NULL cũng có thể là hằng số 0, vì trình biên dịch dù sao cũng phải chuyển đổi tất cả các hằng số 0 thành triển khai thực tế được định nghĩa NULL?)

Tuy nhiên, tôi không thấy điều này trong hành động thực tế và trong các nền tảng chung, địa chỉ không và hằng số không được xử lý giống nhau và đưa ra cùng một thông báo lỗi.

Hơn nữa, thực tế là các hệ điều hành ngày nay thực sự đang lưu trữ toàn bộ trang đầu tiên (phạm vi 0x0000 đến 0xFFFF), chỉ để ngăn truy cập vào địa chỉ 0 do con trỏ NULL của C, (xem http://en.wikipedia.org/wiki/ Zero_page , cũng như "Windows Via C / C ++ của Jeffrey Richter và Christophe Nasarre (được xuất bản bởi Microsoft Press)").

Vì vậy, tôi sẽ yêu cầu bất kỳ ai tuyên bố rằng thực sự đã thấy nó hoạt động, vui lòng chỉ định nền tảng và trình biên dịch, và mã chính xác mà anh ta đã thực sự làm, (mặc dù do định nghĩa mơ hồ trong đặc tả [như tôi đã trình bày] bất kỳ trình biên dịch nào và nền tảng được tự do làm bất cứ điều gì anh ta muốn).

Tuy nhiên, có vẻ như các tác giả của C đã không nghĩ đến điều này, và họ đang nói về "địa chỉ không", và "C đảm bảo rằng nó không bao giờ là một địa chỉ hợp lệ", cũng như "NULL chỉ là một ghi nhớ ", cho thấy rõ ràng rằng ý định ban đầu của nó không phải dành cho" đường cú pháp ".

Không phải do hệ điều hành

Cũng tuyên bố rằng hệ điều hành từ chối quyền truy cập vào địa chỉ 0, vì một số lý do:

1) Khi C được viết, không có hạn chế nào như vậy, như người ta có thể thấy trên wikipage này http://en.wikipedia.org/wiki/Zero_page .

2) Thực tế là các trình biên dịch C đã truy cập địa chỉ bộ nhớ bằng không.

Đây dường như là sự thật từ bài báo sau của BellLabs ( http://www.cs.bell-labs.com/who/dmr/primevalC.html )

Hai trình biên dịch khác nhau về chi tiết trong cách họ đối phó với điều này. Trong phần trước, phần bắt đầu được tìm thấy bằng cách đặt tên một hàm; về sau, giá trị bắt đầu chỉ đơn giản là 0. Điều này cho thấy rằng trình biên dịch đầu tiên được viết trước khi chúng ta có một máy có ánh xạ bộ nhớ, vì vậy nguồn gốc của chương trình không phải ở vị trí 0, trong khi vào thời điểm thứ hai, chúng tôi đã có PDP-11 cung cấp ánh xạ.

(Thực tế cho đến ngày hôm nay (như tôi đã trích dẫn các tài liệu tham khảo ở trên từ wikipedia và microsoft press), lý do hạn chế quyền truy cập vào địa chỉ số 0 là do con trỏ NULL của C! Vì vậy, cuối cùng thì mọi chuyện lại diễn ra theo chiều ngược lại!)

3) Hãy nhớ rằng C cũng được sử dụng để viết hệ điều hành, và thậm chí cả trình biên dịch C!

Trên thực tế, C được phát triển với mục đích viết hệ điều hành UNIX với nó, và như vậy có vẻ như không có lý do gì khiến chúng phải tự giới hạn mình từ địa chỉ 0.

(Phần cứng) Giải thích về cách Máy tính (Vật lý) Có thể Truy cập Địa chỉ Zero

Có một điểm khác tôi muốn giải thích ở đây, làm thế nào nó có thể tham chiếu đến địa chỉ số không?

Hãy nghĩ về nó trong một giây, các địa chỉ được bộ xử lý tìm nạp và sau đó được gửi dưới dạng điện áp trên bus bộ nhớ, sau đó được hệ thống bộ nhớ sử dụng để truy cập địa chỉ thực, nhưng địa chỉ bằng 0 sẽ không có nghĩa là không có điện áp , vậy phần cứng vật lý của hệ thống bộ nhớ truy cập địa chỉ số 0 như thế nào?

Câu trả lời dường như là, địa chỉ số 0 là địa chỉ mặc định, và nói cách khác, địa chỉ số 0 luôn được hệ thống bộ nhớ truy cập khi bus bộ nhớ hoàn toàn tắt, và như vậy bất kỳ yêu cầu nào để đọc hoặc ghi mà không chỉ định địa chỉ thực (mà là trường hợp có địa chỉ bằng không) là tự động truy cập địa chỉ bằng không.


1
Tôi không phản đối bạn, nhưng bài đăng của bạn có một số điểm không chính xác thực tế, ví dụ: rằng bộ nhớ vật lý ở độ lệch 0 là không thể truy cập (do tất cả các công tắc bị tắt? thực sự?), 0 và hằng số 0 có thể hoán đổi cho nhau (chúng có thể không) và những thứ khác.
Hasturkun

Về 0 và hằng số 0, đây là những gì cuốn sách gốc nói, và đây là những gì thử nghiệm thực tế cho thấy, bạn có tìm thấy sự khác biệt thực sự giữa hai điều này không? Nếu có thì trình biên dịch và nền tảng nào? Trong khi nhiều câu trả lời gợi ý rằng có một sự khác biệt mà tôi chưa tìm thấy và chúng không có tài liệu tham khảo để chỉ ra sự khác biệt. Trên thực tế, theo en.wikipedia.org/wiki/Zero_page Và cả "Windows Via C / C ++ của Jeffrey Richter và Christophe Nasarre (do Microsoft Press xuất bản)" toàn bộ trang đầu tiên! được bảo vệ trong máy tính hiện đại chỉ để ngăn chặn null (thực sự lãng phí nhiều hơn một byte!)
halb Yoel

Tất nhiên mẫu bit của địa chỉ được sử dụng để chọn những gì đang được đọc. Nó thường là trường hợp. dù sao, tôi không muốn tranh luận với bạn, tôi chỉ chỉ ra lý do tại sao bạn có thể bị từ chối.
Hasturkun

Tôi không đồng ý với yêu cầu của bạn. Tôi cũng không quan tâm đến việc tiếp tục cuộc thảo luận này.
Hasturkun

6
Yêu cầu phần cứng là vô nghĩa. Để đọc địa chỉ 0, hãy lái xe! Chip Chọn thấp,! RAS cao,! CAS thấp,! WE cao, và tất cả các dòng địa chỉ thấp. Khi xe buýt tắt, CS cao.
MSalters
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.