2015-12-28 26 views
17

Hãy xem xét sau chương trình:Con trỏ trỏ tới mảng với vòng loại const trong C & C++

int main() 
{ 
    int array[9]; 
    const int (*p2)[9] = &array; 
} 

Nó biên dịch tốt trong C++ (Xem demo sống here) nhưng thất bại trong việc lập trong C. Bằng GCC mặc định cho cảnh báo sau đây. (Xem bản trình diễn trực tiếp here).

prog.c: In function 'main': 
prog.c:4:26: warning: initialization from incompatible pointer type [enabled by default] 
    const int (*p2)[9] = &array; 

Nhưng Nếu tôi sử dụng -pedantic-errors tùy chọn:

gcc -Os -s -Wall -std=c11 -pedantic-errors -o constptr constptr.c 

nó mang lại cho tôi sau lỗi biên dịch

constptr.c:4:26: error: pointers to arrays with different qualifiers are incompatible in ISO C [-Wpedantic] 

Tại sao nó bị lỗi trong biên soạn trong C nhưng không có trong C++? Điều gì C & C++ tiêu chuẩn nói về điều này?

Nếu tôi sử dụng const vòng loại trong tuyên bố khai báo mảng, nó cũng biên dịch tốt trong C. Vì vậy, những gì đang xảy ra ở đây trong chương trình trên?

+10

Trong khi tôi hiểu đây là một câu hỏi hay, nhưng chỉ cần hỏi 'Tiêu chuẩn C & C++ nào nói về điều này?' Thì không tốt. Bạn đã cố gắng nhìn vào các tiêu chuẩn? Phần nào bạn không hiểu? Bạn có tìm thấy bất kỳ sự khác biệt nào không? Nỗ lực nghiên cứu của bạn ở đâu? Hy vọng tôi hiểu. :) –

Trả lời

20

GCC-gnu

Trong GNU C, con trỏ đến mảng với vòng loại hoạt động tương tự như con trỏ đến các loại trình độ khác. Ví dụ: giá trị loại int (*)[5] có thể được sử dụng để khởi tạo biến loại const int (*)[5]. Các loại này không tương thích trong ISO C vì vòng loại const được chính thức gắn vào loại phần tử của mảng chứ không phải chính mảng.

C tiêu chuẩn nói rằng (phần: §6.7.3/9):

Nếu đặc điểm kỹ thuật của một loại mảng bao gồm bất kỳ vòng loại, các loại nguyên tố là Somali đủ điều kiện, không phải là . mảng kiểu [...]

Bây giờ nhìn vào chuẩn C++ (phần § 3.9.3/5):

[...] Cv-vòng loại áp dụng cho loại mảng đính kèm với loại phần tử cơ bản, vì vậy ký hiệu “cv T”, trong đó T là loại mảng, tham chiếu đến mảng có phần tử đủ điều kiện. Một loại mảng có các thành phần là cv đủ điều kiện cũng được coi là có cùng chứng chỉ cv như các thành phần của nó. [Ví dụ:

typedef char CA[5]; 
typedef const char CC; 
CC arr1[5] = { 0 }; 
const CA arr2 = { 0 }; 

Loại cả arr1arr2“mảng của 5 const char,”kiểu mảng được coi là có trình độ const-.-endexample]

Do đó, khởi

const int (*p2)[9] = &array; 

là phân loại con trỏ đến mảng [9] của int-con trỏ đến mảng [9] của const int. Điều này không giống với cách gán int * cho một const int * trong đó const được áp dụng trực tiếp cho loại đối tượng con trỏ trỏ tới. Đây không phải là trường hợp với const int(*)[9] trong đó, trong C, const được áp dụng cho các phần tử của đối tượng mảng thay vì đối tượng mà con trỏ trỏ đến. Điều này làm cho việc khởi tạo ở trên không tương thích.

Quy tắc này được thay đổi trong C++. Như const được áp dụng cho đối tượng mảng chính nó, sự phân công giữa các loại cùng con trỏ đến mảng const [9] của int thay vì loại con trỏ đến mảng [9] của intcon trỏ đến mảng [9] của const int.

+0

Liên kết tốt. Nhưng câu trả lời vẫn không nói về những gì tiêu chuẩn C++ nói về điều này? – Destructor

+4

Tôi sẽ gọi đây là lỗi trong ISO C. Điều đó không có ý nghĩa gì cả. Bạn sẽ luôn có thể thêm 'const' vào một mục tiêu con trỏ, ở mọi cấp độ. –

+1

@PravasiMeet; Đã thêm trích dẫn từ tiêu chuẩn C++. – haccks