HOWTO · Arduino
Arduino 어레이 길이
고정 크기 Arduino 배열의 요소 수를 `sizeof()` 연산자로 구하는 방법을 알아보세요.
이 페이지의 내용
Arduino의 고정 크기 배열은 배열 전체를 확인할 수 있는 범위에서 sizeof(array) / sizeof(array[0])로 요소 수를 구할 수 있습니다. 결과는 요소 개수이므로 반복문의 상한으로 사용할 수 있습니다. sizeof()는 바이트 수를 측정하며, 배열 전체의 바이트 크기를 요소 하나의 바이트 크기로 나누면 요소 수를 얻습니다.
Arduino 배열의 길이를 sizeof()로 구하기
예를 들어 values에 정수 다섯 개가 들어 있다면 sizeof(values) / sizeof(values[0])의 결과는 5입니다. 이 시점에는 values가 배열 전체를 나타내므로 이 계산이 가능합니다. 분모에서 해당 배열의 첫 요소 크기를 사용하기 때문에 다른 자료형의 고정 크기 배열에도 같은 식을 적용할 수 있습니다.
sizeof() 나눗셈이 동작하는 이유
sizeof는 함수가 아니라 C++ 연산자입니다. 배열에 적용하면 배열 전체가 차지하는 바이트 수를 알려 줍니다. array[0]에 적용하면 요소 하나가 차지하는 바이트 수를 알려 줍니다. 첫 번째 크기를 두 번째 크기로 나누면 요소 수를 얻습니다. 두 식이 실제 배열과 그 요소 자료형을 가리키는 경우에 성립합니다.
예를 들어 이 식은 고정 크기 float 배열의 요소 수도 구할 수 있으며, 특정 보드에서 float가 몇 바이트인지 미리 가정할 필요가 없습니다. 두 크기는 같은 자료형과 대상 환경을 기준으로 정해지므로 그 비율이 요소 수입니다. 4처럼 바이트 크기를 하드 코딩하지 마세요. 반복문에 필요한 값은 요소 수입니다.
다른 배열 자료형과 차원에 공식 적용하기
요소 자료형이 달라도 공식은 같습니다. readings라는 배열의 요소 수는 sizeof(readings) / sizeof(readings[0])로 구합니다. 초기화 목록을 바꾸더라도 별도의 숫자를 수정할 필요 없이 선언된 배열에 맞춰 개수가 정해집니다.
2차원 고정 크기 배열에서는 배열 전체의 크기를 첫 번째 행의 크기로 나누어 행 수를 구합니다. 첫 번째 행의 크기를 그 행의 첫 요소 크기로 나누면 열 수를 구할 수 있습니다. 예를 들어 int matrix[3][4]에서 sizeof(matrix) / sizeof(matrix[0])는 행 수이고, sizeof(matrix[0]) / sizeof(matrix[0][0])는 열 수입니다. 이 식은 선언된 차원의 크기를 나타내며, 실행 중 크기가 달라지는 컬렉션의 현재 길이를 알아내지는 않습니다.
함수에 배열을 전달할 때 배열 길이 처리하기
배열을 함수 매개변수로 전달하면 해당 매개변수는 첫 요소를 가리키는 포인터로 취급됩니다. 함수 안에서 sizeof(parameter)를 사용하면 호출한 쪽의 배열 전체가 아니라 포인터의 크기를 측정합니다. 따라서 이를 sizeof(parameter[0])으로 나누어도 원래 배열의 요소 수를 알아낼 수 없습니다.
요소 수를 별도 매개변수로 전달하고 반복문의 상한으로 사용하세요. 배열 전체를 확인할 수 있는 호출 지점에서 개수를 계산하면 됩니다. 예를 들면 printValues(values, sizeof(values) / sizeof(values[0]))와 같습니다. 그러면 함수가 전달받은 개수만큼 요소를 처리할 수 있습니다. 여러 함수를 거쳐 배열을 전달할 때는 각 함수가 필요한 정보를 갖도록 배열과 개수를 함께 전달하세요.
sizeof 공식은 식을 계산하는 위치에서 전체 형식을 알 수 있는 고정 크기 배열에 적용됩니다. 실행 중 크기가 바뀌거나 동적으로 할당된 컬렉션의 길이를 추적하지는 않습니다. 그런 경우에는 컬렉션 자체의 길이 확인 방법으로 요소 수를 보관하거나 가져와야 합니다.
Arduino 스케치에서 길이 사용하기
Arduino 스케치에서는 고정 크기 배열을 파일 범위나 setup() 안에 선언하고 같은 범위에서 요소 수를 계산한 다음, 인덱스 0부터 인덱스가 그 개수보다 작은 동안 반복합니다. 이렇게 하면 선언된 배열 범위 안에서 각 요소에 접근할 수 있습니다. 아래 스케치는 보드에서 Arduino의 Serial을 사용합니다. 일반 C++로 컴파일할 때는 간단한 로컬 Serial 대체 구현을 사용해 같은 setup() 로직이 표준 출력에 표시되도록 합니다. 코드와 출력은 그대로 유지되며, 예시에서 영어로 표시되는 레이블은 Count:뿐입니다.
이 섹션의 코드와 표시되는 레이블 또는 출력은 영어로 유지됩니다.
#include <stddef.h>
#ifdef ARDUINO
#include <Arduino.h>
#else
#include <iostream>
class SerialPort {
public:
void begin(unsigned long) {}
void print(const char* value) { std::cout << value; }
template <typename T>
void println(const T& value) { std::cout << value << '\n'; }
};
SerialPort Serial;
#endif
int values[] = {10, 20, 30, 40, 50};
const size_t valueCount = sizeof(values) / sizeof(values[0]);
void setup() {
Serial.begin(9600);
for (size_t i = 0; i < valueCount; ++i) {
Serial.println(values[i]);
}
Serial.print("Count: ");
Serial.println(valueCount);
}
void loop() {
}
#ifndef ARDUINO
int main() {
setup();
}
#endif
10
20
30
40
50
Count: 5
보드에 스케치를 업로드한 뒤 9600 보드레이트로 시리얼 모니터를 열면 값과 개수를 확인할 수 있습니다. 반복문을 보조 함수로 옮긴다면 배열과 함께 valueCount도 명시적으로 전달하세요. 보조 함수는 포인터 매개변수만으로 원래 배열의 길이를 알아낼 수 없습니다.