Um ponteiro para um tipo incompleto pode estar incompleto?

9

Pode int (*)[]ser um tipo incompleto?

C 2018 6.2.5 1 diz:

Em vários pontos dentro de uma unidade de tradução, um tipo de objeto pode estar incompleto (sem informações suficientes para determinar o tamanho dos objetos desse tipo) ou completo (com informações suficientes).

Assim, parece que, se o tamanho de um tipo for conhecido, o tipo estará completo. 6.2.6.1 28 especifica que certos tipos de ponteiros devem ter os mesmos tamanhos (ponteiros voide caracteres, ponteiros para tipos compatíveis, ponteiros para estruturas e ponteiros para uniões), mas os ponteiros para outros tipos podem variar.

Em uma implementação C em que todos os ponteiros, ou todos os ponteiros para matrizes de int, têm o mesmo tamanho, o tamanho de int (*)[]é conhecido e, portanto, seria completo. Em uma implementação que, digamos, usa ponteiros diferentes para matrizes grandes, o tamanho não seria conhecido e, portanto, está incompleto.

Como MM aponta , uma estrutura não deve conter um membro com tipo incompleto, exceto um membro de matriz flexível final, de acordo com uma restrição em 6.7.2.1 3. Isso sugere que uma implementação com um tamanho de ponteiros deve aceitar struct { int (*p)[]; }enquanto uma implementação que tenha diferentes tamanhos para essas matrizes devem diagnosticar uma violação de restrição. (Isso, por sua vez, significa que tal declaração não faz parte do estritamente conforme C.)

Eric Postpischil
fonte
6.2.5 (p22) ajuda? (ou acrescenta mais confusão, permitindo que o tipo incompleto seja completado por declaração posterior?)
David C. Rankin
@ DavidC.Rankin Em 6.2.5 / 20, até é dito que ponteiros são sempre tipos completos
Christophe
@LanguageLawyer: Como isso seria relevante? A pergunta é "Existe um X que não é um Y?", Não "Existe um X que é um Y?"
Eric Postpischil 14/01
@LanguageLawyer: o fato de void *concluir mostra que um ponteiro para um tipo incompleto pode ser concluído. Não mostra se um ponteiro para um tipo incompleto pode ou não estar incompleto. Se alguém perguntasse “Um mamífero pode ser um elefante?”, Mostrar que “Um leão é um mamífero” não forneceria que um mamífero não possa ser um elefante. A pergunta pergunta se o conjunto X de ponteiros para o tipo incompleto pode conter um elemento incompleto. Mostrar que o conjunto X de ponteiros para o tipo incompleto contém um elemento que é concluído é irrelevante.
Eric Postpischil 15/01
@EricPostpischil Oops. Eu interpretei o título como "Um ponteiro para um tipo incompleto pode ser concluído ?"
Language Lawyer

Respostas:

3

Uma matriz de tamanho desconhecido está incompleta:

Um tipo de matriz de tamanho desconhecido é um tipo incompleto. É concluído, para um identificador desse tipo, especificando o tamanho em uma declaração posterior (com ligação interna ou externa).

O tipo, int (*)[]no entanto, não está incompleto: é um ponteiro de uma matriz de inttamanho desconhecido.
E um ponteiro tem um tamanho bem conhecido:

printf ("Size %d\n", sizeof(int (*)[]));

6.2.5 / 23: Um tipo tem tamanho constante conhecido se não estiver incompleto e não for um tipo de matriz de comprimento variável.

Além disso, você pode até tirar a referência dele, graças à semântica da matriz:

typedef int (*T)[];
...
int a[10];
for (int i=0; i<10; i++) a[i]=i;
T p=a;
for (int i=0; i<10; i++) printf ("%d ",(*p)[i]);
printf ("\n");

Editar

Além disso, um ponteiro é sempre um tipo completo. Está escrito preto no branco em 6.2.5 / 20:

Um tipo de ponteiro pode ser derivado de um tipo de função ou objeto, chamado de tipo referenciado. Um tipo de ponteiro descreve um objeto cujo valor fornece uma referência a uma entidade do tipo referenciado. Um tipo de ponteiro derivado do tipo referenciado T às vezes é chamado de '' ponteiro para T ''. A construção de um tipo de ponteiro a partir de um tipo referenciado é chamada '' derivação do tipo de ponteiro ''. Um tipo de ponteiro é um tipo de objeto completo.

Christophe
fonte
Eu acho que você resumiu e o gcc concorda. struct w / apontador para array incompleto é semelhante à pergunta original que iniciou a discussão.
David C. Rankin
Somente o último parágrafo é relevante. O exemplo printfmostra apenas que um ponteiro para uma matriz incompleta está completo na implementação em que foi executado, conforme declarado na pergunta - se não fosse o 6.2.5 20, citado no último parágrafo, ele pode falhar na compilação. 6.2.5 23 também não é relevante; nos diz que o tamanho é conhecido e constante, se estiver completo, e já sabemos que estar completo significa que o tamanho é conhecido.
Eric Postpischil 13/01
6.2.5 20 é interessante. Especulo que não se pretendia ter essa consequência, mas significa que todos os ponteiros para concluir tipos que têm o mesmo tipo quando incompletos devem ter o mesmo tamanho. Por exemplo, todos os ponteiros para matrizes intdevem ter o mesmo tamanho um do outro e todos os ponteiros para matrizes de um certo structtamanho devem ter o mesmo tamanho, embora talvez nem todos os ponteiros para matrizes de tipos diferentes structdevam ter o mesmo tamanho como um ao outro.
Eric Postpischil 13/01
11
@EricPostpischil talvez o texto "Da mesma forma, ponteiros para versões qualificadas ou não qualificadas de tipos compatíveis devem ter os mesmos requisitos de representação e alinhamento". deve ser interpretado para dizer que T(*)[]deve ter o mesmo tamanho que T(*)[5], uma vez que são tipos compatíveis e poderíamos adicionar ou remover qualificadores
MM
Permitir que tipos compatíveis tenham tamanhos diferentes levaria a um monte de problemas, provavelmente é um defeito que o padrão não o exclua explicitamente
MM