0

I am teaching myself C++ by doing microcontroller projects. My current project is using a pair or Adafruit Feather packet radios. The library functions for the radio packets require a C-style string (I believe) which I understand to be an array of char's.

I have already set up an enum to reflect the various actions of the receiver and would like to send that status back to the transmitter. So I want to turn an enum into an array of char's.

In googling ways to convert enum to array of chars, the easiest (for me to understand) was passing the enum variable to a function with a switch statement that would return a char string. But when I try to put the return into my char array, I get the error "invalid conversion from 'char*' to 'char' [-fpermisive]". I've also been struggling to get my head around arrays and pointers to arrays which is still pretty fuzzy in my head.

Here are some snippets of my code which I hope will show enough of what I'm trying to do.

...from my main function

  BLINKING_RIGHT, //0
  BLINKING_LEFT,  //1
  FLASHING,       //2
  SHOWING_BATTERY,//3
  NONE            //4
};

...and the two functions that process the enum to send

void SendStatus()
{
  char data[20] {EnumToString(currentAction)};     //This is the line showing the error
  //itoa (data,static_cast<int>(currentAction),10);
  //data[0]=static_cast<uint8_t>(currentAction);
  //data[1]=0;
  rf69.send(data, sizeof(data));
  rf69.waitPacketSent();
  Serial.println("Sent a reply");
}//end_function SendStatus()

char* EnumToString(CurrentAction inputEnum)
{
  char *statusString;
  switch(inputEnum)
  {
    case 0:
      statusString = "BLINKING_RIGHT"; //0
      return statusString;
      break;
    case 1:
      statusString = "BLINKING_LEFT";  //1
      return statusString;
      break;
    case 2:
      statusString = "FLASHING";       //2
      return statusString;
      break;
    case 3:
      statusString = "SHOWING_BATTERY";//3
    case 4:
      statusString = "NONE";           //4
      return statusString;
      break;
    default:
      return "EnumToString: Invalid enum";
  }
}

I would like help fixing the problem, and, more importantly, help understanding the difference between the type char* and the type char.

jrl
  • 1
  • 1
  • 1
    Create a [mcve] – eerorika Mar 25 '21 at 14:59
  • 1
    The key would be knowing what the `*` means. You are attempting to return a pointer-to-char, but that also isn't going to work. This is because the 'thing' your pointer is supposed to point to doesn't exist anymore. An output parameter would be better. – sweenish Mar 25 '21 at 15:00
  • to Understand the difference between char and char pointer, Please read https://stackoverflow.com/questions/10186765/what-is-the-difference-between-char-array-and-char-pointer-in-c and and https://stackoverflow.com/questions/5727/what-are-the-barriers-to-understanding-pointers-and-what-can-be-done-to-overcome – ma1169 Mar 25 '21 at 15:02
  • 1
    There is a million tutorials and resources on C++ and its types. Please read any of them. If you don't know the difference between char and char* you have not spend more than 5 minutes on reasearching C++ pointers. please value our time. – Piglet Mar 25 '21 at 15:02
  • Why do you put a `break` after every `return`? It's completely redundant, and any good compiler would warn you that it's dead code. – Mark Ransom Mar 25 '21 at 17:42

3 Answers3

2

This line:

char data[20] {EnumToString(currentAction)};

Is wrong because it uses array-initialization to initialize the first element of the array of char (first element which is of type char) with a string (char*). What you want to do is something like this:

char data[20];
strcpy(data, EnumToString(currentAction));

Or simply:

char *data = EnumToString(currentAction);

The latter doesn't involve any kind of copying, and efficiency is important on a micro-controller.

While we're on the point of efficiency, the canonical way of mapping sequential enum values to strings is using an array, which is orders of magnitude more efficient than repeated branching:

// stored as read-only data in the .hex file
static char *names[] = { "BLINKING_RIGHT", "BLINKING_LEFT", "FLASHING", "SHOWING_BATTERY", "NONE" };

// later
const char *data = names[currentAction];
Blindy
  • 65,249
  • 10
  • 91
  • 131
  • I would hope that a good optimiser generates a jump table from the switch. But the array is better even just because of simplicity. – eerorika Mar 25 '21 at 15:24
  • If you take a pointer to a string, you'd better have a way of ensuring the string remains valid as long as you need it. – Mark Ransom Mar 25 '21 at 17:27
1

Difference between char and char*

char is a character object. Characters are numbers. The number value encodes some textual character (in fixed width character encodings; A C++ character represents one "code unit" in variable width unicode encoding).

char* is a pointer object. It is specifically a pointer to a char object. A pointer object points to another object in memory - or points to nothing if null or points to memory where an object was if the pointer is invalid. Pointers are also iterators, and incrementing a pointer makes it point to a successive element of an array.


char data[20] {EnumToString(currentAction)};     //This is the line showing the error

data is an array of 20 objects of type char. {expr} initialises the first element of the array with the expression. In your case, the expression is a call to EnumToString. Thus, you're attempting to initialise a char object using the char* object returned by the function. The type system of C++ protects you from this obvious mistake.

Assuming you have the option of sending less than 20 bytes, a potential simple solution is to avoid using the local array entirely:

std::string_view str = EnumToString(currentAction);
rf69.send(str.data(), str.size());

char *statusString;
statusString = "BLINKING_RIGHT"; //0

This is ill-formed in C++. String literals are arrays of const char, and they are not convertible to pointer to non-const char (since C++11).

As simple fix is to change the variable and the return type to be const char*. That said, using std::string_view may be even more preferable because that way the caller doesn't need to calculate the length of the string at runtime by searching for the null terminator.

eerorika
  • 232,697
  • 12
  • 197
  • 326
0

char (or any T) is a value.

char* (or any T*) is a pointer (a value poining to another value, i.e. address).

Keep in mind what arrays (char[] or any T[]) presented by pointer to 0-th element. Variable of char* can point to an element of an array (to the first element in a special case).

Vitalii
  • 431
  • 4
  • 11