Possible bug about using const array in functions?

Status
Not open for further replies.

Po Ting

Well-known member
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("");
}
}
}
 
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-PROGMEM-use-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().
 
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:
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!
 
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:
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:
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.
 
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.
 
In C/C++, arrays are second class citizens.
not sure if i should feel sad :confused:...

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+"[]");
}
 
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.
 
or a doubly dimensioned array
int gammaTable0[][] =
do you know the max size of each dimension at compile time?
 
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.
 
@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]");
}
 
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,
 
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:
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. :p 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:
@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("");
      }
    }
}
 
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:
@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.
 
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.
 
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_file_format#Bitmap_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?
 
Status
Not open for further replies.
Back
Top