2012-03-20 18 views
47

Ho trovato questo codice su reddit. Avrei pensato che le conversioni di tipo avrebbero reso questo non valido.Perché è valido C

int a[3] = { { {1, 2}, {3, 4}, 5, 6 }, {7, 8}, {9}, 10 }; 

Su clang, ho un paio di avvertimenti su elementi eccessivi e bretelle in un inizializzatore scalare. Ma il contenuto di a è [1, 7, 9].

Questo è effettivamente legittimo, e se lo è, qualcuno potrebbe spiegare cosa sta succedendo esattamente?

+5

+1, molto interessante. – ApprenticeHacker

+4

Con gcc ricevo 24 avvisi. Grande domanda. Vivo e imparo :-) – gbulmer

+1

Yay gcc! Almeno ricevi un avvertimento. – boatcoder

risposta

28

Gli elementi in eccesso vengono semplicemente ignorati. Ci sono due parti di 6.7.8 Inizializzazione che ti interessano. Innanzitutto, dal paragrafo 17:

Ogni elenco di inizializzazione racchiuso presenta un oggetto corrente associato. Quando non sono presenti designazioni, i sottooggetti dell'oggetto corrente vengono inizializzati in base al tipo dell'oggetto corrente: gli elementi dell'array in ordine crescente di pedice, i membri della struttura in ordine di dichiarazione e il primo membro con nome di un sindacato.

Quello spiega perché ottieni 1, 7 e 9: l'oggetto corrente viene impostato da tali parentesi. Quindi sul motivo per cui non si preoccupa degli extra, dal paragrafo 20:

... solo gli inizializzatori sufficienti dalla lista vengono presi in considerazione per gli elementi oi membri del sottoaggregato o il primo membro del gruppo unione contenuta; eventuali rimanenti inizializzatori vengono lasciati per inizializzare l'elemento successivo o membro dell'aggregato di cui l'unione secondaria corrente o unione contenuta è una parte.

+0

Ma perché? E perché è valido passare elementi nidificati dove non ci sono tipi struct/union/class? – ams

+1

ti dispiacerebbe condividere l'url dello standard che stai citando? – dldnh

+0

[collegamento PDF.] (Http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf) –

2
int a[3] = { { {1, 2}, {3, 4}, 5, 6 }, {7, 8}, {9}, 10 }; 

non è valido.

E non è valido per le stesse ragioni int b[1] = {1, 2}; non è valido: a causa C99 dice

(C99, 6.7.8p1) "No initializer si adoperano per fornire un valore per un oggetto non contenuto all'interno dell'entità inizializzato ".

L'ultimo elemento 10 in a inizializzatori tenta di fornire un valore per un oggetto non contenuta all'interno dell'entità in fase di inizializzazione.

+0

Mi piacerebbe sentire un buon dibattito sulle diverse asserzioni fatte dal riferimento che hai citato, e il secondo riferimento citato da Carl. Sembra essere un chiaro conflitto all'interno degli standard, che probabilmente porterà a differenze nelle implementazioni del compilatore fino a quando non verrà risolto. +1 per indicare il diff. – ryyker

Problemi correlati