OVH Cloud OVH Cloud

Ça se fait, ça ?

58 réponses
Avatar
Pierre Maurette
Bonjour,

Je sens que mon prochain message sera un "Oooops !" ;-)

Est-il envisageable de faire ça:

[main.c]
#include<stdio.h>

/* declare & define
* void func1(int* tab);
* void func2(int* tab)
*/
#define PETRUS1
#include "testfunc.c"
#undef PETRUS1
#define PETRUS2
#include "testfunc.c"
#undef PETRUS2

int main(void)
{
int tabtest[]= {1, 2, 3};
func1(tabtest);
func2(tabtest);
return 0;
}

[testfunc.c]
#ifdef PETRUS1
void func1(int* tab)
#endif
#ifdef PETRUS2
void func2(int* tab)
#endif
{
printf("%d\n", tab[0]);
#ifdef PETRUS1
printf("%d\n", tab[1]);
#endif
}

Le but est de centraliser le code source en évitant quelques boucles
(ou plus généralement des tests) mal placées. Il est clair que je
n'utiliserai un truc tordu comme ça uniquement si les performances le
justifient. En revanche, je ne veux pas dupliquer le code source.

En regardant ce que VC8 générait, il m'a semblé constater que sur des
fonctions de cette forme (mais plus complexes):

void func(int* tab, int commutateur)
{
printf("%d\n", tab[0]);
if(commutateur)printf("%d\n", tab[1]);
/* etc. */
}

avec les bonnes options d'optimisation, il pouvait générer deux
fonctions, ou au moins deux blocs avec duplication de certaines parties
du code.

Bonne fin de journée...

--
Pierre Maurette

10 réponses

2 3 4 5 6
Avatar
Antoine Leca
En news:f4rpn0$sto$, Xavier Roche va escriure:
A propos, quelqun sait pourquoi ces machins [les trigraphes] ont
été introduits dans ISO C ?


C'est typique des procédures ISO : c'est pour contenter certains pays (en
l'occurence, d'Europe) qui craignent à bon droit une hégémonie américaine
mais se trompent de cible et plus encore de solution.
En l'occurence, le motif invoqué était de pouvoir entrer des programmes C
avec les jeux de caractères (normalisés par ISO) supposément internationaux
et interopérables.

Le clavier du mec qui a fait la spec était baisé et les touches
[,],etc. n'étaient plus fonctionnelles ?


Il faut se souvenir que ceci a eu lieu en 1989, les ordinateurs n'avaient
pas les caractéristiques actuelles ; en particulier, avec un terminal «
standard » de l'époque, relié avec des lignes 7 bits + parité, en Europe,
les touches [ ] etc (quand elles existaient, par exemple moi je n'en avais
pas sur le Vax que j'utilisais en 1987) pouvaient générer des multibytes
(genre <0E><5B><0F>) qui pourraient gêner certains compilateurs.


Bien sûr, on est typiquement en face d'une invention de comité qui ne résoud
pas correctement le problème :
- Le caractère !, qui est variant dans les différentes pages de code EBCDIC,
n'a pas d'alternative, au point même qu'il est utilisé pour faire le
trigraphe ??!=| (avec une page mal décodée, cela donne ??¦ ou ??|...)

- La séquence ??' (qui vaut ^) se rencontrait souvent à l'époque dans les
codes pour MacOS, dans l'idiome
long Type='????';
avec une erreur syntaxique systématique [ long Type='??^; ]

- le caractère <5B>, visuellement le symbole monétaire au Japon (¥) et en
Corée du Sud (W barré, u20A9), devrait obliger à utiliser un autre
caractère pour représenter la barre inversée dans ces pays... mais la
pratique des Japonais et des Coréens avait déjà imposé, depuis longtemps,
que ce soit le codet <5B> plutôt que le caractère qui importe, quoiqu'en
dise la norme.

- Surtout, les trigraphes, de par leur aspect rébarbatif, ne devaient servir
QUE pour gérer des problèmes de transmissions ; mais pour cela, il aurait
fallu que les dispositifs d'encodage et de décodage fassent les conversions
au vol... donc dans les routines d'entrée depuis le clavier, et d'affichage
à l'écran ; c'est ce qui est fait aujourd'hui pour UTF-8 ; mais il est clair
qu'en 1990 il n'y a eu aucune incitation pour que les vendeurs et
développeurs implémentent ce mécanisme dans leurs chaînes de développement,
pour un profit extrêmement réduit !

Un peu plus tard, et avec le recul, une solution plus intelligente a été
proposée au milieu des années 90 par B. Stroustrup et K. Simonsen, les
digraphes comme %: ou <% et autres semi-mots-clés comme bitand ou and_eq.
Mais ce ne fut pas un succès, car :
- le problème avait essentiellement disparu avec l'abandon des terminaux
causant 7 bits seulement
- certains problèmes comme celui du ! EBCDIC ou du <5B> nippon restaient
entiers
- le système imposait (et impose toujours) un supplément de complexité dans
TOUS les analyseurs syntaxiques de langage C/C++ (surtout avec % qui demande
potentiellement un lookahead de 4 caractères pour ## devenu %:%:), et encore
aujourd'hui ce n'est pas le plus courant (taper donc %: au début d'une
ligne, et regarder si votre coloriseur syntaxique passe automatiquement en
mode « directive du préprocesseur...)


Antoine

Avatar
Antoine Leca
In news:, Thierry B. va escriure:
--{ Pascal Bourguignon a plopé ceci: }--

A-Z 0-9 + - * / ( ) $ = space , . # [ ] % " _ ! & ' ? < > @ ^ ;


C'est pas un peu l'équivalent du Baudot ?



En Baudot (j'ai donné), A et 0 ne sont pas dans le même alphabet... 5 bits,
cela dne fait que 32 codets !

Le jeu de caractères qu'indique Pascal est un poil plus récent, c'est le
code BCDIC ou une variante. Ce sont des codes sur 6 bits, dérivés du codage
Hollerith des cartes perforées.

(EBCDIC = _Extended_ Binary Coded Decimal Interchange Code = extension sur 8
bits)



INT MAIN(INT ARGC,CHAR* ARGV)??<
IF((ARGC==1)??!??!(ARGC==2))??<
PRINTF("GOOD??/n");
ELSE??<
PRINTF("BAD??/n");






Mon gcc a vomi partout sur le clavier :)


Pourtant, gcc est un des compilateurs qui a le plus de facilités avec les
trigraphes (quant aux capitales, il « suffit » de considérer que ce sont
toujours des minuscules et le tour est joué.) Les commentaires de la
documentation de GCC sont très critiques, mais ils montrent aussi que les
auteurs ont fait l'effort de lire et de relire la norme, et de s'efforcer de
l'implémenter ; on ne peut pas forcément en dire autant d'autres auteurs de
compilateurs C !


Antoine



Avatar
Antoine Leca
En news:,
Jean-Marc Bourguet va escriure:

Si on n'a pas de minuscules, faire une implementation conforme du
C est impossible; ce n'est donc pas un argument en faveur des
trigraphes.


Certes (à cause de NULL, INT_MAX et autres FLT_EPSILON).
Mais si tu décrètes que ce qui est visiblement un « A » est le code pour le
a minuscule (5.1.1.2p1 1º), et si tu fournis des versions modifiées de
<stddef.h> <limits.h> et <float.h>, utilisant des « minuscules » dans les
identificateurs de macros, donc qui ressemble à

??:define null 0

ou encore apparaît visuellement comme

??:DEFINE NULL 0

tu vas avoir un truc utilisable pour programmer en C (mais pas pour porter
des programmes étrangers) et assez proche de la norme C90, toutes choses
égales par ailleurs (par exemple et au hasard d'une longue liste, en
supposant que le CDC-machin permette de définir un type char ayant au moins
8 bits.)


C99 est plus compliqué (= encore plus abracadabrantesque), à cause par
exemple de _Bool.


Antoine

Avatar
Jean-Marc Bourguet
"Antoine Leca" writes:

En news:,
Jean-Marc Bourguet va escriure:

Si on n'a pas de minuscules, faire une implementation conforme du
C est impossible; ce n'est donc pas un argument en faveur des
trigraphes.


Certes (à cause de NULL, INT_MAX et autres FLT_EPSILON).
Mais si tu décrètes que ce qui est visiblement un « A » est le code pour le
a minuscule (5.1.1.2p1 1º)


J'avais pas pense a cela. J'aurais du.

Quand j'etais etudiant, l'imprimante etait montee avec une chaine n'ayant
pas de minuscules et tout etait donc imprime en majuscule.

Si j'ai bonne memoire, lors de l'introduction des codes ASCII et EBCDIC, il
y a eu des discussions pour savoir si les lettres des jeux precedants
n'ayant pas de majuscules devaient etre consideres comme des minuscules ou
des majuscules -- les deux pratiques existants. Faudra que je regarde dans
le bouquin de MacKenzie.

A+

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org


Avatar
Gabriel Dos Reis
"Antoine Leca" writes:

| En news:,
| Gabriel Dos Reis va escriure:
| > Et maintenant, on a le probleme de "<:" qui veut dire "[", en C++:
| >
| > std::list<::S> ls; // hahaha - good try
|
| MdR
| Je n'y avais pas pensé, mais c'est excessivement drôle.
| Qu'en pense Bjarne ?

Embarassment.

C'est dur de vivre avec l'histoire.
Les namespaces ont ete inventes longtemps bien apres les digraphes,
l'effet avec les templates n'a pas ete anticipe je crois.

| Comme quoi, il va *vraiment* falloir demander à Dennis d'écrire un article
| pour désintoxer les gens des formulations trop denses (suivant son propre
| style et celui de Ken Thomson)

:-)

| On est pas rendu.
| Et tout cela à cause de ces fichus trigraphes à la gomme ;-)

Yup :-)

-- Gaby
Avatar
Antoine Leca
En news:,
Gabriel Dos Reis va escriure:
Et maintenant, on a le probleme de "<:" qui veut dire "[", en C++:

std::list<::S> ls; // hahaha - good try


MdR
Je n'y avais pas pensé, mais c'est excessivement drôle.
Qu'en pense Bjarne ?

Comme quoi, il va *vraiment* falloir demander à Dennis d'écrire un article
pour désintoxer les gens des formulations trop denses (suivant son propre
style et celui de Ken Thomson)

On est pas rendu.
Et tout cela à cause de ces fichus trigraphes à la gomme ;-)


Antoine

Avatar
Antoine Leca
En news:46788212$0$25952$,
Harpo va escriure:
On Tue, 19 Jun 2007 18:18:33 +0200, Pascal Bourguignon wrote:

Pensez-vous que ce puisse être intéressant d'écrire un
pré-processeur puissant pour le C ?


En tout cas, ça donne des résultats: C++, Objective-C sont écrit (au
moins à l'origine) comme un pré-processeur puissant pour le C.


Oui mais cela définit des langages différents du C.


Dès que tu passes à travers un préprocesseur, tu définis un langage
différent. D'ailleurs, cpp et la bibliothèque standard définissaient un
langage différent (appelé K&R, et plus ambitieux) de celui que compilait
c[012] ou ccom/pcc. Ce qui est intéressant ici, c'est que l'on a choisi
d'appeler C le premier plutôt que le second.


Antoine



Avatar
Pascal Bourguignon
Harpo writes:

On Tue, 19 Jun 2007 16:22:38 +0200, Gabriel Dos Reis wrote:

| Pensez-vous que ce puisse être intéressant d'écrire un pré-processeur
| puissant pour le C ?

Je ne sais pas. Mais les inventeurs du C ont invente m4.


Utiliser m4 est une solution, mais c'est un macro-langage généraliste
peut-être assez compliqué à utiliser et les sources pourrait etre moins
lisibles que lorsque l'on emploie cpp.
Je pensais à quelque chose comme cpp mais avec des variables du
macro-processeur globales ou locales à une macro et la possibiliter
d'itérer et/ou de récurser dans une macro.


Je ne sais pas pourquoi tu te fatigue. Si tu veux un bon système de
macro, utilise Common Lisp!

--
__Pascal Bourguignon__ http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.


Avatar
Pascal Bourguignon
Harpo writes:

On Wed, 20 Jun 2007 17:49:59 +0200, Pascal Bourguignon wrote:

Je pensais à quelque chose comme cpp mais avec des variables du
macro-processeur globales ou locales à une macro et la possibiliter
d'itérer et/ou de récurser dans une macro.


Je ne sais pas pourquoi tu te fatigue. Si tu veux un bon système de
macro, utilise Common Lisp!


Je vais voir ce qu'on peut en faire, mes connaissances en Lisp sont
lointaines et déjà à l'époque très limitées.

En plus de #définir des constantes


(defconstant +pi+ 3.141592 "On a un opérateur DEFCONSTANT")

Mais on peut aussi définir des "symbol-macro":

(define-symbol-macro mypi (* 4 (atan 1)))

ainsi, à chaque fois qu'on écrit MYPI, il est substitué par (* 4 (atan 1)).


Ça permet de cacher des appels fonctions derrière un simple symbole,
comme un #define MYPI (4*atan(1))



et faire des pseudo-fonctions qui
auraient une même manière d'appel que des fonctions en C,


Il y a une déclaration INLINE en Common Lisp, alors si c'est pour
écrire une fonction, ce n'est pas la peine de changer quoi que ce soit:

(declaim (inline square))
(defun square (x) (* x x))

(defun scalar* (a b) (+ (square (- (x a) (x b))) (square (- (y a) (y b)))))


le compilateur génèrera quelque chose comme:

(defun scalar* (a b)
(+ (let ((temp1 (- (x a) (x b)))) (* temp1 temp1))
(let ((temp2 (- (y a) (y b)))) (* temp2 temp2))))


Dans certains cas, on peut aussi définir des "compiler-macro", qui
sont des fonctions qui indiquent comment compiler une fonction en
fonction des arguments passés.

(defun square (x) (* x x))

(define-compiler-macro square (&whole form x)
(cond
((numberp x) ; x est un nombre litéral (square 42)
(* x x)) ; calculé lors de la compilation.
((atom x)
`(* ,x ,x)) ; formule normale "inline" pour (square var)
(t (case (car x) ; on est dans le cas (square (expression ...))
(square (if (= (length x) 2)
`(expt ,(nth 1 x) 4) ; (square (square x))
form)) ; sinon, on utilise la formule normale.
(expt (if (= (length x) 3) (square (expt n p))
(if (numberp (nth 2 x))
`(expt ,(nth 1 x) ,(* 2 (nth 2 x))) ; p est litéral
; alors on calcule (expt n (* 2 p))
; en doublant p au moment de la compilation.
`(expt ,(nth 1 x) (* 2 ,(nth 2 x)))) ; p est expression
; alors on calcule (expt n (* 2 p))
form)) ; forme normale.
(otherwise `(* ,x ,x))))))




Maintenant, on peut aussi écrire des macros normales, lorsqu'on veut
implémenter des abstractions syntactiques (des structures de
controles). Par exemple, on a plusieurs opérateurs de boucles, DO,
DO*, DOTIMES, DOLIST, LOOP, etc.
Écrire une boucle "while" peut se faire avec:

(loop :while condition
:do ...)

ou:

(do ()
((not condition))
...)

Dans les deux cas, il y a une syntaxe permettant plus d'options.


Mais si on veut écrire simplement:

(while condition
...)

on peut définir cette structure de controle avec une macro:

(defmacro while (condition &body body)
`(do () ((not ,condition)) ,@body))


(let ((i 0)
(j 1))
(while (< i 10)
(print (list i j))
(incf i)
(setf j (* 2 j))))





Note, les macros sont des fonctions comme les autres, simplement elles
sont appelées par le compilateur au moment de la compilation avec les
sous expressions symbolique du source comme paramètre, et elles
doivent retourner une expression symbolique qui sera compilée à la
place. On peut utiliser dans le corps d'une macro toutes les
fonctions et opérateurs Common Lisp et définis par l'utilisateur.

On pourrait écrire:

(defmacro while (condition &body body)
(cond
((eq condition 'T) (cons 'loop body))
((eq condition 'NIL) 'NIL)
(t (list* 'do '() (list (list 'not condition)) body))))



C/USER[15]> (macroexpand-1 '(while t (print 'always)))
(LOOP (PRINT 'ALWAYS)) ;
T
C/USER[16]> (macroexpand-1 '(while nil (print 'never)))
NIL ;
T
C/USER[17]> (macroexpand-1 '(while (< a b) (print (list (incf a) b))))
(DO NIL ((NOT (< A B))) (PRINT (LIST (INCF A) B))) ;
T
C/USER[18]>






j'aimerais
aussi utiliser des paramêtres à mots-clé, par exemple des choses comme
ça :
copy(dest=argd, source=args, len=argl);
dans un source.
Ce qui pourrait être utile dans des cas moins triviaux.


(defun copy (&key dest source length)
(do-copy dest source len))

(copy :source src :dest dst :length len)



--
__Pascal Bourguignon__ http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.



Avatar
Charlie Gordon
"Antoine Leca" a écrit dans le message de news:
f5b0jh$hvh$
In news:, Thierry B. va escriure:
--{ Pascal Bourguignon a plopé ceci: }--

INT MAIN(INT ARGC,CHAR* ARGV)??<
IF((ARGC==1)??!??!(ARGC==2))??<
PRINTF("GOOD??/n");
ELSE??<
PRINTF("BAD??/n");






Mon gcc a vomi partout sur le clavier :)


Pourtant, gcc est un des compilateurs qui a le plus de facilités avec les
trigraphes (quant aux capitales, il « suffit » de considérer que ce sont
toujours des minuscules et le tour est joué.) Les commentaires de la
documentation de GCC sont très critiques, mais ils montrent aussi que les
auteurs ont fait l'effort de lire et de relire la norme, et de s'efforcer
de
l'implémenter ; on ne peut pas forcément en dire autant d'autres auteurs
de
compilateurs C !


Pour que gcc accepte les trigraphes, il faut lui spécifier une option de
ligne de commande explicite.
Par défaut, il les reconnait, mais ne les convertit pas, mais emet au
contraire un warning fort opportun.

Un comportement qu'on aimerait voir adopté pour strncpy.

Chqrlie




2 3 4 5 6