Indice de tableau et argc de signedness
Question
C-type (< strong> 5.1.2.2.1 démarrage du programme ) dit:
La fonction appelée au démarrage du programme est nommé principal. [...] Il est défini par une type de retour int et sans Paramètres:
int main(void) { /* ... */ }
ou avec deux paramètres [...] :
int main(int argc, char *argv[]) { /* ... */ }
Et dit plus tard:
La valeur de argc non négative.
- Pourquoi ne devrait pas
argc
être défini comme ununsigned int
, ce qui signifieargc
soi-disant «nombre d'arguments? - Si
argc
être utilisé comme un indice pourargv
?
Je commençais à me demander si la norme C dit quelque chose au sujet du type de l'index de tableau. Est-il signé?
6.5.2.1 souscriptage de tableau :
L'une des expressions doit avoir le type « « pointeur type d'objet » », l'autre expression a type entier , et le résultat est de type '' type .
Il ne dit rien au sujet de son signedness (ou je ne trouve pas). Il est assez fréquent de voir des codes en utilisant les indices de tableau négatifs (de array[-1]
), mais est-ce pas un comportement non défini?
- index de tableau non signé Faut-il?
La solution
La raison de l'int main () est historique - il a toujours été de cette façon, depuis longtemps avant que la langue a été normalisée. L'exigence d'un indice de tableau est qu'il est dans les limites du tableau (ou dans certaines circonstances, un après la fin) -. Quoi que ce soit est non défini d'autre, de sorte que le signedness est immatériel
Autres conseils
1) A propos principal () Type de argc: à mon humble avis la norme continue une tradition très ancienne (plus de 30 ans), et maintenant ... il est tout simplement trop tard pour changer les choses (REMARQUE: sur la plupart des systèmes ni le compilateur, ni l'éditeur de liens, ni la CPU se plaindront si « argc » est défini « non signé », mais vous êtes hors de la norme!)
2) Sur la plupart des implémentations argv [argc] est légal et évalue à NULL. En effet, une autre façon de trouver la fin de la liste des arguments est de itérer sur argv de 0 lorsque se termine argv [i] est NULL.
3) arithmétique Array / pointeur avec des nombres négatifs est légal dans la mesure où la plage d'adresses à partir de (p-n) à p appartient au même objet mémoire. C'EST À DIRE. vous pouvez avoir
char array[100];
char *p;
p = &array[50];
p += -30; /* Now p points to array[20]. */
Cette utilisation de l'arithmétique de pointeur est légal, car le pointeur résultant reste encore à l'intérieur de l'objet de mémoire d'origine ( « tableau »). Le système le plus l'arithmétique de pointeur peut être utilisé pour naviguer en mémoire en violation de cette règle, mais ce n'est pas portable car il est complètement dépendant du système.
En général en C, le « principe de moindre surprise » implique qu'il est préférable de faire une variable signée à moins qu'il y ait une bonne raison pour qu'il soit non signé. En effet, les règles de type promotion peuvent conduire à des résultats inattendus lorsque vous mélangez valeurs signées et non signées: par exemple, si argc
était non signée alors cette simple comparaison conduirait à des résultats surprenants:
if (argc > -1)
(Le -1
est promu unsigned int
, de sorte que sa valeur est convertie en UINT_MAX
, ce qui est presque certainement supérieure à argc
).
1) ARGC est un nombre d'arguments, mais pour être tout à fait honnête, comment pouvez-vous précédez un argument avant le nom du programme qui argv[0]
. Imaginez un programme appelé foo
, vous ne pouvez pas dire simplement args1 foo args2
que cela n'a pas de sens, en dépit de la argc
étant un type signé de int
, à savoir pas une telle chose comme argv[-1]
qui vous obtenez « args1 » ...
2) La raison argc est pas vraiment un indice au vecteur d'argument (d'où « argv ) comme exécution enfourne le nom du programme exécutable dans le zero'th offset, par exemple argv[0]
donc le argc
sera éteint par 1.
3) Les indices de tableau, en termes de manipulation de pointeur, fourni vous êtes dans les limites du bloc de mémoire où le pointeur est à l'aide des indices de tableau négatif est légal que les indices de tableau sont un raccourci pour les pointeurs, et non seulement, ils sont commutative par exemple
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';
Aussi, si vous utilisez et de les manipuler de telle manière qui est en dehors des limites - c'est un comportement non défini et dépendra de la mise en œuvre de l'exécution sur la façon de gérer, peut-être une erreur de segmentation, ou un programme accident ....
4) Dans les environnements * nix, certains ont un troisième paramètre fourni principal char **endvp
, encore une fois ce qui est rarement utilisé dans le monde Microsoft DOS / Windows. Certaines implémentations * nix d'exécution, pour des raisons pré-historiques, vous pourriez passer dans les variables d'environnement par l'exécution.