[Résolu] Comment sauver une chaà®ne de caractères dans une structure C avec NSData?

2»

Réponses

  • AliGatorAliGator Membre, Modérateur
    août 2013 modifié #32
    Pour info, il est également possible d'utiliser les Designated Initializers pour générer des adresses vers des "literals"

    Par exemple :
    void pinc(int* pi)
    {
    printf("value is %d and incrementing\n", *pi);
    *pi = *pi+1;
    }
    int main(int argc, char* argv[])
    {
    int x = 5;
    pinc(&x); pinc(&x); pinc(&x); // affiche 5 puis 6 puis 7, et à  la fin x vaut 8

    pinc(& (int){1}); // appel tout à  fait valide ; affiche 1.
    }
    Note l'utilisation d'accolades, donc de "(int){1}" et non pas "(int)1" qui n'est pas du tout la même chose. "(int){1}" est en quelque sorte la création d'une variable anonyme de type int et de valeur 1 (et non plus la valeur litérale 1 directement), c'est pourquoi on peut prendre ensuite son adresse pour la passer à  la fonction.

    Bon, j'avoue que je ne suis pas fan de cette notation, et ne l'ai jamais utilisée. La seule justification que je verrai d'utiliser "(int){1}" c'est pour des fonctions comme setsockopt :
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));
    Ce qui évite de déclarer un "int optval = 1;" avant juste qui ne servirait à  rien d'autre que de pouvoir passer "&optval" à  cette ligne ensuite, mais bon...



    PS : J'ai édité mon message au dessus, au cas où tu n'aurais pas vu les exemples d'usage donnés


  • en fait c'est bizarre si je fais:



     printf("%p %p \n",tab[1],&tab[1]);


    ça affiche la même adresse


    mais char* str=&tab[1];


    produit un warning


    ]



     




     


     


    Non c'est normal.


     


    Pour un tableau en C, défini ainsi:


    <type> tab[<N>]


    tab et &tab ont la même valeur qui est l'adresse du premier élément du tableau.


     


    Si on fait une analogie avec une variable de type int :


    int i =1;


    &i donne l'adresse de la variable.


    i donne la valeur de la variable


    Pour un tableau c'est pareil, sauf que donner la valeur d'un tableau n'a pas de sens donc on renvoie son adresse.


    int tab[32];


    &tab, c'est bien l'adresse de la variable tab donc l'adresse du tableau.


    Alors que tab devrait renvoyer la valeur de la variable. Mais c'est quoi la valeur d'un tableau ?! 


    On ne sait pas donc on renvoie l'adresse...


     


    Cependant tab et &tab n'ont pas le même type mais là  ça devient subtil :


    http://stackoverflow.com/a/2528328/267152



  • &tab, c'est bien l'adresse de la variable tab donc l'adresse du tableau.




     


    J'ai connu des compilateurs qui renvoyait uen erreur, un tableau est déjà  une adresse, donc l'adresse d'une adresse c'est pas possible.

  • AliGatorAliGator Membre, Modérateur

    J'ai connu des compilateurs qui renvoyait uen erreur, un tableau est déjà  une adresse, donc l'adresse d'une adresse c'est pas possible.

    Ca me parait plus cohérent et plus strict donc plus logique en effet comme comportement, au moins quand tu as l'erreur tu réfléchis à  2 fois, alors que si ça laisse passer tu n'y comprends plus rien et le code n'a plus trop de logique...
  • mpergandmpergand Membre
    août 2013 modifié #36

    c'est pourquoi je disais plus haut que le compilo est sympa avec :


    NSData *data = [NSData dataWithBytes:&mesNoms length:sizeof(mesNoms)] 


     


    Pour moi ça n'a pas de sens.


     


    Faut dire que j'ai pratiqué des compilateurs non ANSI et là  mode "Parano ON" conseillé :)


     


    en ANSI le code suivant ne plante pas si le pointeur est NULL,  car la norme dit que les opérations logiques s'exécutent de gauche à  droite:



    // pt -> pointeur

    if( (p!=NULL) && (*p==0) )
    // bla bla

    J'ai connu des compilateurs qui évaluaient de droite à  gauche et là  plantage si pt est NULL...


    C'est la raison pour laquelle je me vois encore écrire par reflexe:




    if(p!=NULL)
    if(*p==0)
    // bla bla

  • AliGatorAliGator Membre, Modérateur
    Ah ouais mais non ;)
    Y'a une différence entre avoir un compilateur de merde qui ne respecte même pas du tout les normes voire fait l'inverse de ce que la norme dit, et un compilateur qui est tolérant tant que tu ne le forces pas en mode pedentic et c99 et tout le tralala !

    On peut forcer GCC comme LLVM à  être strict et à  respecter le C99 avec qques flags de compilation, et si on ne met pas ces flags, en général ce que ça va permettre c'est de la tolérence, pour autoriser des syntaxes valides mais pas forcément officielles par exemple. Par contre, de là  à  ce que ça modifie totalement le comportement et fasse planter ton application, c'est violent, surtout si la norme spécifie bien que les conditions doivent se lire de gauche à  droite.
    La norme ne préciserait rien, encore, ça laisserait libre choix au compilateur, et là  du coup ok pour le mode parano avec 2 "if" imbriqués. Mais là  la norme précise le cas, si t'as un compilateur qui ne respecte pas la norme là  c'est un autre problème.

    C'est comme si pour freiner avec ta voiture tu utilisais le frein à  main, en disant que certes dans la notice normalement c'est dit que la pédale de frein fait freiner ta voiture, mais sur certaines voitures c'est pas le cas... si tu commences à  avoir des voitures qui ne respectent pas ça et sur lesquelles la pédale de frein accélère au lieu de freiner, on s'en sort plus ^^ Et plutôt que d'adapter ta conduite à  ta voiture-bizarre-qui-ne-respecte-aucun-standard-et-n'en-fait-qu'à -sa-tête, tu devrais plutôt utiliser une voiture qui suit les règles que tout le monde accepte. Ca ne t'empêche pas d'avoir libre choix sur ta voiture (GCC, LLVM, autre...), du moment que c'est une voiture qui respecte au moins un standard connu ;)

  • Le problème à  l'origine était que les spécifications du C sont très souples, comme par exemple pour le sens de l'évaluation des expressions (comme dit plus haut) ou encore la précédence des opérateurs.


    Donc chaque compilateur pouvait avoir un comportement différent, ce qui rendait bien parano et obligeait à  mettre des parenthèses partout:


     


    if ( ((a>10) && (a<100)) || (b!=0) )


     


    pour être sûr que ça s'exécute dans le bonne ordre.


     


    Ce fut le bazar jusqu'à  l'apparition de la norme ANSI et son adoption par la majorité des compliateurs.


  • FKDEVFKDEV Membre
    août 2013 modifié #39
    Malheureusement, quand on travaille dans l'embarqué, on rencontre souvent des bugs de compilateur. Notamment quand on essaye d'utiliser les options d'optimisation.

    Donc, à  côté du C ANSI, les développeurs qui ont un peu de maturité ont leurs règles règles un peu parano pour ne pas avoir de probleme en cas de portage. Car c'est un monde où on peut facilement être amené à  changer de microcontrolleur pour des questions de coûts de revient.


    Par exemple, ne jamais utiliser les bibliothèques fournies avec le compilateur (stdio, etc), donc pas de printf, pas de memcpy, on fait tout à  la mano. Eventuellement, même, pas d'allocation dynamique (malloc)...
  • Je me rends compte que la discussion continue... Mon problème était "Comment communiquer une chaà®ne de caractères via une structure C sauvegardée avec un NSData et récupérée avec CFDataRef. J'avais essayé sans succès CFString et NSString (incompatible avec C++ of course). D'où ma structure C de caractères intégrée dans la grosse. 


     


    Cela marche impeccablement bien. Il a fallu écrire quelques méthodes pour passer de NSString à  ma structure, puis de ma structure à  des CFString, il y a sans doute plus simple, mais cela marche impec. Depuis le host, le nom des sons s'affiche dans le plug. C'est tout ce que je lui demandais...


     


    Une structure C est très stable en termes de mémoire, cela ne bugg jamais. Aussi je n'hésite pas à  m'en servir*. Cela me semble être plus stable (sans que je ne sache trop pourquoi) que 



    char mesNom [38][40] // (j'ai changé le nombre de programmes et de caractères aussi)

    De plus, en faisant cela, ou bien des choses similaires, j'avais des problèmes de compilation, ou bien encore des pertes de mémoire (impossible de relire les caractères normalement sauvegardés...)


     


    *le synthé de "Techno Drive" fonctionne entièrement avec une grosse structure C qui abrite les paramètres et les valeurs de fréquence, de filtre etc. des séquencers, des sons de percussion et des synthés, y compris le synthé polyphonique.


  • mpergandmpergand Membre
    août 2013 modifié #41

    Salut, Hervé


     


    J'ai toujours beaucoup de mal avec tes explications, c'est très confus ...


     



     


    J'avais essayé sans succès CFString et NSString (incompatible avec C++ of course). 



     


    Oui et non, il est possible de convertir du CFStringRef en wstring et vice-versa, mais je suppose que ce n'est pas ce que tu veux faire, vu que core audio utilise des CFString je suppose.


    (je pense aussi à  un problème d'encoding: comment sauvegardes-tu tes strings en UFT8?)


     



     


    De plus, en faisant cela, ou bien des choses similaires, j'avais des problèmes de compilation, ou bien encore des pertes de mémoire (impossible de relire les caractères normalement sauvegardés...)



     


    Mais pour quelle raison, tu as essayé de mettre un point d'arret au chargement de ta structure et de regarder la position des éléments de cette structure en mémoire.


    Le problème pourrait venir d'un problème d'alignement (comme le suggérait  FKDEV)


     


    J'y avait bien pensé, mais tout ça s'exécute sur la même machine avec le même système, donc il ne devrait pas y avoir de problème d'alignement.


     


    Sauf si,  pour les plug-in audio, des options de compilations spécifiques viendraient foutre le bazar.


    C'est une piste à  explorer ...


  • Le problème pourrait venir d'un problème d'alignement (comme le suggérait  FKDEV)
     
    J'y avait bien pensé, mais tout ça s'exécute sur la même machine avec le même système, donc il ne devrait pas y avoir de problème d'alignement.
     
    Sauf si,  pour les plug-in audio, des options de compilations spécifiques viendraient foutre le bazar.
    C'est une piste à  explorer ...


    Sauf si, effectivement, ils ne sont pas compilés de la même manière, l'un avec pragma pack et l'autre sans.
    Cela pourrait aussi etre un probleme d'encoding, surtout s'il y en a un qui sauvegarde en UTF16 par exemple.

    Là  il faudrait savoir ce qu'il se passe exactement quand cela ne marche pas.

    Il faudrait aussi nous montrer avec quel code les string sont copiées dans la structure et avec quels code elles sont relues.

    Un outil pratique dans ce genre de cas, c'est la fenêtre qui montre le contenu de la mémoire :
    tu copies l'asdresse de ta structure et tu vas dans le menu Product|Debug|View Memory de Xcode.
    Tu fais un screenshot de ta structure au départ et à  l'arrivée.
Connectez-vous ou Inscrivez-vous pour répondre.