34 votes

Cas utilisable d'un pointeur vers un tableau avec des limites non spécifiées en C ++ (pas en C)

Considérons le code suivant:

 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 pur, vous pouvez affecter un pointeur à ce type d'adresse d'un tableau de toute dimension. Mais en C ++, vous ne pouvez pas. J'ai trouvé un cas où le compilateur permet d'attribuer une valeur à un tel pointeur:

 struct C
{
    static int v[];
};

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

Mais n'a pu trouver aucun cas utile de ce code.

Quelqu'un peut-il donner un exemple utile (en C ++) d'un pointeur sur un tableau avec des limites non spécifiées? Ou est-ce seulement un vestige de C?

13voto

Ben Voigt Points 151460

Tel un pointeur ne peut pas participer à l'arithmétique des pointeurs, potentiellement utile des choses qui peut encore être fait pour obtenir son type avec decltype ou reinterpret_cast à un autre type de pointeur ou intptr_t. C'est en raison de l'article 3.9p6 dit:

Un type de classe (comme "class X") peuvent être incomplètes à un moment donné dans une unité de traduction et de compléter plus tard; le type "class X" est du même type sur les deux points. Le type déclaré de l'objet de tableau pourrait être un tableau de classe incomplète et donc incomplète; si le type de classe est terminée plus tard dans l'unité de traduction, le type du tableau se complète; le type du tableau de ces deux points est le même type. Le type déclaré de l'objet de tableau pourrait être un tableau de taille inconnue et, par conséquent, être incomplètes à un moment donné dans une unité de traduction et de compléter plus tard; le tableau des types de ces deux points ("tableau d'inconnu lié d' T" et "tableau d' N T") sont de types différents. Le type d'un pointeur de tableau de taille inconnue, ou d'un type défini par un typedef, la déclaration doit être un tableau de taille inconnue, ne peut pas être terminée.

5.3.1 dit:

Remarque: indirection par l'intermédiaire d'un pointeur vers un type incomplète (autres que cv void) est valable. La lvalue ainsi obtenu peut être utilisé de façon limitée (pour initialiser une référence, par exemple); ce lvalue ne doit pas être converti en prvalue, voir 4.1.

Depuis le tableau de pointeur de décomposition peut être réalisée sur la matrice de lvalues sans l'accord de conversion de rvalue, le code de la dpj gauche dans un commentaire est correct:

(*p)[i]

Règle pertinente, à partir de 4.2:

Une lvalue ou rvalue de type " tableau de N T" ou "tableau de l'inconnu lié d' T" peut être converti en prvalue de type "pointeur vers T". Le résultat est un pointeur vers le premier élément du tableau.

3voto

laune Points 8921

Je pense qu'un compilateur doit l'accepter (indépendamment de l'-O réglage) parce que la définition de la statique peut être fournie par une autre unité de compilation. (C'est peut-être un pragmatique déviation de la norme, - je ne suis pas une C++ expert.) Posté le fragment de code peut être compilé, mais il est incomplet et ne peut pas être mis à exécution sans une définition du membre statique.

Fichier c.h:

struct C {
    static int v[];
};

Fichier 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;
}

Fichier y.cpp

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

Compilé et lié à l'aide de (ne-dis-moi-c'est-vieille) g++ 4.3.3. Imprime 1.

Et: oui, je sais que c'est un C cast.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X