C/C++에는 의외로 많은 개발자가 모르는 흥미로운 특징이 있습니다. 바로 배열 첨자 표기법에서 a[i]를 i[a]처럼 뒤집어 쓸 수도 있다는 점입니다. 얼핏 보면 문법 오류처럼 보이지만, 실제로는 아무 문제 없이 컴파일되며 완전히 동일한 결과를 출력합니다.
왜 이런 일이 가능할까요?
그 비밀은 C/C++ 표준의 배열 첨자 연산 정의에 숨어 있습니다. C/C++에서 E1[E2]는 항상 다음과 같이 정의됩니다.
E1[E2] → *((E1) + (E2))
즉, 컴파일러는 내부적으로 포인터 산술(pointer arithmetic)을 수행하여 배열 요소에 접근합니다. 여기에 이항 + 연산자에 적용되는 형 변환 규칙이 더해집니다. E1이 배열 객체이고 E2가 정수라면, E1[E2]는 배열 E1의 E2번째 요소를 의미하게 됩니다.
핵심은 덧셈은 교환 법칙이 성립한다는 점입니다. 따라서 다음 두 식은 완전히 동일합니다.
a[i] = *(a + i) i[a] = *(i + a)
포인터 산술 관점에서 (a + i)와 (i + a)는 같은 메모리 주소를 가리키므로, 결국 a[i]와 i[a]는 본질적으로 같은 표현식인 셈입니다.
예제 코드
#include <iostream>
using namespace std;
int main() {
int array[] = {1, 2, 3, 4, 5, 6, 7};
cout << "array[5] is " << array[5] << endl;
cout << "5[array] is " << 5[array];
}실행 결과
array[5] is 6 5[array] is 6
정리
배열 첨자 연산은 문법적 설탕(syntactic sugar)일 뿐, 실제로는 포인터와 오프셋의 덧셈으로 변환됩니다. 덧셈의 교환 법칙 때문에 피연산자의 순서를 바꿔도 결과가 달라지지 않으며, 그래서 a[i]와 i[a]가 같은 값이 되는 것입니다. 물론 실무 코드에서는 가독성을 위해 반드시 a[i] 형태로 작성하는 것이 좋습니다.