Quelle est la raison pour empêcher la cession à des tableaux?

J’ai essayé de google ceci et j’ai lu:

  • Pourquoi des tableaux du même type et de la même taille ne peuvent-ils pas être atsortingbués?
  • Assigner des tableaux
  • Assigne à array dans struct in c

Mais ils indiquent tous une évidence: vous ne pouvez pas affecter de tableaux, car la norme le dit. C’est excellent et tout, mais je veux savoir pourquoi la norme n’inclut pas la prise en charge de l’assignation à des tableaux. Le comité standard discute des choses en détail, et je serais surpris de ne jamais avoir discuté de la possibilité d’assigner des tableaux. En supposant qu’ils en aient discuté, ils doivent avoir des raisons de ne pas laisser les tableaux être assignés.

Je veux dire, nous pouvons mettre un tableau dans une structure et assigner à la structure juste bien:

struct wrapper { int array[2]; }; struct wrapper a = {{1, 2}}; struct wrapper b = {{3, 4}}; a = b; // legal 

Mais l’utilisation directe d’un tableau est interdite, même s’il accomplit effectivement la même chose:

 int a[2] = {1, 2}; int b[2] = {3, 4}; a = b; // Not legal 

Quelle est la justification du comité standard d’interdire l’atsortingbution à des tableaux?

    Comprenez que l’intention n’était pas de rendre les expressions de tableau non assignables; ce n’était pas le but 1 . Au lieu de cela, ce comportement découle d’une décision de conception que Ritchie a conçue pour simplifier la gestion des tableaux dans le compilateur, mais en contrepartie, elle a créé les expressions de tableaux “objects de seconde classe”; ils perdent leur “disposition” dans la plupart des contextes.

    Lisez cet article (en particulier la section intitulée “Embryonic C”) pour un peu d’arrière-plan; J’ai aussi une réponse plus détaillée ici .


    1. À l’exception possible de Perl ou de PHP 2 , la plupart des WTF en langage flagrant sont des accidents de conception ou le résultat de compromis; la plupart des langues ne sont pas délibérément conçues pour être stupides.

    2. Je ne fais que traîner un peu; Perl et PHP sont des problèmes simples.

    En C, affectation copie le contenu d’un object de taille fixe dans un autre object de taille fixe. Ceci est bien défini et assez simple à implémenter pour les types scalaires (entiers, nombres à virgule flottante, pointeurs, types complexes depuis C99). L’atsortingbution de structures est presque aussi simple; Les plus grandes peuvent nécessiter un appel à memcpy() ou équivalent, mais cela rest simple car la taille et l’alignement sont connus au moment de la compilation.

    Les tableaux sont une autre affaire. La plupart des objects de tableau ont des tailles qui ne sont pas déterminées avant l’exécution. Un bon exemple est argv . L’environnement d’exécution construit un tableau de caractères pour chaque argument de ligne de commande et un tableau de caractères char* contenant des pointeurs sur les arguments. Celles-ci sont mises à la disposition de main via argv , un caractère char** , et via les tableaux char[] alloués dynamicment auxquels pointent les éléments de argv .

    Les tableaux C sont des objects à part entière, mais ils ne sont généralement pas utilisés comme des objects. Au lieu de cela, leurs éléments sont accessibles via des pointeurs et le code passe d’un élément à l’autre à l’aide de l’arithmétique de pointeur.

    Les langues peuvent être conçues pour traiter les tableaux comme des objects de première classe, avec affectation, mais c’est compliqué. En tant que concepteur de langage, vous devez décider si un tableau de 10 entiers et un tableau de 20 entiers sont du même type. S’ils le sont, vous devez décider de ce qui se passe lorsque vous essayez d’assigner l’un à l’autre. Copie-t-il la plus petite taille? Cela provoque-t-il une exception d’exécution? Devez-vous append une opération slice pour pouvoir utiliser des sous-ensembles de tableaux?

    Si int[10] et int[20] sont des types distincts sans conversion implicite, les opérations sur les tableaux sont inflexibles (voir Pascal, par exemple).

    Toutes ces choses peuvent être définies (voir Ada), mais uniquement en définissant des constructions de niveau supérieur à ce qui est typique en C. Au lieu de cela, les concepteurs de C (principalement Dennis Ritchie) ont choisi de fournir des tableaux avec des opérations de bas niveau. Certes, cela est parfois peu pratique, mais c’est un cadre qui peut être utilisé pour implémenter toutes les opérations de tableau de niveau supérieur de tout autre langage.

    La réponse est simple: cela n’a jamais été permis avant que le comité n’intervienne (même l’assignation de struct a été jugée trop lourde) et, compte tenu du fait qu’il ya une décomposition en masortingce, cela aurait toutes sortes de conséquences intéressantes .

    Voyons ce qui changerait:

     int a[3], b[3], *c = b, *d = b; a = b; // Currently error, would assign elements a = c; // Currently error, might assign array of 3? c = a; // Currently pointer assignment with array decay c = d; // Currently pointer assignemnt 

    Ainsi, autoriser l’affectation de tableaux rendrait (jusqu’à) deux assignations actuellement interdites.

    Ce n’est pas le problème cependant, c’est que des expressions presque identiques auraient des résultats très différents.

    Cela devient particulièrement piquant si vous considérez que la notation de tableau dans les arguments de fonction est actuellement juste une notation différente pour les pointeurs.
    Si une assignation de tableau était introduite, cela deviendrait encore plus déroutant.
    Pas assez de gens ne sont pas complètement déconcertés par les choses telles qu’elles sont aujourd’hui …

     int g(int* x); // Function receiving pointer to int and returning int int f(int x[3]);// Currently the same. What afterwards? Change to value-copy? 

    La raison est fondamentalement historique. Même avant ISO C89, il y avait un C qui s’appelait “K & R” C, après Kernighan et Ritchie. Le langage a été conçu pour être suffisamment petit pour qu’un compilateur puisse tenir dans une mémoire extrêmement limitée (selon les normes actuelles) de 64 Ko.

    Ce langage n’autorisait pas l’assignation de tableaux. Si vous vouliez copier des tableaux de même taille, memcpy était là pour vos besoins. Ecrire une memcpy(a, b, sizeof a) au lieu de a = b n’est certainement pas une grosse complication. Il présente l’avantage supplémentaire de pouvoir être généralisé à des tableaux de tailles différentes et à des tranches de tableau.

    Il est intéressant de noter que la solution de contournement des affectations que vous avez mentionnée ne fonctionnait pas non plus dans K & R C. Vous memcpy affecter les membres un par un ou, encore une fois, utiliser memcpy . La première édition du langage de programmation C de K & R mentionne l’affectation de struct comme une fonction pour une implémentation future dans le langage. Ce qui a finalement eu lieu avec C89.

    C est écrit de manière à ce que l’adresse du premier élément soit calculée lors de l’évaluation de l’expression du tableau.

    Citant un extrait de cette réponse :

    C’est pourquoi vous ne pouvez pas faire quelque chose comme

     int a[N], b[N]; a = b; 

    parce que a et b évaluent tous deux les valeurs de pointeur dans ce contexte; c’est équivalent à écrire 3 = 4 . Rien dans la mémoire ne stocke l’adresse du premier élément du tableau. le compilateur le calcule simplement pendant la phase de traduction.

    Peut-être qu’il serait utile de tourner la question et de vous demander pourquoi vous voudriez jamais assigner des tableaux (ou des structures) au lieu d’utiliser des pointeurs? C’est beaucoup plus propre et plus facile à comprendre (du moins si vous avez assimilé le zen de C), et cela a l’avantage de ne pas cacher le fait que beaucoup de travail est caché sous la “simple” affectation de tableaux de plusieurs mégaoctets.