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

Thread: Possible bug about using const array in functions?

  1. #1
    Senior Member
    Join Date
    Sep 2015
    Location
    Taiwan, Asai. (Traditional Chinese)
    Posts
    167

    Possible bug about using const array in functions?

    I think there might be some bug when using PROGMEM const array in functions?

    some codes from POV guidance that you need to call pgm_read_type to work on PROGMEM arrays,
    and codes in teensy just seemed to work well without calling any extra function
    not sure if related or not

    for example,
    const uint16_t gammaTable[] PROGMEM = {/* .... */}

    void loop() {
    consttoserial();
    delay(4000);
    }

    void consttoserial(){
    Serial.println(sizeof(gammaTable)/sizeof(*gammaTable));
    for (int y=0;y<sizeof(gammaTable)/sizeof(*gammaTable);y++) {
    Serial.print(gammaTable[y]);
    Serial.print("\t");
    if ((y+1)%16==0) {
    Serial.println("");
    }
    }
    }
    the script above works well and i get the const array PROGMEM/or not, printed to my serial monitor correctly,
    but after it changed to script below , i get like

    sizeof(array) =4
    sizeof(*array) =2
    and the printed array = {0, 1}

    no matter what the values the original array had,and PROGMEM/or not, i get the same result
    not sure if this is bug, or anything i did wrong? it passes the compiler, but gives incorrect array
    const uint16_t gammaTable[] PROGMEM = {/* .... */}
    void loop() {
    consttoserial(gammaTable);
    delay(4000);
    }

    void consttoserial(const uint16_t *array){
    Serial.println(sizeof(array)/sizeof(*array));
    for (int y=0;y<sizeof(array)/sizeof(*array);y++) {
    Serial.print(array[y]);
    Serial.print("\t");
    if ((y+1)%16==0) {
    Serial.println("");
    }
    }
    }

  2. #2
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    921
    PROGMEM is not needed in teensy 3.x, and you can just declare as const. have a read of this thread: https://forum.pjrc.com/threads/23526...-on-Teensy-3-0
    PROGMEM, pgm_read_byte() and the other AVR names are defined only so code designed for AVR can compile. But they do absolutely nothing on Teensy 3.0.

    I'd recommend adding const to that huge array. If you're not planning to compile on Teensy 2.0 or other AVR boards, you might as well remove the PROGMEM stuff. Accessing the array normally is much nicer and more readable code that using pgm_read_byte().

  3. #3
    Senior Member
    Join Date
    Sep 2015
    Location
    Taiwan, Asai. (Traditional Chinese)
    Posts
    167
    Quote Originally Posted by mortonkopf View Post
    PROGMEM is not needed in teensy 3.x, and you ......-on-Teensy-3-0[/url]
    thanks, nice to hear that i don't need to add PROGMEM anymore
    but that doesn't answer the problem why function uses const array gives incorrect result
    and
    void consttoserial(uint16_t *array) {/*****
    can't pass the compiler

    and my project would like to save as much sRAM as i could,
    it's not a good idea for me to turn const to ram array , and then to function, though that might work
    Last edited by Po Ting; 12-13-2015 at 11:07 AM.

  4. #4
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,757
    Your code does not compile when copied to Arduino. A semicolon is missing after the array, and you have no setup function. Please, follow the Forum Rule. Make sure the code you put into your question actually compiles and demonstrates the problem!

    Something to consider is your code contains an empty array. Using sizeof() for the array will return zero. For example, this code:

    Code:
    const uint16_t gammaTable[] = {/* .... */};
    
    void setup() {
    }
    
    void loop() {
      Serial.print("sizeof(gammaTable) = ");
      Serial.print(sizeof(gammaTable));
      Serial.print(", sizeof(*gammaTable) = ");
      Serial.print(sizeof(*gammaTable));
      Serial.println();
      delay(1000);
    }
    prints this in the serial monitor:

    Code:
    sizeof(gammaTable) = 0, sizeof(*gammaTable) = 2
    sizeof(gammaTable) = 0, sizeof(*gammaTable) = 2
    sizeof(gammaTable) = 0, sizeof(*gammaTable) = 2
    You claimed "sizeof(array) =4", so obviously the code you actually tried was different from the code you posted here on the forum!

    Please, try asking your question again. Before you post, verify the code from your message. Copy it back into Arduino and make sure it really does reproduce the problem. You can get good help here if you follow the Forum Rule. But questions with wrong code will only waste everyone's time!

  5. #5
    Senior Member
    Join Date
    Sep 2015
    Location
    Taiwan, Asai. (Traditional Chinese)
    Posts
    167
    sorry, about skipping the details and the rules...

    here's the complete code,
    compiled by arduino 1.6.5/ teensy3.1 w 96mhz, and teensy loader1.25 beta-2
    serial monitor from arduino

    const uint16_t gammaTable[] = {
    0, 1, 1, 2, 2, 3,};


    void setup() {
    Serial.begin(38400);
    delay(1000);
    Serial.println("TESTTEST");
    }


    void consttoserial(const uint16_t *gammaTable2){
    Serial.println(sizeof(gammaTable2));
    Serial.println( sizeof(*gammaTable2));
    Serial.println(sizeof(gammaTable2)/sizeof(*gammaTable2));
    for (int y=0;y<sizeof(gammaTable2)/sizeof(*gammaTable2);y++) {
    Serial.print(gammaTable2[y]);
    Serial.print("\t");
    if ((y+1)%16==0) {
    Serial.println("");
    }
    }

    }


    void loop() {
    consttoserial(gammaTable);
    delay(4000);
    }
    and it prints

    TESTTEST
    4
    2
    2
    0 1
    which means :
    sizeof(array) =4
    sizeof(*array) =2
    and the printed array = {0, 1}

    and with changed value of the array
    const uint16_t gammaTable[] = { 11, 22, 33 , 44 };
    i get
    TESTTEST
    4
    2
    2
    11 22
    which means only the first two value of the array is used in the function?
    and I also tried removing "const" in function and declaration , gets the same printed result.
    seems nothing to do with const ... at the same time, printing the same array in loop() or setup() gets the correct array
    here's another modified version
    uint16_t gammaTable[] = {
    256, 257, 33 , 44 };


    void setup() {
    Serial.begin(38400);
    delay(1000);
    Serial.println("TESTTEST");
    for (int y=0;y<sizeof(gammaTable)/sizeof(*gammaTable);y++) {
    Serial.print(gammaTable[y]);
    Serial.print("\t");
    if ((y+1)%16==0) {
    Serial.println("");
    }
    }
    }


    void consttoserial(uint16_t *gammaTable2){
    Serial.println(sizeof(gammaTable2));
    Serial.println( sizeof(*gammaTable2));
    Serial.println(sizeof(gammaTable2)/sizeof(*gammaTable2));
    for (int y=0;y<sizeof(gammaTable2)/sizeof(*gammaTable2);y++) {
    Serial.print(gammaTable2[y]);
    Serial.print("\t");
    if ((y+1)%16==0) {
    Serial.println("");
    }
    }

    }


    void loop() {
    consttoserial(gammaTable);
    delay(4000);
    }
    and gets

    TESTTEST
    256 257 33 44 4
    2
    2
    256 257
    i remember the file name sorting function in some POV project, the function with array works correctly, but with array size declared outside the function, might just the sizeof() function gets wrong result in functions,or the size of array is somehow wrong with the program, but the whole array is still readable and correct
    Last edited by Po Ting; 12-14-2015 at 07:50 AM. Reason: i remember...

  6. #6
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    921
    yes, your memory is right, sizeof() function only works with arrays defined at compile time, I believe, and using pointers (*array) might be the issue. I think that only the value two is returned as a pointer is two bytes long irrespective of the array size.

    EDIT: if you know how big your array is going to be, you can declare this such as
    uint16_t gammaTable[4] = ....

    Your code would mean that only two values of the array are printed, as the value of Y will not get higher than 4/2 = 2.
    Last edited by mortonkopf; 12-14-2015 at 10:52 AM.

  7. #7
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,851
    In C/C++, arrays are second class citizens. If you pass an array to a function, it gets converted to a pointer to the first element of the array, and you lose the size information. Typically you would need to pass the number of elements as an additional argument.

  8. #8
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,757
    Yes, gammaTable2 is a pointer to the table, not the table itself. You can't use sizeof() on a pointer to discover the actual size of whatever it points to.

  9. #9
    Senior Member
    Join Date
    Sep 2015
    Location
    Taiwan, Asai. (Traditional Chinese)
    Posts
    167
    In C/C++, arrays are second class citizens.
    not sure if i should feel sad ...

    thanks for everyone, the solution is simple, i shall make another variable array to store the array sizes, or store the array size in the first value of the array
    and just wondering, if it is possible to call the array through some kind of string functions, this could simplify the code, such as imagined code below
    int gammaTable0[]={1,2,3};
    int gammaTable1[]={2,3,6};
    ....
    int gammaTable9[]={2,3,6};
    for (int x =0;x<10;x++) {
    Serial.println("gammaTable"+x+"[]");
    }

  10. #10
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,757
    No, C/C++ do not provide really high-level functionality like automatically printing arrays, or even string concatenation.

    This stuff can be built using C++ objects. Arduino does have a String class which does some of this. But you'd have to use a C++ object for your array, and write the code for converting the array contents to a String object. Generally this is only done when writing libraries, since it's a lot more work than just writing the loop code directly.

  11. #11
    Senior Member
    Join Date
    Jun 2013
    Location
    So. Calif
    Posts
    2,828
    or a doubly dimensioned array
    int gammaTable0[][] =
    do you know the max size of each dimension at compile time?

  12. #12
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,851
    When you create the array for static/global/stack elements, the compiler has to know the dimensions. You can have the dimensions variable, but this introduces extra overhead, and you have to have enough stack or heap space to allocate the array.

  13. #13
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    921
    @Po Ting, hopefully your query is sorted now, but on the printing out of array values you would iterate through, using a for loop to place the array value position within the square brackets:
    for (int x =0;x<10;x++) {
    Serial.print("gammaTable[x]");
    }

  14. #14
    Senior Member
    Join Date
    Sep 2015
    Location
    Taiwan, Asai. (Traditional Chinese)
    Posts
    167
    Quote Originally Posted by stevech View Post
    or a doubly dimensioned array
    int gammaTable0[][] =
    do you know the max size of each dimension at compile time?
    I know, but changing picture consts each time and add more pictures
    could be a lot of enumeration hard working if more flash and picture added or changed.
    I already use 2 dimensions for easier access like
    #define pixels 36
    int gammaTable0[][pixels] = {....} ;
    and the problem is, the picture height of each picture in POV differs, and its difficult to use the same maximum height for each.
    with a 36*80 bmp, 256KB could take about 20 of them in flash. not sure if I could set different height, or use 3 dimension for storing different picture.
    I think I need more examples of those second citizens

    and also, the converter at poisonic gives array with 24 bit, but since without cutting , declaring array with 32 bit wastes some? , not sure if uint24_t exists or i must cut them to byte array if I really want to save some flash
    and must talk about my project i guess, I use teensy 3.1 / micro SD adapter and TLC5947 for the POV
    showing pictures if SD availables,and constant stored pics if SD was not.
    the core could work fine,or at least with enumerated const array showing function,

    another thing I might need is the while connecting the POV with USB, I'm unable to read the SD directly
    I've found some LUFA library discussion in the forum and other webs.
    and mostly written in C? /makefile or something, I couldn't fully understand the C code or how to use them.
    simply I need any example on teensyduino.
    and if i should move those questions to project guidance page?

    thanks for all the help,

  15. #15
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    921
    Quote Originally Posted by Po Ting View Post
    and also, the converter at poisonic gives array with 24 bit, but since without cutting , declaring array with 32 bit wastes some? , not sure if uint24_t exists or i must cut them to byte array if I really want to save some flash
    You could just store your image pixel values as a series of byte type rather than int type. if you convert your image to this, and then just loop through the byte array three bytes at a time, you could avoid the "unused byte space" on the int. It just means writing you own loop function, and using a different image converter to output the pixels into the right format.
    EDIT: actually I am not sure that this would work to reduce space.

    The reason I wrote the PoiSonic 24bit image converter was to have something human readable (the hex array) and directed at those just wanting to shove pixel data into the apa102 pixels.

    Also, i think that I have a project that enumerated through arrays with consecutive alphanumeric names. I will go through my archive to see if it is appropriate / useful.
    Last edited by mortonkopf; 12-15-2015 at 01:08 PM.

  16. #16
    Senior Member
    Join Date
    Sep 2015
    Location
    Taiwan, Asai. (Traditional Chinese)
    Posts
    167
    thanks for @mortonkopf, the idea might save some byte, though teensyduino seems to ignore the bytes/arrays unused at compiler
    so I can't directly know the different. but with function printing the arrays, I can.
    my language in coding is poor, and thus i can't bitbang bmp out into byte arrays directly
    but through your converter page, and another Arduino program i just wrote(?) i can receive the byte-cutted array value at Serial.monitor
    and it needs teensy 3.1 to run, LC doesn't carry enough sram.
    lol, using teensy on some minus purpose. 64kb sram is pretty powerful.

    the 64kb sram is used in my pov project for another powerful usage.

    const uint32_t array1[] = { 0x000000,....., }; //end of array
    uint8_t gammaTable[80 * 108] = {};

    void setup() {
    Serial.begin(38400);
    delay(1000);
    Serial.println("TESTTEST");
    }

    void consttoserial(uint8_t gammaTable2[]) {

    Serial.println("");
    for (int y = 0; y < sizeof(gammaTable); y++) {
    Serial.print("0x");
    Serial.print(gammaTable2[y], HEX);
    Serial.print(",\t");

    if ((y + 1) % 18 == 0) {
    Serial.println("");
    }
    }
    }


    void loop() {
    long count = micros();
    for (int x = 0; x < 80 * 36; x++) {

    gammaTable[3 * x] = array1[x] >> 16;

    gammaTable[3 * x + 1] = array1[x] >> 8;

    gammaTable[3 * x + 2] = array1[x];

    }
    consttoserial(gammaTable);

    Serial.println("");
    Serial.print("time cost : us");
    Serial.println(micros() - count);
    while (true) {
    delay(30000);
    }
    }
    the size of int hex array above is 36*80 ,
    and i get 24,040 bytes from the one with byte array, 27,056 bytes with int array.
    and 35,744 with both arrays,
    from calculations, I should save at least 36*80=2,880 bytes in this array(25%, from 4 byte to 3 byte per RGB pixel),
    and it saves somewhat more, maybe from function or somewhere, if the compiler was honest

    I guess for a few pictures, some hardwork is acceptable,
    Last edited by Po Ting; 12-15-2015 at 05:32 PM. Reason: if the compiler was honest

  17. #17
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    921
    @Po Ting, below is code that accepts different array sizes, and loops through the array. it removes the hard baked code by passing the size and the array name to a function that then does the work. this way you you just put in the array size in the call to the function. You can go a step further if you want, by listing all the array sizes in their own array, and calling those.
    Code:
    const unsigned int array1[] ={1,2,3,4,5,6,7,8,9};
    const unsigned int array2[] ={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
    
    void setup() {
      // put your setup code here, to run once:
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
    arrayDisplay(10, array1);
    arrayDisplay(20, array2);
    }
    
    void arrayDisplay(int Sizes , const unsigned int array[]){
        //run you array display code here, with the given array size
    Serial.println("");
    for (int y = 0; y < Sizes; y++) {
    Serial.print("0x");
    Serial.print(array[y], DEC);
    Serial.print(",\t");
    
    if ((y + 1) % 18 == 0) {
    Serial.println("");
          }
        }
    }

  18. #18
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany NRW
    Posts
    6,925
    or like this (no need to count...)
    Code:
    arrayDisplay(sizeof(array1)/sizeof(unsigned int), array1);
    arrayDisplay(sizeof(array2)/sizeof(unsigned int), array2);
    edit:
    of course, you can use this to declare a const or #define.
    Last edited by Frank B; 12-15-2015 at 08:15 PM.

  19. #19
    Senior Member mortonkopf's Avatar
    Join Date
    Apr 2013
    Location
    London, uk
    Posts
    921
    @Frank B - that looks good. so, whatever type your array is declared as, just divide by that types size. so simple. even less hard baked.

  20. #20
    Senior Member
    Join Date
    Sep 2015
    Location
    Taiwan, Asai. (Traditional Chinese)
    Posts
    167
    have to say, after discussed
    I have no trouble counting the array index or size,
    but just disturbing if I need to use another array/variable for sizes
    I would prefer for loop to display all the const pictures if possible,
    as I display SD-pictures with for loop(even with different durations!details stored in file names, changed from POV codes from the community)
    imagine if you need to change your code everytime you change your .bmps in your SDcard
    bmpDraw("picture1.bmp"); bmpDraw("supersiajin.bmp");... and etc

    compared to const pic, unless I limit all the image to the same height, or i would need to type the array names
    (as array1[], array2[], array3[].... etc) to the function separately because they carry different height,
    and that just makes coding little bit annoyed with enumeration.

  21. #21
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany NRW
    Posts
    6,925
    Why don't you read the dimensions from the bmp file ? In that case you don't need const arrays.

    https://en.wikipedia.org/wiki/BMP_fi...ap_file_header

    If you still want arrays, just declare a struct with the array and a size-information (or ..slightly enhanced..an array of structs..;-) ), and use a pointer to this struct in your function().

  22. #22
    Senior Member
    Join Date
    Sep 2015
    Location
    Taiwan, Asai. (Traditional Chinese)
    Posts
    167
    Quote Originally Posted by Frank B View Post
    Why don't you read the dimensions from the bmp file ? In that case you don't need const arrays.

    https://en.wikipedia.org/wiki/BMP_fi...ap_file_header

    If you still want arrays, just declare a struct with the array and a size-information (or ..slightly enhanced..an array of structs..;-) ), and use a pointer to this struct in your function().

    i don't understand your meaning, is a struct a class or something? and do you mean there is possible to store the .bmp directly in the program flash?

  23. #23
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany NRW
    Posts
    6,925
    Quote Originally Posted by Po Ting View Post
    i don't understand your meaning, is a struct a class or something? and do you mean there is possible to store the .bmp directly in the program flash?
    struct: https://en.wikipedia.org/wiki/Struct...ming_language)

    You could load the BMPs into the Ram, only the one that is displayed.
    How big are they, how many pixels?
    Last edited by Frank B; 12-16-2015 at 09:48 AM.

Posting Permissions

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