Bran's tutorial - putch()

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
vibhory2j

Bran's tutorial - putch()

Post by vibhory2j »

the puts(), putch() function, given in bran's tutorial, prints all the strings, characters corectly on the console.

but the funtion putch() is unable to print any integer value on the console. the function does nothing when asked to print any integer value.
i tried it this way (as given in tutorial) :-

int i;
i = 10/2;
puthch(i);


what could be the problem???
any help.... thanks in advance

cheers
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:Test kernels refuses to print to screen

Post by Solar »

vibhory2j wrote: the puts(), putch() function, given in bran's tutorial, prints all the strings, characters corectly on the console.

but the funtion putch() is unable to print any integer value on the console.
I get an access error on osdever.net ATM, and putch() isn't a standard function, so this is guesswork. But:

1) you didn't really write [tt]puthch(i);[/tt], I hope, as this is spelled incorrectyl;

2) are you sure that putch() is actually intended to print integers? Try feeding it values between, say, 65 and 90. If you see uppercase characters, that putch() accepts int but interprets them as char values. That is common in C I/O, to make room for the non-char value of EOF.
Every good solution is obvious once you've found it.
Cjmovie

Re:Bran's tutorial - putch()

Post by Cjmovie »

Yes, putch is intended for characters. To try and help you understand, vibhory2j, you may want to look up ASCII.

For the record, here is a method of writing a number to output that _SHOULD_ work:

Code: Select all

void PrintInt(unsigned int a){
 while(a > 0){
  putch(a % 10);
  a /= 10;
 }
}
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:Bran's tutorial - putch()

Post by Solar »

Cjmovie wrote: For the record, here is a method of writing a number to output that _SHOULD_ work...
Your function prints last digit first, which probably is not what you intended, and makes the same mistake vibhory2j did originally (printing integers instead of character values), which is certainly not what you intended.

Here's code handling both int and unsigned int correctly, including sign and INT_MIN handling for twos-complement / ASCII machines. Untested but confident. ;)

Code: Select all

#include <limits.h>

void PrintUInt( unsigned int a )
{
    if ( a > 9 )
    {
        PrintUInt( a / 10 );
    }
    putch( ( a % 10 ) + '0' );
}

void PrintInt( int a )
{
    if ( a < 0 )
    {
        putch( '-' );
        if ( a == INT_MIN )
        {
            PrintUInt( ((unsigned int) INT_MAX) + 1 );
        }
        else
        {
            PrintUInt( a * -1 );
        }
    }
}
Every good solution is obvious once you've found it.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:Bran's tutorial - putch()

Post by Candy »

Solar wrote:
Your code eats the stack alive and doesn't handle with locales in which the minus should follow the number.

Point being, you don't care about what it doesn't do or you'd end up with something like GNU Hello, which is the best example ever of an over-engineered project. It's a hello world, with autoconf, automake, locale support etc. Or try GNU True, which is a very long program that only returns true. Based on a define, which defines what it returns (the default program is called false).
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:Bran's tutorial - putch()

Post by Solar »

Candy wrote: Your code eats the stack alive...
Maximum recursion depth is 5 for 16bit, 10 for 32bit or 20 for 64bit. The version I showed works correctly regardless of word width and is simpler than one using an internal buffer. But well, since you asked for it, see bottom of this post...
...and doesn't handle with locales in which the minus should follow the number.
I feel that kernel code should ignore locale issues because of the code bloat involved, especially in a minor case as to whether the minus should lead or trail. (And how numbers are usually grouped, e.g. commas every three digits etc.) You'd have to cater for EBCDIC, for example, where digits don't occupy consecutive places in the code tables...
Point being, you don't care about what it doesn't do or you'd end up with something like GNU Hello, which is the best example ever of an over-engineered project.
Agreed. But printing decimal numbers most-significant digit first is not negotiable IMNSHO. ;-)
It's a hello world, with autoconf, automake, locale support etc.
Nice hint, I always wanted to learn about autoconf and automake. ;)

But now for the non-recursive PrintInt() as requested by Candy:

Code: Select all

/* 5 for 16bit, 10 for 32bit, 20 for 64bit 'int' */
#define PRINTINT_MAXLEN 10

void PrintUInt( unsigned int a )
{
    char buffer[ PRINTINT_MAXLEN + 1 ];
    unsigned int p = PRINTINT_MAXLEN;
    buffer[ p ] = '\0';
    while ( a )
    {
        buffer[ --p ] = ( a % 10 ) + '0';
        a /= 10;
    }
    puts( buffer + p );
}
[tt]PrintInt()[/tt] remains the same. Still assumes two's-complement, ASCII machines and does not take locales into account. If you're feeling reckless, you could drag in <math.h> and <stdlib.h> and determine the max. amount of digits using a log2() on UINT_MAX and using dynamically allocated memory, but that'd be about as much overkill as properly formatting the number according to current setlocale()... :-D
Every good solution is obvious once you've found it.
Cjmovie

Re:Bran's tutorial - putch()

Post by Cjmovie »

Solar wrote:
Cjmovie wrote: For the record, here is a method of writing a number to output that _SHOULD_ work...
Your function prints last digit first, which probably is not what you intended, and makes the same mistake vibhory2j did originally (printing integers instead of character values), which is certainly not what you intended.

Here's code handling both int and unsigned int correctly, including sign and INT_MIN handling for twos-complement / ASCII machines. Untested but confident. ;)

Code: Select all

#include <limits.h>

void PrintUInt( unsigned int a )
{
    if ( a > 9 )
    {
        PrintUInt( a / 10 );
    }
    putch( ( a % 10 ) + '0' );
}

void PrintInt( int a )
{
    if ( a < 0 )
    {
        putch( '-' );
        if ( a == INT_MIN )
        {
            PrintUInt( ((unsigned int) INT_MAX) + 1 );
        }
        else
        {
            PrintUInt( a * -1 );
        }
    }
}
Ooooh, last time I try to help out before school right after waking up from 2 hours of sleep while starting my history project due today.....
lol
vibhory2j

Re:Bran's tutorial - putch()

Post by vibhory2j »

referring to the code by solar :-

Code: Select all

#include <limits.h>

void PrintUInt( unsigned int a )
{
    if ( a > 9 )
    {
        PrintUInt( a / 10 );
    }
    putch( ( a % 10 ) + '0' );
}

void PrintInt( int a )
{
    if ( a < 0 )
    {
        putch( '-' );
        if ( a == INT_MIN )
        {
            PrintUInt( ((unsigned int) INT_MAX) + 1 );
        }
        else
        {
            PrintUInt( a * -1 );
        }
    }
}
i will try to put this in to my kernel. but i suspect the use of include file limits.h as we can't nse built in libraries in the kernel source.
am i right or wrong??? please clarify it....

cheers
pradeep

Re:Bran's tutorial - putch()

Post by pradeep »

Let me make a guess?
If the header file is going to call any system calls are other library routines then you can't have it in your kernel. Suppose if the header file is standalone library then you can have it in your kernel.Because i am doing kernel in asm i don't know much about C.
Please correct me if i am wrong?
AR

Re:Bran's tutorial - putch()

Post by AR »

limits.h is part of the freestanding environment (The "not-running-on-an-OS" environment), basically it's just a header full of defines declaring "sizes" (ranges) of variable types.

If you built a cross compiler, <limits.h> will be part of your freestanding environment and should work fine (provided you aren't using "-nostdinc" on the commandline).
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re:Bran's tutorial - putch()

Post by Solar »

You can use whatever part of the standard library you implemented. <limits.h> is so easy it can actually be auto-generated, as it merely contains a bunch of #define statements referring to the size of integers of your system.

Edit: You might want to have a look at my signature... PDCLib 0.2 isn't much from the user-space perspective, but it has all the freestanding headers (including <limits.h>), and is especially targeted at OS dev'ers like us here, meaning it's dead-easy to adapt to your wishes. Just stay away from the <string.h> functions until 0.3, there are some really stupid bugs in there. ;)
Every good solution is obvious once you've found it.
Post Reply