컴파일러

위의 함수에서 컴파일러가 *b의 읽기를 루프 밖으로 내보내는 최적화를 그대로는 수행할 수 없는 이유는?

void add(int *a, int *b, int n) {
    for (int i = 0; i < n; i++)
        a[i] += *b;
}
  1. A*b는 정수이므로 루프 밖으로 내보내면 값의 정밀도가 떨어지기 때문에
  2. Ba와 b가 같은 장소를 가리킬 가능성이 있어 a[i]에 대한 쓰기로 *b가 바뀔 수 있기 때문에
  3. C포인터를 인수로 받는 함수는 컴파일러가 일절 최적화해서는 안 된다는 규칙이 있기 때문에
정답과 해설 보기

정답: B. a와 b가 같은 장소를 가리킬 가능성이 있어 a[i]에 대한 쓰기로 *b가 바뀔 수 있기 때문에

얼핏 보면 *b는 루프 안에서 바뀌지 않으므로 1번만 읽으면 될 것 같습니다. 그러나 호출하는 쪽이 add(x, &x[3], n)처럼 b가 a의 요소를 가리키는 포인터를 전달하면, a[3]에 대한 쓰기로 *b의 값이 바뀝니다. 컴파일러는 이 가능성(에일리어스)을 부정할 수 없으므로 매번 다시 읽는 코드를 생성합니다. C 언어에서는 포인터에 restrict를 붙여 다른 장소를 가리킨다고 약속하면 최적화할 수 있습니다. 정밀도의 문제도, 최적화가 금지되어 있는 것도 아닙니다.

  • A. 정수 읽기를 옮겨도 정밀도는 변하지 않습니다.
  • B. 올바릅니다. a와 b가 겹칠 가능성(에일리어스)이 있기 때문입니다.
  • C. 포인터를 사용하는 함수도 최적화됩니다.
이 분야 연습하기 분야로 돌아가기

컴파일러의 다른 문제

  1. 컴파일러의 레지스터 할당에서 간섭 그래프를 색칠하는(채색하는) 방법을 사용할 때, 그래프의 노드와 간선이 나타내는 것의 조합으로 올바른 것은?
  2. 레지스터 할당에서 「스필」이 일어나면 생성되는 코드는 어떻게 되는가?
  3. 컴파일러의 명령 스케줄링의 주된 목적은?
  4. 위의 함수의 마지막 재귀 호출에 꼬리 호출 최적화를 적용하면 어떤 효과가 있는가?
  5. 컴파일러와 인터프리터의 차이로 올바른 것은?

이 분야의 비교