2010-10-07 30 views
1

Je veux prendre quelques champs de la structure de paquet en utilisant l'arithmétique de pointeur. Mais qu'est-ce qui ne va pas avec le code ci-dessous?
Dans la première condition je pense que si je vais 4 byte (2 court champ) du début du paquet je reçois tLow .Mais il ne donne pas la valeur attendue. En outre deuxième cas je veux obtenir le champ de données en allant 12 octets du début du paquet Quel est le problème avec mon idée?problème d'affectation de void *

struct packet{ 
     short len; 
     short field; 
     int tLow; 
     int tHigh; 
     void *data; 
} 

int main() 
{ 
    struct packet pack; 
    struct packet *pck; 

    pack.len=3; 
    pack.field=34; 
    pack.tLow=712; 
    pack.tHigh = 12903; 
    pack.data = "message"; 

    pck = &pack; 
    int *timeLow = (int *)pck + 4; // i want to get tLow 
    printf("Time Low :%d\n",*time); 

    char *msg = (char *)pck + 12 ;// want data 
    printf("Message :%s\n",msg); 

    return 0; 
} 
+2

J'espère que c'est un exercice d'apprentissage et non un code de production. C'est un excellent exercice, mais je ne veux jamais voir de vrai code comme celui-ci. –

+0

Vous voulez dire accéder à la méthode des membres struct avec le calcul d'octets ou d'autres choses? – Qxtrml

Répondre

3

Vous certainement mieux en utilisant la méthode classique

int *timeLow = &(pck->tLow); 

Compilateurs sont autorisés à insérer des octets de remplissage entre un membre d'une struct. Les règles pour ces octets de remplissage sont, au mieux, définies par l'implémentation ... vous devez donc consulter votre manuel d'implémentation pour savoir comment (et si) et combien d'octets sont insérés dans votre cas spécifique. A noter également le nombre d'octets de remplissage pourrait changer de compilation à la compilation avec des options différentes ou du compilateur compilateur (ordinateur à ordinateur, ...)

Vous pouvez essayer d'utiliser la C macro offsetof, mais pas assez:

size_t offset = offsetof(struct packet, tLow); 
/* make sure offset is a multiple of sizeof (int*) */ 
int *timeLow = (int*)pck + offset/sizeof (int*); 

ou, un peu moins laid en utilisant un plâtre à (char*)et copier le code d'autres réponses :-)

size_t offset = offsetof(struct packet, tLow); 
int *timeLow = (int*)((char*)pck + offset); 

Oh! et il manque un point-virgule dans votre source

+0

Comme vous l'avez mentionné, votre exemple de code pour 'offsetof' dépend du remplissage du compilateur afin de mettre' tLow' sur un offset qui est divisible par la taille de 'tLow'. Si le compilateur ne faisait pas de remplissage, le décalage serait indivisible. – rwong

+0

Ok je vais utiliser la méthode standard pour accéder aux membres struct.And j'ai réalisé mon erreur dans l'arithmétique du pointeur en traitant pck comme entier.Mais parfois opérations octets nécessaires et dans cette situation je vais utiliser la conversion pck en char et en faisant byte manipulation ou offsetof macro . – Qxtrml

1

lorsque vous écrivez

int *timeLow = (int *)pck + 4 

vous traitez 'PCK' comme pointeur int qui, selon votre système peut être 4 ou 8 octets. Ce ne sera pas correctement compensé dans le struct parce que vous dites alors à avoir un décalage de 4 int

au lieu que vous devez faire comme ce

int *timeLow = (int*)((short *)pck + 2); 
+1

ou (int *) ((unsigned char *) pck + 4) –

+0

merci, j'ai réalisé mon erreur en traitant pck comme entier. D'abord convertir en char puis en faisant le calcul de l'octet est la façon sûre je pense. – Qxtrml

+0

np, facile de faire le mal, fait moi-même. –

0

Shorts ne sont pas nécessairement 2 octets. Tout ce qui est spécifié est qu'ils sont inférieurs ou égaux à la taille de ints. Vous devriez probablement utiliser sizeof()

0

Ceci est faux: pack.data = "message"; Vous utilisez une mémoire non allouée.

Egalement ceci: int *timeLow = (int *)pck + 4; n'est pas garanti de fonctionner (l'alignement de structure varie entre les compilateurs et les systèmes).

+2

Non; la mémoire sur laquelle 'pack.data' pointe est le" message "littéral. C'est bon. Une tentative pour le changer serait un comportement indéfini, et copier une chaîne dans 'pack.data' serait mauvais. –

+0

vous avez raison, David. – vulkanino

2

Vous recherchez offsetof.

Votre code pourrait ressembler à ceci:

int *timeLow = (int*) ((char*)pck + offsetof(struct packet, tLow); 

et comme PMG a souligné,

int *timeLow = &(pck->tLow); 

est la manière canonique d'obtenir un pointeur sur un membre d'un struct.

Cette réponse a également apporté pointer arithmetics sur la table - que j'ai appris aujourd'hui grâce à pmg.

+0

@pmg, vraiment? Je ne peux pas voir comment. –

+0

Comme ça, vous voulez dire? http://www.cs.umd.edu/class/spring2003/cmsc311/Notes/BitOp/pointer.html –

+1

@pmg: le cast '(char *)' a la priorité sur l'addition du pointeur. http://www.difranco.net/cop2220/op-prec.htm Mais ouais, utilisez des parenthèses si confus. – rwong

2

Fondamentalement, vous comptez sur un comportement indéfini. Alignement de la structure, etc. Mais de toute façon ...

(int *) pck + 4. Avance le pointeur 4 * sizeof (int). Ceci est faux, nous voulons avancer par 1 si l'on suppose que le struct est emballé et sizeof (courte) == 2, donc ...

int *timeLow = (int *)pck + 1; // i want to get tLow 
printf("Time Low :%d\n",*timeLow); 

imprime le résultat correct. En ce qui concerne le message, vous devez faire quelques choses sales. Comme je suis sur x86_64, le compilateur a choisi de remplir le void * sur les limites de 8 octets, donc le décalage était de 16 au lieu de 12. 12

Nous recherchons essentiellement un pointeur vers un void *. Ainsi, le code ressemblera à ceci:

char **msg = (char**)((char *)pck + 16) ;// want data 
printf("Message :%s\n",*msg); 

JAMAIS écrire du code comme celui-ci, ce juste illustre un point.

+1

+1 pour le JAMAIS. Ne jamais dire jamais ... sauf si nécessaire :-) – pmg

+0

@pmg: ajouter 'k' à' (char *) 'décale l'adresse par' k * sizeof (char) ', c'est-à-dire le type d'élément, et' sizeof (char) 'donne 1 par définition. – rwong

+0

Oh! Je vois déjà des étoiles ... besoin de repos. merci rwong – pmg