Petit programme en C, avez-vous des remarques etc. ?

Le
Francois Lafont
Bonjour à tous,

Autant le dire tout de suite, je suis vraiment totalement
inexpérimenté en langage C (pour ne pas dire plus). Ceci,
étant dit, j'ai codé un petit programme et j'aimerais bien
avoir, si c'est possible, vos suggestions et critiques. Je
mets le programme en fin de message.

C'est un programme qui se lance en ligne de commandes de cette
manière :

./mon-programme 10 localhost/cgi/machin.pl xxx yyy zzz

Le programme va alors lancer une requête http à l'adresse
http://localhost/cgi/machin.pl en utilisant la lib cURL
(ici, il s'agit d'un script Perl en localhost mais ça pourrait
être autre chose). La valeur 10 correspond à un timeout en
secondes (au delà le programme abandonne la requête), et le
reste des arguments xxx, yyy, zzz (il doit y en avoir au moins
1, mais ce n'est pas forcément 3 arguments, le nombre d'arguments
dépend de la page qui est appelée) est passé en variable POST
à la page http qui est appelée. Les variables POST seront
définies sous cette forme :

token1=xxx
token2=yyy
token3=zzz

Ensuite, les pages qui seront appelées avec ce programme
devront fournir une sortie de la forme :

- une première avec juste le nombre 0, 1, 2 ou 3;
- et des lignes suivantes avec ce qu'on veut, peu importe.

Par exemple :

2
CRITICAL blabla blabla.
Blibli blibli.

est une sortie correcte pour la page web. Ensuite, le
programme, qui aura mis cette sortie dans un buffer,
affichera uniquement les lignes autres que la ligne 1
et devra retourner comme exit code la valeur indiquée
dans la ligne 1 de la sortie de la page web. Si je
reprends l'exemple précédent, le programme devra donc
dans ce cas là afficher en sortie :

CRITICAL blabla blabla.
Blibli blibli.

tout en retournant la valeur 2 comme exit code.
Enfin, si la sortie de la page web appelée est trop
longue, alors le programme devra tronquer cette
sortie suivant une taille limite qui est indiquée
en tant que macro dans le programme.

Voilà pour ce que le programme est censé faire.

Pour l'écrire, je suis parti d'exemples que l'on
trouve ici ou là sur le web à propos de la lib cURL.
Par exemple, un point en particulier sur lequel
j'aimerais bien des avis (même si je suis vraiment
preneur de toute remarque à propos du code), c'est
l'usage du "cast". J'ai souvent entendu dire que
c'était à éviter et qu'on pouvait en général s'en
passer. Or dans le code, le cast est pas mal utilisé.
Peut-être que je m'y suis mal pris Je n'ai pas vu
comment faire autrement par exemple au niveau d'une
fonction qui attend en argument des pointeurs de type
void*. En effet, dans le code on indique que l'on
souhaite écrire la sortie de la requête cURL dans un
buffer en indiquant le nom d'une fonction write_data
qui doit avoir cette signature :

size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp);

où :
- la variable buffer un pointeur vers un buffer qui
contient un bout de la sortie de la requête cURL,
- size*nmemb correspond à la taille de ce buffer,
- userp est un pointeur vers le buffer dans lequel
on souhaite écrire la sortie de cURL (c'est ce
buffer là que l'on récupère dans la fonction main).

Dans la fonction main, userp correspond à la variable
wr_buf qui est un tableau de "char" mais il doit être
casté en void* pour être passé à la fonction write_data,
sachant que, dans le corps de la fonction write_data, je
m'empresse de faire le cast « inverse » (ie je caste
userp en un pointeur de type char*). Voilà par exemple
un point sur lequel je m'interroge. Mais encore une
fois, toutes vos remarques (sur la forme comme sur le
fond) m'intéressent.

Au départ, je pensais que ce programme allait réellement
me servir mais finalement il est probable que je ne l'utilise
pas. Ceci étant, en écrivant ce programme, je me suis pris
au jeu en quelques sortes et j'ai tenté de l'achever tant
bien que mal.

Merci d'avance pour toutes vos remarques et critiques.
François Lafont

-
/* With Debian Wheezy:
*
* sudo apt-get install libcurl4-openssl-dev
* gcc -lcurl -stdÉ9 -o curl-launcher.exe curl-launcher.c
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <curl/curl.h>

#define MAX_BUF 65536
#define MAX_POST_LENGTH 4096
#define OK 0
#define WARNING 1
#define CRITICAL 2
#define UNKNOWN 3

size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp);
int isPositiveInteger(const char s[]);

int main(int argc, char *argv[]) {

if (argc < 4) {
printf("Sorry, bad syntax. You must apply at least 3 arguments.");
printf("%s <timeout> <url> <args>", argv[0]);
return UNKNOWN;
}

if (!isPositiveInteger(argv[1])) {
printf("Sorry, bad syntax. The first argument must be a positive");
printf(" integer (it's a timeout in seconds).");
return UNKNOWN;
}

int timeout = atoi(argv[1]);
char *url = argv[2];

// First step, init curl.
CURL *curl;
curl = curl_easy_init();

if (!curl) {
printf("Sorry, couldn't init curl.");
return UNKNOWN;
}

// Construction of the post variable, a string with this form:
// token1=<urlencoded data1>&token2=<urlencoded data2>&
char post[MAX_POST_LENGTH] = { 0 };
int token_num = 1;
char *urlencoded_str = NULL;
int i = 0;

for (i = 3; i < argc; i++) {

if (token_num > 999) {
printf
("Sorry, the limit number (999) of POST variables is exceeded.");
curl_easy_cleanup(curl);
return UNKNOWN;
}

//printf("C: token%d: [%s]", token_num, argv[i]);

urlencoded_str = curl_easy_escape(curl, argv[i], 0);

// 10 is the max length of the string "token<num>=&".
// The maximum is reached with "token999=&".
int temp_size = 10 + strlen(urlencoded_str) + 1;
char temp[temp_size];
//memset(temp, 0, temp_size*sizeof(char));
sprintf(temp, "token%d=%s&", token_num, urlencoded_str);

if (strlen(post) + strlen(temp) + 1 < MAX_POST_LENGTH) {
strcat(post, temp);
}
else {
printf("Sorry, the max POST size is exceeded.");
curl_easy_cleanup(curl);
return UNKNOWN;
}

curl_free(urlencoded_str);
token_num++;

}

// Remove the last character "&".
post[strlen(post) - 1] = 0;
//printf("C: POST [%s]", post);

char wr_buf[MAX_BUF + 1] = { 0 };

curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post);

// Tell curl that we'll receive data to the function write_data
// which will write the data in wr_buf.
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) wr_buf);

// Allow curl to perform the action.
CURLcode ret;
ret = curl_easy_perform(curl);

if (ret) {
curl_easy_cleanup(curl);
printf("Sorry, exit value of curl is %d.", ret);

switch (ret) {

case CURLE_COULDNT_RESOLVE_HOST:
printf(" Could not resolve the host address.");
break;

case CURLE_OPERATION_TIMEDOUT:
printf(" Operation timeout.");
break;

default:
printf("");
break;

}

return UNKNOWN;
}

curl_easy_cleanup(curl);

/*
printf("-");
printf("%s", wr_buf);
printf("-");
*/

int return_value;
if (!strncmp(wr_buf, "0", 2)) {
return_value = OK;
}
else if (!strncmp(wr_buf, "1", 2)) {
return_value = WARNING;
}
else if (!strncmp(wr_buf, "2", 2)) {
return_value = CRITICAL;
}
else if (!strncmp(wr_buf, "3", 2)) {
return_value = UNKNOWN;
}
else {
printf("Unexpected output of the plugin, return value not");
printf(" displayed or not in {0, 1, 2, 3}.");
return UNKNOWN;
}

printf("%s", wr_buf + 2);
return return_value;

}

// Write data callback function (called within the context
// of curl_easy_perform).
size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp) {

// It is assumed that the type of userp is char*.
char *wr_buf = (char *) userp;

static int wr_index = 0;
int segsize = size * nmemb;

// Check to see if this data exceeds the size of our buffer. If so,
// it's possible to return O to indicate a problem to curl.
// But here, we just stop the function without error (ie, we return
// segsize) and our buffer will be troncated.
if (wr_index + segsize > MAX_BUF) {
if (MAX_BUF - wr_index > 0) {
memcpy((void *) &wr_buf[wr_index], buffer,
(size_t) (MAX_BUF - wr_index));
}
wr_index = MAX_BUF + 1; // wr_buf will be not written anymore.
return segsize;
}

// Copy the data from the curl buffer into our buffer.
memcpy((void *) &wr_buf[wr_index], buffer, (size_t) segsize);

// Update the write index.
wr_index += segsize;

// Return the number of bytes received, indicating to curl that
// all is okay.
return segsize;
}

int isPositiveInteger(const char s[]) {

if (s == NULL || *s == '') {
return 0;
}

int i;
for (i = 0; i < strlen(s); i++) {
// ASCII value of 0 -> 48, of 1 -> 49, , of 9 -> 57.
if (s[i] < 48 || s[i] > 57) {
return 0;
}
}

return 1;
}
-
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 7
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
espie
Le #26266882
In article Francois Lafont
* gcc -lcurl -stdÉ9 -o curl-launcher.exe curl-launcher.c



gcc -stdÉ9 -W -Wall -O2 -o curl-launcher curl-launcher.c -lcurl

Met des warnings, tu apprendras des choses.
Les bibliotheques toujours en fin de ligne. Meme si ca marche a peu pres
avec les gcc recents, entre autre parce que certaines bibliotheques sont
des shared object et pas des vraies bibliotheques, c'est pas une raison de
pas faire les trucs proprement.
Francois Lafont
Le #26267852
Bonjour,

Le 14/07/2014 10:00, Marc Espie a écrit :

gcc -stdÉ9 -W -Wall -O2 -o curl-launcher curl-launcher.c -lcurl

Met des warnings, tu apprendras des choses.



Ok, merci.
Petite question : à quoi sert « -W » par rapport à « -Wall » ? Mettre
uniquement « -Wall » n'est-il pas équivalent ?

Sinon effectivement, j'avais ce warning :

curl-launcher.c:206:17: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

C'est la ligne « for » à la fin qui était incriminée :

int i;
for (i = 0; i < strlen(s); i++) { ...

Si j'ai bien compris, strlen(s) est de type size_t ce qui serait
plus ou moins équivalent à "unsigned int" et du coup le i serait
implicitement converti en "unsigned int". D'où le warning car
potentiellement la valeur de i pourrait être interprétée de manière
« inattendue » par le compilateur. J'ai remplacé le « int i; » par
un « size_t i; » ce qui a entraîné la disparition du warning.
J'ai à peu près bon ?

Les bibliotheques toujours en fin de ligne.



Ok. Je viens de regarder la page man de gcc et effectivement l'endroit
où se trouve l'option -l n'est pas anodin.

Meme si ca marche a peu pres
avec les gcc recents, entre autre parce que certaines bibliotheques sont
des shared object et pas des vraies bibliotheques, c'est pas une raison de
pas faire les trucs proprement.



Oui tout à fait.
Merci pour tes remarques.

--
François Lafont
Lucas Levrel
Le #26268112
Le 14 juillet 2014, Francois Lafont a écrit :

Par exemple, un point en particulier sur lequel
j'aimerais bien des avis (même si je suis vraiment
preneur de toute remarque à propos du code), c'est
l'usage du "cast". J'ai souvent entendu dire que
c'était à éviter et qu'on pouvait en général s'en
passer.



Note le « en général » !

Peut-être que je m'y suis mal pris... Je n'ai pas vu
comment faire autrement par exemple au niveau d'une
fonction qui attend en argument des pointeurs de type
void*.



Il me semble que le cast depuis ou vers void* peut être implicite. Donc tu
pourrais te passer de l'écrire dans le code, mais ce serait considéré
comme malpropre je crois, car ça cacherait un peu ce qui se passe.

Dans la fonction main, userp correspond à la variable
wr_buf qui est un tableau de "char" mais il doit être
casté en void* pour être passé à la fonction write_data,
sachant que, dans le corps de la fonction write_data, je
m'empresse de faire le cast « inverse » (ie je caste
userp en un pointeur de type char*). Voilà par exemple
un point sur lequel je m'interroge.



Et si tu voulais récupérer des flottants, tu ferais des casts depuis/vers
float*. Des entiers ? int*. Etc. L'intérêt du typage void* c'est que
l'utilisateur de la bibliothèque peut passer ce qu'il veut. (Et comme les
fonctions C ne sont pas polymorphes, on ne peut pas vraiment faire
autrement.)

--
LL
Ἕν οἶδα ὅτι οὐδὲν οἶδα (Σωκράτης)
Francois Lafont
Le #26268562
Le 14/07/2014 18:49, Lucas Levrel a écrit :

Par exemple, un point en particulier sur lequel
j'aimerais bien des avis (même si je suis vraiment
preneur de toute remarque à propos du code), c'est
l'usage du "cast". J'ai souvent entendu dire que
c'était à éviter et qu'on pouvait en général s'en
passer.



Note le « en général » !



Oui. Il doit y avoir des exceptions et avec les void*
on doit être en plein dedans.

Peut-être que je m'y suis mal pris... Je n'ai pas vu
comment faire autrement par exemple au niveau d'une
fonction qui attend en argument des pointeurs de type
void*.



Il me semble que le cast depuis ou vers void* peut être implicite. Donc tu pourrais te passer de l'écrire dans le code, mais ce serait considéré comme malpropre je crois, car ça cacherait un peu ce qui se passe.



Dans la ligne :

curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) wr_buf);

où le dernier argument est censé être un void*, si j'enlève le
cast, j'ai effectivement une compilation qui passe. J'ai tout
de même un petit warning (pas super clair pour moi d'ailleurs) :

warning: call to ‘_curl_easy_setopt_err_cb_data’ declared with
attribute warning: curl_easy_setopt expects a private data pointer
as argument for this option [enabled by default]

Dans la fonction main, userp correspond à la variable
wr_buf qui est un tableau de "char" mais il doit être
casté en void* pour être passé à la fonction write_data,
sachant que, dans le corps de la fonction write_data, je
m'empresse de faire le cast « inverse » (ie je caste
userp en un pointeur de type char*). Voilà par exemple
un point sur lequel je m'interroge.



Et si tu voulais récupérer des flottants, tu ferais des casts depuis/vers float*. Des entiers ? int*. Etc.



Ben oui, dans ma logique c'est comme ça que je voyais les
choses, d'où mes interrogations justement.

L'intérêt du typage void* c'est que l'utilisateur de la bibliothèque peut passer ce qu'il veut. (Et comme les fonctions C ne sont pas polymorphes, on ne peut pas vraiment faire autrement.)



Ok, mais dans le corps de la fonction qui attend un void*,
si je suis amené à faire des trucs du genre pointeur[i] alors
dans ce cas, pour que ça fonctionne, il faut forcément que je
convertisse pointeur en autre chose que void*.

Du coup, si j'ai bien compris :

1. Lors de l'appel de la fonction, je convertis explicitement
le pointeur passé en argument effectif en un void*.

2. Dans le corps de la fonction, je peux toujours convertir
sans risque le pointeur en un char* afin de pouvoir faire
des trucs comme p[i], p++ etc. à condition tout de même
que, le pointeur en question pointe bien vers un tableau
(pas forcément un tableau de char) et que je dispose bien,
dans le corps de cette fonction, de la taille du tableau
en question via un sizeof (donc la taille exprimée en unité
de chars).

Donc dans mon programme, la macro MAX_BUF doit correspondre à
la taille du buffer en unité de chars. Auquel cas, je devrais
l'appeler plutôt MAX_BUF_IN_BYTES.

Est-ce correct ?

--
François Lafont
espie
Le #26268622
In article Lucas Levrel
Le 14 juillet 2014, Francois Lafont a écrit :

Par exemple, un point en particulier sur lequel
j'aimerais bien des avis (même si je suis vraiment
preneur de toute remarque à propos du code), c'est
l'usage du "cast". J'ai souvent entendu dire que
c'était à éviter et qu'on pouvait en général s'en
passer.



Note le « en général » !

Peut-être que je m'y suis mal pris... Je n'ai pas vu
comment faire autrement par exemple au niveau d'une
fonction qui attend en argument des pointeurs de type
void*.



Il me semble que le cast depuis ou vers void* peut être implicite. Donc tu
pourrais te passer de l'écrire dans le code, mais ce serait considéré
comme malpropre je crois, car ça cacherait un peu ce qui se passe.



Non! les cast entre void* et d'autres choses servent juste a permettre
de compiler le meme code avec un compilo C++, ce qui est une vaste connerie,
parce que tant qu'a faire, autant faire du C++ directement.

Ca ne rend pas le code specialement plus propre, et surtout c'est dangereux,
car on peut faire des erreurs et se planter d'un niveau de pointeur.

Je rappelle qu'un cast dit globalement au compilo "ne regarde pas, je sais
ce que je fais", et donc qu'il vaut mieux s'en passer quand c'est possible.

En particulier, en C, les void* sont convertibles en autres pointeurs vers
donnees sans cast, et sans warning. C'est necessaire pour que malloc marche,
par exemple.
Francois Lafont
Le #26269182
Le 14/07/2014 20:31, Marc Espie a écrit :

Non! les cast entre void* et d'autres choses servent juste a permettre
de compiler le meme code avec un compilo C++, ce qui est une vaste connerie,
parce que tant qu'a faire, autant faire du C++ directement.

Ca ne rend pas le code specialement plus propre, et surtout c'est dangereux,
car on peut faire des erreurs et se planter d'un niveau de pointeur.

Je rappelle qu'un cast dit globalement au compilo "ne regarde pas, je sais
ce que je fais", et donc qu'il vaut mieux s'en passer quand c'est possible.

En particulier, en C, les void* sont convertibles en autres pointeurs vers
donnees sans cast, et sans warning. C'est necessaire pour que malloc marche,
par exemple.



Ok, si une fonction attend un void* en argument, on
peut lui fournir un truc* sans faire de cast, et ça
passe sans problème. Mais si la fonction en question
se sert de ce pointeur pour ensuite écrire des données
dans un tableau (dont l'adresse de début est donnée
par le pointeur), je suis bien obligé d'écrire le
cast ci-dessous dans le corps de la fonction :

void f(void* p) {
char *t = (char*) p;
// Et on utilise t pour écrire dans le tableau
// via une boucle.
// etc...
}

Non ?

PS : dans la ligne :

curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) wr_buf);

du code donné dans le premier message, si je retire le
cast au niveau du dernier paramètre, j'ai le droit à un
warning comme j'ai indiqué dans mon message précédent.
Dans cet exemple précis, la conversion en void* ne semble
pas automatique.

--
François Lafont
Damien Wyart
Le #26269392
> gcc -stdÉ9 -W -Wall -O2 -o curl-launcher curl-launcher.c -lcurl



* Francois Lafont
Petite question : à quoi sert « -W » par rapport à « -Wall » ? Mettre
uniquement « -Wall » n'est-il pas équivalent ?



-W est utilisé pour obetnir des warnings additionnels à ceux fournis par
-Wall. Dans les versions récentes de gcc, c'est équivalent à -Wextra.

--
DW
espie
Le #26269502
In article Francois Lafont
Le 14/07/2014 20:31, Marc Espie a écrit :

Non! les cast entre void* et d'autres choses servent juste a permettre
de compiler le meme code avec un compilo C++, ce qui est une vaste connerie,
parce que tant qu'a faire, autant faire du C++ directement.

Ca ne rend pas le code specialement plus propre, et surtout c'est dangereux,
car on peut faire des erreurs et se planter d'un niveau de pointeur.

Je rappelle qu'un cast dit globalement au compilo "ne regarde pas, je sais
ce que je fais", et donc qu'il vaut mieux s'en passer quand c'est possible.

En particulier, en C, les void* sont convertibles en autres pointeurs vers
donnees sans cast, et sans warning. C'est necessaire pour que malloc marche,
par exemple.



Ok, si une fonction attend un void* en argument, on
peut lui fournir un truc* sans faire de cast, et ça
passe sans problème. Mais si la fonction en question
se sert de ce pointeur pour ensuite écrire des données
dans un tableau (dont l'adresse de début est donnée
par le pointeur), je suis bien obligé d'écrire le
cast ci-dessous dans le corps de la fonction :

void f(void* p) {
char *t = (char*) p;
// Et on utilise t pour écrire dans le tableau
// via une boucle.
// etc...
}

Non ?



Non.

void f(void *p) {
char *t = p;
// Et on utilise t pour écrire dans le tableau
// via une boucle.
// etc...
}

ca marchera.

(ah, et en style C usuel, tu vas plus normalement ecrire "char *t" que
"char* t"... qui est la aussi plus communement associe a C++.

Tout betement pour eviter l'erreur classique du
char *p, r;
^ tiens, ca c'est pas un pointeur.


Le seul cas courant ou tu auras besoin d'un cast, c'est pour ecrire une
fonction similaire a strchr, ou tu es amene a convertir de const char*
vers char*.
espie
Le #26269542
Ou, si tu preferes, ne confond pas transtypage implicite et cast explicite.

Tu as parfaitement le droit de convertir des valeurs d'un type a un autre
sans mettre de cast en C, et habituellement sans que le compilo moufte,
sauf cas particulier.

Ainsi,

void *p;

...

int *k = p;


ne va pas balancer de warning du tout. C'est totalement legal en C.

Tu reserves les cast aux cas ou ca chouine un peu.

Si ca passe sans le moindre avertissement du compilo, il ne faut surtout
pas mettre de cast, car les cast desactivent *completement* les
avertissements.

Genre:

int i;

void *p = (void *)i; // va passer, alors qu'on voulait &i

Exemple plus drole

void
print(void *t, int n)
{
int i;
int **p = t;

for (i = 0 ; i < n; i++)
printf("%d ", p[i]);
}

On peut etre tente de virer p, mais ca ne sera pas plus lisible, pas plus
efficace (tout compilo decent saura faire son boulot) et ca ouvre la porte
a de grosses erreurs.

void
print(void *t, int n)
{
int i;

for (i = 0 ; i < n; i++)
printf("%d ", ((int **)t)[i]);
}

Par contre, j'aurais plus tendance a ecrire

void
print(const void *t, size_t n)
{
size_t i;
const int **p = t;

for (i = 0 ; i < n; i++)
printf("%d ", p[i]);
}
JKB
Le #26269762
Le Tue, 15 Jul 2014 07:17:37 +0000 (UTC),
Marc Espie
In article Francois Lafont
Le 14/07/2014 20:31, Marc Espie a écrit :

Non! les cast entre void* et d'autres choses servent juste a permettre
de compiler le meme code avec un compilo C++, ce qui est une vaste connerie,
parce que tant qu'a faire, autant faire du C++ directement.

Ca ne rend pas le code specialement plus propre, et surtout c'est dangereux,
car on peut faire des erreurs et se planter d'un niveau de pointeur.

Je rappelle qu'un cast dit globalement au compilo "ne regarde pas, je sais
ce que je fais", et donc qu'il vaut mieux s'en passer quand c'est possible.

En particulier, en C, les void* sont convertibles en autres pointeurs vers
donnees sans cast, et sans warning. C'est necessaire pour que malloc marche,
par exemple.



Ok, si une fonction attend un void* en argument, on
peut lui fournir un truc* sans faire de cast, et ça
passe sans problème. Mais si la fonction en question
se sert de ce pointeur pour ensuite écrire des données
dans un tableau (dont l'adresse de début est donnée
par le pointeur), je suis bien obligé d'écrire le
cast ci-dessous dans le corps de la fonction :

void f(void* p) {
char *t = (char*) p;
// Et on utilise t pour écrire dans le tableau
// via une boucle.
// etc...
}

Non ?



Non.

void f(void *p) {
char *t = p;
// Et on utilise t pour écrire dans le tableau
// via une boucle.
// etc...
}

ca marchera.

(ah, et en style C usuel, tu vas plus normalement ecrire "char *t" que
"char* t"... qui est la aussi plus communement associe a C++.

Tout betement pour eviter l'erreur classique du
char *p, r;
^ tiens, ca c'est pas un pointeur.



Certes. Mais comme on peut écrire du Fortran dans n'importe quel
langage, on préférera :

char *p, *q, *r;
char s, t, u;

Ça évite ce genre d'erreur d'inattention.

Le seul cas courant ou tu auras besoin d'un cast, c'est pour ecrire une
fonction similaire a strchr, ou tu es amene a convertir de const char*
vers char*.



Et que le const char * est piégeux...

JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
=> http://loubardes.de-charybde-en-scylla.fr
Publicité
Poster une réponse
Anonyme