TÓM TẮT TÓM TẮT
(mà tôi cũng sẽ đặt lên hàng đầu):
(0) Nghĩ về con trỏ là địa chỉ thường là một công cụ học tập tốt và thường là triển khai thực tế cho con trỏ đến các loại dữ liệu thông thường.
(1) Nhưng trên nhiều, có lẽ hầu hết, các trình biên dịch con trỏ tới các hàm không phải là địa chỉ, nhưng lớn hơn một địa chỉ (thường là 2 lần, đôi khi nhiều hơn) hoặc thực sự là các con trỏ tới một cấu trúc trong bộ nhớ hơn là chứa các địa chỉ của hàm và các thứ như một hồ bơi không đổi.
(2) Con trỏ tới các thành viên dữ liệu và con trỏ tới các phương thức thường thậm chí còn xa lạ.
(3) Mã x86 kế thừa với các vấn đề về con trỏ FAR và NEAR
(4) Một số ví dụ, đáng chú ý nhất là IBM AS / 400, với "con trỏ chất béo" an toàn.
Tôi chắc chắn bạn có thể tìm thấy nhiều hơn.
CHI TIẾT:
UMMPPHHH !!!!! Nhiều câu trả lời cho đến nay là câu trả lời "lập trình viên" khá điển hình - nhưng không phải là trình biên dịch weenie hay weenie phần cứng. Vì tôi giả vờ là một weenie phần cứng và thường làm việc với các weenies trình biên dịch, hãy để tôi ném vào hai xu của mình:
Trên nhiều, có lẽ hầu hết, trình biên dịch C, một con trỏ tới dữ liệu thuộc loại T
, trên thực tế, là địa chỉ của T
.
Khỏe.
Nhưng, ngay cả trên nhiều trình biên dịch này, một số con trỏ nhất định KHÔNG phải là địa chỉ. Bạn có thể nói điều này bằng cách nhìn vào sizeof(ThePointer)
.
Ví dụ, con trỏ tới các chức năng đôi khi lớn hơn khá nhiều so với các địa chỉ thông thường. Hoặc, chúng có thể liên quan đến một mức độ gián tiếp. bài viết nàycung cấp một mô tả, liên quan đến bộ xử lý Intel Itanium, nhưng tôi đã thấy những người khác. Thông thường, để gọi một hàm, bạn phải biết không chỉ địa chỉ của mã chức năng, mà cả địa chỉ của nhóm hằng số của hàm - một vùng bộ nhớ mà các hằng số được tải với một lệnh tải, thay vì trình biên dịch phải tạo một hằng số 64 bit trong một số lệnh Tải tức thời và Shift và OR. Vì vậy, thay vì một địa chỉ 64 bit, bạn cần 2 địa chỉ 64 bit. Một số ABI (Giao diện nhị phân ứng dụng) di chuyển xung quanh thành 128 bit, trong khi một số khác sử dụng mức độ không xác định, với con trỏ hàm thực sự là địa chỉ của một mô tả chức năng chứa 2 địa chỉ thực tế vừa được đề cập. Cái nào tốt hơn? Phụ thuộc vào quan điểm của bạn: hiệu suất, kích thước mã, và một số vấn đề tương thích - thường mã giả định rằng một con trỏ có thể được chuyển thành dài hoặc dài, nhưng cũng có thể giả sử rằng độ dài dài chính xác là 64 bit. Mã này có thể không tuân thủ tiêu chuẩn, tuy nhiên khách hàng có thể muốn nó hoạt động.
Nhiều người trong chúng ta có những ký ức đau đớn về kiến trúc phân đoạn Intel x86 cũ, với NEAR POINTERs và FAR POINTERS. Rất may, hiện tại chúng gần như đã tuyệt chủng, vì vậy chỉ có một bản tóm tắt nhanh: ở chế độ thực 16 bit, địa chỉ tuyến tính thực tế là
LinearAddress = SegmentRegister[SegNum].base << 4 + Offset
Trong khi ở chế độ được bảo vệ, nó có thể là
LinearAddress = SegmentRegister[SegNum].base + offset
với địa chỉ kết quả được kiểm tra theo giới hạn được đặt trong phân khúc. Một số chương trình được sử dụng không thực sự khai báo con trỏ C / C ++ FAR và NEAR tiêu chuẩn, nhưng nhiều người chỉ nói *T
--- nhưng có trình chuyển đổi trình biên dịch và trình liên kết, ví dụ, con trỏ mã có thể ở gần con trỏ, chỉ là phần bù 32 bit so với bất cứ thứ gì trong thanh ghi CS (Phân đoạn mã), trong khi các con trỏ dữ liệu có thể là các con trỏ FAR, chỉ định cả số phân đoạn 16 bit và bù 32 bit cho giá trị 48 bit. Bây giờ, cả hai số lượng này chắc chắn có liên quan đến địa chỉ, nhưng vì chúng không cùng kích thước, nên số lượng nào là địa chỉ? Ngoài ra, các phân đoạn cũng mang các quyền - chỉ đọc, đọc-ghi, thực thi - ngoài các nội dung liên quan đến địa chỉ thực tế.
Một ví dụ thú vị hơn, IMHO, là (hoặc, có lẽ, là) họ AS / 400 của IBM. Máy tính này là một trong những máy đầu tiên triển khai HĐH trong C ++. Con trỏ trên machime này thường gấp 2 lần kích thước địa chỉ thực tế - ví dụ như bản trình bày nàycho biết, con trỏ 128 bit, nhưng địa chỉ thực tế là 48-64 bit, và một lần nữa, một số thông tin bổ sung, được gọi là khả năng, cung cấp các quyền như đọc, ghi, cũng như giới hạn để ngăn tràn bộ đệm. Có: bạn có thể thực hiện điều này một cách tương thích với C / C ++ - và nếu điều này có mặt ở khắp nơi, PLA và mafia Slav của Trung Quốc sẽ không xâm nhập vào nhiều hệ thống máy tính phương Tây. Nhưng trong lịch sử hầu hết các chương trình C / C ++ đã bỏ qua bảo mật cho hiệu năng. Thú vị nhất, gia đình AS400 cho phép hệ điều hành tạo ra các con trỏ an toàn, có thể được trao cho mã không có đặc quyền, nhưng mã không có đặc quyền không thể giả mạo hoặc giả mạo. Một lần nữa, bảo mật và trong khi mã C / C ++ tuân thủ tiêu chuẩn cẩu thả, nhiều tiêu chuẩn sẽ không hoạt động trong một hệ thống bảo mật như vậy. Một lần nữa, có các tiêu chuẩn chính thức,
Bây giờ, tôi sẽ thoát khỏi hộp xà phòng bảo mật của mình và đề cập đến một số cách khác mà con trỏ (thuộc nhiều loại khác nhau) thường không thực sự giải quyết: Con trỏ tới các thành viên dữ liệu, con trỏ tới các phương thức hàm thành viên và các phiên bản tĩnh của nó lớn hơn một địa chỉ thông thường. Như bài viết này nói:
Có nhiều cách để giải quyết vấn đề này [các vấn đề liên quan đến đơn lẻ so với nhiều người và thừa kế ảo]. Đây là cách trình biên dịch Visual Studio quyết định xử lý nó: Một con trỏ tới hàm thành viên của lớp được thừa kế thực sự là một cấu trúc. "Và họ tiếp tục nói" Đúc một con trỏ hàm có thể thay đổi kích thước của nó! ".
Như bạn có thể đoán từ sự bảo mật (trong) của tôi, tôi đã tham gia vào các dự án phần cứng / phần mềm C / C ++ trong đó một con trỏ được coi giống như một khả năng hơn là một địa chỉ thô.
Tôi có thể tiếp tục, nhưng tôi hy vọng bạn có được ý tưởng.
TÓM TẮT TÓM TẮT
(mà tôi cũng sẽ đặt lên hàng đầu):
(0) nghĩ về con trỏ như địa chỉ thường là một công cụ học tập tốt và thường là triển khai thực tế cho con trỏ đến các loại dữ liệu thông thường.
(1) Nhưng trên nhiều, có lẽ hầu hết, các trình biên dịch con trỏ tới các hàm không phải là địa chỉ, nhưng lớn hơn một địa chỉ (thường là 2X, đôi khi nhiều hơn) hoặc thực sự là các con trỏ tới một cấu trúc trong bộ nhớ hơn là chứa các địa chỉ của hàm và các thứ như một hồ bơi không đổi.
(2) Con trỏ tới các thành viên dữ liệu và con trỏ tới các phương thức thường thậm chí còn xa lạ.
(3) Mã x86 kế thừa với các vấn đề về con trỏ FAR và NEAR
(4) Một số ví dụ, đáng chú ý nhất là IBM AS / 400, với "con trỏ chất béo" an toàn.
Tôi chắc chắn bạn có thể tìm thấy nhiều hơn.