2013-06-15 37 views
9

Khi tôi biên soạn một cái gì đó giống nhưChuyển nhượng <con trỏ đến mảng các hằng> = <con trỏ đến mảng>: con trỏ tương thích

double da[ 3 ] = { 2., 3., 4. }; 
double (* pda)[ 3 ] = &da; 
double const (* cpda)[ 3 ] = pda; // gcc: warning; MSVC: ok 

gcc này cảnh báo tôi

warning: initialization from incompatible pointer type [enabled by default] 

Câu hỏi: vấn đề với là gì bài tiểu luận này? Có, về mặt kỹ thuật, đây là những loại khác nhau, nhưng tôi không thấy bất kỳ mối nguy hiểm nào ở đây, double const (*)[ 3 ] trông thậm chí còn an toàn hơn cho tôi hơn double (*)[ 3 ].

tôi đã làm một số xét nghiệm và kết quả nhầm lẫn tôi thậm chí nhiều hơn:

1) MSVC là khá hài lòng với double const (* cpda)[ 3 ] = pda; chuyển nhượng, không có lỗi, không có cảnh báo.

2) Cả hai gcc và MSVC đang hạnh phúc với điều này

double d = 1.; 
double * pd = &d; 
double const * cpd = pd; // gcc: ok; MSVC: ok 

trong khi đây là những loại khác nhau quá.

3) Trong ví dụ này

double d = 1.; 
double * pd = &d; 
double * * ppd = &pd; 
double const * * cppd = ppd; // gcc: warning; MSVC: error 

gcc đưa ra cảnh báo tương tự nhưng MSVC cho lỗi (!).

Ai ở ngay đây? gcc hoặc MSVC?


Kết quả kiểm tra.

Trình biên dịch:

1) gcc phiên bản 4.7.2: http://www.compileonline.com/compile_c_online.php

2) MSVC (như C++ code) phiên bản 'VS2012CTP' 17.00.51025 cho x86: http://rise4fun.com/vcpp

3) MSVC (dưới dạng mã C) VS2010: thử nghiệm ẩn

int main() 
{ 
    double d = 1.; 

    double * pd = &d; 
    double const * cpd = pd; 
    // gcc: ok 
    // MSVC C++: ok 
    // MSVC C: ok 

    double * * ppd = &pd; 
    double const * * cppd = ppd; 
    // gcc: warning: initialization from incompatible pointer type [enabled by default] 
    // MSVC C++: error C2440: 'initializing' : cannot convert from 'double **' to 'const double **' 
    // MSVC C: ok 

    double da[ 3 ] = { 2., 3., 4. }; 

    double (* pda)[ 3 ] = &da; 
    double const (* cpda)[ 3 ] = pda; 
    // gcc: warning: initialization from incompatible pointer type [enabled by default] 
    // MSVC C++: ok 
    // MSVC C: ok 

    cpd, cpda; 
    return 0; 
} 

Chỉnh sửa:

Tôi vừa biên soạn điều này trên Visual Studio của tôi dưới dạng mã C (không phải C++) và nó không có lỗi, không có cảnh báo nào cả. Tôi đã chỉnh sửa các bài bình luận ở trên mã số

+5

[Bắt buộc đọc] (http://c-faq.com/ansi/constmismatch.html). –

+0

@ n.m. Cảm ơn, tôi hiểu tại sao nó nguy hiểm – kotlomoy

Trả lời

2

gcc là ngay tại đây và chẩn đoán là cần thiết trong C.

double da[ 3 ] = { 2., 3., 4. }; 
double (* pda)[ 3 ] = &da; 
double const (* cpda)[ 3 ] = pda; // diagnostic here 

Về cơ bản bạn đang cố gắng gán một đối tượng kiểu T1 đối tượng thuộc loại T2 (các ràng buộc của việc gán đơn giản áp dụng cho việc khởi tạo).

Trường hợp T1 là con trỏ đến mảng N của T.

T2 là một con trỏ tới một mảng N của const T.

Trong những hạn chế của sự phân công đơn giản, C nói rằng cho con trỏ sau đây sẽ tổ chức (trong C99, 6.5.16.1p1):

cả hai toán hạng là con trỏ đến các phiên bản đủ điều kiện hoặc không đủ tiêu chuẩn của các loại tương thích, và loại được trỏ đến bởi bên trái có tất cả các vòng loại của các loại được trỏ đến bởi quyền

này sẽ cho phép ví dụ một cái gì đó như:

int a = 0; 
const int *p = &a; // p type is a qualified version of &a type 

Nhưng trong ví dụ của bạn, một con trỏ đến một mảng N của const T không phải là phiên bản đủ điều kiện của con trỏ tới mảng N của T. Trong C, mảng không thể là hằng số: không có mảng const, nhưng chỉ mảng của các phần tử const.

+0

Có lỗi chính tả: "Trong đó T1 là một con trỏ tới một mảng N của const T. Và T2 là một con trỏ tới một mảng N của T." - hoàn toàn ngược lại. – kotlomoy

+0

Bạn đã thực hiện điều rõ ràng đối với tôi, cảm ơn – kotlomoy

1

Đây là sự khác biệt giữa C và C++. Làm điều đó loại chuyển đổi const là hoàn toàn tốt đẹp trong C++, nhưng không phải trong C.

+0

Vâng, thực sự Microsoft C++ là so sánh xấu ở đây. Tôi đã cố gắng biên dịch trong VS2010 dưới dạng mã C (xem phần chỉnh sửa). Nhưng đó là so sánh xấu vì Microsoft không hỗ trợ C99. – kotlomoy

+0

Không chỉ là sự khác biệt giữa C và C++. clang khi biên dịch mã C hoạt động như MSVC ở đây. –

6

Đó là một sự khác biệt trong việc giải thích tiêu chuẩn, gcc xem xét các loại không tương thích, trong khi MSVC và clang làm.

6.7.6.1 (2):

Đối với hai loại con trỏ để tương thích, cả hai sẽ hệt có trình độ và cả hai sẽ được con trỏ đến các loại tương thích.

Các loại pdacpda là hệt đủ tiêu chuẩn [không đủ điều kiện ở tất cả], vì vậy câu hỏi là liệu chúng trỏ tới các loại tương thích, ví dụ là double[3]const double[3] loại tương thích?

6.7.6.2 (6):

Đối với hai loại mảng để tương thích, cả hai sẽ có các loại yếu tố tương thích, và nếu cả specifiers kích thước có mặt, và là số nguyên biểu thức hằng số, sau đó cả hai kích thước chỉ định phải có cùng giá trị không đổi. Nếu hai loại mảng được sử dụng trong ngữ cảnh yêu cầu chúng tương thích, thì hành vi không xác định nếu hai thông số kích thước đánh giá các giá trị không bằng nhau.

Câu hỏi đặt ra là doubleconst double là các loại tương thích.

6.7.3 (10):

Đối với hai loại đủ tư cách làm phù hợp, cả hai sẽ có phiên bản giống nhau có trình độ của một loại tương thích; thứ tự các loại vòng loại trong danh sách các nhà cung cấp hoặc vòng loại không ảnh hưởng đến loại được chỉ định.

Tôi muốn nói rằng làm cho doubleconst double không tương thích, vì vậy gcc là đúng.

Các initialisation

double const * cpd = pd; 

được chấp nhận vì những hạn chế của nhiệm vụ (trong đó có liên quan cho khởi động) trong 6.5.16.1 danh sách

các toán hạng bên trái có kiểu nguyên tử, có trình độ, hoặc không đủ tiêu chuẩn con trỏ và (xem xét loại toán hạng bên trái sẽ có sau khi chuyển đổi lvalue) cả hai toán hạng là con trỏ đến phiên bản đủ điều kiện hoặc không đủ tiêu chuẩn của các loại tương thích và loại được chỉ đến bên trái ha s tất cả các vòng loại của loại được trỏ tới bên phải;

là một trong những tình huống được chấp nhận. cpdpd cả hai điểm đến phiên bản đủ điều kiện của double và mục tiêu của toán hạng bên trái có tất cả các vòng loại mà bên phải có (và một số khác, const).

Tuy nhiên, các loại double*const double* không tương thích, do đó

double const * * cppd = ppd; 

là lại không hợp lệ, và đòi hỏi một thông điệp chẩn đoán.

+0

Nó không giải thích điều này 'double const * cpd = pd; // gcc: ok'. Theo nghiên cứu của bạn, 'double const *' và 'double *' không tương thích vì chúng trỏ đến các kiểu không tương thích. Nhưng gcc nghĩ khác đi. – kotlomoy

+2

Không, trong khi các kiểu con trỏ không tương thích, việc gán một 'double *' thành 'const double *' được cho phép rõ ràng bởi 6.5.16.1, xem phần bổ sung. –