[uClibc]printf %c handling on big-endian platform
Ilguiz Latypov
ilatypov at superbt.com
Mon Apr 1 22:48:35 UTC 2002
Hello,
Is there any chance that printf.c could process the %c format specifier
incorrectly? I traced that problem from telnetd daemon.
The attached test program printf_test.c gave expected results after
applying the patch. The output from the earlier version of the program is
shown below.
I don't know if there are other endian conversion issues besides the one
with %c specifier.
Ilguiz
Before the fix in libc/stdio/printf.c:
=============================================================================
# ./printf_test
i %08x 61626364, (char) i %08x 00000064, bytes[0] 61, bytes[1] 62, bytes[2] 63,
bytes[3] 64
len 28, snprintf " (char)(bytes[0]) %c '"
len 28, snprintf " (int)(bytes[0]) %c '"
len 28, snprintf "(int)(bytes[0] << 24) %c 'a'"
#
After the fix in libc/stdio/printf.c:
=============================================================================
# ./printf_test
i %08x 61626364, (char) i %08x 00000064, bytes[0] 61, bytes[1] 62, bytes[2] 63,
bytes[3] 64
len 28, snprintf " (char)(bytes[0]) %c 'a'"
len 28, snprintf " (int)(bytes[0]) %c 'a'"
len 28, snprintf "(int)(bytes[0] << 24) %c '"
#
=============================================================================
-------------- next part --------------
#include <sys/types.h>
#include <stdio.h>
typedef union int_bytes_s {
int i;
u_int8_t bytes[4];
} int_bytes_t __attribute__ ((packed));
int main(int argc, char **argv) {
char s[81];
int_bytes_t opt;
int len;
char ch;
opt.bytes[0] = 'a'; /* 0x61 */
opt.bytes[1] = 'b'; /* 0x62 */
opt.bytes[2] = 'c'; /* 0x63 */
opt.bytes[3] = 'd'; /* 0x64 */
printf("i %%08x %08x, (char) i %%08x %08x, "
"bytes[0] %02x, bytes[1] %02x, bytes[2] %02x, bytes[3] %02x\n",
opt.i, (int)((char)opt.i),
opt.bytes[0], opt.bytes[1], opt.bytes[2], opt.bytes[3]);
memset(s, 0, sizeof(s));
len = snprintf(s, sizeof(s), " (char)(bytes[0]) %%c '%c'",
(char)(opt.bytes[0]));
printf("len %d, snprintf \"%s\"\n", len, s);
memset(s, 0, sizeof(s));
len = snprintf(s, sizeof(s), " (int)(bytes[0]) %%c '%c'",
(int)(opt.bytes[0]));
printf("len %d, snprintf \"%s\"\n", len, s);
memset(s, 0, sizeof(s));
len = snprintf(s, sizeof(s), "(int)(bytes[0] << 24) %%c '%c'",
(int)(opt.bytes[0] << 24));
printf("len %d, snprintf \"%s\"\n", len, s);
ch = 'a';
printf(" (signed char)ch %%02x '%02x'\n",
(signed char)ch);
printf(" (unsigned char)ch %%02x '%02x'\n",
(unsigned char)ch);
printf("(int)((unsigned char)ch) %%02x '%02x'\n",
(int)((unsigned char)ch));
printf("(int)((unsigned char)ch) & 0xff %%02x '%02x'\n",
(int)((unsigned char)ch) & 0xff);
return 0;
}
-------------- next part --------------
Index: libc/stdio/printf.c
===================================================================
RCS file: /usr/local/cvsroot/uClibc/libc/stdio/printf.c,v
retrieving revision 1.1.1.3
retrieving revision 1.2
diff -u -r1.1.1.3 -r1.2
--- libc/stdio/printf.c 1 Apr 2002 17:16:43 -0000 1.1.1.3
+++ libc/stdio/printf.c 1 Apr 2002 22:14:52 -0000 1.2
@@ -1172,7 +1172,14 @@
}
} else { /* char */
s = (char *) buf;
- *s = *((const char *) *argptr);
+ /*
+ * For the little-endian platform, the compiler
+ * will take the byte off *argptr.
+ * On big-endian platform, the compiler will
+ * take the byte at (*argptr + sizeof(int) - 1).
+ * --ilatypov
+ */
+ *s = (char)(*((const int *) *argptr));
s[1] = 0;
slen = 1;
}
More information about the uClibc
mailing list