2009-05-25 37 views

Trả lời

24

Trình biên dịch sẽ biến

index[array] 

vào

*(index + array) 

Với cú pháp bình thường nó sẽ biến

array[index] 

vào

*(array + index) 

và do đó bạn thấy rằng cả hai biểu thức đều đánh giá cùng một giá trị. Điều này giữ cho cả C và C++.

+13

Hình minh họa 'chuyển đổi' này chỉ giữ khi một trong các biến là một con trỏ hoặc một mảng và một là một số nguyên, tức là trường hợp C thông thường. Trong C++, [b] mất tính đối xứng của nó khi toán tử [] có thể là một hàm thành viên quá tải và trình biên dịch không được phép sử dụng * (a + b) thay thế. * (a + b) có thể có một loại khác và một giá trị khác hoặc nó có thể không phải là một biểu thức hợp lệ. –

+0

+1. Mát mẻ. Không bao giờ nghĩ về nó theo cách đó. – ralphtheninja

+0

@Charles: điểm tốt! –

6

Từ những ngày sớm nhất của C, biểu thức a[i] chỉ đơn giản là địa chỉ của [0] được thêm vào i (được phóng to theo kích thước của [0]) và sau đó được tham chiếu. Trong thực tế, tất cả những là tương đương:

a[i] 
i[a] 
*(a+i) 

====

Điều duy nhất tôi muốn được quan tâm là thực tế de-tham khảo. Trong khi tất cả chúng đều sản xuất cùng một địa chỉ , việc tham chiếu có thể là mối quan ngại nếu các loại ai khác nhau.

Ví dụ:

int i = 4; 
    long a[9]; 
    long x = a[i]; //get the long at memory location X. 
    long x = i[a]; //get the int at memory location X? 

tôi đã không thực sự thử nghiệm hành vi đó nhưng nó là cái gì bạn có thể muốn xem ra cho. Nếu nó thay đổi những gì được de-tham chiếu, nó có khả năng gây ra tất cả các loại vấn đề với mảng của các đối tượng là tốt.

====

Cập nhật:

Bạn có thể bỏ qua một cách an toàn các bit trên giữa ===== dòng. Tôi đã thử nghiệm nó dưới Cygwin với một đoạn ngắn và dài và nó có vẻ ổn, vì vậy tôi đoán nỗi sợ hãi của tôi là vô căn cứ, ít nhất là cho các trường hợp cơ bản. Tôi vẫn không biết điều gì sẽ xảy ra với những thứ phức tạp hơn bởi vì nó không phải là thứ mà tôi có thể muốn làm.

+0

Hôm nay nó khác như thế nào ?? – Ben

+2

Tôi không nghĩ nó khác. Ý tôi là nó bắt đầu từ những ngày đầu tiên, không phải là chỉ trong những ngày đầu. – paxdiablo

+0

Điều này là sai. Dù bằng cách nào, trình biên dịch biết thêm một int vào một * dài (theo thứ tự) kết quả trong một * dài, mà sau đó dereferenced dài. Và điều này áp dụng cho bất kỳ loại con trỏ nào, bao gồm cả người dùng xác định. –

5

Như Matthew Wilson thảo luận trong Imperfect C++, điều này có thể được sử dụng để thực thi an toàn kiểu trong C++, bằng cách ngăn chặn sử dụng DIMENSION_OF() -like macro với trường hợp của các loại để xác định người điều khiển phụ, như trong:

#define DIMENSION_OF_UNSAFE(x) (sizeof(x)/sizeof((x)[0])) 

#define DIMENSION_OF_SAFER(x) (sizeof(x)/sizeof(0[(x)])) 

int ints[4]; 

DIMENSION_OF_UNSAFE(ints); // 4 
DIMENSION_OF_SAFER(ints); // 4 

std::vector v(4); 

DIMENSION_OF_UNSAFE(v); // gives impl-defined value; v likely wrong 
DIMENSION_OF_SAFER(v); // does not compile 

Có nhiều điều này, để đối phó với con trỏ, nhưng điều đó đòi hỏi một số mẫu bổ sung thông minh. Kiểm tra việc triển khai STLSOFT_NUM_ELEMENTS() trong thư viện STLSoft và đọc về tất cả trong chương 14 của Imperfect C++.

chỉnh sửa: một số người nhận xét cho rằng triển khai không từ chối con trỏ. Nó (cũng như các kiểu do người dùng định nghĩa), như được minh họa bởi chương trình sau đây. Bạn có thể xác minh điều này bằng các dòng chưa được phân loại 16 và 18. (Tôi đã thực hiện điều này trên Mac/GCC4 và nó từ chối cả hai biểu mẫu).

1 
2 #include <stlsoft/stlsoft.h> 
3 
4 #include <vector> 
5 
6 #include <stdio.h> 
7 
8 int main() 
9 { 
10   int  ar[1]; 
11   int* p = ar; 
12   std::vector<int>  v(1); 
13 
14   printf("ar: %lu\n", STLSOFT_NUM_ELEMENTS(ar)); 
15 
16 //  printf("p: %lu\n", STLSOFT_NUM_ELEMENTS(p)); 
17 
18 //  printf("v: %lu\n", STLSOFT_NUM_ELEMENTS(v)); 
19 
20   return 0; 
21 } 
22 
+0

Triển khai 'kích thước' tốt hơn có thể đạt được với các mẫu: mẫu std :: size_t dimension (T [N] & x) {return N; }. Điều đó sẽ an toàn hơn sizeof (a)/sizeof (a [0]) với mảng (mà không phân rã thành con trỏ). –

+1

hối lộ: vấn đề với điều đó là nó không còn là biểu thức biên dịch. Kỹ thuật được mô tả bởi Wilson minh họa một phiên bản biên dịch. Như tôi đã nói, nó có sẵn trong thư viện STLSoft. – dcw

+0

Ngoài ra còn có một cách để có được một biểu thức thời gian biên dịch: template char (& an_array (T (&) [N])) [N]; Điều đó sẽ đánh giá tham chiếu đến một mảng char có cùng kích thước.Sử dụng nó như: int v [sizeof an_array (another_array)]; –

0

Trong C và C++ (với mảng là một con trỏ hoặc mảng) nó là một tính năng ngôn ngữ: con trỏ số học. Thao tác a [b] trong đó a hoặc b là một con trỏ được chuyển thành số học con trỏ: * (a + b). Với việc bổ sung được symetrical, sắp xếp lại không thay đổi ý nghĩa.

Bây giờ, có sự khác biệt đối với các con trỏ không. Trong thực tế cho một loại A với toán tử quá tải [], thì [4] là một cuộc gọi phương thức hợp lệ (sẽ gọi toán tử A ::) nhưng ngược lại sẽ không biên dịch.