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 :

Question tableau mémoire


Sujet :

C

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Février 2015
    Messages
    30
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Vienne (Limousin)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Février 2015
    Messages : 30
    Points : 27
    Points
    27
    Par défaut Question tableau mémoire
    Bonjour,

    Je me sert de JNI pour appeler une fonction d'une dll. Il y un truc qui cloche mais je n'arrive pas a l'identifier et je me demande si ça ne vient pas de mon alloc de tableau.

    Voici le code
    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
     
    JNIEXPORT jint JNICALL Java_plugin_vision_core_devicemodeler_lib_ExtLib_extractImpl(JNIEnv* _env, jclass _this, jstring _param1, jstring _param2, jstring _param3)
    {
    	if (!LoadLib(_env)) return JNI_FALSE;
     
    	jint result = -1;
     
            // Tableau de paramètres convertis de jstring en const char.
    	const char *param[3];
    	param[0] = _env->GetStringUTFChars(_param1, 0);
    	param[1] = _env->GetStringUTFChars(_param2, 0);
    	param[2] = _env->GetStringUTFChars(_param3, 0);
     
            // Copie du tableau dans un char**
      	char *argv[3];
    	memcpy(argv, param, sizeof argv);
     
            // 
    	result = run(3, argv);
     
    	// End
    	return result;
    }
     
    int run(int argc, char** argv)
    {
    	int doStuff(int argc, char** argv);
     
    	return doStuff(argc, argv);
    }
    En debug le tableau utilisé a l'appel de run(3,argv) semble bien contenir tous les paramètres.
    Mais quand je regarde doStuff(argc,argv) à l'intérieur de la fonction run il ne semble plus y avoir que la première valeur dans le tableau.

    Et donc la fonction doStuff ne s'exécute pas correctement.
    Suis-je tebé parce qu'en fait le débuggeur n'affiche que la première case du tableau? Ou alors il y a un vrai problème?
    Illustration en capture du debuggeur.

    Merci.
    Images attachées Images attachées   

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Pour moi cela me semble logique mais attends un avis d'un expert

    Tu as fait un petite erreur . La signature est (int argc, char* argv[]).
    argv est bien un tableau et donc je pense que ton débogueur le considère comme tel, et il a trouvé la taille de argv par lui-même (peut-être qu'il a lu argc)

    Mais lorsque tu fais l'appel, ton tableau est dégradé en pointeur, et donc ton débogueur voit un pointeur et n'affiche que la première case (il fait juste le déférencement).
    Il faut passer par le débogueur pour afficher les autres valeurs avec la fonctionnalité "watch" ou équivalente.

    La différence entre un tableau et un pointeur , au delà de la syntaxe crochet ou étoile qui est permise pour les 2, est que le tableau n'accepte pas les types incomplets contrairement au pointeur.

    Et enfin ta déclaration anticipée - avancée ("forward declaration") (<- lien wiki français), ligne 27, doit être sortie du bloc fonction (je ne savais pas qu'on pouvait faire ainsi )

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // Tableau de paramètres convertis de jstring en const char.
    	const char *param[3];
    	param[0] = _env->GetStringUTFChars(_param1, 0);
    	param[1] = _env->GetStringUTFChars(_param2, 0);
    	param[2] = _env->GetStringUTFChars(_param3, 0);
     
            // Copie du tableau dans un char**
      	char *argv[3];
    	memcpy(argv, param, sizeof argv);
    Ceci me semble un peu cavalier...

    Et quel est l'intérêt de argv ? Pourquoi run ne prend-il pas les chaînes en const ? Pourquoi ne pas simplement passer param en paramètres ?

    je ne savais pas qu'on pouvait faire ainsi
    Certains compilateurs n'acceptent pas (ça passe sous VS, pas sous clang).
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Février 2015
    Messages
    30
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Vienne (Limousin)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Février 2015
    Messages : 30
    Points : 27
    Points
    27
    Par défaut
    Bonjour,

    Merci pour les retours. tu m'as l'air beaucoup plus à l'aise que tu ne le penses foetus :p.

    J'ai oublié de préciser que le programme s’interrompt comme quand on fait un memory access violation. Je ne reviens pas dans la partie java qui est sensé m'afficher le code retour.


    La signature est (int argc, char* argv[])
    Si je change les signatures en :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
             int run(int argc, char* argv[])
    	{
     		int doStuff(int argc, char* argv[]);
    		return doStuff(argc, argv);
    	}
    C'est le compilateur qui râle.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     error LNK2019: symbole externe non résolu "int __cdecl doStuff(int,char * * const)"  référencé dans la fonction "int __cdecl run(int,char * * const)"
    J'ai changé la déclaration de argv en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
            char **argv = (char**) malloc(sizeof(param));
    	memcpy(argv, param, sizeof param);
    Même comportement.

    Il faut passer par le débogueur pour afficher les autres valeurs avec la fonctionnalité "watch" ou équivalente
    Oui ce sont les images que j'ai partagé c'est en mode débug sur VS j'ai créé un espion et c'est ce qu'il m'affiche.

    Et quel est l'intérêt de argv ? Pourquoi run ne prend-il pas les chaînes en const ? Pourquoi ne pas simplement passer param en paramètres ?
    J'utilise une lib générée et fournie par une autre personne, je dois faire le lien entre la partie java et cette lib.
    La fonction doStuff est définie dans cette lib.
    Je ne peux pas utiliser le tableau de const char* comme paramètre directement.

  5. #5
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    L'allocation est la piste à envisager mais celle-là est mauvaise, ou plutôt incomplète.
    Ce que tu veux c'est 3 pointeurs de char, afin de copier dans chacun le paramètre.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    char** args = malloc(3 * sizeof(char*));
    for (i = 0; i < 3; ++i)
    {
      int len = strlen(params[i]);
      args[i] = malloc((len + 1) * sizeof(char));
      strcpy(args[i], params[i]);
      args[i][len] = 0;
    }
    run(3, args);
    for (i = 0; i < 3; ++i)
      free(args[i]);
    free(args);
    devrait déjà être plus proche de ce que tu devrais avoir.

    Sinon si la fonction ne modifie rien, et a donc juste une signature daubée, un const_cast.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  6. #6
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,
    Citation Envoyé par Dia972 Voir le message
    C'est le compilateur qui râle.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     error LNK2019: symbole externe non résolu "int __cdecl doStuff(int,char * * const)"  référencé dans la fonction "int __cdecl run(int,char * * const)"
    Attention, ce n'est pas le compilateur qui râle, c'est l'éditeur de liens, et la nuance est importante:

    Le compilateur, il va "juste" traduire le code que tu as écrit en une succession d'instructions qui seront compréhensibles par le processeur (dont la représentation la plus proche compréhensible est l'équivalent de l'assembleur).

    Lui, tout ce qui l'intéresse, c'est de savoir qu'il existe une fonction nommée doStuff, qui prend un int (nommé argc) et un pointeur de pointeur sur char (nommé argv) comme paramètres et qui renvoie un entier (au passage: la déclaration que tu fais de cette fonction à l'intérieur de run sous la forme de int doStuff(int argc, char* argv[]); devrait idéalement se faire à l'extérieur et avant de la fonction run même si on peut, effectivement, déclarer une fonction à l'intérieur d'une fonction )

    Quand il va croiser l'appel à la fonction, tout ce qu'il va faire, c'est s'assurer qu'il connaît la fonction (qu'il sait qu'il existe), que les paramètres que tu essaies de lui passer sont cohérent avec ceux que tu essayes de lui transmettre et que le type de la valeur que tu utilise pour éventuellement récupérer le retour de cette fonction est cohérent avec le type de la valeur de retour de la fonction.

    Si, pour une raison ou une autre, le compilateur n'est pas en mesure de convertir l'un des arguments que tu essaye de transmettre ou la valeur renvoyée par la fonction dans le type du paramètre demandé (respectivement dans le type de la variable auquel tu essayes d'assigner le type de retour de la fonction), il émettra une erreur (sans doute proche de "je sais pas convertir XX en YY), et il arrêtera de travailler.

    (il est d'ailleurs bizarre que Visual Studio n'agisse pas de la sorte, mais bon...)

    Une fois que le compilateur a fini de travailler (une fois qu'il a généré ce que l'on appelle un "fichier objet" qui contient les instructions binaires qui seront compréhensibles par le processeur, c'est l'éditeur de liens qui prend le relais.

    Son objectif, c'est de regrouper tous les fichiers objets générés par le compilateur pour créer un exécutable réel.

    A chaque fois qu'il croise l'appel à une fonction dans un fichiers objet, il va faire en sorte que l'appel "pointe" vers l'adresse de l'exécutable (ou de la bibliothèque partagée : .so ou .dll) à laquelle la fonction appelée se trouve.

    Pour ce faire, il peut, en cas de besoin, ce que l'on appelle des "bibliothèques externes" qui sont -- pour faire simple (et donc avec une certaine marge d'erreur), il s'agit d'archives qui contiennent des fichiers objets générés par "quelqu'un d'autre" pour essayer de trouver la fonction en question (qu'il rajoutera alors dans l'exécutable, sauf si elle est dans une bibliothèque partagée) .

    S'il ne trouve pas la fonction en question, il ne sait pas faire son taf, et, bien sur, il n'est pas content : il s'arrête de travailler après avoir émis un erreur de type "undefined reference to <symbole représentant la fonction>" (pour ce qui est de l'éditeur de liens sous linux) ou [b]symbole externe non résolu "la fonction appelée" référencé dans la fonction "la fonction appelante"[/c]

    Dans le cas présent, il semblerait que le compilateur ait décidé (a priori à tord) que char ** et char ** const, étaient "suffisamment proches" que pour accepter l'appel, mais que l'éditeur de liens ait (a priori à raison) été beaucoup plus stricte de ce point de vue, et qu'il ait décidé que... ce n'était pas du tout pareil.

    L'idéal serait donc de faire en sorte que doStuff soit effectivement compilé sous une forme qui prend un char ** const comme paramètre, pour que l'éditeur de liens soit content (et, tant qu'à faire, de faire pareil avec run).

    Cette option serait préférable car, l'un dans l'autre, les paramètres qui ont été transmis en ligne de commande ne devraient jamais être modifiés.

    Maintenant, un minimum de réalisme nous oblige à considérer le fait que, si doStuf a été développée pour accepter un char ** (non const), il y a de très fortes chances que toutes les fonctions auxquelles on doit transmettre ce char ** du fait de l'appel de foncitons en cascade.

    L'idéal théorique serait donc de corriger toutes ces fonctions, mais, la "dure mise en pratique" (et le gestionnaire, qui va calculer le montant que cela lui coutera pour le faire) risquent de ne pas être d'accord . Mais, a priori, (c'est ce que disait bousk ), un simple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    doStuf(argc, const_cast<char **>(argv));
    devrait fonctionner
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Développeur Java
    Inscrit en
    Février 2015
    Messages
    30
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Vienne (Limousin)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Février 2015
    Messages : 30
    Points : 27
    Points
    27
    Par défaut
    Bonjour à tous,

    Je reviens dessus avec un peu de retard, j'ai eu deux semaines .

    La solution de Bousk à bien marché. J'ai aussi rajouté le const_cast et tout fonctionne.

    Merci à koala, pour les précisions.

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

Discussions similaires

  1. [AC-2000] Questions Tableau croisé dynamique
    Par Mycose dans le forum VBA Access
    Réponses: 0
    Dernier message: 02/12/2010, 11h42
  2. [Debutant] question tableau
    Par jocelyn54 dans le forum Débuter
    Réponses: 5
    Dernier message: 17/01/2008, 11h44
  3. [WD9] Fichier HF vers tableau mémoire
    Par Romanops dans le forum WinDev
    Réponses: 8
    Dernier message: 08/06/2006, 12h10
  4. Question tableau
    Par calimero642 dans le forum Langage
    Réponses: 3
    Dernier message: 11/05/2006, 23h09
  5. Question tableau
    Par calimero642 dans le forum Langage
    Réponses: 5
    Dernier message: 05/04/2006, 16h26

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