Petit programme en C, avez-vous des remarques etc. ?
Aucune réponse
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 :
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 :
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
if (argc < 4) {
printf("Sorry, bad syntax. You must apply at least 3 arguments.\n");
printf("%s <timeout> <url> <args>...\n", 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).\n");
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.\n");
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.\n");
curl_easy_cleanup(curl);
return UNKNOWN;
}
// 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.\n");
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]\n", 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.\n");
break;
case CURLE_OPERATION_TIMEDOUT:
printf(" Operation timeout.\n");
break;
int return_value;
if (!strncmp(wr_buf, "0\n", 2)) {
return_value = OK;
}
else if (!strncmp(wr_buf, "1\n", 2)) {
return_value = WARNING;
}
else if (!strncmp(wr_buf, "2\n", 2)) {
return_value = CRITICAL;
}
else if (!strncmp(wr_buf, "3\n", 2)) {
return_value = UNKNOWN;
}
else {
printf("Unexpected output of the plugin, return value not");
printf(" displayed or not in {0, 1, 2, 3}.\n");
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 == '\0') {
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;
}
}
assert(s != NULL); for ( i = 0; s[i] != ' '; i++ ) {
[couic]
} return i != 0; }
[couic]
En revanche, j'avoue que j'ai du mal avec la siouxerie « return i != 0; ». J'ai bien compris que ça permettait de gérer le cas où « *s == ' ' » et que c'est plus concis mais je sais que dans 1 semaine j'arriverai plus à m'en rappeler (j'ai pas trop l'habitude du côté "tout expression" du langage C, même si ça permet des raccourcis).
Un compromis pourrait être
return i != 0 ? 1 : 0;
qui doit être équivalent voire identique en code généré pour tous les compilateurs actuels, et qui est moins « sioux ».
assert(s != NULL);
for ( i = 0; s[i] != ' '; i++ )
{
[couic]
}
return i != 0;
}
[couic]
En revanche, j'avoue que j'ai du mal avec la siouxerie
« return i != 0; ». J'ai bien compris que ça permettait
de gérer le cas où « *s == ' ' » et que c'est plus concis
mais je sais que dans 1 semaine j'arriverai plus à m'en
rappeler (j'ai pas trop l'habitude du côté "tout expression"
du langage C, même si ça permet des raccourcis).
Un compromis pourrait être
return i != 0 ? 1 : 0;
qui doit être équivalent voire identique en code généré pour tous les
compilateurs actuels, et qui est moins « sioux ».
assert(s != NULL); for ( i = 0; s[i] != ' '; i++ ) {
[couic]
} return i != 0; }
[couic]
En revanche, j'avoue que j'ai du mal avec la siouxerie « return i != 0; ». J'ai bien compris que ça permettait de gérer le cas où « *s == ' ' » et que c'est plus concis mais je sais que dans 1 semaine j'arriverai plus à m'en rappeler (j'ai pas trop l'habitude du côté "tout expression" du langage C, même si ça permet des raccourcis).
Un compromis pourrait être
return i != 0 ? 1 : 0;
qui doit être équivalent voire identique en code généré pour tous les compilateurs actuels, et qui est moins « sioux ».
Antoine
Francois Lafont
Le 17/07/2014 08:16, Xavier Roche a écrit :
Préférence personnelle également: je compile les assert() y compris en "release". Sinon ça sert à rien, un assert.
Avec un peu de retard (car je n'avais pas compris la syntaxe de cette expression avec notamment la séquence), est-ce que je pourrais avoir des explications sur les deux lignes ci-dessus.
Plus précisément, pourquoi est-ce qu'on ne pourrait pas simplement se contenter des deux lignes ci-dessous ?
Autrement dit, je ne comprends pas l'intérêt du (void) (...) qui est un cast si je ne me trompe pas et je ne comprends pas ce qu'apporte l'opérateur de séquence dans « (my_abort_function(...), 0) » où l'on évalue donc my_abort_function(...) puis 0.
-- François Lafont
Le 17/07/2014 08:16, Xavier Roche a écrit :
Préférence personnelle également: je compile les assert() y compris en "release". Sinon ça sert à rien, un assert.
Avec un peu de retard (car je n'avais pas compris la
syntaxe de cette expression avec notamment la séquence),
est-ce que je pourrais avoir des explications sur les
deux lignes ci-dessus.
Plus précisément, pourquoi est-ce qu'on ne pourrait pas
simplement se contenter des deux lignes ci-dessous ?
Autrement dit, je ne comprends pas l'intérêt du
(void) (...) qui est un cast si je ne me trompe pas
et je ne comprends pas ce qu'apporte l'opérateur
de séquence dans « (my_abort_function(...), 0) » où
l'on évalue donc my_abort_function(...) puis 0.
Avec un peu de retard (car je n'avais pas compris la syntaxe de cette expression avec notamment la séquence), est-ce que je pourrais avoir des explications sur les deux lignes ci-dessus.
Plus précisément, pourquoi est-ce qu'on ne pourrait pas simplement se contenter des deux lignes ci-dessous ?
Autrement dit, je ne comprends pas l'intérêt du (void) (...) qui est un cast si je ne me trompe pas et je ne comprends pas ce qu'apporte l'opérateur de séquence dans « (my_abort_function(...), 0) » où l'on évalue donc my_abort_function(...) puis 0.
-- François Lafont
Francois Lafont
Le 22/07/2014 17:52, Antoine Leca a écrit :
Un compromis pourrait être
return i != 0 ? 1 : 0;
qui doit être équivalent voire identique en code généré pour tous les compilateurs actuels, et qui est moins « sioux ».
Effectivement c'est moins mystérieux pour moi comme ça, tout en faisant un peu gourou du C. ;)
-- François Lafont
Le 22/07/2014 17:52, Antoine Leca a écrit :
Un compromis pourrait être
return i != 0 ? 1 : 0;
qui doit être équivalent voire identique en code généré pour tous les
compilateurs actuels, et qui est moins « sioux ».
Effectivement c'est moins mystérieux pour moi
comme ça, tout en faisant un peu gourou du C. ;)
Avec un peu de retard (car je n'avais pas compris la syntaxe de cette expression avec notamment la séquence), est-ce que je pourrais avoir des explications sur les deux lignes ci-dessus.
Plus précisément, pourquoi est-ce qu'on ne pourrait pas simplement se contenter des deux lignes ci-dessous ?
Autrement dit, je ne comprends pas l'intérêt du (void) (...) qui est un cast si je ne me trompe pas et je ne comprends pas ce qu'apporte l'opérateur de séquence dans « (my_abort_function(...), 0) » où l'on évalue donc my_abort_function(...) puis 0.
le cast (void) interdit d'écrire des choses comme int x = assert(3);
le (my_abort_function(...), 0) fonctionne avec une fonction qui retourne void, comme : void my_abort_function(const char*, const char*, const char*);
-- Richard
Le 22/07/2014 18:03, Francois Lafont a écrit :
Le 17/07/2014 08:16, Xavier Roche a écrit :
Préférence personnelle également: je compile les assert() y compris en "release". Sinon ça sert à rien, un assert.
Avec un peu de retard (car je n'avais pas compris la
syntaxe de cette expression avec notamment la séquence),
est-ce que je pourrais avoir des explications sur les
deux lignes ci-dessus.
Plus précisément, pourquoi est-ce qu'on ne pourrait pas
simplement se contenter des deux lignes ci-dessous ?
Autrement dit, je ne comprends pas l'intérêt du
(void) (...) qui est un cast si je ne me trompe pas
et je ne comprends pas ce qu'apporte l'opérateur
de séquence dans « (my_abort_function(...), 0) » où
l'on évalue donc my_abort_function(...) puis 0.
le cast (void) interdit d'écrire des choses comme
int x = assert(3);
le (my_abort_function(...), 0) fonctionne avec une fonction qui retourne
void, comme :
void my_abort_function(const char*, const char*, const char*);
Avec un peu de retard (car je n'avais pas compris la syntaxe de cette expression avec notamment la séquence), est-ce que je pourrais avoir des explications sur les deux lignes ci-dessus.
Plus précisément, pourquoi est-ce qu'on ne pourrait pas simplement se contenter des deux lignes ci-dessous ?
Autrement dit, je ne comprends pas l'intérêt du (void) (...) qui est un cast si je ne me trompe pas et je ne comprends pas ce qu'apporte l'opérateur de séquence dans « (my_abort_function(...), 0) » où l'on évalue donc my_abort_function(...) puis 0.
le cast (void) interdit d'écrire des choses comme int x = assert(3);
le (my_abort_function(...), 0) fonctionne avec une fonction qui retourne void, comme : void my_abort_function(const char*, const char*, const char*);
-- Richard
Francois Lafont
Le 22/07/2014 18:47, Richard Delorme a écrit :
le cast (void) interdit d'écrire des choses comme int x = assert(3);
Ok.
le (my_abort_function(...), 0) fonctionne avec une fonction qui retourne void, comme : void my_abort_function(const char*, const char*, const char*);
Mais ça fonctionnerait tout autant avec une fonction qui retourne n'importe quoi puisque dans une séquence « exp1, exp2 » la valeur de exp1 n'est pas prise en compte, non ?
Là, il y a un truc qui m'échappe.
-- François Lafont
Le 22/07/2014 18:47, Richard Delorme a écrit :
le cast (void) interdit d'écrire des choses comme
int x = assert(3);
Ok.
le (my_abort_function(...), 0) fonctionne avec une fonction qui retourne void, comme :
void my_abort_function(const char*, const char*, const char*);
Mais ça fonctionnerait tout autant avec une fonction
qui retourne n'importe quoi puisque dans une séquence
« exp1, exp2 » la valeur de exp1 n'est pas prise en
compte, non ?
le cast (void) interdit d'écrire des choses comme int x = assert(3);
Ok.
le (my_abort_function(...), 0) fonctionne avec une fonction qui retourne void, comme : void my_abort_function(const char*, const char*, const char*);
Mais ça fonctionnerait tout autant avec une fonction qui retourne n'importe quoi puisque dans une séquence « exp1, exp2 » la valeur de exp1 n'est pas prise en compte, non ?
Là, il y a un truc qui m'échappe.
-- François Lafont
Olivier Miakinen
Le 22/07/2014 18:47, Richard Delorme répondait à François Lafont :
Autrement dit, je ne comprends pas l'intérêt du (void) (...) qui est un cast si je ne me trompe pas et je ne comprends pas ce qu'apporte l'opérateur de séquence dans « (my_abort_function(...), 0) » où l'on évalue donc my_abort_function(...) puis 0.
le cast (void) interdit d'écrire des choses comme int x = assert(3);
Oui.
J'ajoute que, même sans le void, écrire une expression avec || sans l'entourer de parenthèses serait un peu risqué. C'est la même chose avec tout opérateur à deux opérandes.
Exemple : #define ajoute(x,y) x + y 2 * ajoute(3,7) -> 2 * 3 + 7 = 13 au lieu de 20 #define ajoute(x,y) (x + y) 2 * ajoute(3,7) -> 2 * (3 + 7) = 20
De même, il faut souvent parenthéser les arguments aussi.
Exemple : #define multiplie(x,y) (x * y) multiplie(2 + 2, 5) -> (2 + 2 * 5) = 12 au lieu de 20 #define multiplie(x,y) ((x) * (y)) multiplie(2 + 2, 5) -> ((2 + 2) * 5) = 20
le (my_abort_function(...), 0) fonctionne avec une fonction qui retourne void, comme : void my_abort_function(const char*, const char*, const char*);
Et donc, cela permet d'utiliser cette expression comme deuxième paramètre d'un || puisque maintenant la valeur de retour est 0 et non pas void.
Cordialement, -- Olivier Miakinen
Le 22/07/2014 18:47, Richard Delorme répondait à François Lafont :
Autrement dit, je ne comprends pas l'intérêt du
(void) (...) qui est un cast si je ne me trompe pas
et je ne comprends pas ce qu'apporte l'opérateur
de séquence dans « (my_abort_function(...), 0) » où
l'on évalue donc my_abort_function(...) puis 0.
le cast (void) interdit d'écrire des choses comme
int x = assert(3);
Oui.
J'ajoute que, même sans le void, écrire une expression avec || sans
l'entourer de parenthèses serait un peu risqué. C'est la même chose
avec tout opérateur à deux opérandes.
Exemple :
#define ajoute(x,y) x + y
2 * ajoute(3,7) -> 2 * 3 + 7 = 13 au lieu de 20
#define ajoute(x,y) (x + y)
2 * ajoute(3,7) -> 2 * (3 + 7) = 20
De même, il faut souvent parenthéser les arguments aussi.
Exemple :
#define multiplie(x,y) (x * y)
multiplie(2 + 2, 5) -> (2 + 2 * 5) = 12 au lieu de 20
#define multiplie(x,y) ((x) * (y))
multiplie(2 + 2, 5) -> ((2 + 2) * 5) = 20
le (my_abort_function(...), 0) fonctionne avec une fonction qui retourne
void, comme :
void my_abort_function(const char*, const char*, const char*);
Et donc, cela permet d'utiliser cette expression comme deuxième
paramètre d'un || puisque maintenant la valeur de retour est 0 et
non pas void.
Autrement dit, je ne comprends pas l'intérêt du (void) (...) qui est un cast si je ne me trompe pas et je ne comprends pas ce qu'apporte l'opérateur de séquence dans « (my_abort_function(...), 0) » où l'on évalue donc my_abort_function(...) puis 0.
le cast (void) interdit d'écrire des choses comme int x = assert(3);
Oui.
J'ajoute que, même sans le void, écrire une expression avec || sans l'entourer de parenthèses serait un peu risqué. C'est la même chose avec tout opérateur à deux opérandes.
Exemple : #define ajoute(x,y) x + y 2 * ajoute(3,7) -> 2 * 3 + 7 = 13 au lieu de 20 #define ajoute(x,y) (x + y) 2 * ajoute(3,7) -> 2 * (3 + 7) = 20
De même, il faut souvent parenthéser les arguments aussi.
Exemple : #define multiplie(x,y) (x * y) multiplie(2 + 2, 5) -> (2 + 2 * 5) = 12 au lieu de 20 #define multiplie(x,y) ((x) * (y)) multiplie(2 + 2, 5) -> ((2 + 2) * 5) = 20
le (my_abort_function(...), 0) fonctionne avec une fonction qui retourne void, comme : void my_abort_function(const char*, const char*, const char*);
Et donc, cela permet d'utiliser cette expression comme deuxième paramètre d'un || puisque maintenant la valeur de retour est 0 et non pas void.
Cordialement, -- Olivier Miakinen
Samuel DEVULDER
Le 22/07/2014 17:52, Antoine Leca a écrit :
Un compromis pourrait être
return i != 0 ? 1 : 0;
Question idiote (quoique), pourquoi pas plutôt
return i ? 1 : 0;
vu qu'est considéré comme vrai tout ce qui n'est pas zéro.
Ok on va me dire que le compilo va transformer la 1ere forme en la 2ème et que la 1ere est bien plus lisible. On dirait du Pascal! Ok, mais on fait du C ou du Pascal ?
Quitte à faire du C, on aurait pu tout aussi bien aussi écrire pour un i entier:
return !!i;
Qui est équivalent de l'opération "(...) ? 1 : 0", mais surtout j'en connais qui aurait écrit directement
return i;
pour exactement la même sémantique (mais pas la même valeur bien entendu).
J'ajoute que j'ai des doutes qu'en l'absence d'un type boolean formel, un compilo sache optimiser l'opérateur ternaire pour obtenir la dernière forme. En effet rien ne lui indique que seule l'info "i est nul/non-nul" nous intéresse comme retour de fonction (en gros c'est le bit Z du registre de statut du processeur qu'il faudrait capturer sémantiquement).
sam.
Le 22/07/2014 17:52, Antoine Leca a écrit :
Un compromis pourrait être
return i != 0 ? 1 : 0;
Question idiote (quoique), pourquoi pas plutôt
return i ? 1 : 0;
vu qu'est considéré comme vrai tout ce qui n'est pas zéro.
Ok on va me dire que le compilo va transformer la 1ere forme en la 2ème
et que la 1ere est bien plus lisible. On dirait du Pascal! Ok, mais on
fait du C ou du Pascal ?
Quitte à faire du C, on aurait pu tout aussi bien aussi écrire pour un i
entier:
return !!i;
Qui est équivalent de l'opération "(...) ? 1 : 0", mais surtout j'en
connais qui aurait écrit directement
return i;
pour exactement la même sémantique (mais pas la même valeur bien entendu).
J'ajoute que j'ai des doutes qu'en l'absence d'un type boolean formel,
un compilo sache optimiser l'opérateur ternaire pour obtenir la dernière
forme. En effet rien ne lui indique que seule l'info "i est nul/non-nul"
nous intéresse comme retour de fonction (en gros c'est le bit Z du
registre de statut du processeur qu'il faudrait capturer sémantiquement).
vu qu'est considéré comme vrai tout ce qui n'est pas zéro.
Ok on va me dire que le compilo va transformer la 1ere forme en la 2ème et que la 1ere est bien plus lisible. On dirait du Pascal! Ok, mais on fait du C ou du Pascal ?
Quitte à faire du C, on aurait pu tout aussi bien aussi écrire pour un i entier:
return !!i;
Qui est équivalent de l'opération "(...) ? 1 : 0", mais surtout j'en connais qui aurait écrit directement
return i;
pour exactement la même sémantique (mais pas la même valeur bien entendu).
J'ajoute que j'ai des doutes qu'en l'absence d'un type boolean formel, un compilo sache optimiser l'opérateur ternaire pour obtenir la dernière forme. En effet rien ne lui indique que seule l'info "i est nul/non-nul" nous intéresse comme retour de fonction (en gros c'est le bit Z du registre de statut du processeur qu'il faudrait capturer sémantiquement).
sam.
Xavier Roche
Le 22/07/2014 21:25, Samuel DEVULDER a écrit :
Quitte à faire du C, on aurait pu tout aussi bien aussi écrire pour un i entier: return !!i; Qui est équivalent de l'opération "(...) ? 1 : 0", mais surtout j'en connais qui aurait écrit directement return i;
pour exactement la même sémantique (mais pas la même valeur bien entendu).
Ah non, ça marchera moins bien si sizeof(size_t) != sizeof(int) :)
Le 22/07/2014 21:25, Samuel DEVULDER a écrit :
Quitte à faire du C, on aurait pu tout aussi bien aussi écrire pour un i
entier:
return !!i;
Qui est équivalent de l'opération "(...) ? 1 : 0", mais surtout j'en
connais qui aurait écrit directement
return i;
pour exactement la même sémantique (mais pas la même valeur bien entendu).
Ah non, ça marchera moins bien si sizeof(size_t) != sizeof(int) :)
Quitte à faire du C, on aurait pu tout aussi bien aussi écrire pour un i entier: return !!i; Qui est équivalent de l'opération "(...) ? 1 : 0", mais surtout j'en connais qui aurait écrit directement return i;
pour exactement la même sémantique (mais pas la même valeur bien entendu).
Ah non, ça marchera moins bien si sizeof(size_t) != sizeof(int) :)
Samuel DEVULDER
Le 22/07/2014 21:33, Xavier Roche a écrit :
Le 22/07/2014 21:25, Samuel DEVULDER a écrit :
Quitte à faire du C, on aurait pu tout aussi bien aussi écrire pour un i entier: return !!i; Qui est équivalent de l'opération "(...) ? 1 : 0", mais surtout j'en connais qui aurait écrit directement return i;
pour exactement la même sémantique (mais pas la même valeur bien entendu).
Ah non, ça marchera moins bien si sizeof(size_t) != sizeof(int) :)
Pourquoi ?
La première avec la double négation me semble indépendante du sizeof.
Le seul soucis que je peux voir avec la 2eme serait une troncature par le transtypage implicite, sauf que cela ne se produit que si la taille de size_t est supérieure strictement à celle des entiers. Est-ce que cela existe? (size_t est défini comme étant un entier non signé dans la norme: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf p254 paragraphe7.17)
Le 22/07/2014 21:33, Xavier Roche a écrit :
Le 22/07/2014 21:25, Samuel DEVULDER a écrit :
Quitte à faire du C, on aurait pu tout aussi bien aussi écrire pour un i
entier:
return !!i;
Qui est équivalent de l'opération "(...) ? 1 : 0", mais surtout j'en
connais qui aurait écrit directement
return i;
pour exactement la même sémantique (mais pas la même valeur bien entendu).
Ah non, ça marchera moins bien si sizeof(size_t) != sizeof(int) :)
Pourquoi ?
La première avec la double négation me semble indépendante du sizeof.
Le seul soucis que je peux voir avec la 2eme serait une troncature par
le transtypage implicite, sauf que cela ne se produit que si la taille
de size_t est supérieure strictement à celle des entiers. Est-ce que
cela existe? (size_t est défini comme étant un entier non signé dans la
norme: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf p254
paragraphe7.17)
Quitte à faire du C, on aurait pu tout aussi bien aussi écrire pour un i entier: return !!i; Qui est équivalent de l'opération "(...) ? 1 : 0", mais surtout j'en connais qui aurait écrit directement return i;
pour exactement la même sémantique (mais pas la même valeur bien entendu).
Ah non, ça marchera moins bien si sizeof(size_t) != sizeof(int) :)
Pourquoi ?
La première avec la double négation me semble indépendante du sizeof.
Le seul soucis que je peux voir avec la 2eme serait une troncature par le transtypage implicite, sauf que cela ne se produit que si la taille de size_t est supérieure strictement à celle des entiers. Est-ce que cela existe? (size_t est défini comme étant un entier non signé dans la norme: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf p254 paragraphe7.17)
Erwan David
Samuel DEVULDER <samuel-dot-devulder-at-laposte-dot-net> écrivait :
Le 22/07/2014 21:33, Xavier Roche a écrit :
Le 22/07/2014 21:25, Samuel DEVULDER a écrit :
Quitte à faire du C, on aurait pu tout aussi bien aussi écrire pour un i entier: return !!i; Qui est équivalent de l'opération "(...) ? 1 : 0", mais surtout j'en connais qui aurait écrit directement return i;
pour exactement la même sémantique (mais pas la même valeur bien entendu).
Ah non, ça marchera moins bien si sizeof(size_t) != sizeof(int) :)
Pourquoi ?
La première avec la double négation me semble indépendante du sizeof.
Le seul soucis que je peux voir avec la 2eme serait une troncature par le transtypage implicite, sauf que cela ne se produit que si la taille de size_t est supérieure strictement à celle des entiers. Est-ce que cela existe? (size_t est défini comme étant un entier non signé dans la norme: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf p254 paragraphe7.17)
Une architecture avec size_t sur 64 bits et int sur 32 ?
-- Les simplifications c'est trop compliqué
Samuel DEVULDER <samuel-dot-devulder-at-laposte-dot-net> écrivait :
Le 22/07/2014 21:33, Xavier Roche a écrit :
Le 22/07/2014 21:25, Samuel DEVULDER a écrit :
Quitte à faire du C, on aurait pu tout aussi bien aussi écrire pour un i
entier:
return !!i;
Qui est équivalent de l'opération "(...) ? 1 : 0", mais surtout j'en
connais qui aurait écrit directement
return i;
pour exactement la même sémantique (mais pas la même valeur bien entendu).
Ah non, ça marchera moins bien si sizeof(size_t) != sizeof(int) :)
Pourquoi ?
La première avec la double négation me semble indépendante du sizeof.
Le seul soucis que je peux voir avec la 2eme serait une troncature par
le transtypage implicite, sauf que cela ne se produit que si la taille
de size_t est supérieure strictement à celle des entiers. Est-ce que
cela existe? (size_t est défini comme étant un entier non signé dans
la norme: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
p254 paragraphe7.17)
Une architecture avec size_t sur 64 bits et int sur 32 ?
Samuel DEVULDER <samuel-dot-devulder-at-laposte-dot-net> écrivait :
Le 22/07/2014 21:33, Xavier Roche a écrit :
Le 22/07/2014 21:25, Samuel DEVULDER a écrit :
Quitte à faire du C, on aurait pu tout aussi bien aussi écrire pour un i entier: return !!i; Qui est équivalent de l'opération "(...) ? 1 : 0", mais surtout j'en connais qui aurait écrit directement return i;
pour exactement la même sémantique (mais pas la même valeur bien entendu).
Ah non, ça marchera moins bien si sizeof(size_t) != sizeof(int) :)
Pourquoi ?
La première avec la double négation me semble indépendante du sizeof.
Le seul soucis que je peux voir avec la 2eme serait une troncature par le transtypage implicite, sauf que cela ne se produit que si la taille de size_t est supérieure strictement à celle des entiers. Est-ce que cela existe? (size_t est défini comme étant un entier non signé dans la norme: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf p254 paragraphe7.17)
Une architecture avec size_t sur 64 bits et int sur 32 ?