I am writing a function for use in a LED project on a esp32. I am using 2D arrays to store RGB hex codes and calling my gradientFunction to send to a BLE controller, but the number colors of may vary:
...
if (counter == 0) {
uint8_t rgb[4][3] = { {0xff, 0x00, 0x00}, {0xff, 0x11, 0x11}, {0xea, 0x1f, 0x10}, {0xff, 0x00, 0x00} };
gradientFunction(rgb);
Serial.println("Red gradient");
}
}
void gradientFunction(uint8_t rgb[][3]) {
int length = sizeof(rgb) / sizeof(rgb[0]);
Serial.println(length);
for (int i = 0; i < length; i++) {
uint8_t bytes[9] = {0x7b, 0x01 + i, 0x0e, 0xfd, rgb[i][0], rgb[i][1], rgb[i][2], length, 0xbf};
pRemoteCharacteristic->writeValue(bytes, 9);
delay(100);
}
}
However, calculating the number of rows (length) returns 1. Printing sizeof(rgb) returns 4 and sizeof(rgb[0]) returns 3. This results in only 1 color code being transmitted to the BLE controller.
I can't seem to figure where I am going wrong with calculating the number of rows, or am I calling the function incorrectly?
C programming FAQ: an array when passed to a function "decays" into a pointer to the first element. This is the very reason why you are able to type uint8_t rgb[][3]
with an empty dimension to begin with: the first item of an array of dimensions uint8_t [n][3]
is always uint8_t [3]
regardless of n.
Therefore sizeof(rgb)
gives the size of a pointer to the first element. The first element being uint8_t [3]
and a pointer to one being uint8_t (*)[3]
. Size 4 on a 32 bit ESP32.
Whereas sizeof(rgb[0])
actually gives the size of the first element, similar to sizeof(uint8_t[3])
, meaning 3.
4 / 3 with integer arithmetic gives a truncated 1.
To solve this, rewrite the function like this instead:
void gradientFunction(uint8_t x, uint8_t y, uint8_t rgb[x][y]) {
uint16_t size = x * y;
This of course assuming that x and y are never larger than 255. Since this is a microcontroller, I'm intentionally using as small as possible integer types. On a PC you wouldn't care and use size_t
instead.