• # Hack de vfscanf(3), quelques réponses

    Posté par . En réponse au message Hack de vfscanf(3), 4 questions. Évalué à 3.

    Enfin, le meilleur pour la fin: l'équivalent en floating point ne marche pas... quand je caste b[w] en long double, j'ai gcc qui se roule en position foetale et couine "error: invalid operands to binary <<
    Je dirai plutôt qu'il te tape sur les doigts pour avoir essayé une chose infâme. En effet, la norme impose que les deux arguments d'un opérateur de décalage soient des entiers:
    6.5.7 Bitwise shift operators
    Syntax
    1 shift-expression:
    additive-expression
    shift-expression << additive-expression
    shift-expression >> additive-expression
    Constraints
    2 Each of the operands shall have integer type.


    Et de surcroît, dès que je caste mes binaires en float/double ils deviennent tout corrompu de l'intérieur, alors que si je me contente de les copier en tant qu'entier ça passe !

    En fait:
    memcpy(buf, & monfloat, sizeof(monfloat));
    snscanf(buf, sizeof(buf), "%bf", & monfloat); /* foire */
    alors que:
    snscanf(buf, sizeof(buf), "%bi", & monfloat); /* marche */
    Tu peux être plus précis ? Tu obtiens quoi comme résultat, précisément ? Et en quoi ça n'est pas ce que tu veux ?

    while (w --) ret += (long long) b[w] << w * 8;
    J'ai un doute, là... Tu ne serais pas, par hasard, en train de supposer qu'un unsigned char fait 8 bits ?
    Tu définis ta fonction comme retournant un unsigned long long et ensuite tu définis ret comme un long long... Ca tombe bien, vu que le code de ta fonction fait que ret pourra contenir une valeur négative ! (bah oui, s'il y a débordement : overflow sur un entier signé, ça peut faire des dégâts collatéraux) Et la conversion d'un entier signé contenant une valeur négative en un entier non-signé se fait modulo le max de l'entier non signé +1 (cf. 6.3.1.3.-2)

    D'où:
    unsigned long long ret = 0;
    /* ... */
    while (w --)
    {
    ret += ((unsigned long long) b[w]) << (w * CHAR_BIT);
    }
    en castant vers un type non signé (c'est plus sûr et évite les comportements indéfinis de certaines limites), et en (sur)parenthésant afin de bien voir ce qu'on fait (toujours faire attention aux règles de priorité des opérateurs...)

    J'ai aussi un "invalid storage class" pour _fetch_float() (la même chose qu'au dessus mais avec des casts en fait :) ) si je lui fait renvoyer un long double...
    Cf. 6.3.1.4-2; je présume que le domaine de valeurs de long long déborde celle de long double sur ton environnement... et donc, quand tu retournes le contenu de ret, il n'est pas garanti que la conversion se fasse (je n'ai pas trouvé si la norme spécifie que cette conversion doit être ok ou non. Je suppose que c'est undefined...) Ca ne serait pas plus simple de définir ret comme un long double dans ce cas ? Ca éviterait des prises de tête à calculer les écarts entre les bornes de <limits.h>...