0
votes

Est-il possible d'utiliser un std :: Array comme conteneur de données pour une structure de pod?

J'essaie de mettre à jour un code de l'héritage C utilisant un tableau en tant que conteneur de données avec accès nommé via des macros sur une solution plus élégante C ++ 17 (sera mise à jour sur C ++ 20 lorsqu'il est disponible, possible C + +20 solutions sont les bienvenues). Désolé s'il y a beaucoup de code, mais mes premières suggestions de la question sur la mise en page sont les bienvenues.

La conception actuelle Legacy C: p>

struct word_arr_t
{
    int16_t var0;
    int16_t myValue;
    int16_t myParameter;
    uint16_t free;
    int16_t var1;
    int16_t var2;
    int16_t var3; //Still no way to get array index from variable name
    int16_t var4;
    int16_t var5;
}word_struct;

std:.array<int16_t, sizeof(word_arr_t) / sizeof(word)> word_array{};
//std:.array<int16_t, sizeof(word_arr_t) / sizeof(word)> word_array{&word_struct}; would be lovely if I could do this.
//word_array.Data = reinterpret_cast<int16_t*>(&word_struct); this would also be good.

extern int send(int16_t* arr, size_t size);

int main()
{
    word_struct.var1 = UINT16_MAX;
    word_struct.myValues = 50;

    //copy struct into array, very very bad as it's not usable unless you know when
    //code writes to the struct and when code writes to the array,
    //this could be solved by wrapping the array into a read only object but still not ideal
    //and extremely slow especially if the struct is very large
    memcpy(word_array.Data, &word_struct, sizeof(word_struct));

    for(auto& a : word_array)
    {
        a = 10;
    }

    return send(word_array.Data, word_array.Size);
}


7 commentaires

BTW, votre calcul de Word_arr_Size n'est pas correct. Les compilateurs sont autorisés à ajouter des octets de rembourrage entre les membres.


En raison d'un remplissage positif entre les membres d'un struct , vous ne pouvez pas traiter le struct comme une matrice; Vous devrez utiliser le "". Opérateur d'accès aux membres, par nom.


Vous pouvez surcharger opérateur [] dans votre struct pour renvoyer les variables de membre.


@Thomasmatthews Pas besoin de s'inquiéter du rembourrage, car la structure est toujours faite de types de même taille (deux octets), le seul rembourrage que le compilateur ajoute est 2 octets et la fin de la structure, je pourrais aussi forcer une 2 Pack d'octets Pour vous assurer que la structure est de la taille que je veux que ce soit au cas où le compilateur décide de mettre un peu de rembourrage autour des membres.


Vous ne pouvez pas garantir la norme C ++ que chaque membre sera placé dans des endroits consécutifs. Votre compilateur peut avoir un #pragma pack ou certains pragma qui fera packer les membres (par exemple les placer dans des emplacements consécutifs). Si vous souhaitez avoir des éléments dans des emplacements consécutifs, les seules garanties sont std :: vecteur , std :: graphique ou un tableau.


Je vais emballer les structures alors, afin qu'ils soient alignés en mémoire, si un décidez de continuer à les utiliser de cette façon.


Pouvez-vous garder cette partie du code comme c? La solution correcte en C n'est pas ce désordre macro, mais d'utiliser un «code> union . C'est beaucoup plus élégant que tout ce qui peut être fait dans la langue et le rembourrage n'est pas un problème ici. Malheureusement, C ++ ne convient pas aux systèmes embarqués car il ne permet pas de punir le type syndical, il doit donc être écrit dans C.


3 Réponses :


0
votes

Vous ne pouvez pas traiter une variable séparée comme une matrice.

pas idéal mais vous pouvez avoir des accesseurs, quelque chose comme: p> xxx pré>

ou index d'énum> p>

enum Index
{
    var0,
    myValue,
    myParameter,
    free,
    var1,
    var2,
    var3,
    var4,
    var5,
};

struct word_arr_t
{
    std::array<std::int16_t, 100> data{}; // your array
};


int main()
{
    word_arr_t word_arr;
    word_arr.data[Index::var1] = INT16_MAX;
    word_arr.data[Index::myValues] = 50;

    send(word_arr.data.data(), word_arr.data.size());
    // ...
}


2 commentaires

J'aime la première solution que vous avez proposée, ce n'est pas si moche, mais ce qui m'inquiète, c'est la façon dont je suis obligé d'utiliser un get () et définir () pour des valeurs que je veux donner un type différent à, appeler également une fonction est un peu laid mais beaucoup mieux puis une macro; En ce qui concerne la deuxième solution, je devrais encore compter sur des counts explicites lorsque je souhaite attribuer une valeur de type différent que j'aimerais vraiment supprimer.


"Vous ne pouvez pas traiter une variable séparée en tant que tableau." Bien sûr, vous pouvez, tout simplement pas en C ++.



0
votes

serait-il possible d'utiliser un std :: Array comme un conteneur de données pour la structure? P>

a POD STREST en C ++ est une classe qui est trivial et a mise en page standard .
Commençant par std :: Array code> comme stockage sous-jacent pour une "structure" signifie que vous ne définissez aucun struct code> avec des membres nommés. Vous devriez écrire une classe qui contient le tableau et les membres qui accédent aux indices du tableau, ce qui peut facilement devenir pas trivial em> et pas la disposition standard em>. P>.

par surcharge opérateur [] code> Vous pouvez accéder aux membres "Array" d'une structure avec la syntaxe de type tableau, tout en conservant la définition code> de la définition et du code POD. p>

si c'est looks em> comme un struct code> et [] code> est comme un std :: Array Code> , alors c'est probablement assez bon em> en ce qui concerne l'utilisateur final. p>

Voici un exemple de programme démontrant que: P>

Is POD: Yes
Element 0: 0 or 0
Element 1: 0 or 0
Element 2: 0 or 0
Element 3: 0 or 0
Element 4: 0 or 0


6 commentaires

L'opérateur [] est une très bonne solution que je ne savais pas non plus que l'ajout d'un opérateur à une structure maintiendrait toujours un pod au lieu d'un objet C ++, le seul inconvénient est que je devrais toujours mettre en œuvre des itérateurs à la main comme je le ferais. Comme la structure pour être utilisé de manière transparente dans le code C ++ moderne (pour des fonctions telles que STD :: Accumulez, STD :: Trouve J'ai besoin d'itérateurs, c'est pourquoi je voudrais que je souhaiterais STD :: Array en tant que conteneur ou interface sous-jacent).


Cela résout tout en temps d'exécution, il est intensif et lent de la branche.


@LUNDIN, vous avez raison, mais la question ne spécifie aucune exigence concernant la performance. Ma réponse souligne ce que je crois que ce serait le moyen le plus gentil pour résoudre le problème, en ce qui concerne la sauvegarde du travail de programmateur et de taper.


@ Project579, l'approche "Uglier" que j'ai enquêtée avant de rédiger cette réponse étendue std :: Array avec les membres de la fonction pour accéder à des indices spécifiques. std :: Array est un type de pod.


"Lent mais élégant" est C ++ en un mot. La version de l'Union J'ai posté la réponse est supérieure à tout ce qui peut être fait en C ++, à la fois en termes de vitesse et de lisibilité. C'est une pod pure, aucun constructeur gonflement sur la start-up, etc. Malheureusement, le comité C ++ est plein de personnes PC, il n'ya donc aucun type punning à être en C ++.


@Lundin, malheureusement, la question a fait nécessite explicitement une solution C ++ 17 ou C ++ 20 car elles se déplacent Away de C. tandis que ma réponse peut ne pas utiliser Les fonctionnalités plus récentes C ++, une réponse qui suggère que l'utilisation de C au lieu de C ++ n'est peut-être pas ce que veut. J'aime votre réponse cependant, et dans de nombreux cas, il est logique de compiler certains C dans un projet C ++.



0
votes

Si la compilation de cette partie du code C est une option, la solution la plus élégante de loin est d'utiliser un «code> union code>. Comme l'alignement n'est pas un problème ici et qu'il n'y aura pas de remplissage. Cela peut être fait en C uniquement, ce qui permet de punir le type à travers les syndicats.

typedef enum
{
  var0_index = 0,
  myValue_index = 1,
  myParameter_index = 2,
  free_index = 3,
  var_1index = 4,
  var_2index = 5,
  var_3index = 6,
  var_4index = 7,
  var_5index = 7,
} var_t;

word_t word = 
{
  // different sorts of designated initializers can be mixed:
    .var0 = x,
  .myValue = y,      
  [var5_index] = z,
};


1 commentaires

Je ne suis pas réellement celui qui a proposé le nom "Word", ces tableaux dans le code sont appelés WordM, Word, Wordi, Wordo, etc. Il s'agit d'un protocole âgé de plus de 15 ans et c'est la convention Dans la bibliothèque (Word Signification Un tableau composé de valeurs 16 bits, il existe également BYTEM, DWordM, QWordm, etc.), je dois conserver ces noms comme les utilisateurs de personnes âgées qui leur sont très habitués; Quoi qu'il en soit, je n'aurais jamais pensé à utiliser un syndicat car ils sont principalement inutiles à C ++, devoir compiler les déclarations de ces structures en C constituent un avantage pour moi.