Question

Bonjour là je travaille sur une mission en C où je dois passer dans un type inconnu de paramètre en fonction.

Par exemple, supposons que je donne les résultats suivants:

int changeCount(void* element)
{
    element.Count = element.Count++;

    return 1;

}

La raison pour laquelle l'élément variable est vide parce qu'il ya 3 types de possibilités. Tous les trois ne sont cependant une variable membre nommée « Count ».

Quand je tente de compiler le code réel je l'ai écrit dans Eclipese, je reçois l'erreur suivante:

  

erreur: requête du membre « Count » dans   quelque chose pas une structure ou d'une union

Je devine ce qui se passe parce que le compilateur ne connaît pas le type de « élément » avant la main. Cependant, je ne vois pas pourquoi cela ne fonctionne pas.

Merci pour l'aide!

Était-ce utile?

La solution

Vous devez lancer le pointeur sur l'un de ces 3 types, puis l'utiliser. Quelque chose comme:

MyType* p = (MyType*)element;
p->count++;

Cependant, vous devez être sûr du type de l'objet que vous présentant comme coulée d'un objet à un mauvais type peut être dangereux.

Autres conseils

D'abord, vous passez un pointeur à vide, ce qui est une approche valable pour les types inconnus, mais vous devez être en passant des pointeurs vers vos différents types d'objets.

C est pas un langage dynamique des informations de type si symbolique est largement effacé avant que le temps d'exécution alors quand vous dites que vos trois types ont tous un membre Count cela ne fonctionne pas avec la conception de votre fonction.

La seule façon que vous pouvez accéder Count est, par votre paramètre void* au type de pointeur correct avant derefencing avec -> ou (*element).Count (à savoir non seulement .).

Sauf si vous comptez sur vos types ayant une configuration compatible (ce qui est susceptible de dépendre de l'implémentation), vous devrez également passer quelque chose qui aide votre fonction de déterminer la distribution correcte à effectuer. À ce stade, vous pouvez être mieux avec trois fonctions séparées et meilleure sécurité de type.

Vous devez jeter le type réel, mais vous pouvez obtenir des résultats inattendus dans les struct n'ont pas la propriété de comptage dans le même endroit.

typedef struct _A 
{
    int count;
    int x;
}A;
int changeCount(void* element)
{
    ((A*)element)->Count++;

    return 1;

}

Rappelez-vous aussi que si vous passez un pointeur vers une struct qui ressemble à vous suivre incrémente le champ x pas le nombre.

typedef struct _B 
{
    int x;      
    int count;

}B;

    B st;
    B* pst = &st;
    changeCount(pst);

Si l'élément .Count est du même type pour chacun de ces 3 types, vous pouvez également utiliser une macro. En supposant qu'il est int, vous pouvez faire ceci:

#define changeCount(a) _changeCount((a), &(a)->Count)

int _changeCount(void* element, int *count)
{
  (*count)++;
  return 1;
}

Cela fonctionne, car l'adresse a.Count sera résolu lorsque vous appelez la fonction, et non après (quand vous ne connaissez pas le type plus). Je suppose que vous avez le bon type lorsque vous appelez la fonction bien. Alors Sometype x; changeCount(x); fonctionnera, mais en passant quelque chose qui est déjà un (void*) ne sera pas.

De plus, votre element.Count = element.Count++; d'expression originale est plutôt bizarre. Si vous voulez incrémenter, utilisez element.Count++ ou element.Count = element.Count + 1.

utiliser un casting.

ClassName(element).count++

également votre element.Count = element.Count ++; ligne est redondant, il vous suffit de faire element.count ++ (qui incrémente la valeur par un)

Lors de la compilation, les rejets C [1] informations la plupart des types, laissant seulement les compensations. Ainsi, votre fonction compilerait à quelque chose comme ça, en pseudocode:


changeCount:
  assign *(*(stack_ptr + offset_element) + offset_Count) + 1
    to *(stack_ptr + offset_element) + offset_Count;
  assign 1 to return_value;
  pop

Le stack_ptr est l'emplacement du cadre de pile qui a été créé lorsque vous appelez ChangeCount, le offset_element est l'emplacement de l'argument de l'élément, par rapport à la stack_ptr, mais ce qui est offset_Count? Gardez à l'esprit, tout le compilateur connaît votre code est juste ce que vous avez montré dans votre exemple; élément est un pointeur générique, pas vraiment un pointeur sur quoi que ce soit. Vous devrez indiquer au compilateur quel élément pointe vers, par coulée ou de l'attribuer à une variable [2]:


typedef struct { int Count; } counted_t;
int changeCount(void* element)
{
    counted_t* counted = element;
    counted.Count++;
    return 1;
}

Cette fonction génère essentiellement le même code (pseudo) comme ci-dessus, mais le compilateur sait maintenant ce que le décalage du comte devrait être.

Vous mentionnez qu'il ya trois possibilités pour le type de quel élément pointe. Il y a deux façons de traiter que: soit un syndicat unique ou une structure « héritée ». Pour une utilisation de l'union distingue, par exemple, une structure avec un élément étant un enum identifier lequel des trois possibilités et un autre élément étant une union des trois structures possibles; c'est à peu près ce que les langues ML (OCaml, Haskell, etc.) appellent un type de données algébrique ou ce qu'est un syndicat en Pascal. Pour "l'héritage", vous pouvez utiliser des définitions de type:


typedef struct { counted_t counted; int i; } counted_int_t;
typedef struct { counted_t counted; double d; } counted_double_t;
typedef struct { counted_t counted; char* s; } counted_charptr_t;

Dans ce cas, vous pouvez utiliser la fonction ChangeCount ci-dessus et passer un pointeur vers un counted_int_t, counted_double_t ou counted_charptr_t.

Qu'est-ce qui se passe est que le compilateur exposera les trois structures avec l'élément de comptage dans les structures « descendantes » au même endroit tant que l'élément counted_t est d'abord . (Au moins, dans chaque compilateur que j'ai jamais utilisé et dans tous les bits de code que je l'ai vu. Je pense que cela fait dans la norme C à un moment donné, mais il est un langage tout à fait normal.)

[1] À l'exception des informations de débogage, si vous avez dit au compilateur d'émettre. Votre programme ne sera pas avoir accès à cette information, cependant, il ne serait pas utile dans ce cas.

[2] x ++ (post-incrémentation) opération incrémente la variable (bien, lvalue) qu 'il est appliqué à; l'affectation dans le code d'origine est inutile.

Ceci est exactement le problème:

  

Je devine ce qui se passe   parce que le compilateur ne connaît pas la   type de « élément » avant la main. pourtant   Je ne vois pas pourquoi cela ne fonctionne pas.

Appel des données de méthode ou député par son nom est généralement pas une caractéristique des langages statiquement typés.

Même un void * ne peut être fiable à un jeté T *, où T est un type, lorsque le pointeur est en fait un pointeur sur ce type.

En C ++, une possibilité est d'avoir les trois types héritent de la même classe basse virtuel X qui possède une méthode Count (à savoir un de ICountable d'interface). Puis, jetant à X * et en utilisant p->Count. Ce serait idiomatiques C ++ - toutes les classes implémentent la même interface et donc ils prennent en charge toute cette méthode. Ce serait une méthode langue prise en charge de type analogue à compter sur la même astuce des décalages struct indiqué dans la réponse de Tommy McGuire, ce qui rend les struct tous similaires par convention . Si vous deviez modifier les struct, ou le compilateur devait s'écarter de la norme pour la pose struct, vous seriez dans l'eau chaude.

Je ne peux pas empêcher de penser que cela est plutôt un problème de jouet, car la méthode est si simple, on généralement pas l'envelopper dans une fonction - on simplement appeler en ligne: T t; t.Count++;

.
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top