Pergunta

Em C. 1.3 de o C++ É (de 2003.É em C++11 É, também), a norma aponta uma diferença entre a ISO do C e C++;ou seja, para

char arr[100];

sizeof(0, arr) retorna sizeof(char*) em C, mas 100 em C++.

Eu posso encontrar nenhuma documentação para sizeof tomar dois argumentos.O óbvio reversão é o operador da vírgula, mas eu não penso assim: sizeof(arr) em C é 100; sizeof(0, arr) é sizeof(char*).Ambos sizeof(0, arr) e sizeof(arr) são 100 em C++.

Eu posso estar ausente o ponto o É neste contexto.Alguém pode me ajudar?Isso é semelhante a uma questão discutida em 09, mas ninguém que se refere o É, e eu não acho a resposta correta foi dada.


Editar:Na verdade, o É falar sobre o operador da vírgula.Então, por alguma razão, (0, arr) retorna um char* em C, mas um char[100] em C++.Por quê?

Foi útil?

Solução

Em C, então, a matriz está decaindo para um ponteiro, por causa da especificação diferente do operador vírgula em relação a rvalues e lvalues (não é o único lugar onde essa diferença pode ser encontrada).Em C ++, a matriz permanece uma matriz, produzindo o resultado correto.

Outras dicas

Em C, o operador vírgula não produz um lvalue, conseqüentemente o array arr que é um lvalue decai em um tipo de ponteiro que é um rvalue (neste caso). Portanto, sizeof(0,arr) torna-se equivalente a sizeof(char*), devido à conversão de lvalue-para-rvalue .

Mas em C ++, o operador vírgula produz um lvalue. Não há conversão de lvalue-para-rvalue . Portanto, sizeof(0,arr) permanece o mesmo, o que é equivalente a sizeof(char[100]).

A propósito, sizeof não é uma função, é um operador. Portanto, o seguinte é C ++ completamente válido (e C, se você imaginar printf em vez de cout):

int a[100], b[200], c[300], d[400];
cout << sizeof(a,b,c,d) << endl;

Demo: http://www.ideone.com/CtEhn

Você pode pensar que passei 4 operandos para sizeof, mas isso está errado. sizeof opera no resultado dos operadores vírgula. E é por causa dos muitos operadores de vírgula que você vê muitos operandos.

4 operandos com 3 operadores vírgulas; assim como em 1+2+3+4, existem 3 operadores, 4 operandos.

O acima é equivalente ao seguinte (válido em C ++ 0x):

auto & result = (a,b,c,d); //first all comma operators operate on the operands.
cout << sizeof (result) << endl; //sizeof operates on the result

Demo: http://www.ideone.com/07VNf

Portanto, é o operador vírgula que faz você sentir que existem muitos argumentos . Aqui, vírgula é um operador, mas na chamada de função, vírgula NÃO é um operador, é simplesmente um separador de argumento.

function(a,b,c,d); //here comma acts a separator, not operator.

Portanto, sizeof(a,b,c,d) opera no tipo do resultado dos operadores ,, exatamente da mesma forma, sizeof(1+2+3+4) opera no tipo do resultado dos operadores +.

Observe também que você não pode escrever sizeof(int, char, short), precisamente porque o operador vírgula não pode operar em tipos . Ele opera apenas em valor . Acho que sizeof é o único operador em C e C ++, que pode operar em tipos também. Em C ++, há mais um operador que pode operar em tipos . Seu nome é typeid.

Ele é um operador da vírgula.E a diferença de que você está falando não tem absolutamente nada a ver com sizeof.A diferença está realmente no lvalue-para-rvalue, matriz-para-ponteiro e similares decadência comportamentos entre as linguagens C e C++.

A linguagem C é bastante trigger-happy, a este respeito:matrizes de decadência para ponteiros praticamente imediatamente (com a exceção de muito poucos contextos específicos), é por isso que o resultado de 0, arr a expressão foi char * escreva.É equivalente a 0, (char *) arr.

Na linguagem C++ matrizes de preservar a eles "arrayness" muito mais tempo.Quando usada no contexto de , operador de matrizes não decaimento para ponteiros (e lvalues não decaimento de rvalues), é por isso que no C++ o tipo de 0, arr a expressão é ainda char[100].

Isto é o que explica a diferença no sizeof comportamento no exemplo. ?: o operador é outro exemplo de um operador que demonstra a mesma diferença em decadência comportamento, i.é. sizeof(0 ? arr : arr) vai lhe dar resultados diferentes em C e C++.Basicamente, tudo o que decorre do fato de que os operadores de C não costumam preservar a lvalueness de seus operandos.Um monte de operadores pode ser usado para demonstrar esse comportamento.

Este não é um sizeof com dois argumentos.sizeof é um operador, não uma função.

Considere que (0, arr) é uma expressão que usa o operador vírgula e todo o resto se encaixa.

sizeof não aceita dois argumentos. Mas também não é uma função, então o (...) não delimita argumentos de função, eles são apenas um parte opcional da sintaxe e reforça o agrupamento. Quando você escreve sizeof(0, arr), o argumento para sizeof é a única expressão 0, arr. Uma única expressão com um operador vírgula, que avalia o expressão à esquerda da vírgula, joga fora seu valor (mas não seu efeitos colaterais) e avalia a expressão à direita da vírgula, e usa seu valor como o valor da expressão completa.

Não tenho certeza sobre C, mas isso pode ser uma diferença entre o langauges. Em C ++, a conversão de matriz em ponteiro não ocorre a menos que é necessário; em C, se bem me lembro, o padrão diz que sempre ocorre, exceto em certos contextos. Incluindo como o operador de sizeof. Neste caso, uma vez que o operador vírgula não têm restrições com relação aos tipos de seus operandos, o a conversão de matriz em ponteiro não ocorre em C ++. Em C, um operatand do operador vírgula não está listado nas exceções, então o a conversão de matriz em ponteiro ocorre. (Neste caso, a matriz é um operando do operador vírgula, e não do sizeof.)

A melhor maneira de ver o que pode estar acontecendo aqui é examinar a gramática do padrão. Se olharmos para o rascunho da seção padrão C99 6.5.3 Operadores unários parágrafo 1 , podemos ver que a gramática para sizeof é:

sizeof unary-expression
sizeof ( type-name )

Portanto, o segundo não se aplica, mas como o sizeof unary-expression se aplica neste caso? Se olharmos para a seção A.2.1 Expressões do padrão de rascunho e trabalharmos com a gramática da seguinte maneira:

unary-expression -> postfix-expression -> primary-expression -> ( expression )

obtemos os parênteses em torno de uma expressão e agora só temos que olhar para a gramática do operador vírgula da seção 6.5.17 Operador vírgula e nós vemos:

expression:
  assignment-expression
  expression , assignment-expression

Portanto, agora temos:

sizeof( expression , assignment-expression )
                   ^
                   |
                   comma operator

tanto a expressão quanto a expressão de atribuição podem nos levar à expressão primária , que tem a seguinte gramática:

primary-expression:
  identifier
  constant
  string-literal
  ( expression )

e 0 é uma constante e arr é um identificador , portanto temos:

 sizeof( constant , identifier )

Então, o que o operador vírgula faz aqui? A seção 6.5.17 parágrafo 2 diz:

O operando esquerdo de um operador vírgula é avaliado como uma expressão vazia; existe um ponto de sequência após sua avaliação. Em seguida, o operando certo é avaliado; o resultado tem seu tipo e valor. 97)

uma vez que o operador vírgula não é uma das exceções em que um array não é convertido em um ponteiro, ele produz um ponteiro ( isso é coberto na seção 6.3.2.1 Lvalues, arrays e designadores de função ) o que significa que acabamos com:

sizeof( char * )

Em C ++ a gramática é muito semelhante, então terminamos no mesmo lugar, mas os operadores de vírgula funcionam de forma diferente. O rascunho da seção padrão C ++ 5.18 Operador vírgula diz:

[...] O tipo e o valor do resultado são o tipo e o valor do operando certo; o resultado é da mesma categoria de valor de seu operando certo [...]

A conversão de

assim e matriz para ponteiro não é necessária e assim terminamos com:

sizeof( char[100] ) 

Como vários já disseram, e quero adicionar apenas uma coisa, sizeof é um operador que recebe uma expressão ou uma expressão de conversão. Por esse motivo, adquiri o hábito de escrever parênteses em um tamanho de apenas se for uma expressão de elenco.

 char *arr;
 struct xxx { ... } v;

Vou escrever

sizeof arr 
sizeof v

mas

sizeof (struct xxx)       /* Note the space after the sizeof, it's important */
sizeof (char *)

Eu faço o mesmo com return sem parênteses, pois não é uma chamada de função, e se eu colocar parênteses, é porque a expressão a seguir precisa deles.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top