The Best Free Software of 2020 | PCMag


최적의 소프트웨어란 구체적인 목적이나 상황, 환경에 따라 다를 수 있다. 마찬가지로 어떤 소프트웨어 설계가 더 좋은 것이냐 하는 것도 구체적인 목적이나 상황, 환경에 따라 달라질 수 있다. 그럼에도 많은 전문가에 의하면 다음과 같은 특성을 갖추어야 좋은 소프트웨어 설계라고 말한다.


1. 이해 용이성 Unerstandability

전체 소프트웨어나 개별 구성 요소에 대해 쉽게 이해할 수 있어야 한다.


2. 수정 용이성 Modifiability or Flexibility

요구 사항의 변경에 따른 수정이 용이해야 한다.


3. 관리 용이성 Maintainability

소프트웨어 유지, 보수, 관리 단게에서 버그 수정이나 장애 대처, 요구 사항 변경, 성능 향상 등의 이유로 소프트웨어를 수정해야 할 경우 이를 쉽게 수행할 수 있어야 한다.


4. 재사용 용이성 Reusability

개발된 소프트웨어 구성 요소들을 다른 소프트웨어를 개발할 때 손쉽게 재사용 가능해야 한다.


5. 테스트 용이성 Testability

소프트웨어가 원하는 동작이나 기능을 수행하는지 테스트하기 쉬워야 한다.


6. 높은 안전성 Reliability

소프트웨어가 오류없이 원하는 작업을 수행할 수 있는 확률이 충분히 높아야 한다.

Sublime Text 3 기본 설정


git commit 메세지를 설정하는 에디터가 기본적으로는 nano 에디터일 텐데, nano에디터에는 익숙하지 않아서 vim으로 바꿨었다. vim으로 바꾸는 커맨드는 다음과 같다.


$ git config --global core.editor vim


하지만, vim도 뭔가 한글 작성시에는 느리게 동작하는 불편함때문에, 이쁜 에디터 중 하나인 sublime text를 사용하기로 했다.


sublime text를 git의 commit 메시지 에디터로 사용하려면 다음과 같은 커맨드를 터미널에 입력하면 된다.


$ sudo ln -s /Applications/Sublime\ Text.app/Contents/SharedSupport/bin/subl /bin/subl


$ git config --global core.editor "subl -n -w"


일반적으로 변수를 상수화시킬 떄 사용하는 예약어로 const키워드를 사용하곤 한다. 그런데, const키워드를 클래스의 멤버함수와 객체에도 사용할 수 있다. 이 경우 어떻게 사용되는지 알아보도록 하자.




1. const 멤버함수

멤버함수에 const를 사용하는 이유는 객체의 멤버변수를 변경시킬 수 없도록 하기 위해서이다.

예를 들어, Get함수의 경우 일반적으로는 private 멤버변수를 반환하는 역할만 하지, 그 멤버변수를 수정하는 일은 절대 없어야 한다.


class Point {

private:

int x_, y_;

public:

Point();

Point(int x, int y);

inline int GetX() const {

return x_;

}

inline int GetY() const {

return y_;

}

}


위와 같이 GetX, GetY 함수는 단순히 private member 변수인 x_, y_의 값을 반환하기만 할 뿐 그 값을 수정하거나 변경하는 일이 없다. 따라서 이러한 함수에는 const키워드를 붙여주는 것이 옳다.


const 키워드가 붙은 const 멤버함수는 객체의 멤버변수를 변경할 수 없는 읽기 전용 함수가 된다. 또한 const 멤버함수는 const로 지정되지 않은 다른 멤버 함수를 호출할 수 없다. 왜냐하면 읽기 전용으로 지정된 const멤버함수에서 const로 지정되지 않은 멤버함수를 호출하게 되면 간접적으로 객체의 멤버변수를 변경시킬수도 있기 때문이다. 


따라서, 앞으로 GetX, GetY와 같은 함수는 const 멤버함수로 선언하는 것이 바람직하다. (그러지 않아도 컴파일 에러는 발생하지 않지만, 코드를 좀 더 견고하고 안전하게 만들기 위해서 필요한 키워드인 것이다.)


참고로 생성자와 소멸자는 const 예약어를 사용할 수 없다. 생성자와 소멸자는 항상 객체의 데이터를 변경시켜야 하기 때문이다.





2. const 객체

멤버변수나 멤버함수 뿐만 아니라 객체에도 const 키워드를 사용할 수 있다. 객체 생성시에 const 키워드를 사용하면, 그 객체는 상수로 취급되어 초기화된 데이터 외의 다른 데이터로 변경할 수 없다. 


const Point pt1(10, 20);

pt1.SetX(30);

pt1.SetY(40);


위와 같은 코드는 컴파일 에러를 발생시킨다. 왜냐하면 SetX, SetY의 멤버함수에서 x_, y_ 멤버 변수값을 변경하려고 하기 때문이다. const키워드가 붙은 객체 인스턴스는 그 멤버변수의 값이 변경되지 않는다.


이러한 논리로 보건대, const 객체는 당연하게도 const 멤버함수만을 제대로 사용할 수 있다. const키워드가 없는 멤버함수는 멤버 변수의 값을 변경할 가능성이 있기 때문에, 호출을 시도하더라도 대부분은 컴파일 에러가 날 것이다.

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줄 이상이 되어버린다면 굳이 인라인 함수를 사용할 이유가 없다. 

ARM 아키텍처에는 16개의 레지스터와 함께 cpsr(current program status register)이라고 하는 레지스터가 존재한다.

cpsr은 다음과 같은 구조인데, 이번 포스팅에서는 이 cpsr에서의 flags 부분에서 overflow, carry flag를 비교해볼 것이다.




보통 overflow 를 흘러넘치다라는 표현으로 받아들이고, overflow랑 carry를 혼동하는 경우가 많다.

나같은 경우, 정확하기 이해하기 전에는 이 두 개념을 완전히 서로 반대로 이해하고 있었는데,


예를 들어 4-bit 연산을 한다고 했을 때,


1) 1000 + 1000 = 10000 (여기서 맨 앞에 있는 1은 사라지게 됨)

이런 경우 overflow가 되는 것이라고 생각했다. (왜냐하면 4개의 비트에서 흘러넘쳤으니깐)

하지만 이 경우에는 carry flag가 set되는 것이다.

즉, carry flag는 최상단 비트에서 캐리가 생겼을 때 set 된다!


반면,

2) 0111 + 0001 = 1000 

그리고 이 경우에는 overflow flag가 set되는 것이다.

왜냐하면, 이들이 signed expression이라고 가정했을 때, 7+1 = 8이 나와야 하지만, -8이 나왔기 때문이다. (overflow로 인한 잘못된 결과)

즉, 부호가 있는 연산에서 최대 표현 숫자를 넘어서서 오버플로우가 난 경우 overflow flag가 set된다!

(같은 부호를 더했을 때 다른 부호가 나오는 것으로도 오버플로우를 인지할 수 있다.)


따라서, signed 에서만 overflow flag가 의미 있고,

unsigned 에서만 carry flag가 의미가 있는 것이다.


하지만 주의해야 할 점은 CPU는 signed/unsigned와 같은 의미를 모른다.

따라서, 내가 지금 무슨 연산을 하고 있던 간에 overflow flag가 set되야 할 때, carry flag가 set되야 할 때는 독립적인 사건이다.

즉, 1000 + 1000 = 10000과 같은 상황에서는 두 플래그가 모두 셋이 될 것이다.

왜냐하면, 부호가 있다고 생각하든 없다고 생각하든, 최상단 비트에서 carry가 생겼으며,

두개의 입력값 모두 최상단 비트는 1인데 결과는 최상단 비트가 0이 되었으므로 오버플로우 플래그도 세팅이 되는 것이다.


즉, 내가 지금 signed 연산을 하고 있더라도, carry flag는 의미는 없지만, set될 수도 있고 아닐 수도 있는 것이다.

왜 의미가 없냐 하면, 어차피 signed연산을 하는 시점에서는 최상단 비트는 오로지 부호의 역할만 하므로 그 이후 캐리가 생기고 말고는 의미가 없는 것이다.



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를 사용하라는 것입니다. 

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

+ Recent posts