2009-08-06 10 views
29

Przeglądanie źródeł jądra Linuksa Znalazłem some piece of code, gdzie blok instrukcji otoczony nawiasem jest traktowany jako wyrażenie a la sepl (lub ML), czyli wyrażenie, której wartość jest wartością ostatniej instrukcji.Czy instrukcje złożone (bloki) są otoczone przez wyrażenia parens w ANSI C?

Na przykład:

int a = ({ 
    int i; 
    int t = 1; 
    for (i = 2; i<5; i++) { 
     t*=i; 
    } 
    t; 
}); 

Szukałem na ANSI C grammar próbuje dowiedzieć się, jak ten kawałek kodu, który mieści się w drzewie parsowania, ale nie zakończyły się sukcesem.

Czy ktokolwiek wie, czy to zachowanie jest wymagane przez standard, czy jest tylko cechą GCC?

Aktualizacja: Próbowałem z flagą -pedantic i kompilator teraz daje mi ostrzeżenie:

warning: ISO C forbids braced-groups within expressions 

Odpowiedz

28

To nazywa się „przygotowała grupa wewnątrz wyrazu”.

Nie jest dozwolone przez ANSI/ISO C ani C++, ale obsługuje go gcc.

+7

Możesz ukryć ostrzeżenie w GCC, wstawiając "__extension__" przed nawiasem otwierającym. – Flimm

28

To jest rozszerzenie gcc o nazwie statement expressions, można znaleźć pełną listę rozszerzeń C here. Jest to w rzeczywistości jeden z many gcc extensions used in the Linux kernel i wygląda na to, że nie jest on wyraźnie wymieniony w dokumencie.

Jak można zaobserwować ostatnie wyrażenie służy jako wartość wyrażenia, dokument mówi (podkr):

ostatnią rzeczą w instrukcji złożonej powinny być wyrazem następnie średnikiem ; wartość tego podwyrażenia służy jako wartość całego konstruktu. (W przypadku korzystania z innego rodzaju ostatniego wyciągu w nawiasach, konstrukt ma typ void, a tym samym skutecznie żadna wartość.)

Jedną z głównych korzyści byłoby zrobić bezpiecznych makra, które pozwoliłyby uniknąć wielokrotnego oceny argumentów z efektami ubocznymi. Podany przykład używa tego niebezpiecznego makra:

#define max(a,b) ((a) > (b) ? (a) : (b)) 

rozpoznawaną albo a lub b dwa razy i może być zapisane, aby wyeliminować ten problem za pomocą wyrażeń rachunku następująco:

#define maxint(a,b) \ 
    ({int _a = (a), _b = (b); _a > _b ? _a : _b; }) 

Uwaga, trzeba jawnie użyć int które mogą ustalona przy użyciu innego gcc rozszerzenie Typeof:

#define max(a,b) \ 
    ({ typeof (a) _a = (a), _b = (b); _a > _b ? _a : _b; }) 

Zauważ, że clang also supports typeof.

+0

Czy można napisać makro, które będzie bezpieczne, bez wyrażeń oświadczeń? – Flimm

+0

@Flimm Nie sądzę, ale nie uważam się za eksperta od makro. Unikałem ich tak bardzo, jak tylko potrafię, chociaż są pewne przypadki, których ciężko jest uniknąć, takich jak toczenie własnych twierdzeń. –

+0

@Flimm To zależy od tego, co chcesz zrobić w twoim makrze, w niektórych przypadkach z pewnością można napisać bezpieczne makro. Dla pełnej funkcjonalności 'max' nie będziesz miał żadnego znaczenia, bez względu na to, co robisz w standardowym C - problem polega na tym, że musisz znać typ argumentów lub musisz dwukrotnie ocenić jeden z nich (z których później jest problem z podejściem makro powyżej). – skyking