Pregunta Caso utilizable de puntero a matriz con límites no especificados en C ++ (no en C)


Considera seguir el código:

int main() {
    int (*p)[]; // pointer to array with unspecified bounds

    int a[] = {1};
    int b[] = {1,2};

    p = &a; // works in C but not in C++
    p = &b; // works in C but not in C++

    return 0;
}

En C puro, puede asignar un puntero a este tipo de dirección de una matriz de cualquier dimensión. Pero en C ++ no puedes. Encontré un caso cuando el compilador permite asignar valor a dicho puntero:

struct C
{
    static int v[];
};

int main() 
{
    int (*p)[] = &C::v; // works in C++ if 'v' isn't defined (only declared)
    return 0;
}

Pero no pude encontrar ningún caso útil de este código.

¿Alguien puede dar un ejemplo útil (en C ++) de puntero a matriz con límites no especificados? ¿O solo queda vestigio de C?


32
2018-06-29 18:12


origen


Respuestas:


Tal puntero no puede participar en la aritmética del puntero, las cosas potencialmente útiles que aún se pueden hacer son obtener su tipo con decltype o reinterpret_cast a otro tipo de puntero o intptr_t. Esto es porque la sección 3.9p6 dice:

Un tipo de clase (como "class X") podría estar incompleto en un punto de una unidad de traducción y completarlo más tarde; el tipo"class X"es el mismo tipo en ambos puntos. El tipo declarado de un objeto de matriz puede ser una matriz de tipo de clase incompleta y, por lo tanto, incompleto; si el tipo de clase se completa más adelante en la unidad de traducción, el tipo de matriz se completa; en esos dos puntos es del mismo tipo. El tipo declarado de un objeto de matriz puede ser una matriz de tamaño desconocido y, por lo tanto, estar incompleto en un punto de una unidad de traducción y completarlo más tarde; los tipos de matriz en esos dos puntos ("matriz de límite desconocido de T"y" conjunto de N  T") son diferentes tipos. El tipo de un puntero a una matriz de tamaño desconocido, o de un tipo definido por una declaración typedef como una matriz de tamaño desconocido, no se puede completar.

5.3.1 dice:

Nota: indirección a través de un puntero a un tipo incompleto (que no sea cv  void) es válida. El valor l así obtenido se puede usar de manera limitada (para inicializar una referencia, por ejemplo); este lvalue no se debe convertir a un valor pr, ver 4.1.

Como el decaimiento de matriz a puntero se puede realizar en valores de matriz sin conversión previa a valor de r, el código dyp que queda en un comentario es correcto:

(*p)[i]

Regla relevante, de 4.2:

Un lvalue o rvalue de tipo 'array of N  T"o "matriz de límite desconocido de T" se puede convertir a un prvalue de tipo "puntero a T". El resultado es un puntero al primer elemento de la matriz.


12
2018-06-29 21:15



Creo que un compilador debería aceptarlo (independientemente de la configuración -O) porque otra unidad de compilación puede proporcionar una definición de estática. (Esta es quizás una desviación pragmática del estándar; no soy un experto en C ++). El fragmento publicado puede compilarse, pero está incompleto y no puede ejecutarse sin una definición del miembro estático.

Archivo c.h:

struct C {
    static int v[];
};

Archivo x.cpp

#include "c.h"
#include <iostream>
int main(){
    int (*p)[] = &C::v; // works in C++ if 'v' isn't defined (only declared)
    std::cout << *((int*)p) << std::endl; 
    return 0;
}

Archivo y.cpp

#include "c.h"
int C::v[3] = {1,2,3};

Compilado y enlazado usando (no se diga lo que es viejo) g ++ 4.3.3. Imprime 1.

Y: sí, sé que es un elenco en C.


2
2018-06-29 20:05