• 3.2.1 sizeof 연산자
  • 3.2.2 쉼표 연산자(Comma operators)
  • 3.2.3 조건 연산자(Conditional operators)

3.2.1 sizeof 연산자

 

sizeof는 그동안 많이 사용했지만 이걸 함수로 생각해야 할지 연산자로 생각해야 할지 고민해볼 시간을 가지진 않았다. C++에서 함수는 마지막에 ()를 사용하여 끝내는데, sizeof는 괄호가 필요 없다. 이에 따라 sizeof를 연산자로 생각하는게 타당하다.

#include <iostream>

int main()
{
	using namespace std;

	float floatNumber;

	cout << sizeof(float)		<< endl;
	cout << sizeof floatNumber	<< endl;

	return 0;
}

sizeof를 사용할 때 가장 많이 사용하는 것은 자료형을 괄호로 감싸서 사용하는 것이나 두 번째 예시를 보면 괄호가 필수적으로 사용되는 것은 아님을 알 수 있다.


3.2.2 쉼표 연산자(Comma operators)

 

쉼표 연산자, 콤마 연산자에 대해서도 크게 생각해보는 시간이 없었는데 이번 기회에 간단하게 정리할 수 있었다. 쉼표 연산자는 모든 연산자들 중에 우선순위가 가장 낮은 연산자이다. 일반적으로 같은 자료형의 메모리 식별자를 선언해줄 때 사용하는데, 개인적으로 모호해질 수 있는 경우가 많아 자주 쓰는 형태는 아니었다.

#include <iostream>

int main()
{
	using namespace std;

	int number01 = 3, number02 = 10;
	int number03 = (++number01, ++number02);

	cout << number01 << " " << number02 << " " << number03 << endl;

	return 0;
}

이런 형태로 코드를 구현하는 경우는 매우 드물겠지만 이처럼 작성하는 경우 number03에 어떤 수가 어떻게 들어갈지 굉장히 모호해진다.


3.2.3 조건 연산자(Conditional operators)

 

삼항 연산자로도 불리는 조건 연산자는 의외로 많이 쓰이는 연산자이다. 간단한 조건에 대한 판단을 할 때 코드가 짧아질 수 있고 가독성 또한 높아진다. if else문으로 다루는 것과 다르지 않지만 어떠한 조건에 의해 여러 줄로 코드를 수행하는 경우가 아니라면 쓸만한 연산자이다.

#include <iostream>

int main()
{
	using namespace std;

	// conditional operator (arithmetic if)
	bool onSale = true;

	int price;

	if (onSale)
		price = 10;
	else
		price = 100;

	cout << price << endl;

	// price를 const로 쓰고싶다면?
	const int constPrice = (onSale == true) ? 10 : 100;

	int bb = 5;
	cout << ((bb % 2 == 0) ? "even" : "odd") << endl;

	return 0;
}

삼항 연산자는 조건이나 반환하는 값이 간단할 때만 사용하자. 삼항 연산자의 반환값은 같은 자료형으로 쓰는 걸 권장한다.

  • 3.1.1 연산자 우선순위(Operator Precedence)
  • 3.1.2 결합 법칙(Associativity) 활용
  • 3.1.3 산술 연산자(arithmetic operators)
  • 3.1.4 증감 연산자(increment decrement operators)

3.1.1 연산자 우선순위(Operator Precedence)

 

사칙연산을 배울 때 우리는 덧셈과 뺄셈보다 곱셈과 나눗셈을 먼저 계산한다는 우선순위를 정해서 연산을 수행한다. 프로그래밍 언어도 많은 연산자가 존재하기 때문에 연산자에 대한 우선순위가 필요하다. 연산자 우선순위를 의도적으로 외우려 하는 것은 매우 힘들기 때문에 일반적으로 연산자 우선순위에 대한 표를 검색으로 찾아서 보거나 결합 법칙을 활용한다.

 

https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B

 

Operators in C and C++ - Wikipedia

From Wikipedia, the free encyclopedia Jump to navigation Jump to search Similar syntax in both computer languages This is a list of operators in the C and C++ programming languages. All the operators listed exist in C++; the column "Included in C", states

en.wikipedia.org


3.1.2 결합 법칙(Associativity) 활용

 

연산자 우선순위는 프로그래밍을 계속하면 몇 가지는 체화되지만 안 되는 것들이 존재할 수 있다. 그럴 때는 의도적으로 괄호를 통해 결합 법칙을 이용하는 방법을 생각할 수 있다. 순서가 애매하다면 프로그래머가 직접 ()를 통해 순서를 확실히 한다.

#include <iostream>

int main()
{
	using namespace std;
	
	int x = 4 + 2 * 3;	// 약속된 연산자 우선순위로 계산된다.
	int y = (4 + 2) * 3;	// 결합법칙 활용

	return 0;
}

경험적으로 봤을 때 결합법칙을 활용하는 경우는 조건문에 많은 조건들이 붙거나 매크로가 여러 번 걸쳐지면서 애매해지는 순간 정도였던 것 같다.


3.1.3 산술 연산자(arithmetic operators)

 

산술 연산자는 우리가 흔히 알고 있는 사칙연산과 나머지 값을 반환하는 modulus operator(나머지 연산)이 있다. 또한 피연산자의 수에 따라 산술 연산자를 분류할 수 있다.

 

아래는 피연산자가 하나인 단항 연산자이다. 우리가 흔히 숫자에 부호를 넣어주는 형태로 사용할 수가 있다.

#include <iostream>

int main()
{
	using namespace std;

	int x = 1;

	int unaryOperatorMinus	= -x;
	int unaryOperatorPlus	= +x;

	return 0;
}

 

아래는 피연산자가 두 개인 이항 연산자 중 나누기와 나머지 연산에 대해 다루었다.

#include <iostream>

int main()
{
	using namespace std;

	int operand1 = 7;
	int operand2 = 4;
	cout << operand1 / operand2			<< endl; // return  1
	cout << float(operand1) / operand2		<< endl; // return  1.75
	cout << operand1 / float(operand2)		<< endl; // return  1.75
	cout << float(operand1) / float(operand2)	<< endl; // return  1.75
	
	cout << -5	/  2	<< endl; // c++ 11부터는 소수점 아래를 절삭하기로 했음 return -2
	cout << -5	%  2	<< endl; // return -1
	cout << -5	% -2	<< endl; // return -1
	cout <<  5	% -2	<< endl; // return  1

	// 복합 연산자
	// 코딩 작업 내용을 줄여준다.
	// 실수를 줄여준다. 보기가 편해진다.
	operand2 += operand1;

	return 0;
}

정수 자료형에 대해 나누기 연산을 수행할 경우 주의할 점은 소수점 아래가 절삭된다는 점이다. 이전에는 이에 대해 어떻게 처리해야 할지 컴파일러마다 모호했지만 C++ 11부터는 소수점 아래를 절삭하는 것으로 결정 났다. 음수에 대한 나머지 연산 또한 return 값에 대해 주의 깊게 볼 필요가 있다. 나누는 피연산자의 부호는 상관없이 나누어지는 수의 부호에 따라 결과 값이 달라진다.

 

이항 연산자는 복합 연산자가 존재한다. 복합 연산자는 코딩 작업 내용을 줄여주며 이에 따라 실수를 줄여줄 수 있고 보기가 편해진다. 처음에는 불편할지 몰라도 계속 쓰다 보면 익숙해지는 것이 복합 연산자이다.


3.1.4 증감 연산자(increment decrement operators)

 

반복문에서 자주 볼 수 있는 연산자가 바로 증감 연산자이다. 반복문 내에서 반복 횟수를 설정하기 위해서 사용한다면 크게 고민 없이 사용할 연산자이지만 그 외의 경우에 쓴다면 전위와 후위에 따른 결과의 차이를 알고 있어야 한다.

#include <iostream>

int main()
{
	using namespace std;

	int number = 5;
	int prefixDecrementNumber	= --number;
	int postfixDecrementNumber	= number--;

	cout << prefixDecrementNumber	<< endl;
	cout << postfixDecrementNumber	<< endl;

	return 0;
}

 

위 코드의 실행 결과는 아래와 같다.

결과

여기서는 차이를 느낄 수 없는 구조이지만 아래의 코드를 실행하면 차이를 확연하게 알 수 있을 것이다.

#include <iostream>

int main()
{
	using namespace std;

	int number01 = 6;
	int number02 = 6;
	cout << number01	<< " " << number02	<< endl;
	cout << ++number01	<< " " << --number02	<< endl;
	cout << number01++	<< " " << number02--	<< endl; // number01을 스트림으로 보낸 뒤에 1을 더해준다.
	cout << number01	<< " " << number02	<< endl;

	return 0;
}

 

전위 후위 연산자 결과

전위 증감 연산자는 해당 연산자가 존재하는 명령문에 도착했을 때 명령문을 수행하기 전 증감 연산자를 수행하고 후위 증감 연산자는 해당 연산자가 존재하는 명령문을 먼저 실행하고서 증감 연산자를 수행한다. 즉, 전위 후위 연산자에 따라 해당 연산자가 존재하는 명령문의 결과가 달라지니 이를 염두에 두고 프로그래밍을 해야 한다.

 

#include <iostream>

int add(int a, int b)
{
	return a + b;
}

int main()
{
	using namespace std;

	int number03 = 1;
	int number04 = 2;
	int addNumber = add(number03, ++number03);

	cout << addNumber << endl;
	addNumber = add(number03, ++number04);
	cout << addNumber << endl;

	return 0;
}

이런 방식으로 프로그래밍을 하면 의도와는 다른 결과를 많이 볼 수 있으니 증감 연산자를 사용할 때는 신중하자.

내가 아는 익숙한 for문과는 for문을 보았기에 이를 기록하려 한다...!


일반적인 for문

 

남들에게는 일반적인 게 아닐 수 있지만 내가 프로그래밍을 하면서 보았던 코드들에서 대부분 for문은 다음과 같은 형태로 구현되어 있었다.

#include <iostream>

using namespace std;

int main()
{
	int arrayTest[10] = { 1,2,3,4,5,6,7,8,9,10 };

	for (int i = 0; i < 10; i++)
	{
		cout << arrayTest[i] << endl;
	}

	return 0;
}

정말 교과서에 나오는 정석적인 for문이다...! 이렇게 생긴 코드를 대부분의 C/C++ 개발자들이 제일 처음 본 반복문이라고 나는 생각한다.


auto 키워드를 활용한 for문

 

주말에 프로그래밍 공부를 조금씩 하다가 발견한 for문이다. 정말 너무 간결하고 nice해서 충격을 먹고 포스팅을 한다.

#include <iostream>

using namespace std;

int main()
{
	int arrayTest[10] = { 1,2,3,4,5,6,7,8,9,10 };

	for (auto element : arrayTest)
	{
		cout << element << endl;
	}

	return 0;
}

for문 첫 줄이 엄청나게 간결해졌다...!! 기존의 for문과 한번 비교 분석을 해보자!

 

우선 첫 번째로 당연히 코드가 간결해지고 코드 작성 시간이 줄어들게 되었다. 이전 코드는 은근히 코드를 작성하면서 기호를 추가하는 경우 끊김이 생기곤 했는데 위처럼 작성하는 경우엔 콜론 하나만 있으니 금방 타이핑을 할 수가 있었다. 두 번째로는 주어진 배열의 길이를 자동으로 for문이 가지게 된다는 점이다. for문을 작성할 때 항상 고민이었던 점은 배열을 사용하는 경우 for문에 해당 배열의 끝 지점이 어디인지 반드시 알고 있어야 했고 이를 잘못 지키는 경우 코드가 제대로 동작하지 않았다. 그래서 항상 어떻게 배열의 길이를 전달해줄까 고민하곤 했는데 이제 이런 고민을 할 필요는 없어졌다.

 

당연히 장점만 있는 것은 아닐 것이다. 바로 직전의 코드처럼 작성한다면 element에 매번 배열의 값이 복사된다. 이는 성능 하락의 주범이 될 수도 있겠다. 언제나 복사는 덜할수록 좋은 것 같다. 그리고 아직 검증은 안 해봤지만 저러한 작성 방식도 openMP가 적용되는지 의문이다. 이건 내일 회사 가서 한번 적용해서 돌려봐야겠다.

 

참고로 복사를 막는 방법으로 구현한 것은 아래와 같다. 참조 연산자를 사용하면 매번 복사하지 않고 수행시킬 수 있게 된다!

#include <iostream>

using namespace std;

int main()
{
	int arrayTest[10] = { 1,2,3,4,5,6,7,8,9,10 };

	for (auto& element : arrayTest)
	{
		cout << element << endl;
	}

	return 0;
}

오랜만에 최신 문물을 접한 느낌으로 충격을 받았다. 기존과 성능 차이가 꽤 있을지는 모르겠지만 적어도 코드가 간결해질 수 있어서 너무 좋은 것 같다. 혹시나 추가 설명이 필요하다면 아래 글을 참고하자!

 

 

Range-based for loop (since C++11) - cppreference.com

Executes a for loop over a range. Used as a more readable equivalent to the traditional for loop operating over a range of values, such as all elements in a container. [edit] Syntax attr(optional) for ( init-statement(optional)range-declaration : range-exp

en.cppreference.com

 

+ Recent posts