Partage
  • Partager sur Facebook
  • Partager sur Twitter

Accès à une variable static d'une fonction.

Sujet résolu
    10 décembre 2023 à 2:07:43

    Bonjour,

    Je suis à peu près persuadé que ce n'est pas possible, mais au cas où il y aurait une astuce, j'aimerais savoir s'il y a un moyen d'accéder à une variable static déclarée dans une fonction.

    J'ai une fonction (dédiée) qui affiche un texte en fading :

    bool SOFT_dispTextFade(char *text, uint32_t time, SDL_Color color)
    {//displays fading text
    
        static CEV_Timer timer = {.run = false};
    
        static SDL_Texture *texture = NULL;
    
        static SDL_Rect clip = CLEAR_RECT,
                        blit = CLEAR_RECT;
    
        static bool isActive = false;
    
        timer.run = isActive;
    
        //creates instance when new text is sent
        if NOT_NULL(text)
        {
            SDL_DestroyTexture(texture);
            texture = CEV_createTTFTexture(text, mainFont, color);
            SDL_QueryTexture(texture, NULL, NULL, &clip.w, &clip.h);
            blit.w = 4*clip.w;
            blit.h = 4*clip.h;
            blit.x = (SCREEN_WIDTH - blit.w)/2;
            blit.y = SCREEN_HEIGHT / 10;
            CEV_timerInit(&timer, time);
            isActive = true;
        }
        else if (isActive)
        {//displaying text while active
            uint8_t alpha = (uint8_t)CEV_map(timer.accu, timer.preset, 0, SDL_ALPHA_OPAQUE, SDL_ALPHA_TRANSPARENT);
            SDL_SetTextureAlphaMod(texture, alpha);
            SDL_RenderCopy(CEV_videoSystemGet()->render, texture, &clip, &blit);
            isActive = !CEV_timerTon(&timer);
    
            if(!isActive)
            {//if done, clearing alloc
                SDL_DestroyTexture(texture);
                texture = NULL;
            }
        }
    
        return isActive || NOT_NULL(texture);
    }

    Comme vous le voyez, elle est en charge des allocs et des destructions.

    Du coup, pour être certain de finir une routine proprement, avec mes libérations en fin de routine, je dois ajouter :

    //waiting display statics to be freed.
        while(SOFT_dispTextFade(NULL, 0, CEV_COLOR_WHITE));

    Ce qui renvient à attendre la fin de l'affichage pour quitter la routine.

    Du coup, j'aimerais pouvoir detruire la texture sans attendre, j'ai pensé à ajouter un argument genre "bool kill" et forcer la destruction de la texture, et c'est probablement comme ça que ça va se finir.

    Au cas où j'apprendrais un nouveau truc..

    Merci.

    • Partager sur Facebook
    • Partager sur Twitter

    Bonhomme !! | Jeu de plateforme : Prototype.

      10 décembre 2023 à 2:50:58

      Hello,

      Hé non, toute les variables déclarées dans une fonction, n'existent qu'au sein de cette fonction. Elles sont inconnues du reste du programme.

      Edit: t'imagines le bordel si deux fonctions déclarent chacune une variable du même nom ?

      -
      Edité par edgarjacobs 10 décembre 2023 à 3:00:10

      • Partager sur Facebook
      • Partager sur Twitter

      On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

        10 décembre 2023 à 8:44:47

        La déclaration static dans une fonction, c'est précisément pour avoir une variable statique (emplacement réservé une fois pour toutes, et dont la durée de vie est celle du programme) qui soit visible seulement depuis la fonction locale, donc).

        Donc la demande initiale est contradictoire.

        Sinon, il faut utiliser des variables globales, déclarées hors des fonctions. (*) Avec un nom bien choisi pour éviter les collisions.

        Variable statique, c'est par opposition aux variables automatiques, qui correspondent à des emplacements réservés sur la pile à chaque appel de la fonction oû elles sont déclarées, et restitués automatiquement en ressortant. Ne pas confondre avec allocation dynamique.

        (*) je crois qu'on peut déclarer aussi les variables globales comme static, et dans ce cas elles ne sont visibles que dans l'unité de compilation (le source) oû elles sont déclarées, ce qui limite les risques d'utilisation indue. A verifier.

        -
        Edité par michelbillaud 10 décembre 2023 à 9:00:07

        • Partager sur Facebook
        • Partager sur Twitter
          10 décembre 2023 à 9:30:29

          michelbillaud a écrit:


          (*) je crois qu'on peut déclarer aussi les variables globales comme static, et dans ce cas elles ne sont visibles que dans l'unité de compilation (le source) oû elles sont déclarées, ce qui limite les risques d'utilisation indue. A verifier.

          Perso je confirme

          • Partager sur Facebook
          • Partager sur Twitter

          Le crayon la gomme et le papier sont les meilleurs outils du programmeur !

            10 décembre 2023 à 10:52:33

            drx a écrit:

            Je suis à peu près persuadé que ce n'est pas possible, mais au cas où il y aurait une astuce, j'aimerais savoir s'il y a un moyen d'accéder à une variable static déclarée dans une fonction.

            Je n'ai pas tout compris, mais pour cette question, c'est possible via un pointeur (mais alors quel intérêt d'avoir une variable static si c'est pour y accéder de l’extérieur). 

            • Partager sur Facebook
            • Partager sur Twitter
            ...
              10 décembre 2023 à 14:07:26

              Salut,

              rouIoude a écrit:

              Je n'ai pas tout compris, mais pour cette question, c'est possible via un pointeur (mais alors quel intérêt d'avoir une variable static si c'est pour y accéder de l’extérieur).

              L'intérêt de la déclarer static ici est sa rémanence, pas sa portée, ça m'évite d'avoir à créer une structure d'instance (et un type) alors que je n'ai besoin que d'une seule instance.

              Comme tu le soulignes, je sais que c'est possible avec un ptr puisque :

              int* fooWithStatic(void)
              {
                  static int toto = 23;
              
                  printf("toto = %d\n", toto);
              
                  return &toto;
              
              }
              
              int main(void)
              {
                  int *ptr = fooWithStatic(),
                      val = 10;
              
                  while (val<15)
                  {        
                     *ptr = val++;
                     fooWithStatic();
                  }
                  
                  return 0;
              }
              toto = 23
              toto = 10
              toto = 11
              toto = 12
              toto = 13
              toto = 14
              
              Process returned 0 (0x0)   execution time : 0.184 s
              Press any key to continue.

              Pour reformuler un peu mieux :

              drx a écrit:

              Je suis à peu près persuadé que ce n'est pas possible, mais au cas où il y aurait une astuce, j'aimerais savoir s'il y a un moyen d'accéder - DIRECTEMENT - à une variable static déclarée dans une fonction.

              Je pensais à un truc dans le genre de : 

              fooWithStatic->toto

              Parce que j'ai peur qu'utiliser un pointeur vers une locale de fonction soit un peu obscur : Ce n'est déjà pas très "typique" et je suis certain que je vais galérer à me relire dans 2 mois avec ma super mémoire de poiscaille.

              C'est pour ça que l'option d'une "syntaxe legit" ou du bit "kill" à l'appel de fonction me semblait plus explicite.

              Mais s'il n'y a pas, il n'y a pas.

              Merci à tous.

              -
              Edité par drx 10 décembre 2023 à 14:08:48

              • Partager sur Facebook
              • Partager sur Twitter

              Bonhomme !! | Jeu de plateforme : Prototype.

                10 décembre 2023 à 16:59:02

                Un exemple historique et tragique d'utilisation de variables statiques, c'est la fonction strtok, qui sert à découper une chaîne en une suite d'éléments (tokens).

                Elle utilise une variable statique pour mémoriser l'adresse de ce qui reste à analyser (un pointeur de caractères)

                Elle a deux paramètres, une adresse de caractères et un ensemble de délimiteurs

                 char *strtok(char *restrict str, const char *restrict delim);
                   

                Typiquement,  la premiere fois qu'on l'appelle, on donne en premier paramètre la chaîne à analyser, et alors son adresse est mémorisée dans le pointeur statique. 
                Les fois suivantes on passe NULL, et l'analyse se fait en utilisant  le pointeur statique.

                Avec cette astuce géniale (ahem...), c'est pas possible de travailler sur deux chaînes en même temps, et si on a deux threads, c'est la cata. On applaudit très fort (déjà que c'était pas une idée brillante d'avoir une fonction d'analyse qui modifie la chaine à analyser...)

                Note : utiliser à la place la version réentrante strtok_r


                Ici https://github.com/walac/glibc/blob/master/string/strtok.c une version qui n'emploie pas une variable statique, mais une variable globale (olds) déclarée static pour limiter sa visiblité, comme expliqué plus haut

                static char *olds;
                
                
                /* Parse S into tokens separated by characters in DELIM.
                   If S is NULL, the last string strtok() was called with is
                   used.  For example:
                	char s[] = "-abc-=-def";
                	x = strtok(s, "-");		// x = "abc"
                	x = strtok(NULL, "-=");		// x = "def"
                	x = strtok(NULL, "=");		// x = NULL
                		// s = "abc\0=-def\0"
                */
                char *
                strtok (s, delim)
                     char *s;
                     const char *delim;
                {
                  char *token;
                
                  if (s == NULL)
                    s = olds;
                
                  /* Scan leading delimiters.  */
                  s += strspn (s, delim);
                  if (*s == '\0')
                    {
                      olds = s;
                      return NULL;
                    }
                
                  /* Find the end of the token.  */
                  token = s;
                  s = strpbrk (token, delim);
                  if (s == NULL)
                    /* This token finishes the string.  */
                    olds = __rawmemchr (token, '\0');
                  else
                    {
                      /* Terminate the token and make OLDS point past it.  */
                      *s = '\0';
                      olds = s + 1;
                    }
                  return token;
                }

                (présente les mêmes inconvénients que déclarer la variable static dans la fonction)
                -----

                Complément, un exemple minimal de ce que je racontais plus haut (variables globales statiques)

                SI on met ceci dans main.c

                extern int x;
                int main() {
                	return x;
                }
                

                et que aux.c contient

                int x = 123;
                

                tout va bien

                $  gcc *.c
                $ ./a.out 
                $ echo $?
                123
                

                depuis le main.c on a pu accéder à la variable globale définie dans aux.c

                Mais si on met static

                static int x = 123;
                

                Les compilations séparées de chaque unité de compilation se passent bien , mais ça proteste au niveau de l'édition des liens

                $ gcc -c aux.c
                $ gcc -c main.c
                
                
                $ gcc main.o aux.o
                /usr/bin/ld: main.o: attention: réadressage sur « x » dans la section en lecture seule « .text »
                /usr/bin/ld : main.o : dans la fonction « main » :
                main.c:(.text+0x6) : référence indéfinie vers « x »
                /usr/bin/ld: attention: création de DT_TEXTREL dans un PIE
                collect2: error: ld returned 1 exit status
                


                Avec static, le nom de la variable globale n'est pas exporté, et donc ne peut pas être référencé par main.c







                -
                Edité par michelbillaud 11 décembre 2023 à 16:23:15

                • Partager sur Facebook
                • Partager sur Twitter

                Accès à une variable static d'une fonction.

                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                • Editeur
                • Markdown