주인장 공지입니다. Lu's…〃 Diary。

반갑습니다. 루사인이라고 합니다.


1. 책 리뷰 & 프로그래밍 일기 블로그입니다.

2. 가끔 성과 글도 올라와요.

3. @Lusain_Kim 에 상주 중.



환영합니다.

[C++17] filesystem Lu's…〃 Programing。


C++17에서, 경로와 디렉터리, 확장자 등에 관련된 연산을 하는 C++ 표준 라이브러리가 추가됐다. boost API 있는 기능이었지만, 사용법은 약간 다른 같다(boost API 적이 없어서 확답을 하겠다).

 

namespace std::experimental::filesystem::v1 정의되어 있으며(#include<experimental/filesystem>), C++ 표준라이브러리와 같이 사용하면 굉장히 편하게 사용이 가능하다.

 

장점 :

  1. 파일 경로를 저장하기 위한 path 클래스를 지원한다.
    path 클래스의 멤버는 문자열과 경로 설정을 위한 기능을 제공한다.
    path 클래스를 사용하여 간단하게 확장자를 확인하고 교체할 있다.
  2. path 클래스에서 UNICODE MULTIBYTE 모두 지원한다. 이것은 std::wstring std::string 같이 문자 집합에 따라 여러 개의 정의가 있는 것이 아니라, 하나의 filesystem 클래스에서 여러 문자 집합으로의 변환을 지원한다는 뜻이다.
    , 문자집합을 변경할 때마다 클래스를 변경할 필요가 없다.
  3. std::wstring, std::string, char, wchar_t  어떤 타입을 인자로 받아도 상관없다.
    2
    번과 이어지는 장점.
  4. 플랫폼 독립적이다.
    • 정확히는 표준을 지원하면 동일한 코드 사용 가능. 표준을 써야하는 이유.
  1. 파일 복사, 디렉토리 생성, 파일/디렉토리 제거, 현재 디렉토리, 임시 디렉토리 등을 확인하는 함수를 제공한다.

 

 

 

이제부터 어떻게 사용하는지 확인해보자.

std::experimental::filesystem::v1 붙이기에는 무리가 있으므로 생략한다.

 

기본적으로 filesystem 정의된 대부분의 함수는 path 클래스를 사용한다.

path 클래스를 사용하는 방법은 매우 간단하다. std::string 동일하게 사용하면 된다.

path 클래스는 문자 배열과 표준 string 클래스를 통한 생성을 지원한다.

 

path myPath = "C:/Lusain/game.txt";

 

여기서 .txt .exe 변경하고 싶으면 다음 멤버함수를 호출한다.

 

myPath.replace_extension(".exe");

 

또는, game 아닌 LusGame으로 변경하고 싶으면 다음 멤버함수를 호출한다.

 

myPath.replace_filename("LusGame.exe");

replace_filename으로 파일명을 바꾸면 확장자까지 바뀌므로 주의.

 

 외부에서 읽은 문자열로 만든 path 클래스가 원하는 확장자를 가졌는지 확인하는 방법은 다음과 같다.

 

if (myPath.extension() == ".txt")// TODO: ~~

 

 

 

리소스를 관리할 , 종류에 따라 여러 디렉토리에 접근해야 한다.
/
연산자가 오버로딩 되어 있기 때문에, 다음과 같이 작성할 있다.

 

// MyData/Image 저장하려고 .

string data {"myImage.png" };

string DirData { "MyData"};

string DirImage {"Image" };

 

path SavePath = DirData / DirImage / data;




 만약 path 클래스의 데이터를 문자열로 가져오고 싶으면 멤버함수를 이용하면 된다.

.c_str()

.generic_string()

.generic_wstring()

.generic_u8string()

.generic_u16string()

.generic_u32string()

.string()

.wstring()

.u8string()

.u16string()

.u32string()

 

여기서 generic_ 붙은 멤버함수는 백슬래쉬(\) 경로 구분자를 슬래쉬(/) 바꿔 반환한다.

 


 

filesystem 파일 또는 디렉토리의 생성, 삭제, 복사, 이름 바꾸기, 이동, 존재 여부 등을 전역 함수로 지원한다. 자세한 것은 MSDN 참고.

 

예시를 들어보자.

파일인지 확인

is_regular_file(path)

디렉토리인지 확인

is_directory(path)

존재하는지 확인

exists(path)

파일명 변경

rename(path, path)

파일 삭제

remove(path)

파일 또는 디렉토리 복사

copy_file(path, path, copy_options)

디렉토리 생성

create_directory(path)

 

 

 

path 디렉토리라면, 이를 인자로 directory_iterator 만들어 해당 디렉토리의 파일을 순회할 있다. 이를 통해 특정 디렉토리의 파일을 모두 얻어오는 함수를 만들 있다. 맨 마지막 인자로 하위 디렉토리를 재귀적으로 추가할 것인지 설정할 수 있다.

 

bool GetFiles(vector<path>& v, const path& Dir, bool bSearchSubDirectories = true)

{

if ( ! is_directory(Dir) ) return false;

for (const auto& entry : directory_iterator { Dir} )

{

if ( is_regular_file( entry.status() ) )

v.push_back( entry.path() );

else if( is_directory( entry.status() ) )

GetFiles(v, entry.path(), bSearchSubDirectories);

}

return true;

}

 

더욱 자세한 것은 MSDN 참고하자. Modern C++부터는 MSDN에서 설명해준다!


Github 학생 개발자 팩을 얻어보자! Lu's…〃 Programing。




github는 가장 유명한 무료 온라인 git 저장소 제공 사이트이다. 

가입을 하기만 해도 무료 공개 레포지토리 생성이 가능하고, 매달 일정 금액을 지불하면 무제한으로 비공개 레포지토리 생성이 가능하다.

학생의 경우, 학생이라는 것만 인증하면 Github Education에서 학생용 개발자 팩이 제공된다.

 이 팩은 매달 일정 금액을 내는 것과 동일하게 무제한 비공개 레포지토리 생성이 가능한 패키지이다. 기한은 2년이고, 2년 뒤에도 학생이라면 갱신이 가능하다.

긴 말 하지 않고, 과정을 전부 스크린샷으로 찍었다. 하나씩 따라가자.




1. https://education.github.com/ 에 접속하여 [Get the pack]을 누른다.




2.  [Get your pack]을 누른다.




3.자신의 Github 계정에 접속한다.




4. [Yes, I'm a student] 버튼을 클릭한다.




5. 정보를 입력한다. 
단, [select your school-issued email address] 항목에서 선택 가능한 학교 계정이 자신의 Github 계정에 등록되어 있어야 한다.




6. 없다면? 등록하러 가자.
http://github.com/settings/emails 에 접속하여 Add email address 에 학교 계정을 입력한다.




7. 학교 계정에서 유효한 계정인지 확인한다.
verify email address 하이퍼링크를 누르면 된다.




8. 정상적으로 등록했다면 5번으로 돌아가 나머지 정보를 입력하고(다시 한 번 말하지만, 학교 계정을 선택해야 한다) 제출하면

끝났다. 당신은 학생 개발자 팩을 얻었다. 이제 마음껏 비공개 레포지토리를 만들자!

※ 만약 기한이 지날 경우, 비공개 레포지토리를 삭제하거나 공개 레포지토리로 변경해야 한다.
 그 땐 학생이 아니라 갓-발자가 되었을 것이므로 돈을 내고 이용하자.


[Visual Studio] 코드로 중단점을 걸어보자 Lu's…〃 Programing。


 디버깅을 할 때 중단점은 굉장히 중요한 요소이다. 원하는 위치에, 원하는 조건과 원하는 때(호출된 위치)에 프로그램을 중단시킬 수 있기 때문이다.

 Visual Studio에선, 중단점/책갈피/열린 파일 등의 정보는 .suo(solution user option) 파일에 저장이 된다. 이 파일은 협업 시 공유할 필요가 없다.

 협업 중, 또는 코드만 보관하는 등 중단점을 저장할 방법이 없다면 debugapi.h 에 있는 함수를 사용하여 중단점을 걸 수 있다.



WINBASEAPI VOID WINAPI DebugBreak(VOID);

라고 돼 있는 함수이고, 자세한 내용은 MSDN 참고.



 끝, 인줄 알았지만 할 게 더 남았다. 이 함수를 호출하면 중단점이 트리거 되는데, 문제는 디버깅을 하지 않을 때 발생한다.

해당 함수는 중단점을 무조건 실행하기 때문에 디버거가 연결되지 않으면 죽어버린다. 

따라서 현재 프로세서가 디버거와 연결되어 있는지 확인할 필요가 있다.

 당연히, 그런 코드 역시 존재한다. debugapi.h에 위치한다.



WINBASEAPI BOOL WINAPI IsDebuggerPresent(VOID);

자세한 내용은 MSDN 참고.


 
 요약하자면, 코드 수준에서 중단점을 찍는 방법은 다음 코드와 같다.



    if (IsDebuggerPresent()) DebugBreak();



x86, x64 플랫폼에서 사용이 가능하니 __asm int 3; 같은 코드는 naver...



 + debugapi.h 는 winbase.h 에 포함되어 있고, winbase.h 는 windows.h 에 포함되어 있다.
 + 디버깅 중 출력이 필요한 일이 있다면 콘솔 창을 쓰지 말고 OutputDebugString() 함수를 쓰자


[C++] std::map을 사용해보자! Lu's…〃 Programing。

 std::map 키와 값이 있는 자료구조인데, 특이한 점은 키들 크기 비교가 가능하면(연산자 오버로딩 등의 방법으로) 어떤 구조체라도 상관이 없다는 점이다. 예를 들어 std::string이라던가, 값이 0부터 늘어나지 않거나 순서대로 증가하지 않는 enum 등등. 그리고 크기 비교가 가능하기 때문에 입력 자동적으로 정렬이 된다.

 

  자료구조는 굉장히 쓰기 쉽게 [] 연산자를 지원하는데, [] 안에키를 입력하면 값에 접근할 있다. 심지어, 해당 키에 대한 값이 초기화되어 있지 않아도 접근이 가능하다. 말이 살짝 어려울 있으니 예제를 보자.

 



#include <map>

 

 

class T { };

 

std::map<int, T*> m;

m[10] = new T{};    // m[10] 어디서도 할당 받지 않았지만 사용이 가능하다!



 

예제에서, m[10] 생성조차 되지 않았지만 호출시점에 공간을 할당하고 T* 값을 만든다. 초기화되지 않았으므로 쓰레기 값이 나올 있지만.

 

이렇듯 std::map 값이 미리 할당되지 않아도 호출 시점에서 할당이 되기 때문에 사용자는 아무 생각없이 편하게 사용하면 되는 자료구조이다. 하지만 이것은 장점인 동시에 단점이다.

 

 만약, 사용자가 잘못된 값을 주어도 std::map 잘못되었다고 판단하지 않고 새로운 키로 받아들여 값을 할당한다. int 같은 정수형 타입은 그런 가능성이 적지만 std::string 경우에는 빈번한 실수이다.

 

 이럴 쓰는 멤버 함수가 있다. at() 바로 그것인데, 함수의 인자는 키이다. 해당 키가 없으면 오류를 출력한다. 또는, count 함수를 사용할 수도 있다. 함수 역시 키를 인자로 받으며, 해당 키를 사용하는 개수를 출력한다. std::multimap 경우엔 2 이상이 있지만, 키가 고유한 std::map 경우에는 0 또는 1 나온다. 당연히 0이면 해당 키가 만들어지지 않았다는 것이다.
 

 

 

자세한 설명은, MSDN 한글화를 놨다. 너무 한글화가 같긴 하지만.

map 클래스 | https://msdn.microsoft.com/ko-kr/library/s44w4h2s.aspx


1 2 3 4 5 6 7 8 9 10 다음