2016-12-30 40 views
7

Trong đoạn này, một con trỏ để VLA được sử dụng để truy cập dễ dàng hơn để một bảng tra cứu lớn:Cast "con trỏ đến const" thành "con trỏ đến const VLA"

#pragma GCC diagnostic warning "-Wcast-qual" 

char 
lookup(int a, int b, int c, char const *raw, int x, int y, int z) 
{ 
    typedef char const (*DATA_PTR)[a][b][c]; 

    DATA_PTR data = (DATA_PTR)raw; 

    return (*data)[x][y][z]; 
} 

GCC 6.2.0 cuộn cảm trên nó trong khi Clang 4.0.0 (thân cây) biên dịch tốt, cả hai đều bật với kích hoạt -Wcast-qual.

In function 'lookup': 
warning: cast discards 'const' qualifier from pointer target type [-Wcast-qual] 
    DATA_PTR data = (DATA_PTR)raw; 
       ^

Mã chạy như mong đợi theo một trong hai cách.

tôi đoán là GCC lẫn lộn một "con trỏ đến VLA của các yếu tố const" và "con trỏ đến const VLA" nhưng tôi đạt ...

Có cách nào để im lặng GCC mà không cần loay hoay với cảnh báo? Đây có phải là lỗi của GCC không?

EDIT1:

Chi tiết về mã thực tế:

struct table { 
    int a; 
    int b; 
    int c; 
    char *raw; 
}; 

char 
lookup2(struct table const *table, int x, int y, int z) 
{ 
    typedef char const(*DATA_PTR)[table->a][table->b][table->c]; 

    DATA_PTR data; 
    data = (DATA_PTR)table->raw; // GCC ok 
    data = (DATA_PTR)(char const *)table->raw; // GCC raises -Wcast-qual 

    return (*data)[x][y][z]; 
} 

EDIT2:

Vì vậy, nó là ... tiêu chuẩn dự thảo C11 nói trong 6.7.3/9:

Nếu cụ thể ation của một loại mảng bao gồm bất kỳ loại vòng loại nào, loại phần tử đủ điều kiện, không phải kiểu mảng.

Xem câu trả lời @hvd.

Một hack để im lặng -Wcast-qual:

DATA_PTR data = (DATA_PTR)(intptr_t)raw; 
+3

"con trỏ tới VLA của các phần tử const" và "con trỏ đến const VLA" là giống nhau. Mảng const là một mảng các phần tử const. Có vẻ như một con bọ. – emlai

+0

Tại sao không làm cho toàn bộ điều an toàn hơn một chút, và tạo 'nguyên' thành' char const (* raw) [a] [b] [c] '? – StoryTeller

+0

@StoryTeller Tôi đã thêm mã có thể trông như thế nào nhưng vẫn là '-Wcast-qual' là lạ. – diapir

Trả lời

6

Đây là vấn đề tồn tại từ lâu trong C. Đó là lý do tương tự tại sao

int array[2]; 
const int (*ptr)[2] = &array; 

không hợp lệ trong C (nhưng sẽ là hợp lệ trong C++): điều này tuyên bố một con trỏ tới một mảng số nguyên const đủ điều kiện, là không a const dãy số nguyên đủ điều kiện, vì vậy quy tắc thông thường mà một con trỏ đến một loại có thể được chuyển đổi hoàn toàn thành po liên quan đến phiên bản loại const loại phù hợp không áp dụng.

Trong trường hợp của bạn, bạn đang chuyển đổi từ const char * (một con trỏ tới một kiểu -qualified const) để char const (*)[a][b][c] (một con trỏ đến một phi const loại -qualified), mà -Wcast-qual là nghĩa vụ phải cảnh báo về.

clang không bao giờ bận tâm để thực hiện điều kỳ quặc đặc biệt này của C, nó xử lý mã C với ngữ nghĩa C++, trong đó nói rằng một mảng của các yếu tố const cũng chính nó là const.

Bạn thường muốn có thể làm việc xung quanh nó bằng cách gói mảng trong một struct:

typedef struct { char d[a][b][c]; } const *DATA_PTR; 

nhưng đây không phải là một lựa chọn cho Vlas. Tôi không tin rằng có một giải pháp thích hợp khác ngoài việc không sử dụng mảng đa chiều ở đây, hoặc không sử dụng -Wcast-qual.

+0

Không quan tâm đến cảnh báo thì ... Bạn có biết về các cá thể không khi sử dụng quy tắc C++ trong C (như clang) có thể nguy hiểm? Không có lý do gì cho nó trong tiêu chuẩn: _6.7.3.9 Nếu đặc tả của một kiểu mảng bao gồm bất kỳ loại vòng loại nào, kiểu phần tử đủ điều kiện, không phải kiểu mảng._ – diapir

+1

@diapir Quy tắc C++ an toàn khi 'const'-correctness xuất hiện và nó cũng đã được đề xuất cho C (mặc dù tôi không biết trạng thái của nó) .Chỉ rủi ro nếu bạn sử dụng nó bây giờ là bạn có thể vô tình viết mã C không hợp lệ/không hợp lệ mà sau đó gây ra lỗi khi trình biên dịch C nghiêm ngặt được sử dụng. – hvd

Các vấn đề liên quan