2

I have a library driven result stored as an int16_t value (and it is a negative, which I can use the absolute value of) and another library function that requires this value a few steps later in the form uin8_t*. How can this be done without using String?

The following code works, but uses dreaded Strings. Is there a way to do this without invoking String or std::string?

 void setup() {
      Serial.begin(9600);
    }

    void loop() {
      delay(5000);
      String initialVal= String(-fetchInt()); 
      Serial.print("Initial value is: ");Serial.println(initialVal);//prints "76"
      uint8_t medianVal[sizeof(initialVal);
      medianVal.getBytes(medianVal, sizeof(initialVal));
      Serial.print("median value is: ");Serial.println(medianVal);//prints "76"
      uint8_t* finalVal = medianVal;
      Serial.print("final value is: ");Serial.println((char*)finalVal);//prints "76"
      }

    int16_t fetchInt(){
      return -76;
    }

So, how can I turn int16_t into uint8_t*?

It has been pointed out in comments below that Serial.println(static_cast<unsigned>(*finalVal)); works, but this solution converts the uint8_t to an unsigned int and the method requires uint8_t*.

I come from Java and the like and it seems crazy that it is so hard to convert an integer to a string.

Orbiting Eden
  • 1,522
  • 13
  • 16
  • That's strange, but if understood correctly - you'd like the absolute value of `firstVal` to be set into `secondVal`, with no regards to its sign (and - given you cast from a 16-bit integer into an 8-bit - with possible loss of data)? – uv_ Dec 11 '18 at 22:03
  • yes. The number is always under 120, so there is no loss of fidelity. – Orbiting Eden Dec 11 '18 at 22:23
  • 1
    you are trying to set a pointer to -76. IS that really what you want. What do you expect to find there? – pm100 Dec 11 '18 at 22:29
  • I am looking for a pointer to the alphanumeric character of -76, not the integer value. This is the strength of a radio signal being bounced back to the sender as a health check. – Orbiting Eden Dec 11 '18 at 22:43
  • 1
    This sounds more like [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). Be specific: what library, which method. – KIIV Dec 12 '18 at 14:28
  • @OrbitingEden What is the library function that requires an _uint8_t*_? – Ted Lyngmo Dec 12 '18 at 16:14
  • The library is Radiohead. I have found a solution thanks to all of your help. The solution was to change the final call to: `Serial.println(*&medianVal);` This both preserves the uint8_t* format and the original absolute value. – Orbiting Eden Dec 12 '18 at 17:01
  • @OrbitingEden That's pretty much `Serial.println(medianVal)`. – KIIV Dec 12 '18 at 20:49
  • @OrbitingEden As KIIV implied, that is pointless. `&medianVal` gives you the address where the `uint8_t` is stored. The `*` before returns the value stored at the address returned by `&medianVal`, which makes the `*&` part a no-op in this context. – Ted Lyngmo Dec 12 '18 at 21:02
  • @KIIV and @Ted, It would be awesome if you could answer the question with code that compiles and whose return value is "76" and not "L". Using the solutions suggested in this thread consistently results in a uint8_t* value of "L" and not "76" - which is independent of the printed result of `Serial.println(*&medianValue);` – Orbiting Eden Dec 12 '18 at 23:29

2 Answers2

5

A pointer of type uint8_t cannot point to an object of type int16_t; you need to copy the value of firstVal, but therefore you'll need a separate object to take on the value.

uint8_t firstValAbs = firstVal >= 0 ? firstVal : -firstVal;
uint8_t* secondVal = &firstValAbs;

Note: uint8_t x = -34 will not give you the absolute value of -34, i.e. it will not result in 34. You'll rather get a two's complement of -34, i.e. 255-34+1 == 222.

Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58
  • This is a great start, but now the numerical value is being converted to a letter (for instance 76 is converted to "L") and there is weirdly a string concatenated from a prior variable labelled "buf". The results convert "-76" to "LHello World!" – Orbiting Eden Dec 11 '18 at 22:21
  • 2
    If you have `uint8_t* secondVal;` you shouldn't do `std::cout << secondVal;` since it's not a null terminated string. Everything after the variable will be printed too (and you probablly had "Hello World" there). You need `std::cout << static_cast(*secondVal)` if you'd like to see the numerical value. Or someone meant to write `std::wcout << L"Hello World"` and put the `L` inside the `"...."`... – Ted Lyngmo Dec 11 '18 at 23:17
  • 1
    Ted, your answer solved my problem. In my code it looks like: `Serial.println(static_cast(*finalVal));` and now outputs the correct number. – Orbiting Eden Dec 12 '18 at 07:48
  • Sorry, I have to re-open this. `static_cast` converted it to an unsigned int and it no longer is accepted by the method that requires uint8_t* as a passed variable. – Orbiting Eden Dec 12 '18 at 08:56
  • The cast to `unsigned` was merely for printing purposes. If the function wants an `uint8_t*` you should give it `finalVal`. – Ted Lyngmo Dec 12 '18 at 15:15
  • Thanks Ted, when I use finalVal, the letter "L" is the product. It seems like I have to convert the int value to a string representing "76". My first approach is going to be to convert the int16_t to a char* using itoa. The second step would be converting the char* to uint8_t* – Orbiting Eden Dec 12 '18 at 23:25
3

int16_t stores a signed numeric value using 16 bits (-32,768 to 32,767).

uint8_t stores an unsigned numeric value using 8 bits (0 to 255).

If you are sure your int16_t value fits into an uint8_t after changing the sign, you can just assign it:

int16_t firstVal = -76;
uint8_t secondVal = -firstVal;

Now, if you need a pointer to the second value, you can just create it. You can not point directly to firstVal because you need to store the changed value.

uint8_t* secondValPointer = &secondVal;

This uint8_t* may be interpreted as a pointer to a character in your library. Normally, you should use char for this purpose (also 8 bits, but it is implementation defined if it is signed or unsigned). You can cast this pointer to char*, although you need to tell the compiler you want to cast between pointers using reinterpret_cast:

char *secondValAsChar = reinterpret_cast<char*>(secondValPointer);

Now, you can treat this pointer as a pointer to character. For example the following code will print 'L' because ASCII code for L is 76:

std::cout << *secondValAsChar << std::endl;

However, you must be very careful with this pointer because secondValAsChar is not a null terminated string, so you may not use the old common methods like strcat.

J. Calleja
  • 4,855
  • 2
  • 33
  • 54
  • For my output I am using Serial.print(). If I use this on other uint8_t* integer values, it outputs the numerical value and not the ASCII character represented by the octet. I must use uint8_t* and not char* because the library function requires it. I edited the code for a compilable example. – Orbiting Eden Dec 12 '18 at 07:31