Page 1 of 1

C++ toString (char*) implmentation

Posted: Tue Mar 22, 2022 12:19 pm
by RadPoseidon
I'm trying to write a function to convert an int to a string for my basic kernel. This is my current implementation:

Code: Select all

const char* toString(int i) {
	unsigned int it = 0;
	char *str;

	// TODO: Fix for negative numbers

	while(i > 0) {
		int n = i % 10;
		str[it] = (char)('0' + n);
		i = i / 10;
		it++;
	}

	return str; // This is line 155
}
However, C++ gives me the warning kernel/kernel.cpp:155:16: warning: 'str' is used uninitialized. I can't figure out what to initialize str to, as initializing it to "" also causes a warning, and ignoring the warning causes the test value of 53 appear as "S ".

Edit: I think that the "S " comes from it reading from a point in memory.

Re: C++ toString (char*) implmentation

Posted: Tue Mar 22, 2022 1:01 pm
by Assembler
Hello RadPoseidon,

The warning is obvious, you're using 'str' without initializing it which should cause a segmentation fault if you run it. You need to either allocate some memory in your 'toString' function or pass it to it.

Code: Select all

char *str = new char[10]; // you probably won't need more that 10 characters.
or
char *str = (char *)malloc(10 * sizeof(char));
Also note that:

Code: Select all

char str[10] won't work because it will be allocated onto the stack of 'toString' which will be destroyed when 'toString' returns.
Finally, your code doesn't exactly do what you're hoping for, indeed it will convert an int value to an array of characters but the array is in reverse order.

Hope that helped.

Re: C++ toString (char*) implmentation

Posted: Tue Mar 22, 2022 1:18 pm
by RadPoseidon
Thank you, I felt it had something to do with memory allocation, but I wasn't sure what to do. I had also conveniently written a function to get the digits in an int shortly beforehand.
I'm getting the error in function `_Z8toStringi': kernel.cpp:(.text+0x514): undefined reference to `_Znam' on link now, but I think it's unrelated to this and more due to a prior implementation of something.

Re: C++ toString (char*) implmentation

Posted: Tue Mar 22, 2022 1:32 pm
by Octocontrabass
That error means the linker can't find your implementation of "operator new[](unsigned long)". (Or perhaps you haven't implemented it yet?)

You can use c++filt or various websites to demangle symbol names.

Re: C++ toString (char*) implmentation

Posted: Tue Mar 22, 2022 2:08 pm
by nullplan
As to your original question, in most cases it is simpler to have the caller provide a buffer. Taking care of the whole domain, a simple implementation might be:

Code: Select all

void toString(int i, char *s) {
  static_assert(-5 % 3 == -2, "Compiler uses symmetric modulo"); /* if this fails, the code below won't work. */
  if (i < 0)
    *s++ = '-';
  else
    i = -i;
  int t = i;
  do s++;
  while (t /= 10);
  *s = 0;
  do *--s = '0' - i % 10;
  while (i /= 10);
}
This always turns the argument negative, because while each positive int can be turned negative, the reverse is not true (INT_MIN cannot be turned positive on most systems). Then it is simply a matter of working with division in the negative numbers. I put an assert in to verify that symmetric modulo is used, but it is used by pretty much all implementations I have ever come across. The alternative would not be pretty. In the case of absolute modulo, you get the inverse of each digit except 0, and the divisions would raise the argument towards -1, unless the argument was 0 from the start.

Now, there are some obvious areas for improvement, still. The buffer is unbounded at the moment, so the caller needs some way of knowing how to allocate enough memory from the start. Or alternatively, the caller could provide a buffer size, but then you need to specify what happens when the buffer runs out. I shall leave that as exercise for the reader.

Re: C++ toString (char*) implmentation

Posted: Wed Mar 23, 2022 7:28 am
by RadPoseidon
Yeah, I missed an article that explained defining new/delete, etc. I thought I had objects working since it let me construct and use a test object.