2010-09-23 6 views
1

De jmorecfg.h:alignement du pointeur dans libjpeg

#define PACK_TWO_PIXELS(l,r) ((r<<16) | l) 
#define PACK_NEED_ALIGNMENT(ptr) (((int)(ptr))&3) 
#define WRITE_TWO_PIXELS(addr, pixels) do {  \ 
     ((INT16*)(addr))[0] = (pixels);  \ 
     ((INT16*)(addr))[1] = (pixels)>>16; \ 
    } while(0) 
#define WRITE_TWO_ALIGNED_PIXELS(addr, pixels) ((*(INT32*)(addr)) = pixels 

Quelqu'un peut-il expliquer la différence entre WRITE_TWO_PIXELS et WRITE_TWO_ALIGNED_PIXELS? Si les pixels sont une pile allouée uint32_t et addr & 3 == 0, ne devraient-ils pas être équivalents?

Merci.

+0

J'ai édité mon exemple. veuillez vérifier à nouveau. Je suis désolé pour l'erreur. – Donotalo

Répondre

2

WRITE_TWO_PIXELS et WRITE_TWO_ALIGNED_PIXELS sont équivalents pour les petites machines d'endian mais pas pour l'architecture big endian.

[Exemple modifié: grâce à Steve Jessop]

Soit, pixels = 0x0A0B0C0D

Pour les grandes machines endian, WRITE_TWO_PIXELS fonctionnent comme suit:

--------------------- 
| 0B | 0A | 0D | 0C | 
--------------------- 
    3 2 1 0   <--- addr 

WRITE_TWO_ALIGNED_PIXELS écriront comme suit:

--------------------- 
| 0D | 0C | 0B | 0A | 
--------------------- 
    3 2 1 0   <--- addr 
+1

Le premier ne devrait-il pas être BADC?'(int16) pixels', qui est' 0xCD', à l'adresse inférieure (que vous avez sur la droite), et '(int16) (pixels >> 16)' à l'adresse supérieure (que vous avez sur la gauche) . Je peux me tromper - avoir les adresses les plus basses sur la droite fait ma tête dedans ;-) –

+0

Je pense que vous avez raison. L'endianness est une chose tellement déroutante! Je vais mettre à jour ma réponse. – Donotalo

2

Dans les deux macros, le seul alignement important est l'alignement de addr. Comme écrit dans la question, ils sont équivalents si addr est aligné sur 32 bits (ce qui signifie que ses deux bits faibles sont nuls), mais seulement si l'architecture cible est également little-endian.

Sur une machine big-endian, les 16 bits supérieurs de pixels doivent être écrits à (INT16*)(addr))[0] et les 16 bits inférieurs à (INT16*)(addr))[1] pour qu'ils soient équivalents.

Sans vérifier ma copie du code source libjpeg, j'imagine que ces définitions devraient être modifiées dans le cadre du portage de la bibliothèque, ou qu'elles sont déjà protégées par une déclaration d'endianness. Si addr n'est pas aligné sur 32 bits, la macro WRITE_TWO_ALIGNED_PIXELS peut provoquer une exception sur les architectures où l'accès non aligné n'est pas autorisé. Bien sûr, dans certains cas, l'accès non aligné est autorisé, mais il est beaucoup plus coûteux que deux accès alignés plus petits, et sur d'autres architectures, l'accès non aligné est difficile à distinguer de l'accès aligné. Les deux macros existent pour rappeler à l'auteur de la bibliothèque de penser à l'alignement et pour normaliser l'approche de gestion de l'accès désaligné afin qu'il puisse être optimisé lors de la construction pour les plates-formes où cela n'a pas d'importance.

+1

"peut provoquer une exception" - encore mieux, apparemment sur certains puces ARM un accès non aligné ne provoque pas d'exception matérielle, il lit/écrit simplement la mauvaise valeur. Cependant, je n'ai jamais utilisé que des ARM. –

+0

@Steve Jessop, Par coïncidence, j'ai juste aidé un collègue à déboguer quelque chose où un octet d'un paquet était zéro alors qu'il ne devrait pas l'être. Il s'est avéré être provoqué par une écriture de 16 bits à une adresse impaire adjacente, qui a apparemment été silencieusement arrondie à l'adresse alignée, saccageant le champ adjacent. C'est dans un noyau ARM dans un SOC propriétaire. Pour autant que nous sachions, aucune exception n'a été levée et il y a des preuves que la lecture a récupéré la valeur écrite. La morale est, faites attention à l'accès mal aligné sur n'importe quelle plateforme, c'est * toujours * un problème de portabilité. – RBerteig