Arduino / Teensy function call difference

Status
Not open for further replies.
I'm observing a difference in compiler behaviour between Arduino and Teensy.

Consider this very simple code - A function that takes a char array as a parameter and, as part of the function, makes changes to individual elements of the array.

Code:
void testFunction(char* data)
{
	// Do stuff

    data[3]='X';
	
	// Do stuff
}

// Test call 1
char data[] = { "TestData1" };
testFunction(data);

// Test call 2
testFunction((char*)"TestData2");


Compile as Arduino - Function sees "data" as a char* and allows modification.

Compile as Teensy - Function sees "data" as a const char* and does not allow modification (test call 2 fails).

Any idea why?

I understood Teensy used the Arduino compiler, so why the difference in behaviour?

I would have thought the Arduino compile was correct, and Teensy is wrong.



Jim
 
The common thing that both compilers are "GCC".
But one is for ARM, the other for ATMEGA. They are different versions, and are called with different flags. If you turn on "verbose compile" you can see the used commandline-options, and compare them.
 
you are casting a const string, do you think you should be modifying that?

the first one is just initializing the char array, this is expected behaviour for both..
 
But one is for ARM, the other for ATMEGA. They are different versions, and are called with different flags. If you turn on "verbose compile" you can see the used commandline-options, and compare them.

Thanks, I'll have a look.

Presume from this the compilers are quite different, hence there are differences in the detail of how they optimise the code.



Jim
 
you are casting a const string, do you think you should be modifying that?
My understanding is that to pass a const string to a function that is expecting a char array, you needed to cast it as char?

How should the string be passed in that scenario?

My background is 30+ years in the VB world (professionally), never done much with C++ until the last couple of years when I got into the Arduino stuff so the nuances of working with char arrays etc. is relatively new to me!

Thanks for the tips.



Jim
 
A guess:
Test Call 2: For AVR, the string ist stored in RAM, because the "F" Macro is missing. So, no problem to modify it.
However, I'm not 100% sure where Teensy stores it.. :) Would have to take a close look... The warning indicates that it is correctly indentified as const.
 
If a CONST variable of any type is passed - by definition as a constant it cannot be modified, like "data[3]='X';". Putting the "quoted string" as a parameter makes it a constant not associated with a variable so it can reside in FLASH not RAM, even if stored in RAM the compiler is right saying you cannot change it.

Looking at the command lines will show the compiler optimizations passed. On Teensy when there are larger resources it tends to compile for SPEED as Fast or Faster. On resource constrained AVR the default is likely toward 'smallest code size'

On T_3.5 there are options to optimize, choosing 'smallest code' will result typically in a smaller flash footprint for code.

Also to see the effect of the couple of KB of code to give faster and more flexible USB that Teensy provides, select USB Type 'No Serial'. That is basically what AVR chips using an external fixed USB chip get to do - and the chips offer fewer options at 110Kbaud versus ~12,000Kbaud on T_3.5
 
A guess:
Test Call 2: For AVR, the string ist stored in RAM, because the "F" Macro is missing. So, no problem to modify it.
However, I'm not 100% sure where Teensy stores it.. :) Would have to take a close look... The warning indicates that it is correctly indentified as const.

Here some code showing what is happening.

Code:
#include "Arduino.h"

void testFunction(char *data)
{
  Serial.printf("Address of data: %010p\n", data);
  Serial.flush();
  // Do stuff

  data[3] = 'X';

  // Do stuff
  Serial.println(data);

  Serial.println("not crashed");
  Serial.flush();
}

void setup()
{
  while (!Serial){ }
  
  
  Serial.println("Test call 1");
  char data[] = {"TestData1"};
  testFunction(data);

  Serial.println("\nTest call 2");
  testFunction((char *)"TestData2");

  Serial.println("done");
}

void loop()
{
}

Printout:
Code:
Test call 1
Address of data: 0x200017c4
TesXData1
not crashed

Test call 2
Address of data: 0x0000292f

In the first case data is living in the RAM (which starts at 0x1FFFF800 for the T-LC I used for the test) The second call the data starts at 0x292F which is in the flash. Accessing this address for writing crashes of course.

My understanding is that to pass a const string to a function that is expecting a char array, you needed to cast it as char?
How should the string be passed in that scenario?

That doesn't make sense? You simply shouldn't pass a const string to a function which tries to change it. What do you expect it to do? The string is const -> can't be changed. The compiler doesn't allow it, but with your cast you forced it to accept it on your on risk... A cast doesn't copy the string from flash to RAM of course.

If you want to change the const string you need to copy it first to a changable location and change it there as you did in your first test case.
 
Here some code showing what is happening.
............
Very many thanks for that, fully understand what's happening and the original behaviour is the one that's wrong!

The reason for the const string being passed was for debugging, the normall call is from a char array (test 1) but for testing I was just injecting a fixed string.

Coming from a VB background the concept of having const parameters is new (and particularly that it can be const when that's not declared in the function), I'm used to just ByRef or ByVal. If ByVal, it creates a copy you can do anything with!



Jim
 
My understanding is that to pass a const string to a function that is expecting a char array, you needed to cast it as char?

That doesn't make sense? You simply shouldn't pass a const string to a function which tries to change it.


Ignore the changing bit (I understand what's gong on there), surely I can't pass a string type to a char in a function call?

string and char would produce a type mismatch ??



Jim
 
Status
Not open for further replies.
Back
Top