7
votes

C méthode d'itération à travers les membres d'une structure comme un tableau?

Disons que j'ai une classe de vecteur: xxx pré>

Mais, je voudrais pouvoir y parcourir sans la convertir à un tableau de flotteurs. Bien qu'un casting soit acceptable dans ce cas, je suis curieux de voir si quelque chose le long des lignes de la fonctionnalité C ++ comme une fonctionnalité de C ++ est faisable dans le droit C. Par exemple, en C ++, depuis std :: vecteur code > a l'indice [] code> surchargé surchargé, je peux transmettre l'adresse de son premier index à une fonction de prise d'un vide * code>. p>

IE,

void do_something_with_pointer_to_mem( void* mem )
{
    // do stuff
}

int main( void )
{
    std::vector< float > v;

    // fill v with values here

    // pass to do_something_with_pointer_to_mem

    do_some_with_pointer_to_mem( &v[ 0 ] );

    return;
}


3 Réponses :


4
votes

Vous n'obtenez pas le sucre syntaxique de C ++, mais il est facile d'écrire la fonction que vous écririez en C ++ comme opérateur [].

 for (int i = 0; i < 3; i++) {
     printf("%f\n", get_vec3(v, i));
 }


2 commentaires

Serait-il avantageux de le faire statique , en ligne ou une combinaison des deux?


statique lui donnerait statique, plutôt que dans la portée mondiale (je ne comprends donc pas pourquoi vous pensez que ce serait bien). Inline serait une optimisation potentielle, mais vous auriez besoin de profiler.



24
votes

Si tous vos champs de structure sont du même type, vous pouvez utiliser un syndicat comme suit: xxx

de cette façon, vous pouvez accéder à chaque champ x, y ou z indépendamment ou itérer sur eux en utilisant le tableau Vect3_A. Cette solution n'a rien coûté en mémoire ou en calcul mais nous pouvons être un peu loin d'une solution C ++.


4 commentaires

Ceci est élégant. Souhaitez-vous expliquer exactement comment cela fonctionne, cependant? Je ne me suis jamais vraiment retrouvé à utiliser des syndicats auparavant; Bien que je sache assez bien C ++, je suis toujours assez nouveau à C.


Comportement non défini? "6.2.6.1.7: Lorsqu'une valeur est stockée dans un membre d'un objet de type syndical, les octets de la représentation de l'objet qui ne correspondent pas à ce membre mais correspondent à d'autres membres prennent des valeurs non spécifiées."


En fait, comme indiqué dans le commentaire ci-dessus, cela peut être dépendant du compilateur. Mais Afaik, la plupart des compilateurs feront une cartographie simple entre les octets des différents membres de l'Union. Donc, dans l'exemple ci-dessus Vect3_A [0] Maps sur X, Vect3_A [1] Maps sur Y et Vect3_A [2] Cartes à Z. Ceci est simplement une moyenne syntaxique d'accéder aux données de structure. L'instance GLOBALE VEC3 sera toujours 3 * Taille de taille (flottante). Une autre solution d'itération consiste simplement à utiliser l'incrémentation du pointeur. Par exemple & x + 1 correspondra à et y. Qui est fondamentalement la même chose que d'utiliser un tableau.


J'ai testé cela sur GCC X64 (Linux), si quelqu'un est intéressé à voir le code. C'est assez simple et je n'ai eu aucun problème :). Il n'y a vraiment pas de raison pragmatique de ce code à utiliser en C ++, que ce soit, puisque GLM prend presque soin de tout cela.



2
votes

Le problème en C avec ce que vous essayez de faire est que vous devez savoir comment passer à travers une structure (c'est-à-dire que vous devez connaître les types). La raison std :: vecteur code> fonctionne comme c'est parce qu'il utilise des modèles (un C ++ code> concept). Cela dit, cela dit, vous pourriez essayer quelque chose de légèrement différent de ce que vous avez suggéré. Si vous ne souhaitez pas utiliser de tableaux, vous pouvez stocker des types génériques. Cependant, lors de la récupération des données et de l'utiliser, l'utilisateur devra savoir quel type de données il s'attend à s'attendre. Ci-dessous évite les matrices (bien qu'une solution potentiellement plus propre existe dans les utiliser) et a une liste liée à la liste de quelque chose qui vous donne la presque même flexibilité de std :: vecteur code> Ceci est une liste liée avec les opérations O (n) code> pour tout (vous pouvez être intelligente et inverser la liste à réaliser, peut-être, o (1) code> insert, mais ceci est simplement par exemple)

#include <stdio.h>
#include <stdlib.h>
typedef struct _item3_t
{
  void *x, *y, *z;
  struct _item3_t* next;
} item3_t;

typedef struct
{
  item3_t* head;
} vec3_t;

void insert_vec3(vec3_t* vec, void* x, void* y, void* z)
{
  item3_t* item = NULL;
  item3_t* tmp  = NULL;
  int i = 0;
  if(vec == NULL)
    return;

  item = malloc(sizeof(item3_t));
  item->x = x;
  item->y = y;
  item->z = z;
  item->next = NULL;

  tmp = vec->head;
  if(tmp == NULL) { // First element
    vec->head = item;
  } else {
    while(tmp->next != NULL)
      tmp = item->next;
    tmp->next = item;
  }
}

// This is one method which simply relies on the generic method above
void insert_vec3_float(vec3_t* vec, float x, float y, float z)
{
  float* xv, *yv, *zv;
  if(vec == NULL)
    return;
  xv = malloc(sizeof(float));
  yv = malloc(sizeof(float));
  zv = malloc(sizeof(float));

  *xv = x;
  *yv = y;
  *zv = z;

  insert_vec3(vec, xv, yv, zv);
}

void init_vec3(vec3_t* vec)
{
  if(vec == NULL)
    return;
  vec->head = NULL;
}

void destroy_vec3(vec3_t* vec)
{
  item3_t* item = NULL, *next = NULL;
  if(vec == NULL)
    return;

  item = vec->head;
  while(item != NULL) {
    next = item->next;
    free(item->x);
    free(item->y);
    free(item->z);
    free(item);
    item = next;
  }
}

item3_t* vec3_get(vec3_t* vec, int idx)
{
  int i = 0;
  item3_t* item = NULL;
  if(vec == NULL)
    return NULL;
  item = vec->head;
  for(i = 0 ; i < idx && item != NULL ; ++i)
    item = item->next;
  return item;
}

void do_something(item3_t* item)
{
  if(item == NULL)
    return;
  float x = *((float*)item->x);
  float y = *((float*)item->y);
  float z = *((float*)item->z);

  // To do - something? Note, to manipulate the actual
  // values in the vector, you need to modify their values
  // at their mem addresses
}

int main()
{
  vec3_t vector;

  init_vec3(&vector);

  insert_vec3_float(&vector, 1.2, 2.3, 3.4);

  printf("%f %f %f\n", *((float*)vec3_get(&vector, 0)->x), *((float*)vec3_get(&vector, 0)->y), *((float*)vec3_get(&vector, 0)->z));

  do_something(vec3_get(&vector, 0));

  destroy_vec3(&vector);

  return 0;
}


0 commentaires