IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Erreur d'initialisation d'un tableau passé en paramètre dans une librairie statique


Sujet :

C

  1. #1
    Candidat au Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2017
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2017
    Messages : 4
    Points : 3
    Points
    3
    Par défaut Erreur d'initialisation d'un tableau passé en paramètre dans une librairie statique
    Bonjour à tous,

    Je n'ai pas trouvé de réponse en cherchant sur le net, alors je me permet de poster ici.
    J'ai développé une librairie statique contenant des fonctions d'encodage/decodage.
    Ces fonctions prennent en paramètre un tableau à initialiser.

    Quand j'appelle ces fonctions directement dans ma librairie, aucun souci, mes tableaux sont correctement initialisés.
    En revanche, dès que j'y fait appel depuis un programme externe, il n'y a plus moyen d'avoir des valeurs correctes...

    Il s'agit de fonctions d'encodage/decodage G711 loi A, loi µ:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    void SetEncodingMap(int law, unsigned char *array, int size){
        int i;
     
        if(size == SIZE_ENCODING_MAP){
            if(law == ALAW){
                for(i = SHRT_MIN; i <= SHRT_MAX; i++){
                    array[(i & 0xffff)] = EncodeAlaw(i);
                }
            }else{
                for(i = SHRT_MIN; i <= SHRT_MAX; i++){
                    array[(i & 0xffff)] = EncodeUlaw(i);
                }
            }
        }
    }
     
    void SetDecodingMap(int law, short *array, int size){
        int i;
     
        if(size == SIZE_DECODING_MAP){
            if(law == ALAW){
                for(i = 0; i < UCHAR_MAX; i++){
                    array[i] = DecodeAlaw(i);
                }
            }else{
                for(i = 0; i < UCHAR_MAX; i++){
                    array[i] = DecodeUlaw(i);
                }
            }
        }
    }
    J'ai effectué les tests suivants:
    - Recompilation avec/sans flags d'optimisation de g++ (-O2, et -O3)
    - Ajout du mot-clé volatile sur les tableaux
    - Appels aux fonctions d'encodage/decodage (EncodeA/Ulaw et DecodeA/Ulaw) depuis un programme externe pour confirmer leur bon fonctionnement (OK)

    Mais je n'ai toujours aucune piste pour résoudre ce problème...

    Merci d'avance

  2. #2
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Et peut-on voir le code appelant dans les deux cas?

    Parce que si le problème n'est pas quelque part, il est ailleurs.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  3. #3
    Candidat au Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2017
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2017
    Messages : 4
    Points : 3
    Points
    3
    Par défaut
    Evidemment.

    Rien de bien sorcier:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    #include <g711.h> //Le header de mes fonctions d'encodage/decodage
     
    void DisplayEncodingMap(unsigned char *g711EncodeMap){
        for(int i = 0; i < SIZE_ENCODING_MAP - 7; i += 8){
            printf("%05d[%03d] | ", i, g711EncodeMap[(unsigned short)i]);
            printf("%05d[%03d] | ", i+1, g711EncodeMap[(unsigned short)i+1]);
            printf("%05d[%03d] | ", i+2, g711EncodeMap[(unsigned short)i+2]);
            printf("%05d[%03d] | ", i+3, g711EncodeMap[(unsigned short)i+3]);
            printf("%05d[%03d] | ", i+4, g711EncodeMap[(unsigned short)i+4]);
            printf("%05d[%03d] | ", i+5, g711EncodeMap[(unsigned short)i+5]);
            printf("%05d[%03d] | ", i+6, g711EncodeMap[(unsigned short)i+6]);
            printf("%05d[%03d]\n", i+7, g711EncodeMap[(unsigned short)i+7]);
        }
    }
     
    void DisplayDecodingMap(short *g711DecodeMap){
        for(int i = 0; i < SIZE_DECODING_MAP - 7; i += 8){
            printf("%03d[%05d] | ", i, g711DecodeMap[(unsigned char)i]);
            printf("%03d[%05d] | ", i+1, g711DecodeMap[(unsigned char)i+1]);
            printf("%03d[%05d] | ", i+2, g711DecodeMap[(unsigned char)i+2]);
            printf("%03d[%05d] | ", i+3, g711DecodeMap[(unsigned char)i+3]);
            printf("%03d[%05d] | ", i+4, g711DecodeMap[(unsigned char)i+4]);
            printf("%03d[%05d] | ", i+5, g711DecodeMap[(unsigned char)i+5]);
            printf("%03d[%05d] | ", i+6, g711DecodeMap[(unsigned char)i+6]);
            printf("%03d[%05d]\n", i+7, g711DecodeMap[(unsigned char)i+7]);
        }
    }
     
     
    int main(int argc, char *argv[]){
        unsigned char g711EncodeMap[SIZE_ENCODING_MAP];
        short g711DecodeMap[SIZE_DECODING_MAP];
     
        SetEncodingMap(ALAW, g711EncodeMap, SIZE_ENCODING_MAP);
        SetDecodingMap(ALAW, g711DecodeMap, SIZE_DECODING_MAP);
     
        DisplayEncodingMap(g711EncodeMap);
        DisplayDecodingMap(g711DecodeMap);
    }
    Et j'ai testé ce code en intégrant directement les fonctions d'encodage/decodage dans le fichier source, sans passer par la librairie statique.
    Pour infos, le fichier g711.h ne contient que les prototypes de mes fonctions, et les définitions de ALAW, SIZE_ENCODING_MAP, et SIZE_DECODING_MAP.

  4. #4
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Bonjour,

    Ça peut être dû au format de passage des paramètres à une fonction (StdCall, CDecl, FastCall).
    Il faut vérifier que la convention d'appel par défaut utilisée lors de la compilation de la librairie statique est bien la même que celle de l'application. On peut aussi forcer une convention; par exemple pour une convention "langage C" on peut utiliser : sous GCC __attribute__((cdecl)), sous Visual __cdecl, ...
    Les flags d'optimisation et utiliser des variables volatile ne devraient jouer aucun rôle, par contre il est préférable que les 2 modules (librairie et application) aient été générés par la même version de compilateur.

  5. #5
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Je ne vois pas d'autre explication plausible.

    Vérifie quand même que les deux fonctions ne soient pas destructrices. Ça m'étonnerait, mais sait-on jamais…

    Par contre, tu devrais paramétrer ta fonction d'affichage avec la taille à afficher, comme ca, plus besoin d'en avoir deux.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  6. #6
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Tu castes explicitement (pourquoi..?) la valeur de ton compteur au sein de tes fonctions d'affichage vers un type entier, probablement de plus petite taille : peut-être n'adresses-tu donc pas correctement tes tableaux ?

    Je me permets un petit conseil accessoire : utilise les opérateurs logiques bit-à-bit uniquement avec des expressions entières non signées si tu ne veux pas avoir de surprises (cf. adressage discutable dans SetEncodingMap).

  7. #7
    Candidat au Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2017
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2017
    Messages : 4
    Points : 3
    Points
    3
    Par défaut
    Problème résolu !

    Je me suis rendu compte au final qu'une autre librairie s'était glissée dans la configuration de mon projet (rien ne vaut un bon Makefile Oo !)
    Et évidemment cette librairie redéfinie SetEncodingMap et SetDecodingMap qui sont eux, complètement KO...

    Du coup, une simple modification des noms de mes fonctions corrige le problème.
    Merci pour vos remarques.

    Juste pour répondre à ternel, je ne me suis pas embêté à paramétrer correctement mes fonctions d'affichage qui n'avaient qu'un intérêt de débuggage très limité, et que je vais désormais supprimer..

    Et pour répondre à Matt_Houston, l'encodage G711 permet de compresser des nombres 16bits signés sur 8bits.
    J'utilise des tableaux de mapping que j'initialise une fois pour toutes au début de mon programme, ainsi pour effectuer compression ou décompression, je n'ai qu'un simple accès mémoire à faire plutôt que de rejouer les algorithmes afin d'optimiser les perfs.
    Tu remarqueras que dans la fonction SetEncodingMap, mon compteur va de SHRT_MIN (<0) à SHRT_MAX(>0) ce qui me permet de calculer les valeurs 8 bits compressées de tous les entiers signés sur 16bits.
    Je masque ensuite mon compteur 32bits (ou 64bits <int>) sur 16bits afin de récupérer un index entre 0 et 65535 et m'affranchir des bits de poids forts forcément mis à '1' dans le cas des valeurs négatives.
    Cette petite astuce me permet de remplir mon tableau sans avoir à différencier les valeurs positives des valeurs négatives, et maîtriser les valeurs de mon tableau

  8. #8
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    J'ai bien compris, mais tu mélanges ici l'adressage de ton tableau avec ce que tu y mets : c'est d'après moi une mauvaise pratique, même si elle ne génère ici pas de comportement indéterminé (et encore, c'est à voir si certaines valeurs signées en complément à deux peuvent être des trap representations ou non..). Tu mélanges également limits.h avec un masque en dur.

    L'adressage se fait si possible en size_t.

  9. #9
    Candidat au Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mars 2017
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2017
    Messages : 4
    Points : 3
    Points
    3
    Par défaut
    D'accord.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [AC-2010] Objet ListBox passé en paramètre dans une fonction = Null
    Par informer dans le forum VBA Access
    Réponses: 2
    Dernier message: 14/05/2016, 11h56
  2. Réponses: 7
    Dernier message: 06/09/2011, 08h27
  3. Réponses: 2
    Dernier message: 22/12/2009, 15h01
  4. comment passé un paramètre dans une requête sql
    Par java2008 dans le forum BIRT
    Réponses: 0
    Dernier message: 03/03/2008, 12h11
  5. Réponses: 32
    Dernier message: 24/07/2006, 19h19

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo