Partage
  • Partager sur Facebook
  • Partager sur Twitter

La LibC des Zéros

Objectif : recoder la libC.

Anonyme
1 août 2012 à 10:29:07

La LibC des Zéros


Bonjour,

Il m'est venu à l'idée de recoder la libC mais seul cela serait un peu compliqué, c'est pourquoi je propose que tous les membres du forum pourraient proposer une ou plusieurs fonctions de la libC.
Vous pourrez bien entendu recoder printf sans que quelqu'un est au préalable recodé vprintf, ou scanf sans vscanf, etc...
Mais au final, on réussira peut être à la recoder entièrement.

Qu'est ce que la libC ?

La libC est l'abréviation de library C, c'est la bibliothèque standard du C, où sont contenus toutes les fonctions standard comme printf, scanf, rand, strlen, strcpy...

Bonne chance à vous !

-
Edité par Anonyme 24 juillet 2020 à 14:14:41

  • Partager sur Facebook
  • Partager sur Twitter
1 août 2012 à 11:33:28

Recoder la libC c'est de la branlette, avec de simple notion tu peux la recoder en partie assez facilement.
Ca donnera un resultat parfois plus propre et plus clair que la libC elle meme.

Printf, n'en parlons pas ! Un seul appel système est nécessaire pour le recoder :)
  • Partager sur Facebook
  • Partager sur Twitter
1 août 2012 à 11:35:09

Ouais, mais c'est pas du jeu de se baser sur un appel système. Tant qu'à faire, autant faire une libC un minimum portable nan ?
  • Partager sur Facebook
  • Partager sur Twitter
1 août 2012 à 11:42:25

Citation : Julienf

Recoder la libC c'est de la branlette, avec de simple notion tu peux la recoder en partie assez facilement.
Ca donnera un resultat parfois plus propre et plus clair que la libC elle meme.

Printf, n'en parlons pas ! Un seul appel système est nécessaire pour le recoder :)



Eh bien, qu'attends-tu ? :lol: Nous attendons l'ensemble de ton code pour recoder la libC avec plaisir !
  • Partager sur Facebook
  • Partager sur Twitter
Staff désormais retraité.
Anonyme
1 août 2012 à 11:45:16

Citation : Lucas-84

Citation : Julienf

Recoder la libC c'est de la branlette, avec de simple notion tu peux la recoder en partie assez facilement.
Ca donnera un resultat parfois plus propre et plus clair que la libC elle meme.

Printf, n'en parlons pas ! Un seul appel système est nécessaire pour le recoder :)



Eh bien, qu'attends-tu ? :lol: Nous attendons l'ensemble de ton code pour recoder la libC avec plaisir !



C'était ironique ? Non ? Enfin j'espère tout du moins :-+
  • Partager sur Facebook
  • Partager sur Twitter
1 août 2012 à 11:55:19

@Sabeurrem je pensais a une libC UNIX.
Mais il me semble que l'appel systeme write() existe aussi sous window.

@Lucas, je vais garder mon code pour moi, il est plus intéressant de le faire sois même :p
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
1 août 2012 à 12:23:53

La partie la plus dure à recoder est je pense les entrées, et notamment scanf. D'autres fonctions comme srand ou setjmp peuvent également être difficiles.

Sinon je trouve ça intéressant comme exercice, je peux fournir un mini-printf que j'ai eu l'occasion de faire, une partie de string.h et la macro assert.
  • Partager sur Facebook
  • Partager sur Twitter
1 août 2012 à 12:28:13

Citation : Julienf

Recoder la libC c'est de la branlette, avec de simple notion tu peux la recoder en partie assez facilement.
Ca donnera un resultat parfois plus propre et plus clair que la libC elle meme.

Printf, n'en parlons pas ! Un seul appel système est nécessaire pour le recoder :)



Bah voyons, et le formattage, et les locales, la représentation des flottants, et tout ça, on s'en fiche, bien sûr. Après, bien sûr on peut jouer sur les mots, si par « en partie » tu veux dire « je code les trucs qui ont l'air facile et je laisse le sale boulot de côté », bah oui, par définition, c'est « de la branlette »...

Un peu de respect et de modestie...
  • Partager sur Facebook
  • Partager sur Twitter
1 août 2012 à 12:50:49

Histoire de participer, un <assert.h> fait à l'instant. Possibilités de bogues par conséquent.

assert.h :

/* 
 * Diagnostics `<assert.h>' : Defines the `assert' and 
 * `static_assert' macros. 
 */

#ifndef H_LP_ASSERT_20120801120125
# define H_LP_ASSERT_20120801120125

# ifdef NDEBUG

/*
 * It refers to another macro, `NDEBUG', which is not defined by 
 * `<assert.h>'. If `NDEBUG' is defined as a macro name at the point
 * in the source file where `<assert.h>' is included, the assert 
 * macro is defined simply as `#define assert(ignore) ((void)0)'. The
 * `assert' macro is redefined according to the current state of 
 * `NDEBUG' each time that `<assert.h>' is included.
 */
#  define assert(ignore) ((void)0)
# else

_Noreturn extern void __assert_failure(const char *, const char *, 
				       const char *, int);

/*
 * The `assert' macro puts diagnostic test into programs; it expands
 * to a `void' expression. When it is executed, if `expression' 
 * (which shall have a scalar type) is false (that is, compares equal
 * to 0), the `assert' macro writes information about the particular
 * call that failed (including the text of the argument, the name of 
 * the source file, the source line number, and the name of the 
 * enclosing function - the latter are respectively the values of the
 * preprocessing macros  `__FILE__' and `__LINE__' and of the 
 * identifier `__func__') on ne standard error stream in a 
 * implementation-defined format. It then calls the `abort' function.
 * The `assert' macro returns no value.
 */
#  define assert(expression) 					    \
	(void)(((expression) == 0) ?                                \
		__assert_failure(#expression, __func__, __FILE__,   \
			         __LINE__) : 0)

# endif /* NDEBUG */

/* The macro `static_assert' expands to `_Static_assert'. */
# define static_assert _Static_assert

#endif /* H_LP_ASSERT_20120801120125 */


assert.c :

#include <stdio.h>
#include <stdlib.h>
#include "assert.h"

#ifndef NDEBUG

_Noreturn void
__assert_failure(const char *expression, const char *func, 
	         const char *file, int line)
{
	fprintf(stderr, "Assertion failed: %s, function %s, " 
		        "file %s, line %d.\n", 
		         expression, func, file, line);
	fflush(stderr);
	abort();
}

#endif /* NDEBUG */


@informaticienzero : Je ne pense pas que srand soit une des fonctions les plus dures à recoder ; la norme est assez laxiste sur son implémentation. Par contre, ce qui est dérangeant, ce sont les fichiers d'en-tête dépendants fortement de l'implémentation (stdarg.h pour ne citer que lui).
  • Partager sur Facebook
  • Partager sur Twitter
Staff désormais retraité.
Anonyme
1 août 2012 à 12:59:52

Intéressant ton code, je ne connaissais pas la macro __func__. Sinon pour participer aussi, voici une partie de string :

string.h
#ifndef MY_STRING_H
#define MY_STRING_H

char * my_strcpy(char * copie, const char * origine);
char * my_strncpy(char * dst, const char * src, int n);
size_t my_strlen(const char * str);
const char * my_strchr(const char * str, int car);
char * my_strcat(char * dest, const char * orig);
int my_strcmp(const char * str1, const char *str2);
int my_strncmp(const char * str1, const char *str2, int n);
char * my_strstr (const char * str, const char * unstr);
char * my_strpbrk(const char * str, const char * c);

#endif


string.c
#include <stddef.h>
#include "my_string.h"

char * my_strcpy(char * dst, const char * src)
{
    size_t i;

    for (i = 0; (dst[i] = src[i]); i++);
    return dst;
}

char * my_strncpy(char * dst, const char * src, int n)
{
    size_t i;

    for (i = 0; (dst[i] = src[i]) && i < n; i++);

    dst[i] = '\0';

    return dst;
}

size_t my_strlen(const char * str)
{
    size_t lg = 0;

    while(str[lg])
        lg++;

    return lg;
}

const char * my_strchr(const char * str, int car)
{
    while(*str)
    {
        if (*str == car || *str == '\0')
            return str;

        else
            str++;
    }

    return NULL;
}

char * my_strcat(char * dest, const char * orig)
{
    my_strcpy(dest + my_strlen(dest), orig);

    return dest;
}

char * my_strncat(char * dest, const char * orig, int n)
{
    my_strncpy(dest + my_strlen(dest), orig, n);

    return dest;
}

int my_strcmp(const char * str1, const char *str2)
{
    while(*str1 == *str2)
    {
        if (*str1 == 0)
            return 0;

        str1++;
        str2++;
    }

    return *str1 < *str2 ? -1 : 1;
}

int my_strncmp(const char * str1, const char *str2, int n)
{
    while(n--)
    {
        if (*str1 == 0 || *str1 != *str2)
            return *str1 < *str2 ? -1 : 1;

        str1++;
        str2++;
    }

    return 0;
}

char * my_strstr (const char * str, const char * unstr)
{
    while(*str)
    {
        if (my_strncmp(str, unstr, my_strlen(unstr)) == 0)
            return (char*)str;

        str++;
    }

    return NULL;
}

char * my_strpbrk(const char * str, const char * c)
{
    size_t i, len = my_strlen(c);

    while(*str)
    {
        for (i = 0; i < len; i++)
        {
            if(c[i] == *str)
                return (char*)str;
        }

        str++;
    }

    return NULL;
}
  • Partager sur Facebook
  • Partager sur Twitter
1 août 2012 à 13:01:35

Citation : informaticienzero

Je ne connaissais pas la macro __func__.



Cherche pas, c'est du C99 (enfin, mon code c'est même du C11, avec l'utilisation de _Noreturn). :p
  • Partager sur Facebook
  • Partager sur Twitter
Staff désormais retraité.
Anonyme
1 août 2012 à 13:06:17

Citation : Lucas-84

Citation : informaticienzero

Je ne connaissais pas la macro __func__.



Cherche pas, c'est du C99 (enfin, mon code c'est même du C11, avec l'utilisation de _Noreturn). :p



Ben écoute, je viens de tester __func__ avec Mingw en C89 strict (-ansi, -pedantic et -pedantic-errors) et ça marche parfaitement.

#include <stdio.h>

#if __STDC_VERSION__ >= 199901L
#error    Code C99
#endif

int main(void)
{
    printf("%s", __func__);

    return 0;
}


Et ça affiche main dans la console. Et cette macro existe même pour VC++, dans une forme légèrement différente :

#include <stdio.h>

int main(void)
{
	printf("%s\n", __FUNCTION__);
}
  • Partager sur Facebook
  • Partager sur Twitter
1 août 2012 à 13:41:53

Vraisemblablement, c'est une extension gcc ; il n'y a rien à propos de __func__ dans la C89. J'ai eu la flemme de lire tout ça.
  • Partager sur Facebook
  • Partager sur Twitter
Staff désormais retraité.
1 août 2012 à 14:00:12

Une toute petite contribution sur 3 fonctions de string.h que tu n'as pas fait :
#ifndef __STRING_H_HO
#define __STRING_H_HO

#include <stddef.h>
#include <wchar.h>

/* Set the first num bytes of the block memory pointed by ptr to the specified value (interpreted as an unsigned char). 

Return value is ptr */
void *memset (void *ptr, int value, size_t num);
wchar_t *wmemset (wchar_t *ptr, wchar_t value, size_t num);

/* Copy the first num bytes of the block memory pointed by source to the block memory pointed by destination. Block memory must not overleap. 

Return value is destination */
void *memcpy (void *dest, const void *src, size_t num);
wchar_t *wmemcpy (wchar_t *dest, const wchar_t *src, size_t num);

/* Move the first num bytes of the block memory pointed by source to the block memory pointed by destination. Block memory may overleap. 

Return value is source */
void *memmove (void *dest, const void *src, size_t num);
wchar_t *wmemmove (wchar_t *dest, const wchar_t *src, size_t num);

#endif

#include "libc.h"

void *memset (void *ptr, int value, size_t num) {
    unsigned char *ptrc = ptr ;
    for (; num > 0 ; num--, ptrc++) {
	*ptrc = (unsigned char)value ;
    }
    return ptr ;
}

wchar_t *wmemset (wchar_t *ptr, wchar_t value, size_t num) {
    for (; num > 0 ; num--, ptr++) {
	*ptr = (unsigned char)value ;
    }
    return ptr ;
}


void *memcpy (void *dest, const void *src, size_t num) {
    unsigned char *destc = dest ;
    const unsigned char *srcc = src ;
    for (; num > 0; num--, destc++, srcc++) {
	*destc = *srcc ;
    }
    return dest ;
}

wchar_t *wmemcpy (wchar_t *dest, const wchar_t *src, size_t num) {
    for (; num > 0; num--, dest++, src++) {
	*dest = *src ;
    }
    return dest ;
}

void *memmove (void *dest, const void *src, size_t num) {
    unsigned char *destc = dest;
    const unsigned char *srcc = src ;
    if (dest <= src) {
	for (; num > 0; num--, destc++, srcc++) {
	    *destc = *srcc ;
	}
    }
    else {
	srcc += (num - 1);
	destc += (num - 1);
	for (; num > 0; num--, destc--, srcc--) {
	    *destc = *srcc ;
	}
    }
    return dest ;
}

wchar_t *wmemmove (wchar_t *dest, const wchar_t *src, size_t num) {
    if (dest <= src) {
	for (; num > 0; num--, dest++, src++) {
	    *dest = *src ;
	}
    }
    else {
	src += (num - 1);
	dest += (num - 1);
	for (; num > 0; num--, dest--, src--) {
	    *dest = *src ;
	}
    }
    return dest ;
}

Je m'excuse d'avance pour les commentaires dans le header, je n'ai pas voulu copié bêtement les commentaires de la lib standard, donc ils sont quelques peu exotiques.

Les fonctions respectent normalement la norme (à savoir que memmove, contrairement à memcpy, permet d'avoir des tableaux qui se chevauchent).

J'accepte toute remarque / modification à apporter car incorrect vis à vis de la norme.

Edit : Refonte de memmove + ajout des version wchar_t, remplacement des #include.
  • Partager sur Facebook
  • Partager sur Twitter
Anonyme
1 août 2012 à 14:04:55

Citation : Lucas-84

Vraisemblablement, c'est une extension gcc ; il n'y a rien à propos de __func__ dans la C89. J'ai eu la flemme de lire tout ça.



Apparemment c'est dit dans la norme que __func__ est un comportement indéterminé car c'est l'implémentation qui choisit ou non si elle l'implémente. Mais à ce que j'ai cru voir, la plupart des compilateurs (tous ?) implémente cette macro, parfois sous un nom différent.

@Holt : intéressant, j'avais complètement oublié que ces trois fonctions se trouvaient dans string.h. :)
  • Partager sur Facebook
  • Partager sur Twitter
1 août 2012 à 14:05:30

Bonjour,

rapidement :

__func__ est defini depuis le C99 et est une extension GCC.

** edit : ouuups, j'ai dit une grosse connerie. Désolé les amis. **

@Julienf : system fait partie de la libC.
Si on part du principe de recoder la libC, il va te falloir recoder system. C'est peut etre simple, c'est peut etre compliqué, j'en sais rien, mais en tout cas ta petite démonstration de "recoder la libC c'est de la branlette" est completement nulle.
Je sais qu'il existe des choses bien plus complexe que recoder la libC, mais recode déjà la famille printf/scanf ENTIEREMENT (cad en n'oubliant pas les format flottant) et tu aura déjà bien galéré.

Mais qui sais, peut etre es-tu un dieu descendu du ciel pour nous pauvre mortel.
  • Partager sur Facebook
  • Partager sur Twitter
1 août 2012 à 14:07:06

Holt, pourquoi malloc toussa pour memmove?
Il te suffit de faire comme memcpy mais en partant de la fin tout simplement
  • Partager sur Facebook
  • Partager sur Twitter
1 août 2012 à 14:07:36

Citation

__func__ est defini depuis le C99 et est une extension GCC.



On est d'accord pour la définition dans la C99/C11. En revanche, la doc' gcc me semble moins explicite. À l'en croire, ce n'est pas défini avant C99. Ils conseillent même ce jeu de macro :

#if __STDC_VERSION__ < 199901L
# if __GNUC__ >= 2
#  define __func__ __FUNCTION__
# else
#  define __func__ "<unknown>"
# endif
#endif
  • Partager sur Facebook
  • Partager sur Twitter
Staff désormais retraité.
1 août 2012 à 14:16:11

Citation : Julienf

Recoder la libC c'est de la branlette, avec de simple notion tu peux la recoder en partie assez facilement.
Ca donnera un resultat parfois plus propre et plus clair que la libC elle meme.

Printf, n'en parlons pas ! Un seul appel système est nécessaire pour le recoder :)



Ah bah c'est sure que recoder la dizaine de fonctions de string.h ça va plutôt vite.

Maintenant va me recoder toutes les fonctions de unistd.h, apres on en reparle d'accord ?

Edit : J'en profite pour ajouter une fonction de string.h

size_t   my_strspn(const char *s1, const char *s2)
{
     char *offset;

     if ((offset = my_strpbrk(s1, s2)) == NULL)
       return (0);
     return (my_strlen(offset));
}
  • Partager sur Facebook
  • Partager sur Twitter
Si debugger, c’est supprimer des bugs, alors programmer ne peut être que les ajouter - Edsger Dijkstra
1 août 2012 à 14:16:54

Citation : Mr21

Holt, pourquoi malloc toussa pour memmove?
Il te suffit de faire comme memcpy mais en partant de la fin tout simplement


Citation : Lucas-84

ÉDIT : Ah, tu as supprimé le passage en question.


Oui effectivement c'était stupide :)

J'ai édité mon code, plus d'allocation dynamique :) (En fait ce qui m'avait induit en erreur, c'est une page de manuelle où il était marqué : The memory areas may overlap: copying takes place as though the bytes in src are first copied into a temporary array that does not overlap src or dest, and the bytes are then copied from the temporary array to dest.

J'ai rajouté les versions wide également :)

J'ai tout de même une question, étant donné que le type wchar_t n'existe pas depuis le début (C90 il me semble, qu'on me corrige / confirme :) ), quelle constantes dois je utiliser (et quelle valeur ?) pour ma compilation conditionnelle ?

Merci :)
  • Partager sur Facebook
  • Partager sur Twitter
1 août 2012 à 14:17:40

Citation : damjuve

Citation : Julienf

Recoder la libC c'est de la branlette, avec de simple notion tu peux la recoder en partie assez facilement.
Ca donnera un resultat parfois plus propre et plus clair que la libC elle meme.

Printf, n'en parlons pas ! Un seul appel système est nécessaire pour le recoder :)



Ah bah c'est sure que recoder la dizaine de fonctions de string.h ça va plutôt vite.

Maintenant va me recoder toutes les fonctions de unistd.h, apres on en reparle d'accord ?



Euh... Le 3/4 des fonctions d'unistd, ce ne sont pas des appels-systèmes ?
  • Partager sur Facebook
  • Partager sur Twitter
Staff désormais retraité.
1 août 2012 à 14:21:00

unistd.h ne fais pas partie de la bibliothèque standard C non (norme ISO) ?
  • Partager sur Facebook
  • Partager sur Twitter
1 août 2012 à 14:28:22

Citation : Holt

unistd.h ne fais pas partie de la bibliothèque standard C non (norme ISO) ?



Effectivement, c'est un en-tête POSIX.
  • Partager sur Facebook
  • Partager sur Twitter
Staff désormais retraité.
1 août 2012 à 14:30:50

Citation : Holt

unistd.h ne fais pas partie de la bibliothèque standard C non (norme ISO) ?



Autant pour moi, disons alors :

"Va coder stdio.h et après on en reparle".

EDIT : De quoi informaticienZero, je vois pas de quoi tu parle :p
  • Partager sur Facebook
  • Partager sur Twitter
Si debugger, c’est supprimer des bugs, alors programmer ne peut être que les ajouter - Edsger Dijkstra
Anonyme
1 août 2012 à 14:33:05

Citation : damjuve

Citation : Holt

unistd.h ne fais pas partie de la bibliothèque standard C non (norme ISO) ?



Autant pour moi, disons alors :

"Va coder cstdio.h et après on en reparle".



Tu fais des remixs C et C++ ? :)
  • Partager sur Facebook
  • Partager sur Twitter
1 août 2012 à 14:46:16

Bonjour,
Il semble difficile de refaire la libC sans syscall (que ce soit les appels systèmes *n?x ou l'API win32). Recoder malloc sans recoder sbrk et sans le syscall brk me semble assez difficile :D

C'est beau de voir le nombre de tech qu'il y a ici pensant pouvoir refaire toutes une lib C car ils en ont fait une partie en piscine de première année et quelques plus délicate en seconde année. Ceci dit, il est vrai que printf n'est pas vraiment difficile à réaliser (et ce dans son ensemble, n'en déplaise à rz0).
  • Partager sur Facebook
  • Partager sur Twitter
1 août 2012 à 14:50:33

Citation : mcgee42


C'est beau de voir le nombre de tech qu'il y a ici pensant pouvoir refaire toutes une lib C car ils en ont fait une partie en piscine de première année et quelques plus délicate en seconde année. Ceci dit, il est vrai que printf n'est pas vraiment difficile à réaliser (et ce dans son ensemble, n'en déplaise à rz0).



De tek on dit :p
Moi j'en ai vu qu'un :-°
  • Partager sur Facebook
  • Partager sur Twitter
Si debugger, c’est supprimer des bugs, alors programmer ne peut être que les ajouter - Edsger Dijkstra
1 août 2012 à 14:51:12

@Julienf: Il fallait pas ouvrir ta bouche, tu te fais lyncher grave.
  • Partager sur Facebook
  • Partager sur Twitter
1 août 2012 à 14:52:46

Citation : damjuve

Citation : mcgee42


C'est beau de voir le nombre de tech qu'il y a ici pensant pouvoir refaire toutes une lib C car ils en ont fait une partie en piscine de première année et quelques plus délicate en seconde année. Ceci dit, il est vrai que printf n'est pas vraiment difficile à réaliser (et ce dans son ensemble, n'en déplaise à rz0).



De tek on dit :p
Moi j'en ai vu qu'un :-°



toi tu sais écrire et moi je sais compter, à nous deux on est presque bon :p
  • Partager sur Facebook
  • Partager sur Twitter
1 août 2012 à 14:54:30

Citation : Eyyub

@Julienf: Il fallait pas ouvrir ta bouche, tu te fais lyncher grave.


Bah en même temps je suis pas sure qu'il ait déjà ouvert les headers pour voir toute les fonctions qu'il y avait dedans. C'est sure que si LibC = LibC selon Epitech ça va pas te prendre trop longtemps à recoder, après si t'es fier de savoir recoder un strlen super vite ...

Edit : @mcgee42 je vois Julienf, ça fait 1. Vasi dénonce le 2eme :p
  • Partager sur Facebook
  • Partager sur Twitter
Si debugger, c’est supprimer des bugs, alors programmer ne peut être que les ajouter - Edsger Dijkstra