Text Based Console with Integers
Text Based Console with Integers
Hi all,
I've got some debug routines that just print strings to the screens. However I need to print the contents of some integer values... Can anyone advise me how to make an Integer into a Char which I can print to the screen?
Rgds,
I've got some debug routines that just print strings to the screens. However I need to print the contents of some integer values... Can anyone advise me how to make an Integer into a Char which I can print to the screen?
Rgds,
Re:Text Based Console with Integers
Something like this should work to convert a number to a hex string:
I'll leave it as an exercise to the reader to adapt this routine for decimal, octal, binary, etc.
Code: Select all
void itox(char *str, int n)
{
char buf[9], ptr;
int digit;
ptr = buf + 8;
do
{
digit = n % 16;
n /= 16;
if (digit >= 10)
*ptr = digit - 10 + 'A';
else
*ptr = digit + '0';
ptr--;
} while (n != 0);
strcpy(str, ptr + 1);
}
Re:Text Based Console with Integers
Or for an asm example try something on these lines:
I don't give any guarantees that code is bug free ;D.
Code: Select all
;eax = number to convert
;ds:esi = pointer to string
mov ebx, 0xa ;We're dividing by 10 to get to base 10
mov ebp, esp ;Store the inital value of the stack pointer
;Do the conversion
.1:
xor edx, edx ;Required before division
div ebx ;Divide eax by 10
add dx, 0x30 ;Adjust decimal digit to ascii char
push dx ;Dump the char on the stack
or eax, eax ;Check to see if is anything left to do
jnz .1
;Store in the string
.2:
pop ax ;Grab a char from the stack
mov byte [ds:esi], al ;Move the char into the string
cmp ebp, esp ;All chars moved?
je .3 ;If so then end
inc esi ;Move to next offset of next char in string
jmp .2 ;Otherwise rinse and repeat
.3:
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Text Based Console with Integers
The "magic" of displaying numbers consist of two basic techniques:Tim Robinson wrote:Code: Select all
digit = n % 16; n /= 16; if (digit >= 10) *ptr = digit - 10 + 'A'; else *ptr = digit + '0';
1. in base N, the digits of a number are the successive remainders of the division by N. E.g, in base 10, 1234 is 4 + 3*10 + 2*10? + 1*10?.
Thus, 4=1234%10, 3=(1234/10)%10, 2=((1234/10)/10)%10, etc.
2. the successive digits (aswell as the successive alphabetic characters) use consecutive codes in the ASCII system. Thus
'1' is '0'+1 and 'B' is 'A'+1. You can also ignore that and code
Code: Select all
static char hexdigits[]="0123456789abcdef";
...
*ptr=hexdigits[digit];
Re:Text Based Console with Integers
Taken from my toy "kernel" and adapted to a standalone C function. This is unoptimized, unreviewed stuff and could probably be done much better. Has special formatting for hex and bin; you'd probably want to add oct handling. Assumes a function write(char*) exists.
Code: Select all
void write_int(UINT integer, UINT base = 16)
{
// prepare C string buffer (array)
char buf[40]; // enough for 2^128 in decimal notation!
char* idx = buf; // pointer into the array
// "slice off" digits from the back with the modulo operator
do
{
UINT digit = integer % base;
if (digit < 10)
{
*idx++ = '0' + digit;
}
else
{
*idx++ = 'A' + (digit - 10);
}
} while ((integer /= base) > 0);
// for hex output, add leading zeroes to "round" length to power of 2,
// and "0x" to declare hexadecimal base.
if (base == 16)
{
while ((idx - buf) < 8) // 32 bit - 8 hex digits
{
*idx++ = '0';
}
*idx++ = 'x';
*idx++ = '0';
}
if (base == 2)
{
while ((idx - buf) < 32) // 32 bit - 32 binary digits
{
*idx++ = '0';
}
*idx++ = 'b';
}
// reverse everything between buf and idx
char* begidx = buf; // first unreversed character
char* endidx = idx - 1; // last unreversed character
while (begidx < endidx)
{
// exchange characters, move indexes
char tmp = *endidx;
*endidx-- = *begidx;
*begidx++ = tmp;
}
*idx++ = 0; // terminate string
write(buf); // write string
}
Every good solution is obvious once you've found it.
Re:Text Based Console with Integers
Ok, thanks, im using the following...
And im just calling it as follows....
Code: Select all
static void Format_D( char* buf, int val )
{
char stack[16];
int top = 0;
int negative;
unsigned uval;
// Convert to sign and unsigned magnitude.
if ( val < 0 ) {
negative = 1;
uval = -val;
}
else {
negative = 0;
uval = val;
}
// Convert magnitude to decimal. We do this in order of least
// significant to most significant digit.
do {
int digit = uval % 10;
stack[top++] = digit + '0';
uval /= 10;
}
while ( uval > 0 );
// Add leading minus sign if negative.
if ( negative ) {
*buf++ = '-';
}
// Put formatted characters in the output buffer.
do {
*buf++ = stack[--top];
}
while ( top > 0 );
// Terminate the output buffer.
*buf = '\0';
}
Code: Select all
void dprintfint(int num)
{
char buf[64];
Format_D(buf, num);
dprintf(buf);
return;
}
Re:Text Based Console with Integers
Some bunch of quick & dirty hackers we are (me included). :'(
Note that stdlib.h - which you will have to implement or port sooner or later anyway - contains functions like lltostr() or ultostr(). You might want to implement and, subsequently, use them instead of hacking some special stuff for your kernel debug.
Note that stdlib.h - which you will have to implement or port sooner or later anyway - contains functions like lltostr() or ultostr(). You might want to implement and, subsequently, use them instead of hacking some special stuff for your kernel debug.
Every good solution is obvious once you've found it.
Re:Text Based Console with Integers
Actually, while the string-to-numeric functions ([tt]atoi()[/tt], [tt]strtol()[/tt], etc.) are defined in ANSI C, the numeric-to-string functions are not, and different versions of them exist. The de facto standard for the numeric-to-string conversion functions are the GCC prototype definitions:
The [tt]ltostr()[/tt] and [tt]ultostr()[/tt] variants do not seem to be as common.
This is based on the information available to me; it may be incorrect or out of date. Comments and corrections are welcome.
Code: Select all
char*???itoa (int, char*, int);
char*???ltoa (long, char*, int);
char*???ecvt (double, int, int*, int*);
char*???fcvt (double, int, int*, int*);
char*???gcvt (double, int, char*);
char* lltoa(long long, char *, int);
char* ulltoa(unsigned long long , char *, int);
wchar_t* lltow(long long, wchar_t *, int);
wchar_t* ulltow(unsigned long long, wchar_t *, int);
This is based on the information available to me; it may be incorrect or out of date. Comments and corrections are welcome.
Re:Text Based Console with Integers
It took me a while to get it right, but here's my version, designed to take advantage of the recursive nature of the underlying algorithm. Oh, I could done an iterative version that was more efficient and took less time to get right, but I just had to be different, didn't I? sigh Damn, I really need to comment this...
You probably wouldn't do it this way in the real world, of course. The chief headache I had with this was making sure the scratch buffer I was currently using didn't evaporate before I had concatenated the results into the caller's buffer; the big breakthrough came when I realized I could allocate the scratch buffer in the call prior to the one using it, and pass it as the buffer argument. That way, when the call returned, the scratch buffer was still allocated, and could be appended to the current buffer, which was in turn the scratch buffer of it's caller, and so on. While it is incredibly inefficent in it's use of stack memory, because the function itself is much smaller, it probably doesn't take much more memory overall than the iterative version does, on average (the worst case scenario is a base 2 negative number, requiring 34 function calls with a frame overhead of ~48 bytes = 1632 bytes of stack space).
I also included the test program, just to show I didn't cheat (too much). There's still one small bug in the way u2string() handles zeroes, but other than that, it should work. C&CW.
Code: Select all
#include <string.h>
const int maxbuffer = 33; // 32 bits + null terminator
char* u2string (unsigned int value, char* buffer, int radix)
{
unsigned int digit, reduction;
char tmp[maxbuffer];
const static char NUMERALS[16][2] = {"0", "1", "2", "3",
"4", "5", "6", "7",
"8", "9", "A", "B",
"C", "D", "E", "F"};
memset(tmp, '\00', (size_t) maxbuffer);
digit = value % radix;
reduction = value / radix;
if (0 != reduction)
{
strcat(buffer, u2string(reduction, tmp, radix));
}
strcat(buffer, NUMERALS[digit]);
return buffer;
}
char* i2string (int value, char* buffer, int radix)
{
char tmp[maxbuffer];
memset(tmp, '\00', (size_t) maxbuffer);
if ((0 > value) && (10 == radix))
{
value = -value;
buffer[0] = '-';
buffer[1] = '\00';
}
else
{
buffer[0] = '\00';
}
strcat(buffer, u2string((unsigned int) value, tmp, radix));
return buffer;
}
I also included the test program, just to show I didn't cheat (too much). There's still one small bug in the way u2string() handles zeroes, but other than that, it should work. C&CW.
Code: Select all
#include <stdio.h>
#include <stdlib.h>
// #include <conio.h> // Windows specific
int main( void )
{
char buffer1[(maxbuffer * 2) + 2], buffer2[(maxbuffer * 2) + 2];
int base, i;
memset(buffer1, '\00', (size_t) ((maxbuffer * 2) + 1));
memset(buffer2, '\00', (size_t) ((maxbuffer * 2) + 1));
for(base = 2; base <= 16; base += 2)
{
printf("%d in base %2d: %s == %s\n", 12765, base,
itoa(12765, buffer1, base),
i2string(12765, buffer2, base));
}
memset(buffer1, '\00', (size_t) ((maxbuffer * 2) + 1));
memset(buffer2, '\00', (size_t) ((maxbuffer * 2) + 1));
for(base = 2; base <= 16; base += 2)
{
printf("%d in base %2d: %s == %s\n", -254, base,
itoa(-254, buffer1, base),
i2string(-254, buffer2, base));
}
memset(buffer1, '\00', (size_t) ((maxbuffer * 2) + 1));
memset(buffer2, '\00', (size_t) ((maxbuffer * 2) + 1));
for(base = 2; base <= 16; base += 2)
{
printf("%d in base %2d: %s == %s\n", 0, base,
itoa(0, buffer1, base),
i2string(0, buffer2, base));
}
memset(buffer1, '\00', (size_t) ((maxbuffer * 2) + 1));
memset(buffer2, '\00', (size_t) ((maxbuffer * 2) + 1));
for(base = 2; base <= 16; base += 2)
{
printf("%d in base %2d: %s == %s\n", 0, base,
itoa(0, buffer1, base),
u2string(0, buffer2, base));
}
/*
// Windows specific function getch() used to pause
// console window in Dev-C++
puts("\nHit any key to continue...");
getch();
*/
}
Re:Text Based Console with Integers
Of course, if all you're doing is printing to the console, then this is the easiest solution:
Since this doesn't save the value, you don't have to play games with extra buffers the way that I had to with [tt]i2string()[/tt] above.
Code: Select all
#include <stdio.h>
void print_unsigned(unsigned int value, unsigned int radix)
{
int digit;
digit = value % radix;
value /= radix;
if (0 != value)
{
print_unsigned(value, radix);
}
putchar ((char) (digit + ((10 > digit) ? (int) '0' : (int) 'A' - 10)));
}
void print_int(int value, unsigned int radix)
{
print_unsigned((unsigned int)(10 == radix ? abs(value) : value), radix);
}