2016-12-30 47 views
7

W tym fragmencie, o wskaźnik do VLA służy do łatwiejszego dostępu do dużego tabeli przeglądowej:Obsada „wskaźnik do const” na „wskaźnik do 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 dławiki na nim podczas Clang 4.0.0 (trunk) kompiluje się dobrze, zarówno z -Wcast-qual włączone.

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

Kod działa zgodnie z oczekiwaniami w dowolny sposób.

Domyślam się GCC myli „wskaźnik do VLA elementów const” i „wskaźnik do const VLA”, ale sięgam ...

Czy jest jakiś sposób, żeby się zamknął GCC bez błahy z ostrzeżeń? Czy to jest błąd GCC?

Edit1:

Szczegóły dotyczące rzeczywistego kodu:

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:

Więc to jest ... C11 standardowy projekt mówi 6.7.3/9:

Jeśli szczególne Typ tablicy zawiera dowolne kwalifikatory typów, typ elementu jest kwalifikowany, a nie typ tablicy.

Zobacz odpowiedź @ hvd.

Jeden Hack uciszyć -Wcast-qual:

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

"Wskaźnik do VLA elementów const" i "wskaźnik do const VLA" to to samo. Tablica const jest tablicą elementów const. Wygląda jak błąd. – emlai

+0

Dlaczego nie sprawić, aby cała sprawa była bardziej bezpieczna dla typu, i przekształcić 'raw' w' char const (* raw) [a] [b] [c] '? – StoryTeller

+0

@StoryTeller Dodałem, jaki kod może wyglądać, ale nadal "-Wcast-qual" jest dziwne. – diapir

Odpowiedz

6

Jest to dawna problem w C. Jest to ten sam powód dlaczego

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

jest nieprawidłowy w C (ale byłoby ważne w C++): to deklaruje wskaźnik do tablicy z liczbą całkowitych const, która jest , a nie a const - kwalifikowaną tablicą liczb całkowitych, więc normalną zasadą, że wskaźnik do typu można niejawnie przekonwertować na wartość po inter do const - kwalifikowana wersja tego typu nie ma zastosowania.

W twoim przypadku, jesteś konwersji z const char * (wskaźnik do const typu -qualified) do char const (*)[a][b][c] (wskaźnik do nieprzestrzegania const typu -qualified), który -Wcast-qual jest podobno ostrzec.

clang po prostu nigdy nie zadał sobie trudu, aby zaimplementować tę szczególną dziwność C, traktuje kod C z semantyką C++, która mówi, że sama tablica z elementów const jest sama w sobie również kwalifikowana const.

Można by normalnie móc obejść poprzez owinięcie tablicę w struct:

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

ale nie jest to opcja dla Włas. Nie sądzę, aby istniało odpowiednie obejście, inne niż niestosowanie w tym miejscu tablic wielowymiarowych lub nie używanie -Wcast-qual.

+0

Błąkając się z ostrzeżeniami jest to ... Czy wiesz o wystąpieniach gdzie używanie reguły C++ w C (jak clang) może być potencjalnie niebezpieczne? Nie ma żadnego powodu dla tego w standardzie: _6.7.3.9 Jeśli specyfikacja typu tablicy obejmuje jakiekolwiek kwalifikatory typów, typ elementu jest tak zakwalifikowany, nie tablica type._ – diapir

+1

@diapir Reguła C++ jest bezpieczna, jeśli chodzi o 'const'-poprawność idzie i została zaproponowana również dla C (choć nie znam jej statusu). teraz jest tak, że możesz przypadkowo napisać nieprawidłowy/nie-jeszcze-ważny kod C, który następnie powoduje błąd, gdy zostanie użyty ścisły kompilator C. – hvd