C++ Programming Inline Function (Working mechanism & Example)


c++언어에서는 인라인 함수라는 것을 제공한다. 인라인이라는 의미는 코드 라인 자체가 안으로 들어간다는 뜻. 즉, 함수의 내용을 호출을 통해서 실행시키는 것이 아니라, 호출하는 코드 자체가 함수 내용의 코드가 되는 효과가 된다는 점이다. 바로 이해한 사람도 있겠지만 아닐 수도 있으니, 예를 들자면...


void PrintHello() {

cout << "Hello, World!" << endl;

}


int main() {

PrintHello();

PrintHello();

return 0;

}


와 같은 코드가 다음과 같이 바뀌게 된다는 뜻이다.


int main() {

cout << "Hello, World!" << endl;

cout << "Hello, World!" << endl;

return 0;

}


눈치챘는가? 인라인 함수는 성능 향상을 위한 것이다. 물론 이렇게 바꿈으로써 실행 코드가 늘어날 수 있다는 단점이 있다. 따라서 인라인 함수는 코드는 작지만(1~3줄 정도) 자주 호출되지 않는 경우에 주로 사용하는 것이 좋다.




| 인라인 함수의 장점


인라인함수는 #define 매크로와 기능이 유사하지만, 인라인 함수만의 장점이 있다.

1. 인라인 함수의 전달인자에 데이터형을 체크할 수 있다. 

(매크로 기능을 활용할 경우에는 파라미터와 리턴값의 데이터 타입을 정확히 '명시'할 수 없게 된다.)

2. 매크로가 갖는 부작용 없이 일반 함수처럼 사용이 가능하다.

(매크로를 사용시에 increment등으로 변수를 넘겨줄 경우 일반적으로 함수를 사용할 때와는 다른 값을 얻게 되는 경우가 많다.)

3. 디버깅이 가능하다. 즉, 현재 변수에 어떤 값이 들어가 있는지 알 수 있다.



| 인라인 함수의 단점


1. 실행 코드가 커진다.

2. 인라인 함수의 구현을 짧게 작성해야 한다. 만약 구현의 내용이 길어진다면 컴파일러는 인라인 함수를 일반 함수로 취급하게 된다.


인라인 함수를 사용함으로써 성능의 향상과 매크로의 부작용을 해결할 수 있다고 하지만, 인라인 함수를 너무 남발하게 되면 실행 코드 자체가 커지게 되는 단점이 있다. 그리고 인라인 함수의 모토는 1~3줄 정도의 짧은 코드를 함수화시킴으로써 효율성의 낭비를 막고자 함이었는데, 코드가 5줄 이상이 되어버린다면 굳이 인라인 함수를 사용할 이유가 없다. 

C# Programming - Online course| Alison

사진 출처: Alison


보통 C# 프로그래밍을 할 때, List<T> 자료구조를 사용하는 경우가 있는데, 이 자료구조는 Add와 Insert라고 하는 두 가지 메서드로 자료구조에 원소를 추가하는 기능을 제공하고 있습니다. 그런데, 두 가지 메서드가 어떤 차이가 있을까? 하는 생각은 해보지 않으셨는지요. 물론 이런 생각이 머릿속에서 바로 직관적으로 해답을 찾고 해결해내실 수도 있겠지만, 그렇지 못한 분들도 계실 듯 하여 글을 조금 적어볼까 합니다.


우선, List<T> 자료구조는 배열을 기반으로 하는 리스트 구조입니다. 이 말은 무슨 말이냐 하면, 엄밀히 말하자면 내부 자료구조는 리스트가 아니라 배열입니다. 배열이긴 하지만, 우리는 리스트를 사용하듯이 사용할 수 있는 클래스라는 것이죠. 원소가 추가될 때마다 배열의 맨 마지막 자리에 원소가 추가되다가, 배열의 크기를 넘어서면 2배로 배열 크기를 늘려서 재할당하는 그런 식인 것입니다. 


이러한 내부의 진실을 알게 되면 조금 더 접근이 쉬운데, 일단은 우리의 화두인 Add, Insert 메서드의 사용 사례부터 봅시다.


List<Object> list = new List<Object>();

list.Add(value);

list.Insert(i, value);


Add, Insert의 사용법을 보면 눈치를 챘을 수도 있는데, 

- Add는 단순히 List<T> 자료구조의 내부에 있는 배열에 맨 마지막 자리에 원소를 추가하는 방식입니다. 

- Insert는 특정 위치에 원소를 추가하는 방식이구요. 따라서, Insert의 경우 i번째가 배열의 맨 마지막 자리가 아니라면 삽입할 위치 뒤에 있는 모든 원소가 뒤로 밀려나야 합니다. 따라서, O(n)의 시간이 걸리게 됩니다.

- 반면, Add는 그냥 단순히 맨 마지막에 원소를 집어넣는 것이라고 했지요? 따라서 O(1)의 시간이 걸립니다.


결론은, 특별한 위치에 원소를 집어넣어야 되는 상황이 발생하지 않는 한, 무조건 Add를 사용하라는 것입니다. 

(단순 원소 추가 기능을 필요로 할 때)

"switch문과 if문의 차이는 무엇일까? 성능의 차이가 있을까?"


switch문과 if문의 성능에 대해서 이야기를 하는 시간을 가져보고자 합니다.

프로그래밍을 배우다 보면 선택문을 사용해야 할 때 if문을 사용하거나 switch문을 사용합니다.

물론 switch문을 쓸 수 있는 경우는 전부 if문으로 대체 가능합니다만,

if문으로 가능한 것들 중 switch문으로 구현 불가능한 경우도 있죠.


이번 포스팅에서는 switch문과 if문 모두 가능한 경우에 대해서 따져보고자 합니다.

(당연한 이야기겠죠... 두 개 동시 사용 가능한 경우에 대해서 이런 논의가 의미가 있는 것이죠)


그리고, 단순히 고수준 언어의 측면에서 보기보단 ISA의 관점에서 풀어서 포스팅을 해보고자 합니다.

따라서, 특정 고수준 언어에 대해서는 이 포스팅의 내용이 옳지 않을수도 있습니다.

왜냐하면 고수준 언어들은 더욱 복잡한 컴파일러에 귀속되어 있는데, 

그 언어의 컴파일러가 어떠한 방식으로 instruction set (혹은 기계어나 어셈블리어)를 만들어가는지는 언어마다 다르기 때문입니다.


제가 공부한 ISA인 MIPS에는 branch statement와 jump statement가 있습니다.

branch statement는 레지스터 2개를 비교해서(혹은 레지스터와 상수를 비교해서) 특정 메모리 번지로 이동할 것이냐 말것이냐?를 결정합니다. 

jump statement는 즉시 특정 메모리 번지로 이동하는 기능을 합니다.


그리고 if문은 branch statement에 기반을 두고 있고,

switch문은 jump statement에 기반을 두고 있습니다.


왜냐하면, if문은 조건이 만족하면 실행/만족하지 않으면 무시 (실행을 할 것이냐 말것이냐?)

switch문은 입력된 값을 보고 특정 위치로 점프 (어떤 코드를 실행할 것이냐?)


switch문은 "점프테이블"을 만들고 switch문의 입력값으로 받은 변수 값만큼 점프 테이블 내에서 이동하면 됩니다.

if문보다 훨씬 쉽네요? 점프 테이블만 만들수 있다면 말이죠.


대충 이 정도 이야기를 하면 어느 정도 눈치를 채셨을 수도 있는데,

if-else문은 각 조건마다 그 조건 처리할수 있게 레지스터를 변경해주는 그런 인스트럭션들이 먼저 선행되야 합니다. 각 조건마다.

그런데, switch문은 점프 테이블을 만들기만 하면 조건이 몇개든 훨씬 빠르고 쉽게 넘어갈 수 있어요.

다만 점프 테이블을 만드는 오버헤드가 있는거죠.


<정리하자면>

if문

장점: 점프 테이블을 만드는 오버헤드가 없다.

단점: if 혹은 else if를 만날 때마다 조건을 만족하는지 안하는지를 확인하기 위한 인스트럭션이 계속해서 필요됨.

즉, 따져야 할 조건의 수가 적을 경우 if-else를 쓰는 것이 유리함.


switch문

장점: switch문 시작시에 입력받은 값을 확인하는 인스트럭션만 필요. 조건을 확인하는 인스트럭션이 필요 없음.

단점: 점프 테이블을 만드는 오버헤드가 있음.

즉, 따져야 할 조건의 수가 많아져도 인스트럭션이 추가로 요구되는 것이 아니기 때문에,

따져야 할 조건이 많은 경우 switch문을 쓰는 것이 유리합니다.


ODROID-XU – ODROID


LG전자 인턴에서 사용했던 보드인 ODROID-U2,

오드로이드 U2는 '하드커*" 사이트에서 구매 가능합니다... 

(직접 언급하면 상업적인 광고효과가 있을까봐... ㅎㅎ *가 궁금하면 메일이나 쪽지 보내주세요)

 

그래서 그 하드커* 사이트를 오랜만에 들어가봤는데, ODROID-XU 라고 하는 친구가 보이더군요??

흠흠 그 친구를 The world's first ARM big.LITTLE architecture based single board computer 라고 자랑해놓았더라구요.

 

big.LITTLE... 이 놈은 무엇인가? 왜 빅을 작게 쓰고 리틀을 크게 썼는지 참 반항아같은(?) 놈입니다만

오늘은 이 '빅 리틀'(big.LITTLE) 이란 놈에 대해서 설명해볼까 합니다.


빅 리틀 아시기 전에 아셔야 하는 배경지식은 바로 이겁니다.

성능이 우선시 되는 코어는 소비 전력이 큽니다. 반대로, 전력이 우선시 되는 코어는 성능이 비교적 약합니다.

이 이유는 아주 간단합니다. "명령어 처리 속도가 높다 = 성능이 좋다." 라고 할 수 있을텐데,

명령어 처리를 짧은 시간에 많이 진행할 수록 전기 회로에 흘러야 할 전류 량은 더 많아지니까 당연히 소비 전력이 커지게 되는 것이죠.

흠흠... 너무 당연한 설명을 하는 건가요?

 

자 이제, 두 개의 아키텍처 A15 , A7 이 있다고 생각해봐요.

A15 는 성능만을 고려한 아키텍처이고, A7 은 저전력을 고려해서 만든 아키텍처 입니다.

그런데 성능도 놓치기 싫고, 저전력도 놓치기 싫죠?

바로 이러한 문제의 솔루션이 빅 리틀입니다.

 

빅 리틀은 상황에 따라 프로세서를 맞게 쓰자는 겁니다.

성능이 필요할 땐 고성능 아키텍처 프로세서를, 

배터리 사용시간을 늘려야할 때는 저전력 아키텍처 프로세서를

쓰자는 겁니다.

 

즉, 두 아키텍처를 결합해서 만든 CPU 아키텍처를 바로 big.LITTLE 아키텍처라고 합니다.


+ Recent posts