Partage
  • Partager sur Facebook
  • Partager sur Twitter

Affecter une valeur négative à un float

en passant par un pointeur

    5 mai 2023 à 23:15:08

    Bonjour, je suis sur une problématique, je n'arrive pas à affecter une valeur négative à mon float.

    J'ai des structures basiques, je ne vais pas toutes les mettre pour + clarté, voici l'une d'entre elles:

    typedef float	t_vector __attribute__((ext_vector_type(3)));
    
    typedef struct	s_color
    {
    	int	r;
    	int	g;
    	int	b;
    }				t_color;
    
    typedef struct	s_ambient_light
    {
    	char		identifier[3];
    	t_color		color;
    	float		ratio;
    }				t_ambient_light;
    
    typedef struct	s_figure
    {
    	t_ambient_light	ambient_light;
    	t_camera		camera;
    	t_light			light;
    	t_sphere		sphere;
    	t_plan			plan;
    	t_cylindre		cylindre;
    }				t_figure;

    Et voici mon test

    t_figure	infos = { 0 };
    	void *ptr = & infos;
    
    	*((int *)(ptr + sizeof(int))) = 42;
    	*((int *)(ptr + sizeof(int) * 2)) = 18;
    	*((int *)(ptr + sizeof(int) * 3)) = 127;
    	*((float *)(ptr + sizeof(int) * 3 + sizeof(float))) = 193.;
    	
    	print_figure_structs(infos);

    Tout fonctionne ici dans ce test, mais si je met la valeur en négative par exemple ici à -193., la valeur se retrouve tronqué! pourquoi ca ?

    Pourriez vous m'aider svp

    • Partager sur Facebook
    • Partager sur Twitter
      6 mai 2023 à 0:13:46

      Hello,

      Ce code fonctionne:

      int main(void) {
      	t_figure infos = { 0 };
          void *ptr = & infos;
      
          *((int *)(ptr + sizeof(int))) = 42;
          *((int *)(ptr + sizeof(int) * 2)) = 18;
          *((int *)(ptr + sizeof(int) * 3)) = 127;
          *((float *)(ptr + sizeof(int) * 3 + sizeof(float))) = -193.;
      	
      	printf("%d\n", *(int*)(ptr + sizeof(int)));
      	printf("%d\n", *(int*)(ptr + sizeof(int) * 2));
      	printf("%d\n", *(int*)(ptr + sizeof(int) * 3));
      	printf("%f\n", *(float *)(ptr + sizeof(int) * 3 + sizeof(float)));
      	
      	return(0);
      }

      Sortie

      42
      18
      127
      -193.000000
      


      Mais pourquoi ces écritures tellement tarabiscotées, qui mettent à rude épreuve les neurones ?

      int main2(void) {
      	t_figure infos = { 0 };
      
      	infos.ambient_light.color.r = 42;
      	infos.ambient_light.color.g = 18;
      	infos.ambient_light.color.b = 127;
      	infos.ambient_light.ratio = -193.;
      	
      	printf("%d\n", infos.ambient_light.color.r);
      	printf("%d\n", infos.ambient_light.color.g);
      	printf("%d\n", infos.ambient_light.color.b);
      	printf("%f\n", infos.ambient_light.ratio);
      	
      	return(0);
      }

      C'est-y-pas plus lisible ?

      -
      Edité par edgarjacobs 6 mai 2023 à 0:57:44

      • 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

        6 mai 2023 à 0:58:45

        Etrange, chez moi cela ne fonctionne pas :/

        Auriez vous une idée du pourquoi du comment ? Et si j'essaie de faire ça comme ça, c'est pour faire une fonction générique qui prend une structure parmi mon ensemble de structure et comme elle contiennent à peu prés toute les mêmes propriétés autant faire ça que de faire une fonction pour chaque structure

        EDIT: Ah si autant pour moi! j'utilisais ma version de printf qui n'était pas complète sur les float >_<

        Merci!

        -
        Edité par antoinelds 6 mai 2023 à 1:02:45

        • Partager sur Facebook
        • Partager sur Twitter
          6 mai 2023 à 1:11:11

          Non, pas la moindre idée. Mais tu ne montres pas ta fonction print_figure_structs().

          Quant à la généricité, tu feras comme tu veux, mais c'est toi qui va te casser la tête à lire tes pointeurs. Je préfère de loin écrire plusieurs fonctions qui seront sans ambiguités.

          Edit: écrire un programme, c'est aussi penser à la lisibilité du code, et à sa maintenance.

          -
          Edité par edgarjacobs 6 mai 2023 à 1:22:01

          • 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

            6 mai 2023 à 3:36:49

            Bon, je viens de réussir mais effectivement je viens de penser à un truc auquel j'aurais du y penser plus tôt.

            Je peux avoir x nombres de structure et ça, ça fausse tout .. enfin peut-être en multipliant j'atteindrai le bon endroit pointé mais bon pour relire après ^^

            Merci en tout cas!

            • Partager sur Facebook
            • Partager sur Twitter
              6 mai 2023 à 11:18:02

              Et l'offset pour accéder au float n'est pas le bon. Il faut "sauter" 4 int pour y accéder
                  *((float *)(ptr + sizeof(int) * 4)) = -193.;
              

              La taille d'un int est souvent la même que celle de float mais pas toujours.
              Mais tous les offsets supposent que les 3 char après alignement reviennent à la taille d'un int (offset du 1er int), ça n'est pas non plus toujours le cas.

              Pour accéder de manière tarabiscotée à ces offsets, il existe la macro offsetof(type,membre).

              • Partager sur Facebook
              • Partager sur Twitter

              En recherche d'emploi.

                6 mai 2023 à 13:46:21

                Selon les alignements mémoire d'une machine à une autre, tu pourras avoir de sacré surprises, des comportements aléatoires...

                Hormis le fait que c'est non maintenable, craignos, et dégueulasse. 

                Je te suggère d'utiliser les champs de structure correctement, genre figure.light.color.r = 6;

                Si vraiment tu veux avoir soit du float, soit du int, tu fais un union.

                Tout est prévu dans le langage pour faire des choses de propres.

                • Partager sur Facebook
                • Partager sur Twitter

                Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                  7 mai 2023 à 11:51:21

                  Fainéant comme je suis, vu qu'il faudra certainement initialiser différentes couleurs, j'écrirais plutôt

                  infos.ambient_light.color = COLOR(42, 18, 127);

                  Ce qui fait une ligne lisible dont l'intention est claire, plutôt que 3 qui bricolent des détails minuscules.

                  Avec la macro toute bête

                  #define COLOR(R,G,B) ((t_color){R,G,B})


                  ou

                  #define COLOR(R,G,B) ((t_color){.r = R, .g = G, .b = B})

                  PS : il me semblait que l'arithmétique était interdite sur les pointeurs génériques.

                  Test avec

                  void foo() {
                  	int n;
                  	void *p = &n;
                     
                  	p++;
                  }
                  
                  $ gcc -std=c17 -Wall -Wextra -pedantic -c  b.c 
                  b.c: Dans la fonction « foo »:
                  b.c:5:3: attention: type d'argument erroné pour un incrément [-Wpointer-arith]
                      5 |  p++;
                        |   ^~
                  
                  

                  et qu'il faudrait plutôt ressortir les  char* pour faire ce genre de sport.


                  PS 2: en effet.

                  1. En C il y a 3 espèces de types

                  • les types d'objets
                  • les types de fonctions
                  • les types incomplets (pour lesquels on n"a pas d'information sur leur taille)
                  2. Le standard C définit void comme un type incomplet
                  3. L'addition n'est permise qu'entre deux types arithmétiques, ou un entier avec un pointeur vers un type d'objet. (donc pas void*)
                  gcc le permet néanmoins, mais c'est une extension.

                  -
                  Edité par michelbillaud 7 mai 2023 à 12:09:13

                  • Partager sur Facebook
                  • Partager sur Twitter
                    10 mai 2023 à 2:44:23

                    Merci pour vos conseils, mais dans ce cas comment puis-je en faire une fonction générique plus propre que ça ?

                    Parce-que la problématique est que j'ai plusieurs structures qui contient les mêmes champs et j'aimerai qu'elle passe toute par une seule fonction plutôt que de créer X structures qui feront exactement la même chose avec une ou deux instructions de plus.

                    Je dois parser ce genre de fichier

                    A 8.2 255,255,255
                    C -50,0,20 8,4,3 70
                    L -40,0,30 0.7 255,255,255
                    pl 12,11,8 4.,1.0,6.0 255,18,225
                    
                    
                    
                    
                    sp 7,12,20 20 255,19,48
                    cy 50.0,0.0,20.6 0,0,1.0 14.2 21.42 10,0,255

                    Je stock déjà mon fichier ligne par ligne dans une liste chainée (remix @mbillaud #ptr_array)

                    #ifndef CONTENT_FILE_H
                    # define CONTENT_FILE_H
                    
                    # include "libft.h"
                    # include <math.h>
                    
                    #ifndef MIN_CONTENT_CAPICITY
                    # define MIN_CONTENT_CAPICITY	20
                    #endif
                    
                    #ifndef MAX_CONTENT_READ
                    # define MAX_CONTENT_READ	1
                    #endif
                    
                    typedef struct	s_content_file
                    {
                    	size_t					size;
                    	size_t					capacity;
                    	char					*line;
                    	struct s_content_file	*next;
                    }				t_content_file;
                    
                    t_content_file	*cf_new(void);
                    size_t			cf_size(t_content_file *cf);
                    void			cf_add(char c, t_content_file *cf);
                    void			cf_delete(t_content_file *cf);
                    
                    #endif
                    

                    avec les infos adéquat de la ligne en question, et voici leur implémentation

                    t_content_file	*cf_new(void)
                    {
                    	t_content_file	*cf;
                    
                    	cf = malloc(sizeof(t_content_file));
                    	if (cf)
                    	{
                    		cf -> size = 0;
                    		cf -> capacity = MIN_CONTENT_CAPICITY;
                    		cf -> line = malloc(cf -> capacity + 1);
                    		cf -> next = 0;
                    	}
                    	return (cf);
                    }
                    
                    void	cf_add(char c, t_content_file *cf)
                    {
                    	if (cf -> size == cf -> capacity)
                    	{
                    		cf -> capacity *= 2;
                    		cf -> line = realloc(cf -> line, cf -> capacity);
                    	}
                    	cf -> line[cf -> size++] = c;
                    }
                    
                    void	cf_delete(t_content_file *cf)
                    {
                    	t_content_file	*tmp;
                    
                    	tmp = cf;
                    	while (cf)
                    	{
                    		cf -> size = 0;
                    		cf -> capacity = 0;
                    		ft_memdel((void **)& cf -> line);
                    		tmp = cf -> next;
                    		free(cf);
                    		cf = tmp;
                    	}
                    }
                    
                    size_t	cf_size(t_content_file *cf)
                    {
                    	return cf -> size;
                    }
                    

                    Et pour finir j'ai mes structures

                    #ifndef FIGURE_H
                    # define FIGURE_H
                    
                    #ifndef AMBIENT_LIGHT_IDENTIFIER
                    # define AMBIENT_LIGHT_IDENTIFIER "A"
                    #endif
                    
                    #ifndef CAMERA_IDENTIFIER
                    # define CAMERA_IDENTIFIER "C"
                    #endif
                    
                    #ifndef LIGHT_IDENTIFIER
                    # define LIGHT_IDENTIFIER "L"
                    #endif
                    
                    #ifndef SPHERE_IDENTIFIER
                    # define SPHERE_IDENTIFIER "sp"
                    #endif
                    
                    #ifndef PLAN_IDENTIFIER
                    # define PLAN_IDENTIFIER "pl"
                    #endif
                    
                    #ifndef CYLINDER_IDENTIFIER
                    # define CYLINDER_IDENTIFIER "cy"
                    #endif
                    
                    typedef float	t_vector __attribute__((ext_vector_type(3)));
                    
                    typedef struct	s_color
                    {
                    	int	r;
                    	int	g;
                    	int	b;
                    }				t_color;
                    
                    typedef struct	s_ambient_light
                    {
                    	char		identifier[3];
                    	t_color		color;
                    	float		ratio;
                    }				t_ambient_light;
                    
                    typedef struct	s_camera
                    {
                    	char		identifier[3];
                    	t_vector	viewpoint;
                    	t_vector	orientation;
                    	float		FOV;
                    }				t_camera;
                    
                    typedef struct	s_light
                    {
                    	char		identifier[3];
                    	t_vector	point;
                    	t_color		color;
                    	float		brightness;
                    }				t_light;
                    
                    typedef struct	s_sphere
                    {
                    	char		identifier[3];
                    	t_vector	point;
                    	t_color		color;
                    	float		diameter;
                    }				t_sphere;
                    
                    typedef struct	s_plan
                    {
                    	char		identifier[3];
                    	t_vector	point;
                    	t_vector	orientation;
                    	t_color		color;
                    }				t_plan;
                    
                    typedef struct	s_cylinder
                    {
                    	char		identifier[3];
                    	t_vector	center;
                    	t_vector	cylinder_axis;
                    	float		diameter;
                    	float		height;
                    	t_color		color;
                    }				t_cylinder;
                    
                    typedef struct	s_figure
                    {
                    	t_ambient_light	ambient_light;
                    	t_camera		camera;
                    	t_light			light;
                    	t_sphere		sphere;
                    	t_plan			plan;
                    	t_cylinder		cylinder;
                    }				t_figure;
                    
                    #endif
                    

                    Et enfin, le code général qui en prend charge toute les structures (même si c'est pas propre, je vous l'accorde)

                    #include "parse.h"
                    
                    char	*get_data(char *s)
                    {
                    	int	start;
                    	int	i;
                    
                    	start = 0;
                    	i = 0;
                    	while (ft_isspace(s[i]))
                    		i++;
                    	start = i;
                    	while (s[i] && !ft_isspace(s[i]))
                    		i++;
                    	if (!s[i])
                    		return (s + i);
                    	s[i] = 0;
                    	return (s + start);
                    }
                    
                    static
                    bool	set_color(const char *s, int * const ptr)
                    {
                    	int			nb;
                    	int			i;
                    
                    	i = 0;
                    	while (*s)
                    	{
                    		nb = 0;
                    		while (ft_isdigit(*s))
                    		{
                    			nb = (nb * 10) + *s++ - '0';
                    			if (nb > 255)
                    				return (false);
                    		}
                    		if (i != 2 && *s != ',')
                    			return (false);
                    		*(ptr + i++) = nb;
                    		if (!*s)
                    			break ;
                    		s++;
                    	}
                    	return (true);
                    }
                    
                    static
                    char	*set_vector(char *s, float * const ptr)
                    {
                    	const size_t	size = ft_strlen(s);
                    	size_t			act_size;
                    	char			*find;
                    	int				i;
                    
                    	i = 0;
                    	while (i < 3)
                    	{
                    		find = ft_strchr(s, ',');
                    		if (!find && i != 2)
                    			return (NULL);
                    		if (i != 2)
                    			*find = 0;
                    		*(ptr + i) = atof(s);
                    		act_size = ft_strlen(s);
                    		if (size > act_size + 1)
                    			s += act_size + 1;
                    		else
                    			return (NULL);
                    		i++;
                    	}
                    	return (s);
                    }
                    
                    bool	fill_struct(char *content, char *origin, const size_t size, void * const ptr)
                    {
                    	size_t	act_size;
                    
                    	content = get_data(content);
                    	if (ft_strcmp((char *)ptr, AMBIENT_LIGHT_IDENTIFIER) == 0) {
                    		*(float *)(ptr + sizeof(t_color) + sizeof(float)) = atof(content); // ratio
                    		act_size = ft_strlen(content);
                    		if (size > act_size + 1)
                    			content += act_size + 1;
                    		else
                    			return (false);
                    		return (set_color(content, ptr + sizeof(char [3]) + 1));
                    	}
                    	content = set_vector(content, ptr + sizeof(t_vector));	// viewpoint/point/center
                    	if (!content)
                    		return (false);
                    	if (ft_strcmp((char *)ptr, CAMERA_IDENTIFIER) == 0
                    		|| ft_strcmp((char *)ptr, PLAN_IDENTIFIER) == 0
                    		|| ft_strcmp((char *)ptr, CYLINDER_IDENTIFIER) == 0) {
                    		content = get_data(content);
                    		content = set_vector(content, ptr + (sizeof(t_vector) * 2)); // orientation
                    		if (!content)
                    			return (false);
                    		if (ft_strcmp((char *)ptr, PLAN_IDENTIFIER) == 0)
                    			return (set_color(content, ptr + (sizeof(t_vector) * 3)));
                    		content = get_data(content);
                    		*(float *)(ptr + sizeof(t_vector) * 3) = atof(content);
                    		if (ft_strcmp((char *)ptr, CYLINDER_IDENTIFIER))
                    			return (origin + (size - 1) == content + ft_strlen(content));
                    		content += ft_strlen(content) + 1;
                    		content = get_data(content);
                    		*(float *)(ptr + sizeof(t_vector) * 3 + sizeof(float)) = atof(content);
                    		content += ft_strlen(content) + 1;
                    		return (set_color(content, ptr + (sizeof(t_vector) * 3) + (sizeof(float) * 2)));
                    	}
                    	content = get_data(content);
                    	*(float *)(ptr + (sizeof(t_vector) * 2) + sizeof(t_color)) = atof(content); // ratio/diameter_sphere
                    	act_size = ft_strlen(content);
                    	return (size > act_size + 1 && set_color(content + act_size + 1, ptr + (sizeof(t_vector) * 2)));
                    }
                    
                    static
                    int	get_index_from_identifier(const char *identifier)
                    {
                    	const char * const identifiers[MAX_PARAMETERS] = {
                    		AMBIENT_LIGHT_IDENTIFIER, CAMERA_IDENTIFIER, LIGHT_IDENTIFIER,
                    		SPHERE_IDENTIFIER, PLAN_IDENTIFIER, CYLINDER_IDENTIFIER
                    	};
                    	int	i;
                    
                    	i = 0;
                    	while (i < MAX_PARAMETERS)
                    	{
                    		if (ft_strcmp(identifier, identifiers[i]) == 0)
                    			return (i);
                    		i++;
                    	}
                    	return (-1);
                    }
                    
                    bool	parse_line(t_content_file *node, t_figure *infos)
                    {
                    	void * const addrs[MAX_PARAMETERS] = {
                    		& infos -> ambient_light,
                    		& infos -> camera,
                    		& infos -> light,
                    		& infos -> sphere,
                    		& infos -> plan,
                    		& infos -> cylinder,
                    	};
                    	char	*tmp;
                    	size_t	act_size;
                    	int		index;
                    
                    	tmp = node -> line;
                    	tmp = get_data(tmp);
                    	index = get_index_from_identifier(tmp);
                    	if (index == -1)
                    		return (false);
                    	ft_strcpy((char *)addrs[index], tmp);
                    	act_size = ft_strlen(tmp);
                    	if (node -> size > act_size + 1)
                    		tmp += act_size + 1;
                    	return (fill_struct(tmp, node -> line, node -> size, addrs[index]));
                    }
                    

                    Comment auriez-vous fait, vous ? 

                    Dalfab a écrit:

                    Pour accéder de manière tarabiscotée à ces offsets, il existe la macro offsetof(type,membre).

                     Je ne connaissais pas cette macro, merci!

                    Fvirtman a écrit:

                    Selon les alignements mémoire d'une machine à une autre, tu pourras avoir de sacré surprises, des comportements aléatoires...

                     Si j'utilise toujours sizeof() pour déterminer la taille du type en question, en quoi cela va me porter préjudice ?

                    michelbillaud a écrit:

                    Fainéant comme je suis, vu qu'il faudra certainement initialiser différentes couleurs, j'écrirais plutôt

                    infos.ambient_light.color = COLOR(42, 18, 127);

                    Ce qui fait une ligne lisible dont l'intention est claire, plutôt que 3 qui bricolent des détails minuscules.

                    Avec la macro toute bête

                    #define COLOR(R,G,B) ((t_color){R,G,B})


                    ou

                    #define COLOR(R,G,B) ((t_color){.r = R, .g = G, .b = B})
                    Les compounds oui, très utile je l'admet!

                    michelbillaud a écrit:

                    PS : il me semblait que l'arithmétique était interdite sur les pointeurs génériques.

                    Test avec

                    void foo() {
                    	int n;
                    	void *p = &n;
                       
                    	p++;
                    }
                    
                    $ gcc -std=c17 -Wall -Wextra -pedantic -c  b.c 
                    b.c: Dans la fonction « foo »:
                    b.c:5:3: attention: type d'argument erroné pour un incrément [-Wpointer-arith]
                        5 |  p++;
                          |   ^~
                    
                    

                    et qu'il faudrait plutôt ressortir les  char* pour faire ce genre de sport.


                    PS 2: en effet.

                    1. En C il y a 3 espèces de types

                    • les types d'objets
                    • les types de fonctions
                    • les types incomplets (pour lesquels on n"a pas d'information sur leur taille)
                    2. Le standard C définit void comme un type incomplet
                    3. L'addition n'est permise qu'entre deux types arithmétiques, ou un entier avec un pointeur vers un type d'objet. (donc pas void*)
                    gcc le permet néanmoins, mais c'est une extension.

                    Je ne savais pas du tout que c'était une extension de gcc!
                    • Partager sur Facebook
                    • Partager sur Twitter
                      10 mai 2023 à 10:01:45

                      antoinelds a écrit:

                      Merci pour vos conseils, mais dans ce cas comment puis-je en faire une fonction générique plus propre que ça ?

                      Parce-que la problématique est que j'ai plusieurs structures qui contient les mêmes champs et j'aimerai qu'elle passe toute par une seule fonction plutôt que de créer X structures qui feront exactement la même chose avec une ou deux instructions de plus.

                      Je dois parser ce genre de fichier

                      A 8.2 255,255,255
                      C -50,0,20 8,4,3 70
                      L -40,0,30 0.7 255,255,255
                      pl 12,11,8 4.,1.0,6.0 255,18,225
                      
                      
                      
                      
                      sp 7,12,20 20 255,19,48
                      cy 50.0,0.0,20.6 0,0,1.0 14.2 21.42 10,0,255


                      Le problème, c'est qu'on (= moi, au moins) ne comprend pas ce que tu veux faire, concrètement.

                      Faisons simple, ta fonction (générique ou pas), à partir d'une des lignes de ce fichier, elle doit produire quoi ? Que ferait

                      type_resultat  resultat = mystere("sp 7,12,20 20 255,19,48");
                      





                      • Partager sur Facebook
                      • Partager sur Twitter
                        10 mai 2023 à 15:28:15

                        antoinelds a écrit:

                        Je dois parser ce genre de fichier

                        A 8.2 255,255,255
                        pl 12,11,8 4.,1.0,6.0 255,18,225
                        

                        Comment auriez-vous fait, vous ? 

                        Si c'était moi...

                        Supposons que le but soit de ranger ces données dans un tableau de structures (probablement celles que tu as définies). (Ou une liste chaînée de structures, peu importe... sauf pour moi, je préfère les tableaux.)

                        Chaque ligne obéit à une syntaxe (je ne sais pas laquelle, j'imagine qu'en relisant tes structures on pourrait la deviner mais je n'ai pas le temps) : plusieurs "mots" séparés par des espaces, la syntaxe dépendant du premier "mot".

                        Si c'était moi, je lirais le fichier caractère par caractère et je mettrais le "mot courant" dans une chaîne de caractères de longueur fixe, par exemple 100 (à mon avis ça rentre).

                        Je lis les caractères du fichier un par un jusqu'à tomber sur un espace ou fin de ligne. Le premier mot courant est donc "A". Une seule lettre, c'est un nom de point. Je le stocke dans mon tableau. Je sais qu'après un nom de point, il y aura un coefficient suivi d'un triplet RVB.

                        Je continue à lire les caractères du fichier un par un jusqu'à tomber sur un espace ou fin de ligne. Le mot courant est cette fois "8.2". C'est le coefficient qui suit le nom de point, je le convertis en nombre à virgule avec 'sscanf', et je le stocke dans mon tableau.

                        Je continue à lire les caractères du fichier un par un jusqu'à tomber sur un espace ou fin de ligne. Le mot courant est "255,255,255". C'est un triplet RVB, je récupère les trois entiers avec 'sscanf' et je les stocke dans le tableau.

                        J'ai noté qu'on a fait un passage à la ligne, donc on a fini de lire le point.

                        Je continue à lire les caractères du fichier un par un jusqu'à tomber sur un espace ou fin de ligne. Le mot courant est cette fois "pl". Ah, cette fois la syntaxe attendue est : triplet d'entiers, triplet de nombres à virgule, triplets d'entiers.

                        Et ainsi de suite...

                        Algorithme :

                        Tant_que pas fin de fichier :
                            numpoint = 0
                            Lire(mot)
                            Exploiter(mot)
                        Fin Tant_que
                        ---------------------------------------------------
                        Lire(mot) :
                            i = 0
                            c = Lire_dans_fichier
                            Tant_que c <> ' ' et c <> '\n' :
                                mot[i] = c
                                i++
                            Fin Tant-que
                            mot[i+1] = '\0'
                        ---------------------------------------------------
                        Exploiter(mot) :
                            Si longueur(mot) == 1 :
                                Exploiter_point(mot)
                            Sinon si longueur(mot) == 2 et (autre critère...)
                                Exploiter_truc(mot)
                            Sinon si longueur(mot) == 2 et (encore un autre critère...)
                                Exploiter_machin(mot)
                        ---------------------------------------------------
                        Exploiter_point(mot) :
                        // Syntaxe attendue : lettre, coeff, triplet RVB
                            Tableau_Point[numpoint].nom = mot    // strcpy
                            Recup_coeff
                            Recup_RVB
                            numpoint++
                        ---------------------------------------------------
                        Recup_coeff :
                            Lire(mot)
                            sscanf(mot,"%d", &n)
                            Tableau_Point[numpoint].coeff = n
                        ---------------------------------------------------
                        Recup_RVB :
                            Lire(mot)
                            sscanf(mot,"%f,%f,%f", &r, &v, &b)
                            Tableau_Point[numpoint].R = r
                            Tableau_Point[numpoint].V = v
                            Tableau_Point[numpoint].B = b
                        

                        Quelque chose comme ça (là j'ai fait vite, c'est juste pour décrire l'idée).

                        -
                        Edité par robun 10 mai 2023 à 15:30:58

                        • Partager sur Facebook
                        • Partager sur Twitter
                          10 mai 2023 à 20:18:22

                          Hello,

                          michelbillaud a écrit:

                          Le problème, c'est qu'on (= moi, au moins) ne comprend pas ce que tu veux faire, concrètement.


                          Faisons simple, ta fonction (générique ou pas), à partir d'une des lignes de ce fichier, elle doit produire quoi ? Que ferait

                          type_resultat  resultat = mystere("sp 7,12,20 20 255,19,48");

                           Avec cette ligne en question en input, voici ce que cela donnerait avec ma structure correspondante, ici t_sphere

                          typedef struct	s_sphere
                          {
                          	char		identifier[3];
                          	t_vector	point;
                          	t_color		color;
                          	float		diameter;
                          }				t_sphere;

                          sphere.identifier = "sp"

                          sphere.point = { .x = 7, .y = 12, .z = 20 }

                          sphere.diameter = 20

                          sphere.color = { .r = 255, g = 19, .b = 48 }

                           Je me rend compte que l'identifier ne sert à rien, mais à part ça, ça devrait être comme ça (lien du Sujet)

                          robun a écrit:

                          Si c'était moi...

                          Supposons que le but soit de ranger ces données dans un tableau de structures (probablement celles que tu as définies). (Ou une liste chaînée de structures, peu importe... sauf pour moi, je préfère les tableaux.)

                          Chaque ligne obéit à une syntaxe (je ne sais pas laquelle, j'imagine qu'en relisant tes structures on pourrait la deviner mais je n'ai pas le temps) : plusieurs "mots" séparés par des espaces, la syntaxe dépendant du premier "mot".

                          Si c'était moi, je lirais le fichier caractère par caractère et je mettrais le "mot courant" dans une chaîne de caractères de longueur fixe, par exemple 100 (à mon avis ça rentre).

                          Je lis les caractères du fichier un par un jusqu'à tomber sur un espace ou fin de ligne. Le premier mot courant est donc "A". Une seule lettre, c'est un nom de point. Je le stocke dans mon tableau. Je sais qu'après un nom de point, il y aura un coefficient suivi d'un triplet RVB.

                          Je continue à lire les caractères du fichier un par un jusqu'à tomber sur un espace ou fin de ligne. Le mot courant est cette fois "8.2". C'est le coefficient qui suit le nom de point, je le convertis en nombre à virgule avec 'sscanf', et je le stocke dans mon tableau.

                          Je continue à lire les caractères du fichier un par un jusqu'à tomber sur un espace ou fin de ligne. Le mot courant est "255,255,255". C'est un triplet RVB, je récupère les trois entiers avec 'sscanf' et je les stocke dans le tableau.

                          J'ai noté qu'on a fait un passage à la ligne, donc on a fini de lire le point.

                          Je continue à lire les caractères du fichier un par un jusqu'à tomber sur un espace ou fin de ligne. Le mot courant est cette fois "pl". Ah, cette fois la syntaxe attendue est : triplet d'entiers, triplet de nombres à virgule, triplets d'entiers.

                          Et ainsi de suite...

                          Algorithme :

                          Tant_que pas fin de fichier :
                              numpoint = 0
                              Lire(mot)
                              Exploiter(mot)
                          Fin Tant_que
                          ---------------------------------------------------
                          Lire(mot) :
                              i = 0
                              c = Lire_dans_fichier
                              Tant_que c <> ' ' et c <> '\n' :
                                  mot[i] = c
                                  i++
                              Fin Tant-que
                              mot[i+1] = '\0'
                          ---------------------------------------------------
                          Exploiter(mot) :
                              Si longueur(mot) == 1 :
                                  Exploiter_point(mot)
                              Sinon si longueur(mot) == 2 et (autre critère...)
                                  Exploiter_truc(mot)
                              Sinon si longueur(mot) == 2 et (encore un autre critère...)
                                  Exploiter_machin(mot)
                          ---------------------------------------------------
                          Exploiter_point(mot) :
                          // Syntaxe attendue : lettre, coeff, triplet RVB
                              Tableau_Point[numpoint].nom = mot    // strcpy
                              Recup_coeff
                              Recup_RVB
                              numpoint++
                          ---------------------------------------------------
                          Recup_coeff :
                              Lire(mot)
                              sscanf(mot,"%d", &n)
                              Tableau_Point[numpoint].coeff = n
                          ---------------------------------------------------
                          Recup_RVB :
                              Lire(mot)
                              sscanf(mot,"%f,%f,%f", &r, &v, &b)
                              Tableau_Point[numpoint].R = r
                              Tableau_Point[numpoint].V = v
                              Tableau_Point[numpoint].B = b
                          

                          Quelque chose comme ça (là j'ai fait vite, c'est juste pour décrire l'idée).

                           Oui c'est déjà un peu ce que je fait, ma fonction get_data sert à ça justement, skip les espaces et me renvoyer juste le bout de chaine correspondante, si j'ai

                          "    12,25,35  20 14"

                          Elle me renverra alors

                          "12,25,35\0  20 14"

                          Et une fois le contenu récupérer je n'aurais juste a skip le \0 pour passer a la prochaine "data" 

                          Mais le problème est le même, c'est que avec tout ce que tu me dis je suis obligé de créer plusieurs fonctions pour chaque structs, après peut-être que c'est moi qui me prend la tête pour rien, et de le fait de créer une fonction pour une structure ne sera jamais mieux que d'en créer autant qu'il y en a. 

                          -
                          Edité par antoinelds 10 mai 2023 à 20:20:30

                          • Partager sur Facebook
                          • Partager sur Twitter
                            10 mai 2023 à 21:03:07

                            S'il y a plusieurs syntaxes différentes pour des types de lignes différents, je serais tenté de choisir entre ces deux alternatives :

                            − Soit on crée en effet plusieurs fonctions pour lire les données en fonction de la syntaxe. Est-ce vraiment un inconvénient ? C'est plus simple, donc plus rapide.

                            − Soit on organise les données différemment. Il me semble que c'est parfois cette solution qu'il faut choisir, en tout cas il ne faut pas hésiter à passer du temps à bien définir l'organisation des données. Mais pour ce que tu fais, je ne sais pas si c'est possible.

                            Après, tout dépend de l'objectif. Si tu as un but pragmatique − ce truc doit marcher − autant aller au plus simple. Mais si tu fais ça pour progresser, je comprends ta démarche : tu vas peut-être en baver, mais aussi progresser.

                            • Partager sur Facebook
                            • Partager sur Twitter
                              10 mai 2023 à 22:05:48

                              robun a écrit:

                              Après, tout dépend de l'objectif. Si tu as un but pragmatique − ce truc doit marcher − autant aller au plus simple. Mais si tu fais ça pour progresser, je comprends ta démarche : tu vas peut-être en baver, mais aussi progresser.

                              C'est exactement ça, je ne veux pas aller au plus simple enfin c'est pas mon but de chercher le plus dur possible non plus mais comme tu l'a si bien dit, bien organiser ses données, au début de ma formation c'est ce que je faisais j'allais au plus simple et j'me disais que de toute façon ce n'est qu'un projet d'école mais en ce moment à chaque nouveau projet je peux rester très longtemps avant de démarrer juste parce-que je me prend la tête à tout organiser correctement. du moins à essayer

                              En tout cas je prend note, merci pour t'es conseils et je vais réfléchir à nouveau si je peux essayer de voir la conception complètement différemment de ce que j'ai pu faire jusqu'à maintenant. je trouvais le fait de jouait avec les adresses c'était cool et c'est la première fois que je fait ça, mais c'est vrai que pour une personne tiers lisant le code, il va s'en mordre les doigts et me maudire :lol:

                              Merci je reviendrai vers vous si j'ai réussi à faire quelquechose de ma matière grise!

                              • Partager sur Facebook
                              • Partager sur Twitter
                                10 mai 2023 à 22:18:01

                                La fonction "generique" qui remplit des structures différentes selon le contenu de la chaîne à analyser , ça ressemble au pattern "factory" (*)

                                Une possibilité serait qu'elle retourne une structure contenant

                                • Une indication de la nature de l'objet (une énumération,  typiquement)
                                • Une union des différentes structures possibles (ou un pointeur générique void* si les structures sont allouées dynamiquement)

                                Ça mériterait un exemple pour illustrer le concept, mais ça sera pas ce soir.

                                Pour faire plus riche, on pourrait même avoir une factory générique, auprès de qui on inscrit (dynamiquement) les fonctions de parsing. On lui dit par exemple, si le premier mot de la ligne est "sp", faut appeler "parse_sphere" qui fera le boulot. Mais bon, c'est peut être un "overkill".

                                (*) ah ben oui, les patterns de conception, c'est pas que pour les langages OO.

                                -
                                Edité par michelbillaud 10 mai 2023 à 22:34:42

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  10 mai 2023 à 22:27:44

                                  michelbillaud a écrit:

                                  La fonction "generique" qui remplit des structures différentes selon le contenu de la chaîne à analyser , ça ressemble au pattern "factory" (*)

                                  Une possibilité serait qu'elle retourne une structure contenant

                                  • Une indication de la nature de l'objet (une énumération,  typiquement)
                                  • Une union des différentes structures possibles (ou un pointeur générique void* si les structures sont allouées dynamiquement)

                                  Ça mériterait un exemple pour illustrer le concept, mais ça sera pas ce soir.

                                  (*) ah ben oui, les patterns de conception, c'est pas que pour les langages OO.


                                  J'avoue que pour l'instant c'est assez flou, j'allais aussi demander un exemple minimaliste mais apparramment ce sera pas pour ce soir, alors j'attendrais votre exemple avec impatience!
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    10 mai 2023 à 23:11:33

                                    > Ça mériterait un exemple pour illustrer le concept, mais ça sera pas ce soir.

                                    J'ai encore craqué.


                                    En simplifiant, juste pour montrer le concept.  Il s'agit d'analyser une ligne contenant un mot (tag) et la description d'un structure dont le type exact (structure contenant un int ou un double) dépend du tag

                                    Les trois tests dans le main

                                      test("entier 123");
                                        test("reel 3.14");
                                        test("wtf abcd");

                                    produisent

                                    Analyse de "entier 123" :
                                    = un entier qui vaut 123
                                    
                                    Analyse de "reel 3.14" :
                                    = un réel qui vaut 3.140000
                                    
                                    Analyse de "wtf abcd" :
                                    = un machin inconnu
                                    


                                    Reste plus qu'à lire le code source pour comprendre

                                    #include <stdio.h>
                                    #include <stdlib.h>
                                    #include <stdbool.h>
                                    #include <string.h>
                                    
                                    // les deux types de structures
                                    
                                    struct s_int {
                                        int n;
                                    };
                                    
                                    struct s_double {
                                        double d;
                                    };
                                    
                                    // les fonctions qui retournent une structure
                                    // à partir de sa description
                                    
                                    struct s_int parse_int (const char *descr)
                                    {
                                        struct s_int r;
                                        sscanf(descr, "%d", &r.n );
                                        return r;
                                    }
                                    
                                    struct s_double parse_double (const char *descr)
                                    {
                                        struct s_double r;
                                        sscanf(descr, "%lf", &r.d );
                                        return r;
                                    }
                                    
                                    // énumération des types possibles
                                    
                                    enum e_type {
                                        ERROR,
                                        INT,
                                        FLOAT
                                    };
                                    
                                    // structure pouvant contenir les résultats possibles
                                    
                                    struct s_result {
                                        enum e_type type;
                                        union {
                                            struct s_int    r_int;
                                            struct s_double r_double;
                                        };
                                    };
                                    
                                    // analyse une ligne formée d'un tag (indiquant le type)
                                    // et d'une description (dépendante du type)
                                    
                                    struct s_result parse(const char *string)
                                    {
                                        char tag[10];
                                        char descr[10];
                                    	struct s_result r;
                                        // on isole le tag de la description
                                        // c'et très rudimentaire parce qu'il est tard
                                        sscanf(string, "%s %s", tag, descr);
                                    
                                    	/*
                                        printf("string\t\"%s\"\n"
                                               "tag\t\"%s\"\n"
                                               "desc\t\"%s\"\n\n",
                                               string, tag, descr);
                                        */
                                    	if (strcmp(tag, "entier") == 0) {
                                    		r.type = INT;
                                    		r.r_int = parse_int(descr);
                                    	} else if (strcmp(tag, "reel") == 0) {
                                    		r.type = FLOAT;
                                    		r.r_double = parse_double(descr);
                                    	} else {
                                    		r.type = ERROR;
                                    	}
                                    	return r;
                                    
                                    }
                                    
                                    // exécution d'un test
                                    
                                    void test(const char string[])
                                    {
                                    	printf("Analyse de \"%s\" :\n", string);
                                        struct s_result r = parse(string);
                                        switch (r.type) {
                                        case INT :
                                            printf("= un entier qui vaut %d\n",
                                                   r.r_int.n);
                                            break;
                                        case FLOAT :
                                            printf("= un réel qui vaut %lf\n",
                                                   r.r_double.d);
                                            break;
                                    	case ERROR :
                                    		printf("= un machin inconnu\n");
                                        }
                                    	printf("\n");
                                    }
                                    
                                    int main()
                                    {
                                        test("entier 123");
                                        test("reel 3.14");
                                        test("wtf abcd");
                                        return EXIT_SUCCESS;
                                    }
                                    

                                    C'est tout pour aujourd'hui.

                                    Les décompositions par sscanf sont très rudimentaires. Il faudrait se servir des regexps pour faire ça bien, mais je m'en rappelle jamais.

                                    -
                                    Edité par michelbillaud 10 mai 2023 à 23:18:34

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      11 mai 2023 à 0:00:32

                                      Oui très intéréssant ! ca va être compliqué d'adapter ça à mon cas mais je vais quand même voir ce que je peux faire! merci du coup de main et de l'exemple!!
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        11 mai 2023 à 10:01:26

                                        Résumé du chapitre précédent :

                                        • Le truc ci-dessus, c'était pour le problème de "polymorphisme", où une fonction doit fournir des résultats de type différents.
                                        • Pour ça on décide que la fonction retourne une structure avec indication de la nature de ce qui a été trouvé, et une union de tous les types concernés.
                                        Bon maintenant, le parsing.   Le truc, c'est de s'occuper des détails le plus tard possible.

                                        Une approche objet : on définit un objet "parser" dont le rôle est de gober successivement les éléments de la chaîne de caractères, et de fournir les valeurs correspondantes en les plaçant à un emplacement indiqué.
                                        Par exemple :
                                        void parser_get_int(t_parser *parser,
                                                            int *where);
                                        ça va aller regarder si le prochain élément de la chaîne est bien un int correct, et l'envoyer dans *where.
                                        Au passage, ça va faire "avancer" le scanner, qui garde un pointeur sur le prochain caractère à traiter.
                                        Donc on va se définir des get_int, des get_float, get_identifier, et à partir de ça on peut construire des trucs de plus haut niveau
                                        void parser_get_ambiant_light(t_parser *parser,
                                                                      t_ambiant_light *where)
                                        {
                                            parser_get_identifier(parser, where->identifier, 2);
                                            parser_get_float(parser, & where->ratio);
                                            parser_get_color(parser, & where->color);
                                        }
                                        avec get_color qui fait 3 appels à get_int, en vérifiant qu'il y a bien les virgules entre (code à la fin).


                                        Le test :
                                            test_ambiant_light("A 8.2 255,255,255");
                                        
                                        permet de vérifier que ça a l'air de marcher

                                        cc -std=c17 -Wall -Wextra -pedantic -Werror -Wno-unused -D_XOPEN_SOURCE=700 -g    prog.c   -o prog
                                        ./prog
                                        # Analyse d'une chaine
                                        ## test_ambiant_light("A 8.2 255,255,255")
                                        ID      A
                                        ratio   8.200000
                                        color   (255, 255, 255)
                                        Hourra !
                                        x x x
                                        Le code
                                        #include <stdio.h>
                                        #include <stdlib.h>
                                        #include <stdbool.h>
                                        #include <ctype.h>
                                        #include <string.h>
                                        
                                        /*
                                        	Problème : on  veut remplir une structure
                                        	de type "t_ambiant_light" à partir des informations
                                        	fournies par une chaine de caractères comme
                                        	    A 8.2 255,255,255
                                        	soit
                                        	- un identifiant A
                                        	- un ratio 8.2
                                        	- une couleur décrite par 3 entiers séparés par des
                                        	  virgules.
                                        */
                                        
                                        // voila les types
                                        
                                        typedef struct  s_color {
                                            int r;
                                            int g;
                                            int b;
                                        } t_color;
                                        
                                        typedef struct  s_ambient_light {
                                            char        identifier[3];
                                            t_color     color;
                                            float       ratio;
                                        } t_ambiant_light;
                                        
                                        /*
                                        	pour ça on va employer un objet "parser"
                                        	qui extrait les informations de la ligne
                                        */
                                        
                                        typedef struct s_parser {
                                            const char *next;  // prochain caractère à utiliser
                                            const char *error;  // NULL si pas d'erreur
                                        } t_parser;
                                        
                                        void parser_start(t_parser *parser, const char string[])
                                        {
                                            parser->error = NULL;
                                            parser->next = string;
                                        }
                                        
                                        char parser_next_char(const t_parser *parser)
                                        {
                                            return *(parser->next);
                                        }
                                        
                                        void parser_advance(t_parser *parser)
                                        {
                                            (parser->next) ++;
                                        }
                                        
                                        bool parser_end_reached(t_parser* parser)
                                        {
                                            return parser_next_char(parser) == '\0';
                                        }
                                        
                                        void parser_notify_error(t_parser *parser, char message[])
                                        {
                                            parser->error = message;
                                        }
                                        
                                        void parser_ignore_spaces(t_parser *parser)
                                        {
                                            while (isspace(parser_next_char(parser))) {
                                                parser_advance(parser);
                                            }
                                        }
                                        
                                        void parser_get_identifier(t_parser *parser,
                                                                   char *where, int max_length)
                                        {
                                            parser_ignore_spaces(parser);
                                            if (parser_end_reached(parser)) {
                                                parser_notify_error(parser,
                                                                    "end of string when identifier expected");
                                                return;
                                            }
                                            char c;
                                            int length = 0;
                                            while (isalnum(c = parser_next_char(parser))) {
                                                length ++;
                                                if (length > max_length) {
                                                    parser_notify_error(parser, "identifier too long");
                                                    return;
                                                }
                                                *where++ = c;
                                                parser_advance(parser);
                                            }
                                            *where = '\0';
                                            if (length == 0) {
                                                parser_notify_error(parser, "empty identifier");
                                                return;
                                            }
                                        }
                                        
                                        
                                        bool is_valid_float_char(char c)
                                        {
                                            return isdigit(c) ||
                                                   strchr("+-.Ee", c);
                                        }
                                        
                                        void parser_get_float(t_parser *parser,
                                                              float *where)
                                        {
                                            parser_ignore_spaces(parser);
                                            if (parser_end_reached(parser)) {
                                                parser_notify_error(parser,
                                                                    "end of string when float expected");
                                                return;
                                            }
                                            int buffer_size = 10;
                                            char buffer[10];
                                            int length = 0;
                                            char c;
                                            while (is_valid_float_char(c = parser_next_char(parser))) {
                                                buffer[length++] = c;
                                                if (length >= buffer_size) {
                                                    parser_notify_error(parser, "float too long");
                                                    return;
                                                }
                                                parser_advance(parser);
                                            }
                                            *where = '\0';
                                            if (length == 0) {
                                                parser_notify_error(parser, "float missing");
                                                return;
                                            }
                                            if (sscanf(buffer, "%f", where) != 1) {
                                                parser_notify_error(parser, "incorrect float number");
                                                return;
                                            }
                                        }
                                        
                                        // ne marche que pour les entiers non signés
                                        
                                        void parser_get_int(t_parser *parser,
                                                            int *where)
                                        {
                                            parser_ignore_spaces(parser);
                                            if (parser_end_reached(parser)) {
                                                parser_notify_error(parser,
                                                                    "end of string when int expected");
                                                return;
                                            }
                                            int buffer_size = 10;
                                            char buffer[10];
                                            int length = 0;
                                            char c;
                                            while (isdigit(c = parser_next_char(parser))) {
                                        		buffer[length++] = c;
                                                if (length >= buffer_size) {
                                                    parser_notify_error(parser, "int too long");
                                                    return;
                                                }
                                                
                                                parser_advance(parser);
                                            }
                                            if (length == 0) {
                                                parser_notify_error(parser, "int missing");
                                                return;
                                            }
                                        	buffer[length] = '\0';
                                            if (sscanf(buffer, "%d", where) != 1) {
                                        		printf("DEBUG '%s'\n", buffer);
                                        		parser_notify_error(parser, "incorrect int number");
                                                return;
                                            }
                                        }
                                        
                                        
                                        void parser_get_color(t_parser *parser, t_color *where)
                                        {
                                              parser_get_int(parser, & where->r);
                                            if (parser_next_char(parser) == ',') {
                                                parser_advance(parser);
                                            } else {
                                                parser_notify_error(parser, "missing comma between R and G in color");
                                                return;
                                            }
                                            parser_get_int(parser, & where->g);
                                            if (parser_next_char(parser) == ',') {
                                                parser_advance(parser);
                                            } else {
                                                parser_notify_error(parser, "missing comma between G and B in color");
                                                return;
                                            }
                                            parser_get_int(parser, & where->b);
                                        }
                                        
                                        void parser_get_ambiant_light(t_parser *parser,
                                                                      t_ambiant_light *where)
                                        {
                                            parser_get_identifier(parser, where->identifier, 2);
                                            parser_get_float(parser, & where->ratio);
                                            parser_get_color(parser, & where->color);
                                        }
                                        
                                        
                                        void test_ambiant_light(const char string[])
                                        {
                                            printf("## test_ambiant_light(\"%s\")\n", string);
                                            t_parser parser;
                                            parser_start(&parser, string);
                                        
                                            t_ambiant_light ambiant_light;
                                            parser_get_ambiant_light(&parser, &ambiant_light);
                                            if (parser.error != NULL) {
                                                printf("Error whilst parsing: %s\n", parser.error);
                                                return;
                                            }
                                        
                                            printf("ID\t%s\n"
                                                   "ratio\t%f\n"
                                                   "color\t(%d, %d, %d)\n",
                                                   ambiant_light.identifier,
                                                   ambiant_light.ratio,
                                                   ambiant_light.color.r,
                                                   ambiant_light.color.g,
                                                   ambiant_light.color.b);
                                        }
                                        
                                        int main()
                                        {
                                            printf("# Analyse d'une chaine\n");
                                            test_ambiant_light("A 8.2 255,255,255");
                                            return EXIT_SUCCESS;
                                        }
                                        

                                        x x x
                                        Comme vous voyez, j'ai fait des petites fonctions

                                        char parser_next_char(const t_parser *parser)
                                        {
                                            return *(parser->next);
                                        }
                                        
                                        void parser_advance(t_parser *parser)
                                        {
                                            (parser->next) ++;
                                        }
                                        
                                        bool parser_end_reached(t_parser* parser)
                                        {
                                            return parser_next_char(parser) == '\0';
                                        }
                                        
                                        void parser_notify_error(t_parser *parser, char message[])
                                        {
                                            parser->error = message;
                                        }
                                        
                                        void parser_ignore_spaces(t_parser *parser)
                                        {
                                            while (isspace(parser_next_char(parser))) {
                                                parser_advance(parser);
                                            }
                                        }
                                        pour gagner en abstraction (= éviter de m'embrouiller dans des détails techniques, ce qui est la difficulté). En mettant des "inline", ça garantirait que c'est sans impact sur les performances.




                                        -
                                        Edité par michelbillaud 11 mai 2023 à 12:24:21

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          12 mai 2023 à 10:53:03

                                          Une version un peu améliorée

                                          • les trois fonctions pour le parsing des objets de base (int, float, id) se ressemblaient : utilisation d'une fonction paramétrée par un prédicat (fonction qui dit si les caractères sont admis, un format de conversion du résultat, une table de messages,...). Exemple
                                          // Parser: type de base int (entier non signé en fait)
                                          
                                          const char *messages_for_int[] = {
                                              [TOKEN_IS_MISSING] = "end of string when int expected",
                                              [TOKEN_IS_TOO_BIG] = "int number has too much digits",
                                              [TOKEN_EXPECTED] = "an int number was expected",
                                              [TOKEN_CONVERSION_FAILED] = "int conversion failed"
                                          };
                                          
                                          
                                          // ne marche que pour les entiers non signés
                                          bool is_valid_int_char(char c)
                                          {
                                              return isdigit(c);
                                          }
                                          
                                          void parser_get_int(t_parser *parser,
                                                              int *where)
                                          {
                                              char buffer[20];
                                              parser_get_token(parser, &is_valid_int_char,
                                                               sizeof(buffer), buffer,
                                                               "%d", where, messages_for_int);
                                          }
                                          
                                          • inlining pour les petites fonctions (faut juste mettre "static inline" devant la déclaration)
                                          • les fonctions de parsing s'arrêtent à la première erreur
                                          • plus de tests

                                          Voila ce que ça affiche

                                          billaud@sims:~/Essais/parser2$ make
                                          cc -std=c17 -Wall -Wextra -pedantic -Werror -Wno-unused -D_XOPEN_SOURCE=700 -g    prog.c   -o prog
                                          billaud@sims:~/Essais/parser2$ make run
                                          ./prog
                                          # Analyse d'une chaine correcte
                                          ## test_ambiant_light("A 8.2 255,255,255")
                                          ID      A
                                          ratio   8.200000
                                          color   (255, 255, 255)
                                          
                                          # Quelques tests d'erreur
                                          ## test_ambiant_light("    ")
                                          Error whilst parsing: end of string when id expected
                                          
                                          ## test_ambiant_light("? 8.2 255,255,255")
                                          Error whilst parsing: an identifier was expected
                                          
                                          ## test_ambiant_light("12 8.2 255,255,255")
                                          ID      12
                                          ratio   8.200000
                                          color   (255, 255, 255)
                                          
                                          ## test_ambiant_light("xxx 8.2 255,255,255")
                                          Error whilst parsing: id has more than 2 chars
                                          
                                          ## test_ambiant_light("A x.2 255,255,255")
                                          Error whilst parsing: a float number was expected
                                          
                                          ## test_ambiant_light("A 8.2 xxx,255,255")
                                          Error whilst parsing: an int number was expected
                                          
                                          ## test_ambiant_light("A 8.2 25x,255,255")
                                          Error whilst parsing: missing comma between R and G in color
                                          
                                          ## test_ambiant_light("A 8.2 253+255,255")
                                          Error whilst parsing: missing comma between R and G in color
                                          
                                          ## test_ambiant_light("A x.2 255,255")
                                          Error whilst parsing: a float number was expected
                                          



                                          #include <stdio.h>
                                          #include <stdlib.h>
                                          #include <stdbool.h>
                                          #include <ctype.h>
                                          #include <string.h>
                                          
                                          /*
                                          	Problème : on  veut remplir une structure
                                          	de type "t_ambiant_light" à partir des informations
                                          	fournies par une chaine de caractères comme
                                          	    A 8.2 255,255,255
                                          	soit
                                          	- un identifiant A
                                          	- un ratio 8.2
                                          	- une couleur décrite par 3 entiers séparés par des
                                          	  virgules.
                                          */
                                          
                                          // voila les types
                                          
                                          typedef struct  s_color {
                                              int r;
                                              int g;
                                              int b;
                                          } t_color;
                                          
                                          typedef struct  s_ambient_light {
                                              char        identifier[3];
                                              t_color     color;
                                              float       ratio;
                                          } t_ambiant_light;
                                          
                                          /*
                                          	pour ça on va employer un objet "parser"
                                          	qui extrait les informations de la ligne
                                          */
                                          
                                          typedef struct s_parser {
                                              const char *next;  // prochain caractère à utiliser
                                              const char *error;  // NULL si pas d'erreur
                                          } t_parser;
                                          
                                          static inline
                                          void parser_start(t_parser *parser, const char string[])
                                          {
                                              parser->error = NULL;
                                              parser->next = string;
                                          }
                                          
                                          
                                          static inline
                                          char parser_next_char(const t_parser *parser)
                                          {
                                              return *(parser->next);
                                          }
                                          
                                          static inline
                                          void parser_advance(t_parser *parser)
                                          {
                                              (parser->next) ++;
                                          }
                                          
                                          
                                          static inline
                                          bool parser_end_reached(t_parser* parser)
                                          {
                                              return parser_next_char(parser) == '\0';
                                          }
                                          
                                          static inline
                                          void parser_notify_error(t_parser *parser, const char message[])
                                          {
                                              parser->error = message;
                                          }
                                          
                                          static inline
                                          bool parser_has_error(t_parser *parser)
                                          {
                                              return parser->error != NULL;
                                          }
                                          
                                          static inline
                                          const char * parser_get_error_message(t_parser *parser)
                                          {
                                              return parser->error;
                                          }
                                          
                                          static inline
                                          void parser_ignore_spaces(t_parser *parser)
                                          {
                                              while (isspace(parser_next_char(parser))) {
                                                  parser_advance(parser);
                                              }
                                          }
                                          
                                          enum error_message_number {
                                              TOKEN_IS_MISSING,
                                              TOKEN_IS_TOO_BIG,
                                              TOKEN_EXPECTED,
                                              TOKEN_CONVERSION_FAILED
                                          };
                                          
                                          /*
                                          const char *generic_messages[] = {
                                              [TOKEN_IS_MISSING] = "end of string reached when token expected",
                                              [TOKEN_IS_TOO_BIG] = "token is too big",
                                              [TOKEN_EXPECTED] = "token is empty",
                                              [TOKEN_CONVERSION_FAILED] = "token conversion failed"
                                          };
                                          */
                                          
                                          void parser_get_token(t_parser *parser,
                                                                bool(*is_char_ok)(char),
                                                                int buffer_size,
                                                                char buffer[buffer_size],
                                                                const char conversion_format[],
                                                                void *where,
                                                                const char *messages[])
                                          {
                                              parser_ignore_spaces(parser);
                                              if (parser_end_reached(parser)) {
                                                  parser_notify_error(parser,
                                                                      messages[TOKEN_IS_MISSING]);
                                                  return;
                                              }
                                              char c;
                                              int length = 0;
                                              while (is_char_ok(c = parser_next_char(parser))) {
                                                  buffer[length ++] = c;
                                                  if (length >= buffer_size) {
                                                      parser_notify_error(parser, messages[TOKEN_IS_TOO_BIG]);
                                                      return;
                                                  }
                                                  parser_advance(parser);
                                              }
                                              buffer[length] = '\0';
                                              if (length == 0) {
                                                  parser_notify_error(parser, messages[TOKEN_EXPECTED]);
                                                  return;
                                              }
                                              if (sscanf(buffer, conversion_format, where) != 1) {
                                                  parser_notify_error(parser, messages[TOKEN_CONVERSION_FAILED]);
                                                  return;
                                              }
                                          }
                                          
                                          
                                          // Parser : type de base "identificateur"
                                          
                                          const char *messages_for_id[] = {
                                              [TOKEN_IS_MISSING] = "end of string when id expected",
                                              [TOKEN_IS_TOO_BIG] = "id has more than 2 chars",
                                              [TOKEN_EXPECTED] = "an identifier was expected",
                                              [TOKEN_CONVERSION_FAILED] = "**programmer error (parsing id)**"
                                          };
                                          
                                          bool is_valid_identifier_char(char c)
                                          {
                                              return isalnum(c);
                                          }
                                          
                                          void parser_get_identifier(t_parser *parser,
                                                                     char *where)
                                          {
                                              char buffer[3];
                                              parser_get_token(parser, &is_valid_identifier_char,
                                                               sizeof(buffer), buffer,
                                                               "%s", where, messages_for_id);
                                          }
                                          
                                          // Parser : type de base "float"
                                          
                                          const char *messages_for_float[] = {
                                              [TOKEN_IS_MISSING] = "end of string when float expected",
                                              [TOKEN_IS_TOO_BIG] = "float number has too much digits",
                                              [TOKEN_EXPECTED] = "a float number was expected",
                                              [TOKEN_CONVERSION_FAILED] = "float conversion failed"
                                          };
                                          
                                          bool is_valid_float_char(char c)
                                          {
                                              return isdigit(c) ||
                                                     strchr("+-.Ee", c);
                                          }
                                          
                                          void parser_get_float(t_parser *parser,
                                                                float *where)
                                          {
                                              char buffer[20];
                                              parser_get_token(parser, &is_valid_float_char,
                                                               sizeof(buffer), buffer,
                                                               "%f", where, messages_for_float);
                                          }
                                          
                                          // Parser: type de base int (entier non signé en fait)
                                          
                                          const char *messages_for_int[] = {
                                              [TOKEN_IS_MISSING] = "end of string when int expected",
                                              [TOKEN_IS_TOO_BIG] = "int number has too much digits",
                                              [TOKEN_EXPECTED] = "an int number was expected",
                                              [TOKEN_CONVERSION_FAILED] = "int conversion failed"
                                          };
                                          
                                          
                                          // ne marche que pour les entiers non signés
                                          bool is_valid_int_char(char c)
                                          {
                                              return isdigit(c);
                                          }
                                          
                                          void parser_get_int(t_parser *parser,
                                                              int *where)
                                          {
                                              char buffer[20];
                                              parser_get_token(parser, &is_valid_int_char,
                                                               sizeof(buffer), buffer,
                                                               "%d", where, messages_for_int);
                                          }
                                          
                                          
                                          // parser: type composé "color"
                                          
                                          void parser_get_color(t_parser *parser, t_color *where)
                                          {
                                              parser_get_int(parser, & where->r);
                                              if (parser_has_error(parser)) return;
                                              if (parser_next_char(parser) == ',') {
                                                  parser_advance(parser);
                                              } else {
                                                  parser_notify_error(parser, "missing comma between R and G in color");
                                                  return;
                                              }
                                              parser_get_int(parser, & where->g);
                                              if (parser_has_error(parser)) return;
                                              if (parser_next_char(parser) == ',') {
                                                  parser_advance(parser);
                                              } else {
                                                  parser_notify_error(parser, "missing comma between G and B in color");
                                                  return;
                                              }
                                              parser_get_int(parser, & where->b);
                                          }
                                          
                                          // parser: type composé "ambiant light"
                                          
                                          void parser_get_ambiant_light(t_parser *parser,
                                                                        t_ambiant_light *where)
                                          {
                                              parser_get_identifier(parser, where->identifier);
                                              if (parser_has_error(parser)) return;
                                              parser_get_float(parser, & where->ratio);
                                              if (parser_has_error(parser)) return;
                                              parser_get_color(parser, & where->color);
                                          }
                                          
                                          // -----------------------------------------------
                                          // Les tests
                                          //
                                          
                                          void test_ambiant_light(const char string[])
                                          {
                                              printf("## test_ambiant_light(\"%s\")\n", string);
                                              t_parser parser;
                                              parser_start(&parser, string);
                                          
                                              t_ambiant_light ambiant_light;
                                              parser_get_ambiant_light(&parser, &ambiant_light);
                                              if (parser_has_error(&parser)) {
                                                  printf("Error whilst parsing: %s\n\n",
                                                         parser_get_error_message(&parser));
                                                  return;
                                              }
                                          
                                              printf("ID\t%s\n"
                                                     "ratio\t%f\n"
                                                     "color\t(%d, %d, %d)\n\n",
                                                     ambiant_light.identifier,
                                                     ambiant_light.ratio,
                                                     ambiant_light.color.r,
                                                     ambiant_light.color.g,
                                                     ambiant_light.color.b);
                                          }
                                          
                                          int main()
                                          {
                                              printf("# Analyse d'une chaine correcte\n");
                                              test_ambiant_light("A 8.2 255,255,255");
                                          
                                              printf("# Quelques tests d'erreur\n");
                                              test_ambiant_light("    ");
                                              test_ambiant_light("? 8.2 255,255,255");
                                              test_ambiant_light("12 8.2 255,255,255");
                                              test_ambiant_light("xxx 8.2 255,255,255");
                                              test_ambiant_light("A x.2 255,255,255");
                                              test_ambiant_light("A 8.2 xxx,255,255");
                                              test_ambiant_light("A 8.2 25x,255,255");
                                              test_ambiant_light("A 8.2 253+255,255");
                                              test_ambiant_light("A x.2 255,255");
                                          
                                              return EXIT_SUCCESS;
                                          }
                                          



                                          -
                                          Edité par michelbillaud 12 mai 2023 à 11:01:55

                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            13 mai 2023 à 22:20:56

                                            Merci beaucoup!!! Je vais regarder tout ça plus en détail demain mais je me devais de répondre!

                                            Sérieux c'est un vrai boulot que tu (je me permet de te tutoyer) as fourni, aussi il y a une chose que je comprend pas depuis ptr_array, tu fais des sortes de getters en C mais je comprend pas l'avantage hormis le faite que ce soit + lisible/compréhensible ?

                                            J'ai eu le temps de survoler et c'est vrai que c'est un boulot monstre! Aussi, on est d'accord que messages_for_int est une variable globale ?

                                            Je sens que je vais bien me régaler demain, sérieusement merci encore!

                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              13 mai 2023 à 23:09:11

                                              L'avantage c'est justement que c'est plus compréhensible. On n'a pas une infinité de neurones, alors on se simplifie le boulot pour arriver à le faire avec ceux qu'on a.

                                              Et l'abstraction. La plupart du code ne s'occupe pas de faire avancer des pointeurs sur une chaîne.  Et on pourrait facilement remplacer par un truc qui prend les caracteres dans un FILE*, au lieu d'une chaîne.

                                              -
                                              Edité par michelbillaud 14 mai 2023 à 0:00:16

                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                13 mai 2023 à 23:10:15

                                                antoinelds a écrit:

                                                Aussi, on est d'accord que messages_for_int est une variable globale ?

                                                Oui, mais qui n'est connue que du code qui se trouve après la ligne 202. Par exemple, la fonction parser_get_identifier() ne la connait pas. C'est ce qu'on appelle la portée des variables.

                                                -
                                                Edité par edgarjacobs 13 mai 2023 à 23:12:04

                                                • 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

                                                  14 mai 2023 à 8:05:11

                                                  On pourrait la déclarer directement dans la fonction messages_for_int  ça serait aussi bien. Ça limiterait la portée de la déclaration au strict nécessaire:

                                                  • C'est la seule fonction qui s'en sert
                                                  • Le code de la fonction n'est pas long
                                                  void parser_get_machin(,,,,)
                                                  {
                                                       static const char* messages [] = ....;
                                                  
                                                       ...
                                                       parser_get_token(......, messages);
                                                  }

                                                   Un point délicat : il faut y mettre le qualificateur  static.  Sinon, si on ne met pas static,

                                                  • c'est censé être un tableau alloué automatiquement (sur la pile) quand on rentre dans la fonction
                                                  • et qui disparaît quand on en sort
                                                  • Or, on affecte  l'adresse de ses éléments pour la notification, dans le champ messages de l'objet parser, qui s'en sert une fois ressorti de la fonction qui a "créé" le tableau de messages.
                                                  • Trouble ensues, and shit happens.

                                                  Ce qui fait la distinction entre

                                                  • Portée des déclarations 
                                                  • Durée de vie des objets déclarés

                                                   (Ici "objet" au sens C : l'espace mémoire qui contient une donnée représentant des informations)


                                                  Ps j'ai lu plus haut getter/setter. Hum. Pas vraiment. L'intention est de matérialiser par des appels de fonction les services que peut assurer l'objet (au sens approche orientée-objet). Afin d'encapsuler les détails de représentation matérielle pour ne pas avoir à "en connaître" plus loin . C'est pas d'aller chercher/changer la valeur d'un champ.

                                                  Les getters setters, c'est souvent dans la prog orientée objets mal enseignée (*) aux débutants, où

                                                  • On part d'une structure avec des champs
                                                  • On les planque avec private pour faire joli
                                                  • On se demande comment on va y accéder quand même.

                                                  Bref, on part de la représentation interne, plutôt que des services qui sont la raison d'exister de l'objet.

                                                   (*) si vous me branchez là-dessus, on n'est pas sortis...


                                                  PS2: en parlant de qualificateurs, il en manque pour les tables de messages.

                                                  Ce sont des tables contenant des pointeurs vers des chaînes constantes. Mais on n'a pas le droit de modifier les tables en cours d'exécution, donc la déclaration devrait être

                                                  // oups
                                                  // const char *messages[] = ...
                                                  
                                                  // mieux
                                                     const char * const messages[] = ...
                                                  // 11111        22222
                                                  

                                                  Avec un const en plus.  Tableau de pointeurs non modifiables vers des octets non modifiables.


                                                  Comme ça devient lourdingue, c'est raisonnable et avantageux de déclarer un type

                                                  #include <stdio.h>
                                                  
                                                  typedef const char * const table_messages[];
                                                  
                                                  table_messages  french = {"oui", "non"};
                                                  
                                                  void foo(table_messages m) {
                                                  	printf("ça marche = %s\n", m[0]);
                                                  }
                                                  
                                                  int main()
                                                  {
                                                  	foo(french);
                                                  	return EXIT_SUCCESS;
                                                  }

                                                  -
                                                  Edité par michelbillaud 14 mai 2023 à 13:03:47

                                                  • Partager sur Facebook
                                                  • Partager sur Twitter

                                                  Affecter une valeur négative à un float

                                                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                  × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                  • Editeur
                                                  • Markdown