Forum Programmation.c shm_open() référence indifinie !!!

Posté par  .
Étiquettes : aucune
0
20
fév.
2006
j'utilise linux depuis peu de temps, je l'ai installé pour pouvoir travailler sur les programmes C de temps réel. j'ai installé donc la version suse 8.1 PROFESSIONAL avec la version gcc 3.2 comme c'est indiqué avec la ligne de commande gcc -v :

Reading specs from /usr/lib/gcc-lib/i486-suse-linux/3.2/specs
Configured with: ../configure --enable-threads=posix --prefix=/usr --with-local-prefix=/usr/local --infodir=/usr/share/info --mandir=/usr/share/man --libdir=/usr/lib --enable-languages=c,c++,f77,objc,java,ada --enable-libgcj --with-gxx-include-dir=/usr/include/g++ --with-slibdir=/lib --with-system-zlib --enable-shared --enable-__cxa_atexit i486-suse-linux
Thread model: posix
gcc version 3.2

j'essaie de compiler le programme ci-dessous:

gcc -o shmsem -g -lm shmsem8.c

/* shmsem.c*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <semaphore.h>


#define gotoxy(x,y)printf("\033[%d;%dH",y,x)

caddr_t pg_addr;
sem_t *mysemp;
sem_t *cpt;
int fd;

typedef struct p{
char nom[20];
char prenom[20];
int age;
}FICHE;

void Menu();
void Ecrire();
void shmsem();
void Lire();
void Quitter();

void Menu()
{
gotoxy(30,1);
printf("***** M E N U *****\n");
gotoxy(20,3);
printf("Tapez (1) Ecrire :?\n");
gotoxy(20,5);
printf("Tapez (2) Lire :?\n");
gotoxy(20,7);
printf("Tapez (3) Quitter :?\n");
gotoxy(20,9);
printf("Votre choix : ");
}
/*
prendre le sémaphore encoder puis libérer le sémaphore.
pendant que le processus écrit les autres sont bloqués
*/

void shmsem()
{
int size = sizeof(FICHE);

fd = shm_open("example", O_RDWR|O_CREAT,S_IRWXO|S_IRWXG|S_IRWXU);
if (fd < 0)
{
perror("open error ");
exit(0);
}
if ((ftruncate(fd, size)) == -1)
{
perror("ftruncate failure");
exit(0);
}

pg_addr = (caddr_t) mmap(0, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED,fd, 0);
if (pg_addr == (caddr_t) -1)
{
perror("mmap failure");
exit(0);
}
/*le sémaphore initial*/
mysemp = sem_open("mysemp", O_CREAT | O_RDWR, 0644, 1);
if (mysemp == (void *)-1)
{
perror("sem_open() failed ");
}
/*le sémaphore compteur*/
cpt = sem_open("mycpt", O_CREAT | O_RDWR, 0644, 0);
if (cpt == (void *)-1)
{
perror("sem_open() failed ");
}
sem_post(cpt);
}
void Ecrire()
{
FICHE nouveau;
int a;
char n[20], p[20];
/* ATTENTE DU SEMA : SEM_WAIT */
printf ("En attente.....\n");
sem_wait(mysemp);

printf ("ECRITURE\n");
fflush(stdin);
printf("Nom:");
scanf("%s",&n);
fflush(stdin);
printf("Prenom:");
scanf("%s",&p);
printf("Age:");
scanf("%d",&a);

strcpy(nouveau.nom, n);
strcpy(nouveau.prenom, p);
nouveau.age=a;
memcpy(pg_addr, &nouveau, sizeof(FICHE));

/* LIBERATION DU SEMA : SEM_POST */
sem_post(mysemp);
}
/*
prendre le sémaphore, lire, afficher et libérer le sémaphore.
pendant que le processus lit les autres sont bloqués
*/
void Lire()
{
FICHE pers;
printf ("LECTURE\n");
/* ATTENTE DU SEMA : SEM_WAIT */
printf ("En attente......\n");
sem_wait(mysemp);

memcpy(&pers, pg_addr, sizeof(FICHE));
printf ("Nom : %s\t Prenom : %s\t Age : %d\n",pers.nom,pers.prenom,pers.age);
/* LIBERATION DU SEMA : SEM_POST */
sem_post(mysemp);
fflush(stdin);
getchar();
}
/*
le dernier processus qui reste doit détruire toutes les ressources :
mémoire partagée et sémaphore.
*/
void Quitter()
{
int val;
sem_wait(cpt);
sem_getvalue(cpt,&val);
if(val==0)
{
sem_close(mysemp);
sem_close(cpt);
sem_unlink ("mysemp");
sem_unlink("mycpt");
close(fd);
shm_unlink("example");
}
}

main()
{
char car;
shmsem();
do
{
printf("\033[2J");
Menu();
/* ignore tous les caracteres non alphanumeriques */
while(!isalnum(car=getchar()));
switch (car)
{
case '1': Ecrire();
break;
case '2': Lire();
break;
case '3': Quitter();
break;
default: fprintf(stderr,"%c: commande inconnue !\n",car);
}
}while (car != 'q');

getchar();
}
mais à la compilation j'obtiens les ereeurs suivantes:
/tmp/ccIlvtPs.o: dans la fonction « shmsem »:
/home/karimi/psindus/labo8/shmsem8.c:55: référence indéfinie vers « shm_open »
/home/karimi/psindus/labo8/shmsem8.c:74: référence indéfinie vers « sem_open »
/home/karimi/psindus/labo8/shmsem8.c:80: référence indéfinie vers « sem_open »
/home/karimi/psindus/labo8/shmsem8.c:85: référence indéfinie vers « sem_post »
/tmp/ccIlvtPs.o: dans la fonction « Ecrire »:
/home/karimi/psindus/labo8/shmsem8.c:94: référence indéfinie vers « sem_wait »
/home/karimi/psindus/labo8/shmsem8.c:112: référence indéfinie vers « sem_post »
/tmp/ccIlvtPs.o: dans la fonction « Lire »:
/home/karimi/psindus/labo8/shmsem8.c:124: référence indéfinie vers « sem_wait »
/home/karimi/psindus/labo8/shmsem8.c:129: référence indéfinie vers « sem_post »
/tmp/ccIlvtPs.o: dans la fonction « Quitter »:
/home/karimi/psindus/labo8/shmsem8.c:140: référence indéfinie vers « sem_wait »
/home/karimi/psindus/labo8/shmsem8.c:141: référence indéfinie vers « sem_getvalue »
/home/karimi/psindus/labo8/shmsem8.c:144: référence indéfinie vers « sem_close »
/home/karimi/psindus/labo8/shmsem8.c:145: référence indéfinie vers « sem_close »
/home/karimi/psindus/labo8/shmsem8.c:146: référence indéfinie vers « sem_unlink »
/home/karimi/psindus/labo8/shmsem8.c:147: référence indéfinie vers « sem_unlink »
/home/karimi/psindus/labo8/shmsem8.c:149: référence indéfinie vers « shm_unlink »
collect2: ld returned 1 exit status

apparemment gcc ne recoonait pas les fonctions pour la mémoire partagée des fichiers en-têtes <sys/types.h> et <sys/mman.h>
ou alors est-ce un problème du linker j'ai fait le tour d'internet pour voir si quelqu'un avait eu précédemment ce genre de problèmes, mes recherches étaient vaines alors je m'adresses à vous dans l'espoir que vous puissiez m'aider s'il vous plaît et merci encore
  • # man shm_open

    Posté par  . Évalué à 5.

    NOTES
    These functions are provided in glibc 2.2 and later. Programs using these functions must specify the -lrt flag to cc in order to link against the required ("realtime") library.

    Utilise la commande suivante et ça devrait compiler :
    gcc -o shmsem -g -lm -lrt shmsem8.c
  • # En passant...

    Posté par  . Évalué à 3.

    Pour avoir un prototype complet, il faut préciser les paramètres. Dans le cas où une fonction ne prend pas de paramètre, il faut la déclarer ainsi:
    type_retour nom_fonction(void)

    Si on la définit de la manière que tu as faite
    type_retour nom_fonction()
    alors on retombe sur les "anciennes" déclarations (au sens C), et aucun contrôle n'est fait par le compilateur sur les paramètres envoyés: voir la phrase 6.7.5.3.p14 du n1124:
    The empty list in a function declarator that is not part of a
    definition of that function specifies that no information about the number or types of the parameters is supplied.

    comparée avec 6.7.5.3.p10:
    The special case of an unnamed parameter of type void as the only item in the listspecifies that the function has no parameters.

    Donc avec tes protoypes
    void Menu();
    void Ecrire();
    void shmsem();
    void Lire();
    void Quitter();
    tu as le droit d'appeler ensuite les fonctions avec des paramètres quelquonques, ce qui diminue l'utilité du protoype...
    - - - - - - -
    main()
    {

    Les deux seules manières portables de définir main sont int main(void)et int main(int argc, char **argv) (ou des définitions compatibles, comme char *argv[]). Le reste est dépendant de la plate-forme.

    - - - - - - -
      char car;
      do
      {
        <snip>
        /* ignore tous les caracteres non alphanumeriques */
        while(!isalnum(car=getchar()));

    Non. getchar() renvoie un int. Sa valeur de retour exacte est:
    - soit le prochain caractère en unsigned char;
    - soit EOF si le flux est "fini".
    cf. 7.19.7.1p2
    If the end-of-file indicator for the input stream pointed to by stream is not set and a next character is present, the fgetc function obtains that character as an unsigned char converted to an int

    7.19.7.1 p3:
    If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the endof-
    file indicator for the stream is set and the fgetc function returns EOF.

    et 7.19.1p3
    EOF
    which expands to an integer constant expression, with type int and a negative

    Donc, envoyer le résultat de getchar (qui est un équivalent de getc(stdin), lui-même (quasi) équivalent à fgetc(stdin)) dans un char peut causer une perte d'information si ton implémentation définit le char comme signé.
    En pratique, EOF peut valoir par exemple -1, qui correspond parfois à la valeur signed char du caractère ÿ, si je me souviens bien. Ce qui signifie que, si tu lis ce ÿ avec ton code (ou d'autres caractères suivant l'environnement), sa valeur unsigned déborde la capacité du signed char, et retombe sur -1 par les règles de conversions entières. Tu croiras voir un EOF, donc isalnum() renvoie faux, et le while le bouffera sans broncher... Dans ton cas, ce n'est pas forcément grave, mais l'erreur peut porter à conséquence dans d'autres contextes.
    • [^] # Re: En passant...

      Posté par  . Évalué à 3.

      Oups... J'ai mangé un mot en citant le paragraphe 7.19.1p3
      EOF
      which expands to an integer constant expression, with type int and a negative value
      . (c'est moi qui souligne).

      Et mon commentaire
      Donc, envoyer le résultat de getchar [...] dans un char peut causer une perte d'information si ton implémentation définit le char comme signé.
      est incomplet: la perte d'information arrivera même si le char est non signé (vu que EOF est une valeur qui se rajoute à l'ensemble des valeurs valides des caractères).
      • [^] # Re: En passant...

        Posté par  . Évalué à 2.

        serais-tu entrain de nous dire que ce code qui
        fait fi de la portabilité, qui n'utilise pas les fonctions standards comme définies dans la documentation, qui n'initialise pas ses variables avant de les utiliser, qui utilise des pointeurs avant de regarder s'ils pointent vers quelquechose, qui est fortement "buffer-overflow-able" est du code crade ? :))
        • [^] # Re: En passant...

          Posté par  . Évalué à 1.

          merci à tous pour vos éclaircissements !!!
        • [^] # Re: En passant...

          Posté par  . Évalué à 2.

          C'est vrai, j'avais lu en très grande diagonale, sachant que la réponse au pbolème était déjà donnée.. Mais c'est vrai que
          pg_addr = (caddr_t) mmap(0, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_SHARED,fd, 0);
          if (pg_addr == (caddr_t) -1)
          {
          perror("mmap failure");
          exit(0);
          }
          est très moche. Caster -1 en pointeur, c'est assez ignoble (au passage, c'est non portable). mmap() renvoie MAP_FAILED en cas d'erreur (suivant POSIX; après si l'implémentation n'est pas conforme, c'est autre chose...).
          De plus, exit(0) pour signaler une erreur ! EXIT_FAILURE sert à ça.
          Qui plus est, faire un exit() alors qu'on a soi-même défini une fonction Quitter, c'est illogique.

          En relisant un peu mieux, on a aussi:
          - fflush(stdin);, cf. http://c-faq.com/stdio/stdinflush2.html .
          - scanf(), cf. http://mapage.noos.fr/emdel/notes.htm#saisie
          - int size = sizeof(FICHE);, alors que sizeof renvoie un size_t, et que c'est justement ce que mmap() est censé recevoir...

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.