#######################################
# #
# Norme de développement in * #
# #
# Made by Nicolas Sadirac #
# Login rn@epita.fr #
# #
#######################################
Version du 11 octobre 2000 04h45.
Cette norme a pour but d'uniformiser l'écriture des programmes au sein
d'EPITA et d'EPITECH. Elle concerne:
1) La nomination des objets
2) La présentation globale (paragraphes)
3) La présentation locale (lignes)
4) Headers (fichier includes)
5) Des recommandations (non obligatoires)
6) Un exemple de Makefile
1) La nomination des objets :
Les objets (variable, fonctions, macros, types, fichiers ou
répertoires) doivent avoir des noms les plus explicites ou
mnémoniques.
Les abréviations sont TOLEREES dans la mesure ou elles permettent de
réduire significativement la taille du nom sans en perdre le sens. Les
parties des noms composites serons séparées par '_'.
ex:
#define MAX_LINE_SIZE 256
#define COMMENT_CHAR '#'
#define MAX_ANIM_NAME_LENGTH 64
#define MAX_FILE_NAME_LENGTH 1024
* Tous les identifiants (fonctions, macros, types, variables etc.) doivent
être en anglais.
* Les noms de variables et de fonctions de fichiers et de répertoires
doivent être composes exclusivement de minuscules, de chiffres et
de '_'.
* Les noms de macros doivent être en majuscules. Leurs paramètres ont
des noms comme `Ceci', pas comme `CA', et pas plus `ainsi'.
# define XFREE(Var) \
do \
{ \
if (Var) \
free(Var); \
} \
while (0)
* Dans le cas de la déclaration d'une structure le nom
commencera par "s_", pour un type par "t_", pour une union par
"u_" et pour une enum "e_".
ex:
typedef unsigned char t_cmap[CMAP_NBR_COL*CMAP_SIZE];
typedef unsigned char t_pixel;
struct s_picture
{
int width;
int height;
t_cmap cmap;
t_pixel *picture;
};
typedef struct s_picture t_picture;
ATTENTION on peut avoir aussi :
typedef struct s_picture
{
int width;
int height;
t_cmap cmap;
t_pixel *picture;
} t_picture;
* Les noms de globales (si il doit absolument y en avoir) commenceront
par "gl_"
2) Présentation globale
* L'indentation sera celle obtenue avec Emacs (avec la config dans
/u/a1/.env/.emacs)
int get_type(char type_char)
{
t_types *types;
for (types = types_tab; types->type_val; types++)
if (types->type_val == type_char)
return (types->type_val);
return (FALSE);
}
* On passe toujours a la ligne après '{', '}' ou une structure de
contrôle. On indente une première fois pour les accolades, puis une
seconde pour leur contenu.
if (cp) return (cp); /* Incorrect */
if (cp) {return (cp);} /* Incorrect */
if (cp) /* Admis */
{
return (cp);
}
if (cp) /* Correct */
{
return (cp);
}
Selon sa configuration, Emacs indentera comme dans le troisième ou
quatrième exemple. Les deux sont acceptés, le dernier préféré.
Pour les mêmes raisons, la taille du saut de l'indentation peut varier.
On préfèrera 2 espaces.
* On sautera une ligne entre la déclaration de variable et les
instructions. On met une variable par ligne. Il ne doit pas y avoir
d'autres lignes vides dans les blocs. si vous avez envie de séparer
des parties d'un bloc faites soit plusieurs blocs, soit une
fonction, soit une macro.
t_script *load_script(char *file_name)
{
FILE *fd;
t_script *script_head;
t_script *last_script;
char line_buff[MAX_LINE_SIZE+2];
int current_line;
int nbr_line;
current_line = 0;
nbr_line = 0;
script_head = SCRIPT_END;
F_FOPEN(fd, file_name, "r", "script file");
...
* Une ligne ne doit pas exceder 80 caracteres.
* On fera attention à avoir des fonctions courtes et claires,
de 25 lignes maximum (entre les 2 accolades).
On évitera aussi d'avoir plus de 5 fonctions par fichier, une
serait l'idéal.
* Il ne doit pas y avoir de commentaires dans les fonctions. Si il y a
besoin de commentaires ils doivent se trouver avant la la fonction.
/*
** cette fonction calcule ....
*/
void *func_mort_de_rire()
{
}
* Les commentaires sont commencés et terminés par une ligne seule. Toutes
les lignes intermédiaires s'alignent sur elles, et commencent par `**'
/*
** Correct
*/
/*
* Incorrect
*/
* La déclaration de paramètre se fera a la syntaxe ISO/ANSI C
type func(type1 p1, type2 p2, type3 p3)
{
}
voire
type func(type1 p1,
type2 p2,
type3 p3)
{
}
3) Présentation locale
* Un espace derrière le `;' et derrière la `,' :
for (i = 0; i < 255; i++)
sum(&acu, i);
* Pas d'espace entre le nom d'une fonction et la '(' par contre toujours
un espace entre un mot clé C (avec argument) et la '('
script_head = SCRIPT_END;
F_FOPEN(fd, file_name, "r", "script file");
while (!feof(fd))
{
if (!fgets(line_buff, MAX_LINE_SIZE+1, fd)
|| *line_buff == COMMENT_CHAR)
continue;
line_buff[strlen(line_buff) - 1] = END_OF_STRING;
#if (DEBUG&D_LOAD)
my_printf("got:\"%s\"\n", line_buff);
#endif
put_in_script(&script_head, &last_script, line_buff);
}
...
Ceci concerne `for' etc. mais aussi `return' et `sizeof'.
* On remarquera que `return' est une structure de contrôle du C, et `exit'
une fonction, donc attention aux espaces devant la parenthèse.
/* Correct */
if (!cp)
exit(1);
return (cp)
/* Deux fois incorrect */
if (!cp)
exit (1);
return(cp)
Lorsque `return' prend un argument, ce dernier doit etre entre parentheses:
/* Correct */
return (0);
/* Incorrect */
return 0;
* Au maximum on doit trouver 4 paramètres dans une fonction. (La
fonction qui possédera au maximum 4 paramètres aura une vitesse
exécution plus rapide que celle qui en passera plus). Pour passer
plus d'information faites une structure et passez un pointeur sur
cette structure.
* Le symbole de pointeur (*) porte toujours sur la variable (ou
fonction), et jamais sur le type:
char *cp; /* Correct */
char* cp; /* Incorrect */
* On alignera les déclarations avec des tab (sous Emacs M-I)
type v1;
struct s_toto *first_toto;
struct s_toto my_struct_toto;
int *tmp_int;
* Lorsqu'on déclare une variable on ne peut affecter en même temps une
valeur excepte lorsqu'on utilise une variable static.
int bidon = 1; /* Incorrect */
static int pipot = 1; /* Correct */
int dum; /* Correct */
* Affectations : il doit y avoir un espace entre la variable gauche et
le signe d'affectation, de même pour la variable a droite.
var1 = var2
var1 += var2
var1 *= var2
* Opérateurs unaires. Pas d'espace.
*cp
&cp
-n
* Opérateurs bi/ternaires. Tous les opérateurs binaires et ternaires
sont séparés des arguments par un espace de part et d'autre.
if (a % 10)
return (cp ? cp : DEFAULT_STRING)
* Les #if et #ifdef indentent d'un caractère les directives cpp
qui suivent. Les #else et #endif marquent les conditions dont
ils sont issus.
#ifndef DEV_BSIZE
# ifdef BSIZE
# define DEV_BSIZE BSIZE
# else /* !BSIZE */
# define DEV_BSIZE 4096
# endif /* !BSIZE */
#endif /* !DEV_BSIZE */
4) Mots interdits
* Vous n'avez pas droit au switch.
5) Headers
* La norme dans son intégralité est valide pour les headers.
* On les protégera contre double inclusion. Si le fichier est foo.h,
la macro témoin est FOO_H_
#ifndef FOO_H_
# define FOO_H_
/*
** Content of foo.h
*/
#endif /* !FOO_H_ */
* Toutes les fonctions, variables etc. exportées par foo.c sont
prototypées dans foo.h.
* Les fonctions et variables non exportées par foo.c sont déclarées
static.
* foo.c inclue toujours foo.h.
* Les headers ne doivent pas faire d'include eux-mêmes. A l'extrême
limite on pourra inclure des headers non systèmes, mais *jamais*
d'inclusion de headers systèmes.
6) Recommandations
Le suivi de ces recommandations est conseillé, mais pas obligatoire.
* Certaines fonctions de la bibliothèque C peuvent retourner une
valeur particulière lorsqu'elles échouent. Le code principal ne
doit pas être polué par le traitement de ces valeurs
exceptionnelles, aussi faut-il introduire des versions de ces
fonctions qui traitent les erreurs elles-mêmes par un appel à exit.
Ces fonctions doivent porter le nom de la fonction de la lib C,
préfixé par "x".
void *xmalloc(size_t n)
{
void *p;
p = malloc(n);
if (p == 0)
{
fprintf(stderr, "Virtual memory exhausted\n");
exit(1);
}
return (p);
}
* Il est recommandé de commenter en anglais.
7) Un exemple de Makefile :
On prendra soin de toujours compiler avec les options d'optimisation
(-g).
#
# Makefile for PCE in play
#
# Made by zool
# Login
#
# Started on Sat Oct 16 11:41:48 1993 zool
## Last update Fri Oct 20 10:35:30 2000 assistant c unix
#
CC = cc
YACC = yacc -d
COMP = gzip -f
UNCOMP = gunzip -f
RM = rm -f
STRIP = echo strip
#
NAME = play
IPATH = -I. -I../include
OPTI = -g #-O2
LPATH = -L.
#
CFLAGS = $(OPTI) $(IPATH)
LDFLAGS = $(OPTI) $(LPATH)
LIBS =
#
#
L_SRC = main.c load_script.c send_it.c play_it.c proto_init.c\
proto_send.c proto_pict.c
L_OBJS = main.o load_script.o send_it.o play_it.o proto_init.o \
proto_send.o proto_pict.o
INCL = gen.h ../include/spe.h config.h\
local_func.h play.h proto.h
SRC = $(L_SRC)
OBJS = $(L_OBJS)
#
#
#
all : $(NAME)
$(NAME) : $(OBJS)
$(CC) $(LDFLAGS) -o $(NAME) $(OBJS) $(LIBS)
$(STRIP) $(NAME)
re : clean all
clean :
-$(RM) $(OBJS)
-$(RM) *~
-$(RM) \#*
fclean : clean
-$(RM) $(NAME)
comp : fclean
$(COMP) $(SRC) $(INCL)
ucomp :
$(UNCOMP) $(SRC) $(INCL)
.y.o :
$(YACC) $<
$(CC) -c $(CFLAGS) y.tab.c
-@$(RM) y.tab.c
mv y.tab.o $*.o
mv y.tab.h $*.h
.SUFFIXES: .h.Z .c.Z .y.Z .l.Z .x.Z .x\
.c.gz .h.gz .l.gz .y.gz .x.gz \
.x.z .c.z .h.z .l.z .y.z
.c.Z.c .h.Z.h .l.Z.l .y.Z.y .x.Z.x \
c.gz.c .h.gz.h .l.gz.l y.gz.y .x.gz.x \
.x.z.x .c.z.c .h.z.h .l.z.l .y.z.y :
-$(UNCOMP) $<
.x.h :
rpcgen $*.x
@-$(RM) rnusers_svc.c
.c.o :
$(CC) $(CFLAGS) -c $<
#
# deps
#
$(OBJS) : $(INCL)
main.o : main.c
load_script.o : load_script.c
send_it.o : send_it.c
play_it.o : play_it.c
proto_init.o : proto_init.c
proto_send.o : proto_send.c
proto_pict.o : proto_pict.c