C 언어 | 흐름 제어 | 진위 판정

두 값의 대소 관계를 확인해서 관계 연산이나, 두 값이 동일한지 여부를 확인하는 등가 연산을 소개한다.

관계 연산과 등가 연산

지금까지의 프로그램은 항상 위에서 아래로 순서대로 실행되는 순서대로 실행했지만 프로그램은 상황에 따라 처리를 변경시킬 필요가 있다. 즉, 분기나 반복하는 처리이다. 이러한 조건 분기나 반복 처리 프로그래밍의 기본 중의 기본이며, 가장 중요한 부분이기도 하므로, 이 장에서는 철저히 그 구조를 설명하고, 프로그램의 흐름을 자유롭게 제어할 수 있게 될 때까지 해보도록 하자.

프로그램은 프로그램의 흐름을 제어하기 위해 어떤 정보를 소재로 해야 한다. 예를 들어, “변수 A가 100 이하 이면” 또는 “변수 A와 변수 B의 값이 같으면"과 같은 비교의 결과로 프로그램을 분기시킬 수 있다면, 상황에 따른 적절한 처리로 진행할 수 있다고 생각할 수 있다.

그래서 C 언어에는 비교 결과가 참(TRUE) 또는 거짓(FALSE)인지에 따라 상황을 판단한다. 진위는 값에 의해 식별되도록 0이면 거짓, 그렇지 않으면 참이라고 해석된다. 예를 들어, 변수 A가 변수 B와 동일한지 여부를 판단한 결과, 동일한 상태를 참이라고 하고, 동일하지 않은 상태를 거짓이라고 한다.

일반적으로 값의 비교는 관계 연산자, 등가 연산자 및 논리적 연산자를 사용한다. 이러한 연산자는 표현식을 확인하여, 그 결과에 따라 참 또는 거짓을 반환한다. 사실 실체는 수치이므로 이러한 연산자가 반환하는 결과는 int형이다. 각 연산자는 표1에 정리한다.

표1

관계 연산자

연산자 내용
A < B A가 B보다 작으면 참
A <= B A가 B와 같거나 작으면 참
A > B A가 B보다 크면 참
A >= B A가 B와 같거나 크면 참

등가 · 부등가 연산자

연산자 내용
A == B A와 B가 같으면 참
A != B A와 B가 같지 않으면 참

논리 연산자

연산자 내용
A && B A와 B가 참이면 참
A || B A 또는 B가 참이면 참
!A A가 거짓이면 참

“같으면"라고 판단을 할 경우는 A = B가 아니라 A == B인 점에 유의하자. A = B로 기술하면 B를 A에 대입한다는 의미가 되어 버리기 때문에 잘못된 결과를 얻을 수 있게 될 것이다. 해당 연산에 의한 실수를 방지하기 위해서는 왼쪽 피연산자에 상수를 가져오는 습관을 들이는 방법이 있다. 왼쪽 피연산자가 정수의 경우 실수로 대입 연산자 =를 지정 버려도 상수 값을 할당할 수 없기 때문에 컴파일 오류가 발생한다. 따라서 등가 연산을 지정하는 곳에 대입 연산자를 지정하는 실수에 알아차릴 수 있을 것이다.

그러나 (A = B) == 0 구문은 잘못 곳이 않았다. 대입 연산자 =는 결과(이 경우는 최종적인 A의 값)을 반환하기 위해, 어떤 계산 결과를 판단하고자 하는 경우에 사용하는 것은 가능하다. 예를 들어, 어떤 계산을하고 그 결과를 변수에 저장한 후, 오류 검사 등을 실시하는 경우에 이를 이용할 수 있다. B + C의 결과를 A에 저장하지만, 그 결과가 0인지 여부를 판단하는 경우 (A = B + C) == 0라고 기술하면, 그 진위를 묻는 수 있다 .

논리 연산자는 등가 · 부등가 연산자보다 등가 · 부등가 연산자는 관계 연산자보다 우선 순위가 낮기 때문에, 이러한 연산자를 동시에 사용하는 경우는 의식할 필요가 있다.

코드1

#include <stdio.h>

int main() {
 int iVar1 , iVar2;
  printf("2개 값을 입력해 주세요. >");
 scanf("%d %d" , &iVar1 , &iVar2);

 printf("iVar1 == iVar2 = %d\n" , iVar1 == iVar2);
  printf("iVar1 < 1000 = %d\n" , iVar1 < 1000);
  printf("iVar1 < iVar2 && iVar1 > 100 = %d\n" , (iVar1 < iVar2) && (iVar1 > 100));

  return 0;
}

이 프로그램을 실행하면 두 값을 입력하도록 요구한다. 값은 iVar1과 iVar2 변수에 각각 저장되어 다음 조건식에 의해 그 값의 관계를 확인하고 있다.

최초의 printf()는 iVar1과 iVar2가 동일한지 여부를 확인한다. 만약, 입력한 두 값이 동일한 값이면, 이 결과는 참이 되므로 0이 아닌 값이 출력된다. 일반적으로 참을 나타내는 0 이외의 값은 1이 사용된다. 다음의 printf() 함수는 iVar1가 1000보다 낮은지 여부를 확인한 결과를 출력하고, 마지막 printf() 함수는 iVar1이 iVar2보다 낮고, iVar1가 100보다 큰지 여부를 확인한 결과를 출력한다.

마지막의 논리 연산자 &&를 이용한 조건식은 조금 복잡하게 보이지만, 이렇게 하면 매우 유연한 비교를 할 수 있다. && 연산자에 의해 “좌우의 비교 결과가 참일 때만 참이다"라는 체크를 할 수 있다.

&&와 || 특징으로 조건에 따라서는 왼쪽 피연산자를 분석한 시점에서 결과를 알 수 있다. 논리 연산자는 항상 왼쪽 피연산자에서 오른쪽 피연산자의 순서로 분석하는 것이지만, &&는 피연산자가 거짓이면 다른 피연산자가 어떻든 간에 결과는 거짓이다. 따라서 만약 왼쪽 피연산자가 거짓이면 오른쪽 피연산자이 어째던 결과는 항상 거짓임을 보장되기 때문에 프로그램은 오른쪽 피연산자를 확인하지 않고 false를 반환한다. 마찬가지로 || 연산자의 경우는 한쪽이 피연산자가 참이면 그 결과는 항상 참임을 보장되므로 왼쪽 피연산자가 참이면, 오른쪽 피연산자는 확인하지 않고 참을 반환한다.

항상 이것을 의식할 필요는 없지만, 진위 여부를 확인시에 어떤 연산을 수행하는 식이 포함된 경우는 위험하다. 예를 들어, 논리 연산자의 오른쪽 피연산자로 증가 또는 감소를 사용한 경우 왼쪽 피연산자만으로 결과가 판정되어 버리면, 오른쪽 피연산자는 계산되지 않는다. 이것은 코드2에서 입증될 수 있다.

코드2

#include <stdio.h>

int main() {
 int iVar = 0 , iTmp;

  iTmp = 0 && iVar++;
 printf("iVar = %d\n" , iVar);
  return 0;
}

코드2의 iTmp = 0 && iVar ++;행을 보도록 한다. 왼쪽 피연산자에 상수 0을 지정하고 있는데, 이는 곧 거짓이다. 프로그램은 왼쪽 피연산자를 확인한 시점에 이 식의 결과가 거짓임을 보증할 수 있기 때문에, 오른쪽 피연산자를 확인할 필요가 없다. 따라서 iVar++는 실행되지 않기 않아서 printf는 iVar 값을 0으로 표시하는 것이다. 6번째 줄의 코드를 1 && iVar ++와 같이 써서 변경하면 iVar++가 수행이 되고확인한다는 것을 확인할 수 있다.

그런데 “한쪽이 참, 다른 한쪽이 거짓일 때 참"이라는 결과를 얻고 싶다면 어떻게하면 좋을까? 이런 논리 연산을 배타적 논리합이라고 한다. 배타적 논리합은 C 언어의 3가지 논리 연산자를 사용하여 계산할 수 있다. 비트 논리 연산과 혼동하지 말자. 여기의 배타적 논리합은 조건식의 논리 값을 얻기 위한 것이다.

이것을 실현하려면 평가해야 두 피연산자 중 하나가 참인지 확인하고, 쌍방이 참이라면 부정해서 거짓으로하면 된다. 한쪽이 참이면 참인 것은 논리합 bool1 || bool2, 양쪽이 참이라면 참인 것은 논리곱 bool1 && bool2이다. 첫번째는 논리합과 논리곱을 부정한 결과를 논리곱을 구한다.

(bool1 || bool2) && !(bool1 && bool2)

이를 구하면 bool1과 bool2 중 “한쪽은 참, 다른 한쪽은 거짓이면 참"이라는 배타적인 결과를 얻을 수 있다.

코드3

#include <stdio.h>

int main()
{
  int iBool1 , iBool2;
  printf("2개의 연산값을 입력해 주세요. >");
  scanf("%d %d" , &iBool1 , &iBool2);

 printf("iBool1 XOR iBool2 = %d\n" , (iBool1 || iBool2) && !(iBool1 && iBool2));
  return 0;
}

이것은 입력된 두 값 중에 한쪽이 참이고 다른 한쪽이 거짓인 경우에만 참인 결과를 얻기위한 테스트 프로그램이다. 양쪽의 피연산자가 거짓 또는 진실인 경우는 0(거짓)이 표시되고, 그렇지 않으면 1(참)인 결과를 얻을 수 있을 것이다.