2012-01-31 42 views
13

Wyobraźmy mam tej funkcji C (i odpowiadający prototypu w pliku nagłówka)Czy jest niezdefiniowanym zachowaniem, aby odrzucić stałość parametru funkcji?

void clearstring(const char *data) { 
    char *dst = (char *)data; 
    *dst = 0; 
} 

Czy jest zachowanie niezdefiniowane w powyższym kodzie odlewania const dala, czy jest to tylko strasznie złą praktyką programowania ?

Załóżmy nie ma const wykwalifikowanych obiekty wykorzystywane

char name[] = "pmg"; 
clearstring(name); 
+2

Jeśli obsada nie jest UB, myślę, że powinna być :) – pmg

+0

z pewnością masz stopę prosto w celownik strzelby! –

+1

@pmg: jeśli sama obsada byłaby UB, to nie ma sensu, aby język na to pozwalał - kompilator może łatwo wykryć, że 'const' został dodany do obsady, w ten sam sposób, w jaki wykrył, że' char * dst = data; 'jest nielegalne. Oczywiście są pewne bezsensowne rzeczy, które standard dopuszcza z przyczyn historycznych, ale twierdzę, że to nie jest jedna z nich :-) –

Odpowiedz

20

próba zapisu *dst jest UB jeśli rozmówca przechodzi Ci wskaźnik do const obiekt lub wskaźnik do łańcucha dosłownym.

Ale jeśli wywołujący przekazuje ci wskaźnik do danych, które w rzeczywistości są zmienne, wtedy zachowanie jest zdefiniowane. Utworzenie const char*, które wskazuje na modyfikowalną char, nie powoduje, że ta niezmienna jest ta char.

Więc:

char c; 
clearstring(&c); // OK, sets c to 0 
char *p = malloc(100); 
if (p) { 
    clearstring(p); // OK, p now points to an empty string 
    free(p); 
} 
const char d = 0; 
clearstring(&d); // UB 
clearstring("foo"); // UB 

Oznacza to, że czynność jest bardzo nierozważne, bo to jest tak łatwe dla dzwoniącego powodować UB. Ale w rzeczywistości można go używać z określonym zachowaniem.

+4

+1: (im) zmienność jest nieodłączną właściwością samego obiektu, niezależnie od kwalifikacji wskaźnik używany do uzyskania dostępu ... – Christoph

+0

Czy to UB z powodu 'C99 6.6 §9' lub z powodu' C99 6.7.3 §5'? – Lundin

+1

@Lundin: ten drugi (i 6.4.5/6 zamiast 6.7.3/5 w przypadku literału ciągu, ponieważ literały łańcuchowe nie są obiektami "const" w C). Stałe adresowe nie mają z tym nic wspólnego. –

0

Rozważmy funkcję taką jak strstr, która, jeśli podany zostanie wskaźnik do części obiektu zawierającego ciąg, zwróci wskaźnik do potencjalnie innej części tego samego obiektu. Jeśli metoda zostanie przekazana wskaźnikowi do obszaru pamięci tylko do odczytu, zwróci wskaźnik do obszaru pamięci tylko do odczytu; podobnie, jeśli otrzyma wskaźnik do zapisywalnego obszaru, zwróci wskaźnik do zapisywalnego obszaru.

nie ma sposób C jako funkcja zwraca const char * po poddaniu const char * i powrót zwykły char * podawany zwykłą char *. Aby być kompatybilnym ze sposobem strstr, zanim pomysł został dodany do języka const char *, musi przekonwertować wskaźnik zakotwiczony na wskaźnik o nieustalonej wartości. Chociaż prawdą jest, że jako funkcja biblioteczna strstr może być uprawniona do wykonywania takich odlewów, nawet jeśli kod użytkownika nie mógłby, ten sam wzorzec pojawia się wystarczająco często w kodzie użytkownika, że ​​byłoby praktycznie zabronić tego.

Powiązane problemy