2010-03-14 11 views
6

Il C standard (5.1.2.2.1 all'avvio del programma) dice:di Array indice e argc signedness

La funzione chiamata all'avvio del programma prende il nome principale. [...]
Essa è definita con un tipo ritorno di int e senza parametri:
int main(void) { /* ... */ }

o con due parametri [...]:
int main(int argc, char *argv[]) { /* ... */ }

E poi dice:

Il valore di argc deve essere non negativo.

  • Perché non dovrebberoargc essere definito come un unsigned int, argc suppone che significa 'numero di argomenti'?
  • È necessario utilizzare argc come indice per argv?

Così ho iniziato a chiedermi se lo standard C dice qualcosa sul tipo di indice dell'array. È firmato?

6.5.2.1 Array indicizzazione di:

Una delle espressioni avranno tipo '' puntatore al tipo di oggetto '', l'altra espressione ha intero tipo, e il risultato ha tipo '' tipo ''.

Non dice nulla sulla sua firma (o non l'ho trovato). È piuttosto comune vedere codici che utilizzano indici di array negativi (array[-1]) ma non è un comportamento non definito?

  • Gli indici dell'array devono essere senza segno?
+0

Basta dichiararlo non firmato, non accadrà nulla di male. In realtà è chiamato con 3 argomenti, è possibile aggiungere char * env []. –

+0

@nobugz, sì, so che non accadrà nulla di brutto, mi stavo chiedendo perché 'argc' è firmato secondo lo standard. 'char * envp []' dipende dalla piattaforma e 'char * apple []' è su MacOSX/Darwin. –

+0

Questa domanda è un duplicato di http: // StackOverflow.it/questions/1773897/why-is-argc-an-int-piuttosto-than-an-unsigned-int – caf

risposta

6

Il motivo per l'int in main() è storico, è sempre stato così, molto prima che la lingua fosse standardizzata. Il requisito di un indice di array è che si trova entro i limiti dell'array (o in alcune circostanze, uno dopo la fine) - qualsiasi altra cosa non è definita, quindi la signness è irrilevante.

3

1) Informazioni su main() argc type: IMHO lo standard continua una tradizione molto antica (più di 30 anni!), E ora ... è semplicemente troppo tardi per cambiare le cose (NOTA: sulla maggior parte dei sistemi né sul compilatore , né il linker, né la CPU si lamenteranno se "argc" è definito "unsigned", ma tu sei fuori dallo standard!)

2) Sulla maggior parte delle implementazioni argv [argc] è legale e viene valutato su NULL. In effetti, un modo alternativo per trovare la fine dell'elenco degli argomenti è di eseguire iterazione su argv da 0 che termina quando argv [i] è NULL.

3) L'aritmetica di array/puntatore con numeri negativi è legale fino a quando l'intervallo di indirizzi da (p-n) a p appartiene allo stesso oggetto di memoria. OSSIA si può avere

char array[100]; 
char *p; 

p = &array[50]; 
p += -30; /* Now p points to array[20]. */ 

Questo utilizzo di puntatori è legale perché il puntatore risultante rimane ancora dentro l'oggetto di memoria originale ("allineamento"). Sulla maggior parte del sistema, l'aritmetica del puntatore può essere utilizzata per navigare in memoria in violazione di questa regola, ma NON è portabile poiché è completamente dipendente dal sistema.

+2

Avendo argv [argc] NULL è richiesto dallo standard. – AProgrammer

-2

1) Argc è un argomento conteggio, ma per essere onesti, come si può anteporre un argomento prima del nome del programma che è argv[0]. Immaginate un programma chiamato foo, non si può semplicemente dire args1 foo args2 come che è privo di significato, nonostante la argc essere un tipo di firma int, vale a dire una cosa come argv[-1] che vi porterà 'args1' ...

2) La ragione argc non è realmente un indice al vettore argomento (da qui 'argv') come runtime infila il nome del programma eseguibile nella zero'th di offset, cioè argv[0] quindi la argc sarà off di 1.

3) Indici di matrice, in termini di manipolazione puntatore, fornito ci si trova all'interno dei limiti del blocco di memoria a cui si trova il puntatore, utilizzando gli indici di array come negativo è legale poiché gli indici di array sono una scorciatoia per i puntatori e non solo, sono commutativi per es.

 
char v[100]; 
char *p = &v[0]; 

You can do this: 

p[55] = 'a'; 

Which is the same as 

*(p + 55) = 'a'; 

You can even do this: 

p = &v[55]; 

p[-10] = 'b' /* This will stuff 'b' into 45'th offset! */ 

Which is the same as 

*(p - 10) = 'b'; 

Anche se si utilizza array e di manipolarli in modo tale che è al di fuori dei confini - che è un comportamento indefinito e dipenderà l'attuazione della fase di esecuzione su come gestire la cosa, forse un errore di segmentazione , o un crash del programma ....

4) In ambienti * nix, alcuni avrebbero un terzo parametro fornito al principale char **endvp, anche questo è usato raramente nel mondo Microsoft di DOS/Windows. Alcune implementazioni run-time * nix, per ragioni pre-storiche, è possibile passare le variabili di ambiente tramite il tempo di esecuzione.

+0

1) Ho chiesto perché 'argc' non è senza segno nello standard, non se potessi usare indici negativi. 2) La mia seconda domanda era la relazione tra la signness di 'argc' e la signness di un indice dell'array (parametro aka operator []). 4) Lo so, ma non è scritto nello standard. –

3

In generale in C, il "principio di minima sorpresa" implica che è preferibile rendere una variabile firmata a meno che non vi sia una buona ragione per non firmarla. Questo perché le regole tipo di promozione può portare a risultati imprevisti quando si mescolano firmato e valori senza segno: per esempio, se argc era firmato allora questo semplice confronto porterebbe a risultati sorprendenti:

if (argc > -1) 

(Il -1 è promosso a unsigned int, quindi il suo valore viene convertito in UINT_MAX, che è quasi certamente maggiore di argc).

+0

Questo è un modo interessante di spiegarlo. –

Problemi correlati