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 typuconst 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.
Dlaczego musisz odłączyć zmienną, którą tylko czytasz? – StenSoft
@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ź). –
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