if (flags & BINARY) {
res = _fetch_float(b, width, flags);
b += width; bufsize -= width;
} else {
*p = '0円';
res = strtod(buf, (char **) NULL);
}
if (flags & LONGDBL)
*va_arg(ap, long double *) = res;
else if (flags & LONG)
*va_arg(ap, double *) = res;
else
*va_arg(ap, float *) = res;
nassigned++;
}
Et la fonction de conversion, clone de celle utilisée pour les int:
static long double _fetch_float(const u_char *b, size_t w, int flags)
{
long double ret = 1;
int sys_endian = 0; /* 0 == big endian, little endian otherwise */
if (*(char *) & ret == 1) sys_endian = 1;
if (flags & BIG) sys_endian = 0; else if (flags & LITTLE) sys_endian = 1;
if (flags & TRUNK) {
if (
(sys_endian == 1 && (flags & HIBYTES)) ||
(sys_endian == 0 && (flags & LOBYTES))
) {
/* should begin from the MSB */
if (flags & LONGDBL) b += sizeof(long double);
else if (flags & LONG) b += sizeof(double);
else b += sizeof(float);
b -= w;
}
}
ret = 0;
/* fetch bytes, storing them using the given endianness */
if (sys_endian) {
while (w --) ret += ((u_quad_t) b[w]) << (w * CHAR_BIT);
} else {
size_t i = 0;
while (w --) ret += ((u_quad_t) b[w]) << (i ++ * CHAR_BIT);
}
return ret;
}
Mais le plus étrange, c'est que le code suivant marche:
r = snscanf(float_buffer, sizeof(long_buffer), "%bi", & f);
Donc en fait en utilisant le code path des entiers, ça passe même sous Mac (mais bon ça marche que sur les archis où sizeof(int) == sizeof(float)).
Alors, peut être que c'est les shifts qui passent pas, je vais essayer avec une union, mais bon, ça me trouble que _fetch_int() marche et pas ça :)
[^] # Re: Hack de vfscanf(3), quelques réponses
Posté par JaguarWan . En réponse au message Hack de vfscanf(3), 4 questions. Évalué à 1.
Par contre le problème avec les floats reste entier... Voilà ce qui se passe quand je fais:
printf("float, system endianness : %f (0x%x)\n", f, (int) f);
memcpy(float_buffer, (char *) & f, sizeof(f));
f = 0;
r = snscanf(float_buffer, sizeof(long_buffer), "%bf", & f);
printf("returns %i, i = %f (0x%x)\n", r, f, (int) f);
Sur ma Slack x86, le programme de test donne ça :
float, system endianness : 1337.123413 (0x539)
returns 4, i = 4079200000.000000 (0x80000000)
Sur Mac OS X, PearPC, ça donne:
float, system endianness : 1337.123413 (0x539)
returns 4, i = 1151804416.000000 (0x44a72400)
Voilà ce qui se passe dans snscanf pour les floats binaires:
if ((flags & SUPPRESS) == 0) {
double res; /* d'origine */
if (flags & BINARY) {
res = _fetch_float(b, width, flags);
b += width; bufsize -= width;
} else {
*p = '0円';
res = strtod(buf, (char **) NULL);
}
if (flags & LONGDBL)
*va_arg(ap, long double *) = res;
else if (flags & LONG)
*va_arg(ap, double *) = res;
else
*va_arg(ap, float *) = res;
nassigned++;
}
Et la fonction de conversion, clone de celle utilisée pour les int:
static long double _fetch_float(const u_char *b, size_t w, int flags)
{
long double ret = 1;
int sys_endian = 0; /* 0 == big endian, little endian otherwise */
if (*(char *) & ret == 1) sys_endian = 1;
if (flags & BIG) sys_endian = 0; else if (flags & LITTLE) sys_endian = 1;
if (flags & TRUNK) {
if (
(sys_endian == 1 && (flags & HIBYTES)) ||
(sys_endian == 0 && (flags & LOBYTES))
) {
/* should begin from the MSB */
if (flags & LONGDBL) b += sizeof(long double);
else if (flags & LONG) b += sizeof(double);
else b += sizeof(float);
b -= w;
}
}
ret = 0;
/* fetch bytes, storing them using the given endianness */
if (sys_endian) {
while (w --) ret += ((u_quad_t) b[w]) << (w * CHAR_BIT);
} else {
size_t i = 0;
while (w --) ret += ((u_quad_t) b[w]) << (i ++ * CHAR_BIT);
}
return ret;
}
Mais le plus étrange, c'est que le code suivant marche:
r = snscanf(float_buffer, sizeof(long_buffer), "%bi", & f);
Donc en fait en utilisant le code path des entiers, ça passe même sous Mac (mais bon ça marche que sur les archis où sizeof(int) == sizeof(float)).
Alors, peut être que c'est les shifts qui passent pas, je vais essayer avec une union, mais bon, ça me trouble que _fetch_int() marche et pas ça :)
J'ai mis à jour le source sur http://mammouth.tuxfamily.org/vfscanf.c si tu souhaites voir la chose en intégralité.