简体   繁体   中英

Itoa stopping strcat from properly appending

I am trying to append a series of char arrays in Arduino C++. I have a char array "outputString", and a series of other char arrays that I with to append with via strcat. I also have a checkSum generator that generates the checksum and I used Itoa to convert the checksum value from an int into a base16 character array for appending. This is what it looks like:

char cmdtype[6] = "AAAAA"; //The 5-letter command
bool canPrint = true;

int checkSumGenerator(char message[]) {
  int checkSum = 0;
  for (int i = 0; i < 21; ++i)  //Remove the Checksum character, as well as the Null Character
  {
    checkSum ^= message[i];
  }
  Serial.println(checkSum);
  Serial.println("Printed checksum.");
  return checkSum;
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600); // usb port serial
}

void loop() {
  //Collect data.
  if (Serial.available() > 0 && canPrint == true) {
    char outputString[] = "TOSBC_";
    Serial.println(outputString);
    
    strcat (outputString, cmdtype);
    Serial.println(outputString);
    strcat (outputString, "_");
    Serial.println(outputString);
    strcat (outputString, "00001212");
    strcat (outputString, "_");
    Serial.println("Line w/ "00001212" should be below");
    Serial.println(outputString);

    int outputCheckSum = checkSumGenerator(outputString);
    char outputCheckSumHex[3];
    itoa (outputCheckSum, outputCheckSumHex, 16); //Commenting this line seems to remove the "00001212" thing.

    Serial.println(outputCheckSum);
    //Serial.println(outputCheckSumHex);

    Serial.println(outputString);
    canPrint = false; //Only want it to print once.

  }
}

Under this code, the output is the following:

10:40:23.740 -> TOSBC_
10:40:23.740 -> TOSBC_AAAAA
10:40:23.740 -> TOSBC_AAAAA_
10:40:23.740 -> Line w/ cmdparam should be below
10:40:23.740 -> TOSBC_AAAAA_00001212_
10:40:23.740 -> 87
10:40:23.740 -> Printed checksum.
10:40:23.740 -> 87
10:40:23.740 -> TOSBC_A57   //What I'm expecting is "TOSBC_AAAAA_00001212_57"

I am not entirely sure why that is the case. I don't know how itoa could possibly affect strcat from working properly, but this is something else I tried, and doing so allowed "00001212" to be printed.

int outputCheckSum = checkSumGenerator(outputString);
char outputCheckSumHex[3];
//itoa (outputCheckSum, outputCheckSumHex, 16); //Commenting this line seems to remove the "00001212" problem.

The output is:

10:43:29.178 -> TOSBC_
10:43:29.178 -> TOSBC_AAAAA
10:43:29.178 -> TOSBC_AAAAA_
10:43:29.178 -> Line w/ '00001212' should be below
10:43:29.178 -> TOSBC_AAAAA_00001212_
10:43:29.178 -> 87
10:43:29.178 -> Printed checksum.
10:43:29.178 -> 87
10:43:29.178 -> TOSBC_AAAAA_00001212_

Directly providing a value for outputCheckSum, like so, is also something I tried. It did not fix the problem.

int outputCheckSum = 87;
char outputCheckSumHex[3];
itoa (outputCheckSum, outputCheckSumHex, 16); 

Please let me know if more information is required to solve this issue.

The char outputString[] = "TOSBC_"; declaration gives the array just enough space to hold the initializer string; that is, the size of the array will be determined from the number of elements in the string literal – which will 7 (the 6 visible characters plus a nul terminator).

Thus, attempting any strcat() on that will overflow the array's bounds and, as such, will be undefined behaviour (UB).

The fact that problems don't appear immediately (ie after the first few calls to strcat ) is just one of the many possible manifestations of the UB. What appears to be happening, in your case, is that the compiler has assigned the memory for the outputCheckSumHex array right after that for outputString , and your call to ltoa is thus overwriting what has (by unlucky chance) already been written there by the earlier – and invalid – calls to strcat .

The fix is trivial: just declare the outputString array with an explicitly specified size, and one that will make it large enough to accommodate all possible appended strings:

  if (Serial.available() > 0 && canPrint == true) {
    char outputString[100] = "TOSBC_"; // Specify a big enough size here!
    Serial.println(outputString);
    //...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM