Search code examples
cstringoperating-systemprintfstandard-library

Hexidecimal not printing properly in homemade printf() function


I'm writing an OS and was having problems with making a printf() function.

When going through the switch statement that has determined that there is a % and is now trying to figure out what the next character is, this happens:

print(string str) will print a string str to stdout (but without %x, %d, %s, etc).

itoa(int n, string str, const uint8_t base) will convert an int to a string of the specified base.

case 'i':
case 'd': {     // interger
    const string str =
        itoa(
        va_arg(args, int),
        str, 10);
    print(str);
    i++;
    break;
}

case 'X':
case 'x': {     // hexidecimal
    const string str2 =
        itoa(
        va_arg(args, int),
        str2, 16);
    print("0x");
    print(str2);
    i++;
    break;
}

%d and %i does exactly what it should, but %x doesn't work properly if the input is less than 16 for some reason. But the weird thing is if I comment out the part that handles %d and %i, %x works. I have no idea why this is happening. I've tried switching around what d and x do and so on but nothing has worked. I've also tried making sure all of the other functions are working and they are.

In case anyone wanted to see the full code, here it is:

strLen(string str) finds the length of string str.

printch(char c) prints a character c .

void printf (const string format, ... )
{
    const size_t length = strLen(format);
    va_list args;
    va_start (args, format);

    // print every character in string
    for (size_t i=0; i < length; i++)
    {
        // percent signals special functionality
        if (format[i] == '%')
        {
            switch (format[i+1])
            {
                case '%':       // "%%" = %
                    printch('%');
                    break;

                case 'i':
                case 'd': {     // interger
                    const string str =
                        itoa(
                        va_arg(args, int),
                        str, 10);
                    print(str);
                    i++;
                    break;
                }

                case 'x': {     // hexidecimal
                    const string str2 =
                        itoa(
                        va_arg(args, int),
                        str2, 16);
                    print("0x");
                    print(str2);
                    i++;
                    break;
                }

                case 'c':       // character
                    printch(
                    va_arg(args, char));
                    i++;
                    break;

                case 's':       // string
                    print(
                    va_arg(args, string));
                    i++;
                    break;

                default:
                    i++;
                    break;
            }
        }
        else printch(format[i]);
    }

    va_end (args);
}

Does anyone know what is going on here and how to fix it? Please help!


Solution

  • When commenting out unrelated code makes the code in question "work", you can be certain that you are looking at undefined behavior. Your code does not really "work"; it does not cause an error that manifests itself in the output.

    In your situation the problem appears to be with the buffer that you pass to itoa: you are passing an empty string to it, rather than passing a buffer. You should pass a small buffer to itoa, and only then construct a string from it, like this:

    char buf2[17];
    itoa(va_arg(args, int), buf2, sizeof(buf2));
    const string str2(buf2, sizeof(buf2));