web-dev-qa-db-fra.com

Équivalent Visual C ++ de __attribute__ de GCC ((__packed__))

Pour certains compilateurs, il existe un spécificateur d'emballage pour les structures, par exemple ::

 RealView ARM compiler has "__packed" 
 Gnu C Compiler has "__attribute__ ((__packed __))" 
 Visual C++ n'a pas d'équivalent, il a seulement le "#pragma pack (1)" 

J'ai besoin de quelque chose que je puisse mettre dans la définition struct.

Toute info/hack/suggestion? TIA ...

45
Malkocoglu

Je ne connais pas une manière astucieuse de le faire, mais vous pourriez peut-être faire quelque chose d'horrible comme ceci:

#include "packed.h"
struct Foo { /* members go here */ } PACKED;
#include "endpacked.h"

Ensuite, pour MSVC, pack.h:

#define PACKED
#pragma pack(Push,1)

endpacked.h

#pragma pack(pop)
#undef PACKED

Pour gcc, pack.h:

#define PACKED __attribute__ ((__packed__))

endpacked.h:

#undef PACKED

Fondamentalement, l'emballage dépend trop de la plate-forme. Supposons que votre structure compressée contienne des champs 8 bits et envisagez un système avec un octet 16 bits. Il ne peut pas avoir de structure représentant vos données simplement en les compressant - vous devez savoir comment les octets 8 bits sont convertis en octets 16 bits lors du transfert entre les deux systèmes. La structure sur la machine 16 bits peut nécessiter des champs de bits, auquel cas vous devez savoir comment l'implémentation les dispose.

Donc, si le code est destiné à être généralement portable, vous devrez peut-être simplement définir les structures compactées dont vous avez besoin dans une section spécifique à la plate-forme de votre fichier d'en-tête. Ou plutôt, structurez votre code afin qu'un futur port puisse le faire s'il le doit.

28
Steve Jessop

Vous pouvez définir PACK comme ceci pour GNU gcc

#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__))

et comme ceci pour Visual C++:

#define PACK( __Declaration__ ) __pragma( pack(Push, 1) ) __Declaration__ __pragma( pack(pop) )

Et utilisez-le comme ceci:

PACK(
struct myStruct
{
    int a;
    int b;
});
72
Steph

Je sais que cette question est ancienne maintenant, mais je pense qu'il existe une meilleure solution que celles publiées plus tôt. Il est possible de mettre le pragma dans le cas MSVC dans la ligne de déclaration struct après tout. Considérer ce qui suit:

#ifdef _MSC_VER
#  define PACKED_STRUCT(name) \
    __pragma(pack(Push, 1)) struct name __pragma(pack(pop))
#Elif defined(__GNUC__)
#  define PACKED_STRUCT(name) struct __attribute__((packed)) name
#endif

Ensuite, cela peut être utilisé comme suit:

typedef PACKED_STRUCT() { short a; int b } my_struct_t;
PACKED_SRUCT(my_other_struct) { short a; int b };

etc.

La clé ici est que l'utilisation de __pragma ne doit être que autour de la ligne de déclaration de la structure. Cela doit inclure le nom de la structure s'il lui est donné, d'où le nom étant un paramètre de la macro. Bien sûr, cela est facile à étendre à enum/class, que je laisserai au lecteur comme exercice!

Le programme de test sur la page MSDN de documentation du pack est utile pour le vérifier.

[~ # ~] modifier [~ # ~]

Il s'avère que lors de mes tests, j'utilisais le compilateur Intel sous Windows. En utilisant icl.exe, cette approche fonctionne sans problème, mais avec le compilateur Microsoft (cl.exe), ce n'est pas le cas (testé avec 2010 et 2013).

15
Sam Jansen

Vous pouvez le faire dans l'autre sens puisque GCC prend en charge les pragmas liés au pack VC++. Regardez ici pour plus d'informations.

Extrait...

Pour la compatibilité avec les compilateurs Microsoft Windows, GCC prend en charge un ensemble de directives #pragma Qui modifient l'alignement maximal des membres des structures (autres que les champs de bits de largeur nulle), des unions et des classes définies par la suite. La valeur n ci-dessous doit toujours être une petite puissance de deux et spécifie le nouvel alignement en octets.

#pragma pack(n) définit simplement le nouvel alignement.

#pragma pack() définit l'alignement sur celui qui était en vigueur au début de la compilation (voir aussi l'option de ligne de commande -fpack-struct[=<n>] voir Options de génération de code).

#pragma pack(Push[,n]) pousse le paramètre d'alignement actuel sur une pile interne, puis définit éventuellement le nouvel alignement.

#pragma pack(pop) restaure le paramètre d'alignement à celui enregistré en haut de la pile interne (et supprime cette entrée de pile).

Notez que #pragma pack([n]) n'influence pas cette pile interne; il est donc possible d'avoir #pragma pack(Push) suivie de plusieurs instances de #pragma pack(n) et finalisée par une seule #pragma pack(pop).

Certains objectifs, par exemple i386 et powerpc, prennent en charge le ms_struct#pragma qui présente une structure en tant que __attribute__((ms_struct)) documentée.

#pragma ms_struct on Active la disposition des structures déclarées.

#pragma ms_struct off Désactive la disposition des structures déclarées.

#pragma ms_struct reset Revient à la disposition par défaut.

8
Autodidact

Une autre solution, selon les compilateurs que vous devez prendre en charge, consiste à remarquer que GCC prend en charge les pragmas d'emballage de style Microsoft depuis au moins la version 4.0.4 (la documentation en ligne est disponible sur gnu.org pour les versions 3.4.6 et 4.0.4 - les pragmas ne sont pas décrits dans les premiers et sont dans les seconds). Cela vous permet d'utiliser simplement #pragma pack(Push,1) avant une définition de structure et #pragma pack(pop) après la définition et il sera compilé dans les deux.

6
Tom

Pourquoi avez-vous besoin de quelque chose pour aller dans la structure?

Je pense que #pragma pack(1) est le même, ou est-ce que je manque quelque chose?

Tu peux le faire:

struct Foo
{
#pragma pack(Push, 1)
int Bar;
#pragma pack(pop)
};

Mais ça a l'air moche.

2
graham.reeds