Spotkałem wiele zastosowań makro uninitialized_var()
zaprojektowany, aby pozbyć się ostrzeżeń, takich jak:
warning: ‘ptr’ is used uninitialized in this function [-Wuninitialized]
Dla GCC ( <linux/compiler-gcc.h>
) Jest zdefiniowany taki sposób:
/*
* A trick to suppress uninitialized variable warning without generating any
* code
*/
#define uninitialized_var(x) x = x
Ale odkryłem też, że <linux/compiler-clang.h>
ma to samo makro zdefiniowane w inny sposób:
#define uninitialized_var(x) x = *(&(x))
Dlaczego mamy dwie różne definicje? Z jakiego powodu pierwszy sposób może być niewystarczający? Czy pierwsza droga jest wystarczająca tylko dla klga lub w innych przypadkach?
C Przykład:
#define uninitialized_var(x) x = x
struct some {
int a;
char b;
};
int main(void) {
struct some *ptr;
struct some *uninitialized_var(ptr2);
if (1)
printf("%d %d\n", ptr->a, ptr2->a); // warning about ptr, not ptr2
}
2 odpowiedzi
Kompilatory są uznawane za rozpoznawanie pewnych konstruktów jako wskazówki, że autor zamierzał coś celowo, gdy kompilator inaczej ostrzega o tym. Na przykład, biorąc pod uwagę if (b = a)
, GCC i Clang ostrzegają, że przydział jest używany jako warunkowy, ale nie ostrzegają o if ((b = a))
, nawet jeśli jest równoważny pod względem standardu C. Ten konkretny konstrukt z dodatkowymi nawiasami po prostu został ustawiony jako sposób, aby powiedzieć kompilatorowi autor, który naprawdę zamierza ten kod.
Podobnie, x = x
został ustawiony jako sposób, aby powiedzieć GCC, aby nie ostrzec o x
jest niezainicjowany. Są chwile, w których funkcja może pojawić się , aby mieć ścieżkę kodu, w której obiekt jest używany bez zainicjowania, ale autor wie, że funkcja jest przeznaczona, aby nie być używana z parametrami, która kiedykolwiek spowodowałaby to szczególne Ścieżka kodu do wykonywania i ze względu na wydajność, chcą uciszyć ostrzeżenie kompilatora, a nie dodać inicjalizację, która nie jest właściwie niezbędna do poprawności programu.
Blang był prawdopodobnie zaprojektowany, aby nie rozpoznawać idiomu GCC dla tego i potrzebował innej metody.
Dlaczego mamy dwie różne definicje?
Niejasny, ale spekuluję, że to dlatego, że Clanang nadal wytwarza ostrzeżenie dla x = x
, gdy x
jest niezainicjowany, ale nie dla x = *(&(x))
. W prawie każdej okolicznościach * , w którym jedna z tych wyrażeń ma dobrze zdefiniowane zachowanie, drugi ma takie same dobrze zdefiniowane zachowanie. W innych okolicznościach, takich jak gdy wartość x
jest niezdefiniowana lub nieokreślona, oba mają niezdefiniowane zachowanie, albo zachowanie x = x
jest zdefiniowany i nieokreślony, więc ten ostatni dostarcza się brak przewagi.
Z jakiego powodu pierwszy sposób może być niewystarczający?
Ponieważ zachowanie zarówno jest niezdefiniowane w przypadkach użytkowania, dla których wydają się być przeznaczone. To wcale nie jest zaskakujące, że różni kompilatory radzą sobie z inaczej.
Czy pierwsza droga jest wystarczająca tylko dla klga lub w innych przypadkach?
Oba wyrażenia "znaczenie i zachowanie są niezdefiniowane . W pewnym sensie nie można bezpiecznie stwierdzić, że albo wystarczy na nic. W empirycznym poczuciu tego, czy przy użyciu jednego lub innych głupców niektórzy kompilatory nie emitują ostrzeżeń, że inaczej byliby, a nadal powinni , emitują, że są, są, są i / lub będą Kompilatory, które obsługują niezdefiniowane zachowanie związane z obydwoma tymi wyrażeniami inaczej niż GCC i Clang.
* Wyjątkiem, gdy x
jest zadeklarowany za pomocą klasy pamięci register
, w którym to przypadku druga ekspresja ma niezdefiniowane zachowanie niezależnie od tego, czy x
ma dobrze zdefiniowany wartość.
Podobne pytania
Nowe pytania
c
C jest językiem programowania ogólnego przeznaczenia, używanym do programowania systemów (system operacyjny i systemy wbudowane), bibliotek, gier i wielu platform. Ten znacznik powinien być używany w przypadku ogólnych pytań dotyczących języka C, zgodnie z definicją w standardzie ISO 9899 (najnowsza wersja 9899: 2018, chyba że określono inaczej - również oznaczanie żądań dotyczących wersji za pomocą c89, c99, c11 itd.). C różni się od C ++ i nie należy go łączyć ze znacznikiem C ++ bez racjonalnego powodu.