C언어 기초 – 표현식 – C언어 강의 9

C언어 기초 – 표현식

C언어로 쓰여진 소스 코드를 분해하다 보면 표현식, 문장, 블록과 같은 용어를 듣게 됩니다. C언어가 아니라 자바, 파이썬 같은 고급언어에서 자주 듣게 되는 용어로 꼭 C뿐만 아니라 다른 언어에서도 적용되니까 C에서 개념을 확립하는 것이 좋습니다. C언어는 언어 자체의 가치가 높지만 이를 잘 배워두면 향후 다른 언어를 마스터하기 위한 기초 지식으로 작용하는 경우가 많습니다.

초반부가 다소 지루한 것이 벽이긴 한데 시작이 쉬운 다른 상업용 언어들과 달리 학습에 대한 내적인 보상이 좀 늦은 만큼 지식의 기쁨도 크다고 할 수 있습니다. 학습이 어려울 때는 밑바탕을 완성해간다고 생각하면 좋을 듯 합니다.

표현식(Expresssion)

표현식의 원어는 Expression 으로 사전의 번역은 ‘표현’입니다. 캠브리지 영영 사전에서는 the act of saying what you think or showing how you feel using words or actions: 으로 당신이 생각하는 것을 말하는 것 혹은 단어나 행동을 사용하는 것을 어떻게 느끼는지 보여주는 것 입니다.

문장(statement)은 표현식의 조합으로 구성되고 표현식은 연산자와 피연산자의 조합입니다.

C언어의 표현식은 코드의 생각, 즉 의도를 담고 있습니다. 상수인 3, 7이나 연산자 +나 -는 그 자체로 어떤 의미를 가지지 않습니다. 예를 들어서 소스코드에 3 7 + – 0 x var 같은 요소를 나열해도 그 자체로는 의미가 없습니다.

그러나 이것들을 조합하여 표현식을 만들면 3+7 과 같은 의미가 만들어 집니다. 사람은 3+7 을 보면 자동으로 10을 떠올립니다. 프로그래밍의 표현식 3 + 7은 CPU관점으로 해석합니다. 3을 범용 레지스터 ax에 load(적재)하고 7을 ax에 가산하라는 명령어가 작동합니다. 3과 7은 이진수인 0000 0011, 0000 0111 로 변환되어서 가산(add)기를 실행합니다. 여기다가 a = 3 + 7 같은 할당연산자를 결합하면 이제 3+7의 결과를 레지스터에서 가져와서 a라는 변수의 메모리에 입력하는 동작을 합니다. 이것도 표현식입니다.

*표현식은 연산자와 피연산자의 조합입니다. 연산자(Operator)에는 + – * / 같은 기본 연산자가 있고 사용자가 정의 연산자를 만드는 것고 허용됩니다. 피연산자(Operand)는 5, 3.14 같이 상수와 변수들이 될 수 있습니다. 예를 들어 3 이나 -4 같은 상수도 표현식입니다.(- 부호는 단항연산자지만 편의상 상수로 취급) 다음은 표현식의 예입니다.

  • 3, 10, -20 -> 정수 상수
  • 3.14, -0.999 -> 부동소수점 상수
  • 2+2, 5-2, 3*2, 10/2 -> 사칙연산
  • x = 3 *3 -> 사칙연산 + 할당 연산자
  • x++, –x -> 증감연산자
  • count < 5, x == 1 -> 관계연산자
  • (a > 1) && 1 -> 논리연산자

표현식은 연산자가 하나만 있는 경우, 피연산자가 하나만 있는 경우 등 다양한 조합을 만들 수 있지만 C언어의 중요한 특징은 어떤 표현식라도 최종적인 하나의 값을 가진다는 것 입니다. C언어의 특징에 대해서 좀더 알아보겠습니다. 표현식 3 + 5 의 결과값은 8 입니다. 이 정도는 이해가 쉽습니다. 그렇다면 3 + 5 * 2 는 어떨까요? 연산자에는 우선순위가 있어서 3 + (5*2) 와 같은 중간 단계를 거쳐서 13 이 됩니다. 이것을 연산할 때는 5와 2를 곱한 값 10이 중간 계산 결과이고 다시 3 과 10을 더한 값이 표현식의 최종 값입니다. 5*2의 결과값은 보이지 않지만 존재합니다. 3 + 5 * 2 – 8 / 2 + 7 같이 보이지 않는 단계가 늘어나는데 표현식을 작성할 때 고려해야 할 사항입니다. (이 과정을 조절함으로써 효율성을 높인다)

또 하나는 a = 3+5 같은 표현식입니다. 이 표현식도 결과값을 갖나요? 그렇습니다. 예를 들면 아래와 같은 코드는 8의 결과를 리턴합니다. a에 8을 할당하지만 표현식의 값은 8이라는 뜻입니다. a에 8을 할당하는 행위가 표현식이기도 하지만 그 결과는 8입니다. a라는 변수에 8을 저장하는 것과 8이라는 표현식의 리턴값을 가지는 것의 미묘한 차이가 있다는 점은 중요합니다.

int a;
printf("%d\n",(a = 3+5));

표현식의 최종값은 관계연산자 <, > 들이나 논리연산자 &&, || 들에도 적용됩니다. 아래 코드의 실행값은 0 입니다. 비교를 해서 참과 거짓을 평가하는 동작과 그 동작의 결과로 나오는 표현식의 값을 구분합니다.

int count = 0;

printf("%d\n",count < 5);

lvalue와 rvalue

표현식에는 2+1 처럼 계산을 하는 동작이 있고 a = 3 처럼 할당하는 동작이 있습니다. 할당할 때 양쪽을 나눠서 a를 lvalue 3을 rvalue 라고 합니다. a는 lvalue가 될 수 있지만 3은 될 수 없습니다. 그 이유는 lvalue에는 어떤 값을 할당하기 위한 변수가 필요하기 때문입니다. 3은 상수로 3에 7을 할당하거나 9를 할당할 수 없습니다. 당연한 말 같지만 컴퓨터는 3이란 메모리 장소에 0011 이란 기계어로 정의했기 때문에 여기에 0111 (7) 이나 1001 (9)를 저장하지 않습니다. 3 = 7이라는 표현식의 컴파일을 시도하면 C컴파일러는 lvalue required as left operand of assignment 와 같은 에러 메시지를 출력하는데 변수 a같은 lvalue가 =의 피연산자로 와야 한다는 것 입니다.

상수는 lvalue가 되지 못하지만 변수는 lvalue도 될 수 있고 rvalue도 될 수 있습니다.

마무리

사람이 코드를 볼 때와 컴퓨터가 코드를 해석하는 것은 차이가 있습니다. 사실 C언어에서 나오는 대부분의 난해한 용어들은 인간의 관점이 아니라 컴퓨터, 특히 CPU와 메모리의 관점에서 해석하면 이해가 쉬워지는 경향이 있습니다. C언어를 오래 공부해도 학습의 성과가 더디게 나온다면 순수하게 컴퓨터의 관점에서 접근해 보는 것도 하나의 방법입니다.

C언어의 표현식은 코드를 만드는 가장 기본 단위이고 연산자와 피연산자의 조합으로 하나의 결과값을 리턴합니다. lvalue와 rvalue는 컴파일러의 중요한 규칙이므로 기억해둡니다.

외부 참고 문서

Expressions – cppreference.com

Leave a Comment