Mais tu ne detectes rien ici !!! ca suppose que tu sais suffisamment
de choses sur le comportement du code pour dire `attention, sur les 5000
lignes de code presentes, il y en a 5 qui peuvent ne pas marcher sur
cette machine.'
Dans la pratique, en C, les types abstraits dont tu me parles m'ont
toujours complique la vie en terme de portage.
Ca va certainement te paraitre choquant, mais dans de l'audit de code,
moins on a d'indirection a la con a travers des types abstraits, moins
on se tape de bugs cretins.
Le C n'est pas fait pour utiliser des types abstraits. Il n'a pas de
notion de type abstrait. Typedef fait de l'equivalence de types.
Pas de garde-fou. Nada. Rien.
J'ai deja passe quelques heures a debugguer du code bati aux dessus
de typedef foireux, je m'en passerais bien. Je prefere largement
limiter le nombre de niveaux d'indirections. Et j'ai deja passe du
temps a debugguer des include foireux qui definissaient du typedef a
gogo.
Le langage est pourri de ce point de vue. Les noms de types sont
globaux.
Des que tu as deux projets un peu gros que tu veux utiliser
simultanement, les types abstraits en question te foutent la zone.
Mais tu ne detectes rien ici !!! ca suppose que tu sais suffisamment
de choses sur le comportement du code pour dire `attention, sur les 5000
lignes de code presentes, il y en a 5 qui peuvent ne pas marcher sur
cette machine.'
Dans la pratique, en C, les types abstraits dont tu me parles m'ont
toujours complique la vie en terme de portage.
Ca va certainement te paraitre choquant, mais dans de l'audit de code,
moins on a d'indirection a la con a travers des types abstraits, moins
on se tape de bugs cretins.
Le C n'est pas fait pour utiliser des types abstraits. Il n'a pas de
notion de type abstrait. Typedef fait de l'equivalence de types.
Pas de garde-fou. Nada. Rien.
J'ai deja passe quelques heures a debugguer du code bati aux dessus
de typedef foireux, je m'en passerais bien. Je prefere largement
limiter le nombre de niveaux d'indirections. Et j'ai deja passe du
temps a debugguer des include foireux qui definissaient du typedef a
gogo.
Le langage est pourri de ce point de vue. Les noms de types sont
globaux.
Des que tu as deux projets un peu gros que tu veux utiliser
simultanement, les types abstraits en question te foutent la zone.
Mais tu ne detectes rien ici !!! ca suppose que tu sais suffisamment
de choses sur le comportement du code pour dire `attention, sur les 5000
lignes de code presentes, il y en a 5 qui peuvent ne pas marcher sur
cette machine.'
Dans la pratique, en C, les types abstraits dont tu me parles m'ont
toujours complique la vie en terme de portage.
Ca va certainement te paraitre choquant, mais dans de l'audit de code,
moins on a d'indirection a la con a travers des types abstraits, moins
on se tape de bugs cretins.
Le C n'est pas fait pour utiliser des types abstraits. Il n'a pas de
notion de type abstrait. Typedef fait de l'equivalence de types.
Pas de garde-fou. Nada. Rien.
J'ai deja passe quelques heures a debugguer du code bati aux dessus
de typedef foireux, je m'en passerais bien. Je prefere largement
limiter le nombre de niveaux d'indirections. Et j'ai deja passe du
temps a debugguer des include foireux qui definissaient du typedef a
gogo.
Le langage est pourri de ce point de vue. Les noms de types sont
globaux.
Des que tu as deux projets un peu gros que tu veux utiliser
simultanement, les types abstraits en question te foutent la zone.
Dans l'article <g5u567$9e9$,
Marc Espie écrit:Mais tu ne detectes rien ici !!! ca suppose que tu sais suffisamment
de choses sur le comportement du code pour dire `attention, sur les 5000
lignes de code presentes, il y en a 5 qui peuvent ne pas marcher sur
cette machine.'
En général, le programmeur est censé savoir ce qu'il écrit. Au moment
où il ajoute du code qui n'est pas conforme sur telle ou telle
implémentation, il ajoute l'assert qui va bien au début du code
(éventuellement en double) et le problème est bien détecté le jour
où l'implémentation en question est utilisée. C'est aussi ce que
disponibles. Au moins l'utilisateur sait pourquoi ça ne peut pas
marcher.
Dans l'article <g5u567$9e9$1@biggoron.nerim.net>,
Marc Espie <espie@lain.home> écrit:
Mais tu ne detectes rien ici !!! ca suppose que tu sais suffisamment
de choses sur le comportement du code pour dire `attention, sur les 5000
lignes de code presentes, il y en a 5 qui peuvent ne pas marcher sur
cette machine.'
En général, le programmeur est censé savoir ce qu'il écrit. Au moment
où il ajoute du code qui n'est pas conforme sur telle ou telle
implémentation, il ajoute l'assert qui va bien au début du code
(éventuellement en double) et le problème est bien détecté le jour
où l'implémentation en question est utilisée. C'est aussi ce que
disponibles. Au moins l'utilisateur sait pourquoi ça ne peut pas
marcher.
Dans l'article <g5u567$9e9$,
Marc Espie écrit:Mais tu ne detectes rien ici !!! ca suppose que tu sais suffisamment
de choses sur le comportement du code pour dire `attention, sur les 5000
lignes de code presentes, il y en a 5 qui peuvent ne pas marcher sur
cette machine.'
En général, le programmeur est censé savoir ce qu'il écrit. Au moment
où il ajoute du code qui n'est pas conforme sur telle ou telle
implémentation, il ajoute l'assert qui va bien au début du code
(éventuellement en double) et le problème est bien détecté le jour
où l'implémentation en question est utilisée. C'est aussi ce que
disponibles. Au moins l'utilisateur sait pourquoi ça ne peut pas
marcher.
Tu supposes deux choses qui sont fausses.
- le programmeur sait ce qu'il ecrit;
- c'est la meme personne qui relit le code derriere.
Cote autoconf, plus le temps passe, moins j'aime. J'etais deja pas tres fan
au depart, mais a force de corriger des bugs dans les scripts auto-generes
de 5000 lignes, on finit par se dire qu'il n'y a pas grand chose a sauver
dedans.
La seule chose a sauver, sans doute, c'est l'idee d'avoir des ifdef
feature-based, et pas os-based.
Si tu veux une infrastructure plutot mieux, cmake se debrouille nettement
mieux.
De toutes facons, tot ou tard, tous ces systemes grossissent jusqu'a
etre incontrolable. C'est un vrai probleme...
Tu supposes deux choses qui sont fausses.
- le programmeur sait ce qu'il ecrit;
- c'est la meme personne qui relit le code derriere.
Cote autoconf, plus le temps passe, moins j'aime. J'etais deja pas tres fan
au depart, mais a force de corriger des bugs dans les scripts auto-generes
de 5000 lignes, on finit par se dire qu'il n'y a pas grand chose a sauver
dedans.
La seule chose a sauver, sans doute, c'est l'idee d'avoir des ifdef
feature-based, et pas os-based.
Si tu veux une infrastructure plutot mieux, cmake se debrouille nettement
mieux.
De toutes facons, tot ou tard, tous ces systemes grossissent jusqu'a
etre incontrolable. C'est un vrai probleme...
Tu supposes deux choses qui sont fausses.
- le programmeur sait ce qu'il ecrit;
- c'est la meme personne qui relit le code derriere.
Cote autoconf, plus le temps passe, moins j'aime. J'etais deja pas tres fan
au depart, mais a force de corriger des bugs dans les scripts auto-generes
de 5000 lignes, on finit par se dire qu'il n'y a pas grand chose a sauver
dedans.
La seule chose a sauver, sans doute, c'est l'idee d'avoir des ifdef
feature-based, et pas os-based.
Si tu veux une infrastructure plutot mieux, cmake se debrouille nettement
mieux.
De toutes facons, tot ou tard, tous ces systemes grossissent jusqu'a
etre incontrolable. C'est un vrai probleme...
Dans l'article <g5vngh$h2m$,
Marc Espie écrit:Tu supposes deux choses qui sont fausses.
- le programmeur sait ce qu'il ecrit;
Mauvais programmeur, changer de programmeur.
Ce genre de programmeur n'est pas censé écrire en C.
Dans l'article <g5vngh$h2m$1@biggoron.nerim.net>,
Marc Espie <espie@lain.home> écrit:
Tu supposes deux choses qui sont fausses.
- le programmeur sait ce qu'il ecrit;
Mauvais programmeur, changer de programmeur.
Ce genre de programmeur n'est pas censé écrire en C.
Dans l'article <g5vngh$h2m$,
Marc Espie écrit:Tu supposes deux choses qui sont fausses.
- le programmeur sait ce qu'il ecrit;
Mauvais programmeur, changer de programmeur.
Ce genre de programmeur n'est pas censé écrire en C.
Si tu veux une infrastructure plutot mieux, cmake se debrouille nettement
mieux.
Si tu veux une infrastructure plutot mieux, cmake se debrouille nettement
mieux.
Si tu veux une infrastructure plutot mieux, cmake se debrouille nettement
mieux.
--{ Marc Espie a plopé ceci: }--
Si tu veux une infrastructure plutot mieux, cmake se debrouille nettement
mieux.
C'est d'ailleur une question que je me pose depuis longtemps.
Je suis aussi de plus en plus effrayé par le 'monstre' automachin,
et je cherche un truc plus simple/moderne/facile pour configurer
des softs à trois balles en C. J'entend parler de cmake, mais aussi
de scons...
--{ Marc Espie a plopé ceci: }--
Si tu veux une infrastructure plutot mieux, cmake se debrouille nettement
mieux.
C'est d'ailleur une question que je me pose depuis longtemps.
Je suis aussi de plus en plus effrayé par le 'monstre' automachin,
et je cherche un truc plus simple/moderne/facile pour configurer
des softs à trois balles en C. J'entend parler de cmake, mais aussi
de scons...
--{ Marc Espie a plopé ceci: }--
Si tu veux une infrastructure plutot mieux, cmake se debrouille nettement
mieux.
C'est d'ailleur une question que je me pose depuis longtemps.
Je suis aussi de plus en plus effrayé par le 'monstre' automachin,
et je cherche un truc plus simple/moderne/facile pour configurer
des softs à trois balles en C. J'entend parler de cmake, mais aussi
de scons...
In article <20080717220053$,
Vincent Lefevre wrote:Euh, les assert, c'est au runtime (en C). Donc beaucoup trop tard
en prod.
Pas trop tard: tout d'abord, c'est reproductible, car ça se met
typiquement au début du programme, et ça se détecte lors du beta test
de la toute première version.
Bzzzt! Ca suppose que tu aies des tests de couverture *complets*,
deja, et qui tombent sur ces bugs-la. C'est quand la derniere
fois que tu as vu ce genre de choses ?
Dans tes tests, tu verifies ce qui se passe si tu alloues des
structures de 5G ?
tu verifies que les tailles sont affichees correctement, par
exemple ?
In article <20080717220053$0de5@ay.vinc17.org>,
Vincent Lefevre wrote:
Euh, les assert, c'est au runtime (en C). Donc beaucoup trop tard
en prod.
Pas trop tard: tout d'abord, c'est reproductible, car ça se met
typiquement au début du programme, et ça se détecte lors du beta test
de la toute première version.
Bzzzt! Ca suppose que tu aies des tests de couverture *complets*,
deja, et qui tombent sur ces bugs-la. C'est quand la derniere
fois que tu as vu ce genre de choses ?
Dans tes tests, tu verifies ce qui se passe si tu alloues des
structures de 5G ?
tu verifies que les tailles sont affichees correctement, par
exemple ?
In article <20080717220053$,
Vincent Lefevre wrote:Euh, les assert, c'est au runtime (en C). Donc beaucoup trop tard
en prod.
Pas trop tard: tout d'abord, c'est reproductible, car ça se met
typiquement au début du programme, et ça se détecte lors du beta test
de la toute première version.
Bzzzt! Ca suppose que tu aies des tests de couverture *complets*,
deja, et qui tombent sur ces bugs-la. C'est quand la derniere
fois que tu as vu ce genre de choses ?
Dans tes tests, tu verifies ce qui se passe si tu alloues des
structures de 5G ?
tu verifies que les tailles sont affichees correctement, par
exemple ?
Le problème est que si tu stockes un (void *) 0 et que tu le relis en
T *, rien n'est garanti par la norme: tu n'es pas certain d'obtenir
un pointeur nul, ni même une valeur valide de pointeur vers T (e.g.
ça peut planter à ce moment).
Le problème est que si tu stockes un (void *) 0 et que tu le relis en
T *, rien n'est garanti par la norme: tu n'es pas certain d'obtenir
un pointeur nul, ni même une valeur valide de pointeur vers T (e.g.
ça peut planter à ce moment).
Le problème est que si tu stockes un (void *) 0 et que tu le relis en
T *, rien n'est garanti par la norme: tu n'es pas certain d'obtenir
un pointeur nul, ni même une valeur valide de pointeur vers T (e.g.
ça peut planter à ce moment).
En news:20080718003505$, Vincent Lefevre va escriure:Le problème est que si tu stockes un (void *) 0 et que tu le relis en
T *, rien n'est garanti par la norme: tu n'es pas certain d'obtenir
un pointeur nul, ni même une valeur valide de pointeur vers T (e.g.
ça peut planter à ce moment).
En fait il n'est pas besoin d'avoir affaire à des pointeurs nuls. Si tu
émets un (void*)&objet, et que tu le relis en T* (avec T type de objet),
rien n'est garanti par la norme, et surtout pas que tu puisses récupérer ton
objet.
Exemple pratique : sur certaines architectures, les adresses sont des
adresses de int/click/cluster/que_sais_je, donc un pointeur vers char (et
donc un void*) est plus « gros », à l'adresse classique se rajoute une
sous-adresse pour savoir de quel char il s'agit à l'intérieur du machin dont
on a l'adresse.
Évidemment, dans ce cas-là, sizeof(char*) > sizeof(T*).
Si par hasard le mode de passage des paramètres veut que l'on ait la
sous-adresse _avant_ l'adresse (c'est débile, mais bon, avec les
gros-boutiens tout est possible), tu as une erreur directe, la fonction
variadique va lire la sous-adresse et l'interpréter comme une adresse, BOUM.
Cependant la cause la plus claire de problème est le cas indirect : comme le
void* est plus gros, cela décale les paramètres suivants; donc en lisant le
T* on va lire l'adresse de objet et c'est OK, on récupère ce que l'on veut;
par contre la sous-adresse qui suit n'a pas été dépilée, et quand la
fonction variadique va lire l'argument suivant, BOUM.
En news:20080718003505$44a9@ay.vinc17.org, Vincent Lefevre va escriure:
Le problème est que si tu stockes un (void *) 0 et que tu le relis en
T *, rien n'est garanti par la norme: tu n'es pas certain d'obtenir
un pointeur nul, ni même une valeur valide de pointeur vers T (e.g.
ça peut planter à ce moment).
En fait il n'est pas besoin d'avoir affaire à des pointeurs nuls. Si tu
émets un (void*)&objet, et que tu le relis en T* (avec T type de objet),
rien n'est garanti par la norme, et surtout pas que tu puisses récupérer ton
objet.
Exemple pratique : sur certaines architectures, les adresses sont des
adresses de int/click/cluster/que_sais_je, donc un pointeur vers char (et
donc un void*) est plus « gros », à l'adresse classique se rajoute une
sous-adresse pour savoir de quel char il s'agit à l'intérieur du machin dont
on a l'adresse.
Évidemment, dans ce cas-là, sizeof(char*) > sizeof(T*).
Si par hasard le mode de passage des paramètres veut que l'on ait la
sous-adresse _avant_ l'adresse (c'est débile, mais bon, avec les
gros-boutiens tout est possible), tu as une erreur directe, la fonction
variadique va lire la sous-adresse et l'interpréter comme une adresse, BOUM.
Cependant la cause la plus claire de problème est le cas indirect : comme le
void* est plus gros, cela décale les paramètres suivants; donc en lisant le
T* on va lire l'adresse de objet et c'est OK, on récupère ce que l'on veut;
par contre la sous-adresse qui suit n'a pas été dépilée, et quand la
fonction variadique va lire l'argument suivant, BOUM.
En news:20080718003505$, Vincent Lefevre va escriure:Le problème est que si tu stockes un (void *) 0 et que tu le relis en
T *, rien n'est garanti par la norme: tu n'es pas certain d'obtenir
un pointeur nul, ni même une valeur valide de pointeur vers T (e.g.
ça peut planter à ce moment).
En fait il n'est pas besoin d'avoir affaire à des pointeurs nuls. Si tu
émets un (void*)&objet, et que tu le relis en T* (avec T type de objet),
rien n'est garanti par la norme, et surtout pas que tu puisses récupérer ton
objet.
Exemple pratique : sur certaines architectures, les adresses sont des
adresses de int/click/cluster/que_sais_je, donc un pointeur vers char (et
donc un void*) est plus « gros », à l'adresse classique se rajoute une
sous-adresse pour savoir de quel char il s'agit à l'intérieur du machin dont
on a l'adresse.
Évidemment, dans ce cas-là, sizeof(char*) > sizeof(T*).
Si par hasard le mode de passage des paramètres veut que l'on ait la
sous-adresse _avant_ l'adresse (c'est débile, mais bon, avec les
gros-boutiens tout est possible), tu as une erreur directe, la fonction
variadique va lire la sous-adresse et l'interpréter comme une adresse, BOUM.
Cependant la cause la plus claire de problème est le cas indirect : comme le
void* est plus gros, cela décale les paramètres suivants; donc en lisant le
T* on va lire l'adresse de objet et c'est OK, on récupère ce que l'on veut;
par contre la sous-adresse qui suit n'a pas été dépilée, et quand la
fonction variadique va lire l'argument suivant, BOUM.
In article <g623ii$mo4$, Antoine Leca wrote:Exemple pratique : sur certaines architectures, les adresses sont des
adresses de int/click/cluster/que_sais_je, donc un pointeur vers
char (et donc un void*) est plus « gros », à l'adresse classique se
rajoute une sous-adresse pour savoir de quel char il s'agit à
l'intérieur du machin dont on a l'adresse.
Évidemment, dans ce cas-là, sizeof(char*) > sizeof(T*).
[...] Cependant la cause la plus claire de problème est
le cas indirect : comme le void* est plus gros, cela décale les
paramètres suivants; donc en lisant le T* on va lire l'adresse de
objet et c'est OK, on récupère ce que l'on veut; par contre la
sous-adresse qui suit n'a pas été dépilée, et quand la fonction
variadique va lire l'argument suivant, BOUM.
Il me semble me souvenir que c'est explicitement interdit par la
norme, que les cast d'objets vers void* and back preservent la
valeur...
ce qui veut dire que sur ces archis, tu dois reserver de la
place en plus pour tes void* pour permettre les cast.
In article <g623ii$mo4$1@shakotay.alphanet.ch>, Antoine Leca wrote:
Exemple pratique : sur certaines architectures, les adresses sont des
adresses de int/click/cluster/que_sais_je, donc un pointeur vers
char (et donc un void*) est plus « gros », à l'adresse classique se
rajoute une sous-adresse pour savoir de quel char il s'agit à
l'intérieur du machin dont on a l'adresse.
Évidemment, dans ce cas-là, sizeof(char*) > sizeof(T*).
[...] Cependant la cause la plus claire de problème est
le cas indirect : comme le void* est plus gros, cela décale les
paramètres suivants; donc en lisant le T* on va lire l'adresse de
objet et c'est OK, on récupère ce que l'on veut; par contre la
sous-adresse qui suit n'a pas été dépilée, et quand la fonction
variadique va lire l'argument suivant, BOUM.
Il me semble me souvenir que c'est explicitement interdit par la
norme, que les cast d'objets vers void* and back preservent la
valeur...
ce qui veut dire que sur ces archis, tu dois reserver de la
place en plus pour tes void* pour permettre les cast.
In article <g623ii$mo4$, Antoine Leca wrote:Exemple pratique : sur certaines architectures, les adresses sont des
adresses de int/click/cluster/que_sais_je, donc un pointeur vers
char (et donc un void*) est plus « gros », à l'adresse classique se
rajoute une sous-adresse pour savoir de quel char il s'agit à
l'intérieur du machin dont on a l'adresse.
Évidemment, dans ce cas-là, sizeof(char*) > sizeof(T*).
[...] Cependant la cause la plus claire de problème est
le cas indirect : comme le void* est plus gros, cela décale les
paramètres suivants; donc en lisant le T* on va lire l'adresse de
objet et c'est OK, on récupère ce que l'on veut; par contre la
sous-adresse qui suit n'a pas été dépilée, et quand la fonction
variadique va lire l'argument suivant, BOUM.
Il me semble me souvenir que c'est explicitement interdit par la
norme, que les cast d'objets vers void* and back preservent la
valeur...
ce qui veut dire que sur ces archis, tu dois reserver de la
place en plus pour tes void* pour permettre les cast.