O índice de array e signedness argc
Pergunta
O href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1336.pdf" rel="nofollow noreferrer"> C padrão 5.1.2.2.1 programa de inicialização ) diz:
A função chamada na inicialização do programa é nomeado principal. [...]
Deve ser definida com um tipo de retorno de int e sem parâmetros:
int main(void) { /* ... */ }
ou com dois parâmetros [...] :
int main(int argc, char *argv[]) { /* ... */ }
E depois diz:
O valor de argc será não negativo.
- Por não deve
argc
ser definida como umaunsigned int
,argc
supostamente significa "contagem de argumento? - deve
argc
ser usado como um índice paraargv
?
Então, eu comecei a pensar se o padrão C diz algo sobre o tipo de índice da matriz. É assinado?
6.5.2.1 Matriz subscripting :
Uma das expressões terão Tipo ‘‘ ponteiro para tipo de objeto ’’, o outro expressão terá tipo inteiro , eo resultado tem tipo ‘‘ tipo ’’.
Ela não diz nada sobre a sua signedness (ou eu não encontrá-lo). É bastante comum ver códigos usando negativos variedade índices (array[-1]
), mas não é indefinido comportamento?
- índices de matriz deve ser assinado?
Solução
A razão para o int em main () é histórica - que sempre foi assim, desde muito antes da linguagem foi padronizada. A exigência de um índice de array é que ele está dentro dos limites da matriz (ou, em algumas circunstâncias, um após o final) -. Qualquer outra coisa é indefinido, de modo que o signedness é imaterial
Outras dicas
1) Sobre main () Tipo de argc: IMHO o padrão continua uma tradição muito antiga (mais de 30 anos), e agora ... é simplesmente tarde demais para as coisas mudam (Nota: na maioria dos sistemas nem o compilador, nem o vinculador, nem a CPU vai reclamar se "argc" está definido "sem sinal", mas você está fora do padrão!)
2) Na maioria das implementações argv [argc] é legal e é avaliada como nula. Na verdade, uma forma alternativa para encontrar o fim da lista de argumentos é iterar em argv de 0 terminação quando argv [i] é NULL.
3) aritmética Array / ponteiro com números negativos é legal, tanto quanto o intervalo de endereço a partir de (p-n) para p pertence à mesma objecto de memória. OU SEJA você pode ter
char array[100];
char *p;
p = &array[50];
p += -30; /* Now p points to array[20]. */
Este uso de aritmética de ponteiro é legal porque o ponteiro resultante ainda permanece dentro do objeto de memória original ( "array"). Na maioria dos sistema da aritmética de ponteiro pode ser usado para navegar na memória em violação desta regra, mas isso não é portátil, uma vez que é completamente dependente do sistema.
Em geral C, o "princípio da menor surpresa" implica que é preferível fazer uma variável assinado a menos que haja uma boa razão para que ele seja assinado. Isso ocorre porque as regras de promoção tipo pode levar a resultados inesperados quando você mistura assinados e não assinados valores: por exemplo, se argc
não estava assinado, então esta simples comparação levaria a resultados surpreendentes:
if (argc > -1)
(A -1
é promovido a unsigned int
, então o seu valor é convertido para UINT_MAX
, que é quase certamente maior do que argc
).
1) ARGC é uma contagem de argumento, mas para ser honesto, como você pode preceder um argumento antes do nome do programa que argv[0]
. Imagine um programa chamado foo
, você não pode simplesmente dizer args1 foo args2
como que não faz sentido, apesar da argc
sendo um tipo assinado de int
, ou seja, existe tal coisa como argv[-1]
que vai te 'args1' ...
2) O argc razão não é realmente um índice para o vetor de argumento (daí ' argv ') como o tempo de execução enfia o nome do programa executável para o zero'th offset, ou seja argv[0]
daí o argc
vai estar fora por 1.
3) índices de matriz, em termos de manipulação de ponteiros, fornecido você está dentro dos limites do bloco de memória onde o ponteiro está, usando subscritos matriz como negativo é legal, os índices de matriz são um atalho para os ponteiros, e não só isso, eles são comutativa eg
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';
Além disso, se você usar e manipular matrizes de tal forma que está fora dos limites - que é um comportamento indefinido e vai depender da implementação do tempo de execução sobre a forma de lidar com isso, talvez uma falha de segmentação, ou um programa acidente ....
4) Em ambientes * nix, alguns teriam um terceiro parâmetro fornecido para char **endvp
principal, novamente este é raramente usado no mundo Microsoft do DOS / Windows. Alguns nix implementações em tempo de execução *, por razões pré-histórico, você poderia passar as variáveis ??de ambiente através do tempo de execução.