Itération sur même type struct membres en C
Est-il possible d'effectuer une itération d'une structure C, où tous les membres sont de même type, à l'aide d'un pointeur. Voici un exemple de code qui ne compile pas:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int mem1 ;
int mem2 ;
int mem3 ;
int mem4 ;
} foo ;
void my_func( foo* data )
{
int i ;
int* tmp = data ; //This line is the problem
for( i = 0; i < 4; ++i )
{
++tmp ;
printf( "%d\n", *tmp ) ;
}
}
int main()
{
foo my_foo ;
//
my_foo.mem1 = 0 ;
my_foo.mem2 = 1 ;
my_foo.mem3 = 2 ;
my_foo.mem4 = 3 ;
//
my_func( &my_foo ) ;
return 0 ;
}
Les membres de truc devrait être aligné dans la mémoire pour être l'un après l'autre, en supposant que votre compilateur/kernel n'essaie pas de fournir de protection de la pile de débordement de la mémoire tampon.
Donc ma question est:
Comment puis-je effectuer une itération sur les membres d'une structure C qui sont du même type.
Avez-vous essayé avec un plâtre, comme
David, avec la dernière mise à jour, le code fonctionne maintenant. Cette cession génère une fonte avertissement du compilateur. J'espérais qu'il y a un plus "élégant" de la solution.
Selon le langage C spécification, il n'est pas nécessaire que les champs de la structure sont les unes à côté des autres dans la mémoire; les compilateurs sont autorisés à insérer le remplissage entre les membres de champ. Si vous voulez itération, utiliser un tableau.
int * tmp = (int *)data'
? Quel message d'erreur avez-vous l'obtenir?David, avec la dernière mise à jour, le code fonctionne maintenant. Cette cession génère une fonte avertissement du compilateur. J'espérais qu'il y a un plus "élégant" de la solution.
Selon le langage C spécification, il n'est pas nécessaire que les champs de la structure sont les unes à côté des autres dans la mémoire; les compilateurs sont autorisés à insérer le remplissage entre les membres de champ. Si vous voulez itération, utiliser un tableau.
OriginalL'auteur Misha M | 2009-12-08
Vous devez vous connecter pour publier un commentaire.
Le plus simple serait de créer un syndicat, une partie qui contient chacun de ses membres individuellement et une partie qui contient un tableau. Je ne suis pas sûr si la plate-forme dépendant de rembourrage peut interférer avec l'alignement.
Comme l'a souligné ci-dessous, alors que cela fonctionne avec de nombreux compilateurs et des plates-formes, il peut échouer sur les autres. Veuillez faire vos responsables d'une faveur et d'écrire des tests unitaires pour cette itération, lorsqu'elle tombe sur un étrange système un jour, il sera immédiatement évident.
Je suis d'accord, à tout le moins, quelque chose comme
assert((void*)&my_foo.s.mem4 == (void*)&my_foo.a.mem[3]);
emk, déjà fait 🙂 Mark, merci pour l'exemple.
OriginalL'auteur Mark Ransom
La plupart des tentatives à l'aide d'une union avec un tableau de données sont sujettes à l'échec. Elles résistent à une chance décente de travail aussi longtemps que vous ne l'utilisez int s, mais pour d'autres, surtout les plus petits, les types, ils sont susceptibles de ne pas assez souvent car le compilateur ne peut (et surtout avec les petits types souvent) ajouter le remplissage entre les membres d'une
struct
, mais n'est pas autorisé à le faire avec des éléments d'un tableau).C ne, cependant, ont un
offsetof()
macro que vous pouvez utiliser. Il donne le décalage d'un élément dans unestruct
, de sorte que vous pouvez créer un tableau de décalages, puis (avec un peu de soin dans la coulée de), vous pouvez ajouter un décalage à l'adresse de la structure pour obtenir l'adresse du membre. Les soins dans le casting, c'est parce que le décalage en octets, de sorte que vous besoin de jeter l'adresse de l'struct
àchar *
, puis ajouter le décalage, alors jetez le résultat à la catégorie de membre (int
dans votre cas).Jerry, merci. Je vais étudier offsetof(). Cela ne sonne comme la meilleure solution, puis à l'aide d'un syndicat.
OriginalL'auteur Jerry Coffin
De la langue du point de vue: vous ne pouvez pas. les données les membres de cette structure ne sont pas... euh.. "iteratible" en C, peu importe s'ils sont de même type ou de types différents.
Utiliser un tableau au lieu d'un tas de membres indépendants.
La langue, tel que défini, ne soins si vous avez un tableau ou une structure. Vous pouvez parcourir un tableau, mais pas une struct.
OriginalL'auteur AnT
Vous pouvez également utiliser un sans nom de l'union/struct:
Cela pourrait ne pas fonctionner sur certains compilateurs, int ce cas, vous aurez à explicitily nom de l'union et de la structure à l'intérieur de
foo
,OriginalL'auteur Andreas Brinck
Comme vous le dites, vous devez être prudent de l'alignement et de la mémoire d'autres problèmes d'implantation. Vous devriez être bien de le faire avec
int
s bien.Mais je m'interroge sur le degré de lisibilité de ce serait faire de votre code.
Incidemment,
Je ne pense pas qu'est-ce que vous pensez que cela fonctionne, mais je ne suis pas entièrement sûr de ce que vous voulez qu'il fasse. Utilisation
++tmp;
si vous voulez étape à l'autreint
membre de la mêmefoo
objet.J'ai essayé cette approche antérieure, mais l'obtention de l'adresse du premier membre n'a pas fonctionné non plus. L'adresse qu'il a continué de faire était mal.
Dave, ++tmp ne fonctionnera pas pour toutes les architectures, d'où l'utilisation de sizeof. Si vous êtes de droite, qui ne fonctionne pas, soit, sizeof(toto) doit être sizeof(int). Grâce Fixe en question
Je ne suis toujours pas sûr que c'est correct. Pourquoi
i * sizeof(int)
?encore une fois, pourquoi ++tmp ne pas fonctionner pour toutes les architectures? Je pense qu'il faut avancer tmp par la taille de la chose, c'points. Je crois que c'est la partie de la norme, si quelqu'un peut point à la partie de la norme qui définit ce, qui pourrait l'aider.
OriginalL'auteur dave4420
Voici une autre approche; je n'ai jamais eu de raison de le faire, mais il a l'avantage de ne pas coucher en place de la structure de la définition. Créer un tableau de pointeurs sur des membres qui vous intéresse, puis itérer sur ce tableau:
De cette façon, vous n'avez pas à vous soucier des problèmes d'alignement mordre, vous, et vous pouvez arbitrairement ordre de la façon dont vous souhaitez effectuer une itération sur les membres (par exemple, vous pouvez commander de sorte que le pied est "mem4, mem3, mem2, mem1").
OriginalL'auteur John Bode
Vous devriez être en mesure de lancer les foo pointeur vers un pointeur de int.
Une solution plus propre serait de déclarer foo comme suit.
Parcourir le tableau int.
Vous pourriez aller pour créer des fonctions de membre de l'accès et/ou de manipuler le tableau int.
OriginalL'auteur William Bell