Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 12 of 12

Thread: Arduino / Teensy function call difference

  1. #1
    Junior Member
    Join Date
    Apr 2021
    Location
    Leicestershire, UK
    Posts
    14

    Arduino / Teensy function call difference

    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

  2. #2
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    8,372
    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.

  3. #3
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,804

    Wink

    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..

  4. #4
    Junior Member
    Join Date
    Apr 2021
    Location
    Leicestershire, UK
    Posts
    14
    Quote Originally Posted by Frank B View Post
    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

  5. #5
    Junior Member
    Join Date
    Apr 2021
    Location
    Leicestershire, UK
    Posts
    14
    Quote Originally Posted by tonton81 View Post
    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

  6. #6
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    8,372
    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.

  7. #7
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    14,206
    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

  8. #8
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,477
    Quote Originally Posted by Frank B View Post
    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.

  9. #9
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    8,372
    Thank you, Luni

  10. #10
    Junior Member
    Join Date
    Apr 2021
    Location
    Leicestershire, UK
    Posts
    14
    Quote Originally Posted by luni View Post
    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

  11. #11
    Junior Member
    Join Date
    Apr 2021
    Location
    Leicestershire, UK
    Posts
    14
    Quote Originally Posted by luni View Post
    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

  12. #12
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    1,477
    Quote Originally Posted by TheMadHouse View Post
    ... surely I can't pass a string type to a char in a function call?...
    Sorry, I was a bit sloppy when I wrote "string". Of course I meant to say c_string, i.e. a plain old char array.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •