Tại sao C sử dụng dấu hoa thị cho con trỏ?
Đơn giản - vì B đã làm.
Vì bộ nhớ là một mảng tuyến tính, nên có thể hiểu giá trị trong một ô là một chỉ mục trong mảng này và BCPL cung cấp một toán tử cho mục đích này. Trong ngôn ngữ gốc, nó được đánh vần rv
và sau đó !
, trong khi B sử dụng unary *
. Do đó, nếu p
là một ô chứa chỉ mục của (hoặc địa chỉ của) hoặc con trỏ tới) một ô khác, *p
đề cập đến nội dung của ô được trỏ, là giá trị trong biểu thức hoặc là mục tiêu của phép gán.
Từ sự phát triển của ngôn ngữ C
Đó là nó. Tại thời điểm này, câu hỏi không thú vị bằng "tại sao python 3 sử dụng .
để gọi một phương thức? Tại sao không ->
?" Chà ... bởi vì Python 2 sử dụng .
để gọi một phương thức.
Hiếm khi một ngôn ngữ tồn tại từ không có gì. Nó có ảnh hưởng và dựa trên một cái gì đó đến trước.
Vậy, tại sao B không sử dụng !
để hủy đăng ký một con trỏ như BCPL tiền nhiệm của nó đã làm?
Vâng, BCPL là một chút dài dòng. Thay vì &&
hoặc ||
BCPL được sử dụng logand
và logor
. Điều này là do hầu hết các bàn phím không có ∧
hoặc ∨
phím và không bằng nhau thực sự là từ NEQV
(xem Hướng dẫn tham khảo BCPL ).
B dường như đã được truyền cảm hứng một phần để thắt chặt cú pháp hơn là có các từ dài cho tất cả các toán tử logic này mà các lập trình viên đã làm khá thường xuyên. Và do đó, !
đối với sự tham gia đã trở thành *
như vậy !
có thể được sử dụng cho phủ định logic. Lưu ý rằng có một sự khác biệt giữa toán tử đơn nguyên *
và toán tử nhị phân *
(phép nhân).
Vâng, những gì về các lựa chọn khác , như thế ->
nào?
Đã ->
được thực hiện cho đường cú pháp xung quanh derefrences lĩnh vực struct_pointer->field
đó là(*struct_pointer).field
Các tùy chọn khác như <-
có thể tạo phân tích mơ hồ. Ví dụ:
foo <- bar
Có phải là để được đọc là:
(foo) <- (bar)
hoặc là
(foo) < (-bar)
Tạo một toán tử đơn nguyên bao gồm một toán tử nhị phân và một toán tử đơn nguyên khác rất có thể có vấn đề vì toán tử đơn nguyên thứ hai có thể là tiền tố cho một biểu thức khác.
Hơn nữa, điều quan trọng nữa là cố gắng giữ cho mọi thứ được gõ thường xuyên đến mức tối thiểu. Tôi ghét phải viết:
int main(int argc, char->-> argv, char->-> envp)
Điều này cũng trở nên khó đọc.
Các nhân vật khác có thể đã có thể ( @
không được sử dụng cho đến khi Mục tiêu C chiếm đoạt nó ). Mặc dù một lần nữa, điều này đi vào cốt lõi của 'C sử dụng *
vì B đã làm'. Tại sao B không sử dụng @
? Chà, B đã không sử dụng tất cả các nhân vật. Không có bpp
chương trình (so sánh cpp ) và các ký tự khác có sẵn trong B (chẳng hạn như #
sau này được sử dụng bởi cpp).
Nếu tôi có thể đoán được lý do tại sao - đó là vì các phím ở đâu. Từ một hướng dẫn trên B :
Để tạo điều kiện cho việc thao tác địa chỉ khi có vẻ được khuyến khích, B cung cấp hai toán tử địa chỉ đơn nhất *
và &
. &
là toán tử địa chỉ, vì vậy &x
là địa chỉ của x
, giả sử nó có một. *
là toán tử gián tiếp; *x
có nghĩa là "sử dụng nội dung của x làm địa chỉ."
Lưu ý rằng đó &
là shift-7 và *
là shift-8. Sự gần gũi của họ với nhau có thể là một gợi ý cho lập trình viên về những gì họ làm ... nhưng đó chỉ là dự đoán. Người ta sẽ phải hỏi Ken Thompson về lý do lựa chọn đó được đưa ra.
Vì vậy, có bạn có nó. C là như vậy bởi vì B đã. B là như vậy bởi vì nó muốn thay đổi từ cách BCPL.
->
đang được sử dụng trong ngôn ngữ C như một toán tử quy ước - khi truy cập các trường trong một cấu trúc :struct_pointer->field
, viết tắt của(*struct_pointer).field
.