2016-12-30 16 views
7

В этом фрагменте указателя на VLA используется для облегчения доступа к большой справочной таблице:Cast «указатель на константный» в «указатель на константные 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 дроссели на нем, в то время как Clang 4.0.0 (багажник) компилируется просто отлично, оба с -Wcast-qual включены.

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

Код работает как ожидалось в любом случае.

Моя догадка НКУ путает «указатель на VLA из константных элементов» и «указатель на константные VLA», но я тянусь ...

Есть ли способ, чтобы заткнуться GCC без возился с предупреждениями? Это ошибка GCC?

EDIT1:

Подробные сведения о фактическом коде:

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:

Так что это ... стандартный проект C11 говорит 6.7.3/9:

Если спецификация Ион типа массива включает в себя квалификаторы любого типа, тип элемента является настолько квалифицированным, а не типом массива.

См. Ответ @hvd.

Один хак, чтобы заставить замолчать -Wcast-qual:

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

«указатель на VLA элементов const» и «указатель на const VLA» - это одно и то же. Массив const представляет собой массив элементов const. Похоже на ошибку. – emlai

+0

Почему бы не сделать все это более безопасным с типом и сделать 'raw' в' char const (* raw) [a] [b] [c] '? – StoryTeller

+0

@StoryTeller Я добавил, как выглядит код, но тем не менее, что '-Wcast-qual' странно. – diapir

ответ

6

Это давняя проблема в C. Это та же самая причина, почему

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

недопустим в C (но будет действительным в C++): это объявляет указатель на массив из const -qualified integers, который является not a const -qualified массив целых чисел, поэтому нормальное правило, что указатель на тип может быть неявно преобразован t o указатель на const -qualified версия этого типа не применяется.

В вашем случае, вы конвертируете из const char * (указатель на const -qualified типа) в char const (*)[a][b][c] (указатель на не- const -qualified типа), которые, как предполагается -Wcast-qual предупредить о.

clang просто никогда не потрудился реализовать эту особую странность C, он рассматривает C-код семантикой C++, в которой говорят, что массив из элементов const сам по себе является также и кодом const.

Вы бы нормально быть в состоянии работать вокруг него, окружив массив в struct:

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

, но это не вариант для Власа. Я не верю, что есть подходящее обходное решение, отличное от использования многомерных массивов вообще, или не используя -Wcast-qual.

+0

С помощью предупреждений это тогда ... Знаете ли вы о случаях где использование правила C++ в C (например, clang) потенциально может быть опасным? В стандарте нет никаких оснований: _6.7.3.9 Если спецификация типа массива включает в себя квалификаторы любого типа, тип элемента является настолько квалифицированным, а не тип массива._ – diapir

+1

@diapir. Правило C++ безопасно, поскольку «const» -правильность идет, и он также был предложен для C (хотя я не знаю его статуса). Единственный риск, если вы его используете теперь вы можете случайно записать недействительный/еще не действующий C-код, который затем вызывает ошибку при использовании жесткого компилятора C. – hvd