Number Base Conversion in C

Instructions

Write a C program that reads a number from the user input in either hexadecimal or decimal format and converts it to binary, decimal, and hexadecimal representations. The program should handle both positive and negative numbers.

Your program must read a series of characters encoded in ASCII format from the standard input (STDIN). These characters will represent a number in either decimal or hexadecimal format. Below, you will find the necessary functions for reading/writing information from/to the standard input/output, along with a concise illustration of how they can be utilized:

int read(int __fd, const void *__buf, int __n){
    int ret_val;
  __asm__ __volatile__(
    "mv a0, %1           # file descriptor\n"
    "mv a1, %2           # buffer \n"
    "mv a2, %3           # size \n"
    "li a7, 63           # syscall read code (63) \n"
    "ecall               # invoke syscall \n"
    "mv %0, a0           # move return value to ret_val\n"
    : "=r"(ret_val)  // Output list
    : "r"(__fd), "r"(__buf), "r"(__n)    // Input list
    : "a0", "a1", "a2", "a7"
  );
  return ret_val;
}

void write(int __fd, const void *__buf, int __n)
{
  __asm__ __volatile__(
    "mv a0, %0           # file descriptor\n"
    "mv a1, %1           # buffer \n"
    "mv a2, %2           # size \n"
    "li a7, 64           # syscall write (64) \n"
    "ecall"
    :   // Output list
    :"r"(__fd), "r"(__buf), "r"(__n)    // Input list
    : "a0", "a1", "a2", "a7"
  );
}

void exit(int code)
{
  __asm__ __volatile__(
    "mv a0, %0           # return code\n"
    "li a7, 93           # syscall exit (93) \n"
    "ecall"
    :   // Output list
    :"r"(code)    // Input list
    : "a0", "a7"
  );
}

void _start()
{
  int ret_code = main();
  exit(ret_code);
}

#define STDIN_FD  0
#define STDOUT_FD 1

int main()
{
  char str[20];
  /* Read up to 20 bytes from the standard input into the str buffer */
  int n = read(STDIN_FD, str, 20);
  /* Write n bytes from the str buffer to the standard output */
  write(STDOUT_FD, str, n);
  return 0;
}

Input

  • A 32-bit number represented by a string of up to 10 characters, followed by a newline character ("\n").
    • If the string represents a number in the hexadecimal base, it will start with characters "0x".
    • Otherwise, it will start with a number from 1 to 9 or with the minus sign (-), indicating that the number to be read is negative.
    • Note: The minus sign (-) will not be used in inputs in hexadecimal representation (e.g., -0x12 is not a valid input).

Output

After reading the 32-bit number, you should print the following information followed by newline characters:

  • The value in binary base preceded by "0b". If the number is negative, you must display the value in two's complement representation (as illustrated in the third example below);
  • The value in decimal base assuming that the 32-bit number is encoded in two's complement representation (In this case, if the most significant bit is 1, the number is negative);
  • The value in hexadecimal base preceded by "0x". If the number is negative, you must show the value in two's complement representation (as illustrated in the third example below);
  • The value in decimal base assuming that the 32-bit number is encoded in unsigned representation and its endianness has been swapped. - For example, assuming the 32-bit number 0x00545648 was entered as input, after the endian swap, the number becomes 0x48565400, and its decimal value is 1213617152.

Examples

Test CaseInputOutput
15456480b10000101001101110000
545648
0x85370
1884489728
20x5456480b10101000101011001001000
5527112
0x545648
1213617152
3-5456480b11111111111101111010110010010000
-545648
0xfff7ac90
2427254783
40x800000000b10000000000000000000000000000000
-2147483648
0x80000000
128

Notes and Tips

  • This exercise challenges you to apply your understanding of number representation and conversion in C language. It's essential to consider edge cases, such as handling negative numbers, when designing and implementing your program.
  • Note that the code for the write and read functions contains assembly instructions for the RISC-V architecture; as such, it is not possible to compile this code (as it is) for other architectures.
  • You may assume that all input values will be small enough to be encoded within 32 bits.
  • For printing the signed number in decimal base, we recommend:
    • Check if the number is negative by examining the most significant bit (MSB).
    • If it is negative:
      • Print the "-" sign;
      • Print the negated value of the number (consider the two's complement representation as discussed in the theory class).
  • The RISC-V simulator stores data written with the write syscall in internal buffers and only displays the content in the terminal after encountering a newline character ("\n").
  • In debugging mode, the terminal only accepts interactive debug commands. To provide input data to your program, you must use the "Standard IO" feature in the "Operating System" tab or the "write-stdin" command in the terminal.
  • We have identified two minor issues in the simulator. For now, we have updated the example in the prompt and suggest considering:
    • The input "-1" will not be provided to your program.
    • When using the read function, request a larger number of bytes than necessary (for this exercise, we suggest using the read function with n = 20, as shown in the example).
  • You can test your code using the simulator's assistant from this link.
    • Simply select your program, click on the assistant icon (small eye in the top-right corner of the screen), and click "Run Tests."