2015-02-18 10 views
6

Wyjaśnienie: Moje pytanie brzmi:Czy UB odrzuca const i odczytuje wartość?

  • Czy UB go używać lwartością typu int uzyskać dostęp do obiektu skutecznej typu const int?

To pytanie ma dwa przykłady kodu, które używają lwartością typu int uzyskać dostęp do obiektu skutecznej typu const int, a moim zamiarem jest doprowadzenie do tego z jak najmniejszym rozproszenia, jak to możliwe. Jeśli oprócz tego konkretnego problemu istnieje inne źródło UB, proszę zostaw komentarz, a ja postaram się zaktualizować próbkę kodu.


Oto konkretny przykład kodu do dyskusji:

#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    const int c = 5; 

    printf("%d\n", *(int *)&c); 
} 

Powodem myślę, że może to być UB jest to, że ścisła reguła aliasing zdaje się mówić, że to UB:

C11 6.5/7

Dostęp do obiektu ma jego przechowywana wartość wyłącznie przez wyrazem lwartość że ma jeden z następujące typy:

  • rodzajem zgodny z efektywnym typem obiektu,
  • wykwalifikowanym wersja typu zgodnego z efektywnym typem obiektu,
  • ...

skuteczny rodzaj obiektu (6,5/6) tutaj jest const int.

Pierwszy podpunkt: int i const int nie są kompatybilne rodzaje (6.2.7/1 6.7.3/10).

Drugi punkt wypunktowania: int nie wydaje się być kwalifikowaną wersją const int, ponieważ nie wyprodukowaliśmy go, dodając kwalifikatory. Jednak 6.2.5/26 jest niejasne:

Każdy nie kwalifikowany typ ma kilka kwalifikowanych wersji tego typu, odpowiadających kombinacjom jednego, dwóch lub wszystkich trzech kryteriów const, volatile i restrict. Kwalifikowane lub niekwalifikowane wersje typu są różnymi typami, które należą do tej samej kategorii typów i mają takie same wymagania dotyczące odwzorowania i wyrównania. Typ wyprowadzony nie jest kwalifikowany przez kwalifikatory (jeśli istnieją) typu, z którego pochodzi.

Nie określa, co oznacza "kwalifikowana wersja const int", definiuje jedynie termin "wersja kwalifikowana", gdy zostanie zastosowany do niewykwalifikowanego typu.


drugiej próbki Kod:

int *pc = malloc(sizeof *pc); 
memcpy(pc, &c, sizeof c); 
printf("%d\n", *pc); // UB? 

Ponieważ memcpy zachowuje skuteczną typu (6.5/6), poprzez czytanie *pc ma dokładnie takie samo oddziaływanie surowe zasady aliasingu w przeczytaniu *(int *)&c czyni w pierwszym przykładzie.

+0

Dlaczego musisz odłączyć zmienną, którą tylko czytasz? – StenSoft

+0

@StenSoft Nie potrzebuję *, ale byłoby ciekawie wiedzieć, czy to UB czy nie, i ta sama zasada jest istotna w innych pytaniach (np. Dodana przeze mnie odpowiedź). –

+0

Mogę ci powiedzieć na pewno to może nie działać w praktyce (odrzucając const na małym POD). Wpadłem na to w dupę, gdy GCC umieściło w rejestrze postać stałą, a potem zmęczyłem się, by ją zmodyfikować :) Zaowocowało to "SGIBUS" lub "SIGTERM" (minęło kilka lat, odkąd to się stało). Bałagan z konstytucją na własne ryzyko :) – jww

Odpowiedz

2

Nie jest. To, co znaleźliście, to dlaczego nie można wszczepić implicite.

[6.2.5/26], stwierdza:

Każdy typ niewykwalifikowany ma kilka wykwalifikowanych wersje tego typu, odpowiednio do połączenia z jednego, dwóch lub wszystkich trzech const, lotne i ograniczyć kwalifikatory. Kwalifikowane lub niekwalifikowane wersje typu są różnymi typami należącymi do tej samej kategorii typów i mają takie same wymagania dotyczące odwzorowania i wyrównania.

(Uwaga. Każdy niewykwalifikowany typu const int jest nieograniczone, ale int to bez zastrzeżeń.)

z przypisie:

same wymagania reprezentacyjne i wyrównywania są przeznaczone do zrozumienia wymienne jako argumenty funkcji, zwracają wartości z funkcji i członków związków.

Oznacza to, że czytanie będzie działało w ten sam sposób i przyniesie taką samą wartość.

[6.7.3/6] określa UB tylko modyfikacji:

Jeżeli próbuje się zmodyfikować przedmiotu zdefiniowanego w rodzaju const zakwalifikowanych przez zastosowanie lwartością z const wykwalifikowanych type, zachowanie jest niezdefiniowane.

+0

Przypisy nie są normatywne, ale w żadnym wypadku nie mówimy o argumentach funkcji, zwracamy wartości z funkcji lub członków związków, więc nie widzę, jak to ma zastosowanie i jak wyciągnąć z tego wniosek, że odczyt musi być OK.Co myślisz o równoważnym pytaniu, ale z 'volatile' zamiast' const'? –

+0

Ma takie same wymagania dotyczące odwzorowania i wyrównania, więc powinieneś być w stanie odczytać go w ten sam sposób. Przypis jest przydatny w zrozumieniu przyczyny. W przypadku lotności [6.7.3/6] określa, że ​​wszelkie nielotne odniesienie do lotnych jest UB. – StenSoft

+0

Dobre spostrzeżenie na temat wyraźnego zakazu zmienności w 6.7.3/6, usunąłem ten akapit z mojego pytania –