cpp(stl)

cpp4(파일입출력/바이너리모드/저수준출력)

yam3u 2025. 3. 19. 20:46

250318 수업 정리본 + 모르는 것..

 

시작하기에 앞서.. 제일 중요한 개념..

연속성에 관하여 두 단어를 꼭 기억해야함

continuous : 시간의 연속성

contiguous : 공간의 연속성

교수님께서 정말 아주아주 강조하셨다..지난학기 cpp할때 너무 잘알고있었는뎋 분명.

한번 더 까먹으면 큰일날듯


copy

std::array<int, 1000> hello{};

는 지난 글에서 다뤘으니.. (안전배열) 까먹으면 다시 그걸 보도록 하자..

우리 array는 빈틈없이 메모리가 연속되어있음. 이걸 contiguous한 메모리라고 한다!!

아 참고로...

sizeof(hello)는, 바이트수를 반환 (여기서는 4000바이트)

hello.size()는 원소의 개수를 반환 (여기서는 1000개)

 

std::copy() 가 무엇이냐..

└ STL의 알고리즘 중 하나로.. 한 범위의 요소들을 다른 범위로 복사하는 역할을 함.

std::copy(first, last, d_fist)

first부터 last(last는 포함x)을 d_first부터 시작하는 위치에 놓고 복사시킴.

반환은 마지막으로 복사된 요소의 다음위치 반환.

 

여기서는..

std::istream_iterator<int>{in}  : 파일 in에서 정수를 처음부터, 

{} : 파일의 끝까지

hello.bigin() 부터해서 복사

하겠다는 의미를 가짐

요약하자면,, 파일에서 읽은 정수(데이터)들을 hello 배열의 처음부터 저장하도록 설정함.

이로써 int 1000개에 있던 값들이 hello에 복사가 됨!


Sort 

std::sort 

vs

std::ranges::sort (cpp최신표준)

둘이 정확히 뭐가 다르냐...

기능은 일단 똑같음. (둘다 정렬 알고리즘)

일단 sort는.. 반복자가 필요함. 반복자 begin, end를 명시적으로 써준것처럼 직접 범위를 지정해야했음

또한 반복자를 지원하는 컨테이너에서만 사용이 가능했다..

그러나 

ranges::sort는.. 위의 사진처럼 그냥 컨테이너 통채로 넣으면 알아서 정렬해줌!

반복자가 필요없다!! -> 코드가 길어질 이유가 없다. 


다음은.. 내가 정말 취약한부분에 대해 다뤘는데..

바로 이진수 관련이다.. 나는 이진수관련 수업을 안들었어서ㅜㅜ(16진수도 잘모름. 걍몰라요.)

그래서 개념을 한번 잡고가보자한다^^

 

*10진수

└ 우리가 평소에 쓰는 숫자 개념.. (0~9 사용)

*16진수

└ 16개의 숫자를 사용하는 숫자체계..└ 0~9까지는 똑같지만, 10부터는 15는 A~F를 사용함..0 1 2 3 4 5 6 7 8 9 A B C D E F이런식..ex) 26은 16진수로 1A (26 ÷ 16 = 1(몫), 나머지 10 = A) => 1A255은 16진수로 (255  ÷ 16 = 15(몫), 나머지 15 = F) => FF

*2진수

└ 0과 1만 사용하는 숫자체계컴퓨터는 모든 수를 2진수로 저장함..5 -> 10110 -> 1010보통 컴퓨터는 2진수로 데이터를 저장하지만, 사람이 읽기 어려워 16진수를 사용한다고함.(변환과정이 필요)

사용할 숫자는 0x01020304 -> 16진수 숫자임. (0x 가붙어있으면 16진수...라네염)

Little Endian 리틀 인디언

쉽게 말해.. 낮은 주소에 작은 바이트부터 먼저 저장하는 방식! (LSB -> MSB)

0x01, 0x02, 0x03, 0x04가 있으면..

저장될때 0x04 부터 저장이 됨..! 

앞에 있을수록 가장 큰 자리(MSB)를 가지고,

뒤에 있을수록 가장 작은 자리(LSB)를 가지는 것..! 

그래서 저장 순서는 04 03 02 01 이런 순서로 저장됨..

우리가 숫자를 더할때... 1234+5678의 계산을 한다 할때..

일의자리부터 차근차근 계산하지, 다짜고짜 천의자리부터 계산하지는 않는 것처럼(왜냐면 어디에서 올림이 될 지 모르니)

똑같이 생각하면 편하다.. (결론은 데이터 계산을 할 때 낮은 바이트부터 계산하는 것이 편리함) -> Little Endian..

 

Big Endian도 존재하는데, Little Endian이랑 반대되는개념.. 낮은 주소에 높은 바이트부터 저장하는 방식..

여기서는 01 02 03 04 이런식으로 저장한다고 생각하면됨!

 

자이제 수업에서 다뤘던 것을 생각해보며...

이게 뭔말인가? 만약 1690이라는 숫자가 있을 때... 컴퓨터는 1690을 아스키코드(문자)로 보고,

'1', '6', '9', '0' 이렇게 1바이트씩 하나씩 저장함.. -> 총 4바이트가 필요. + 뒤에 공백(띄어쓰기) 1바이트 = 최소 5바이트가 필요함

아니 이것은 너무 낭비가 아닌가~~~ 싶은거지...

그래서 이걸.. 바이너리하게! (2진수->16진수표현) 형식으로 저장하면 1690을 최소 2바이트만 사용해서 저장할 수 있음!(4바이트도 가능)

메모리 사용량이 훨씬 적어진다는거지.... 이제 우리는 숫자를 바이너리로 저장하면 공간을 절약할 수 있단 걸 알게됨

 

* 참고

16비트 정수(2바이트) -> 0~ 65'535 사이 숫자

32비트 정수(4바이트) -> 0~ 4'294'967'295 사이 숫자

*

 

그럼 이 낭비를 막기 위해 우리는 Little Endian을 사용한다 !

-> 이게 뭔말인가??

Little Endian은 작은 바이트부터 저장하는 방식이라고 했음

1690을 16진수로 보면 0x06 0x9A임. 이걸 리틀 인디언으로 저장하면

0x9A 0x06 순으로 저장이 됨. 

 

이걸 시험문제에 어떻게 낼지 예상해보자면...

12'345'678이 존재할 때... 평균 몇바이트가 필요하니?!

아스키로 저장시엔 최소 9바이트(공백포함), 바이너리(리틀인디언)으로 저장시 4바이트

(9+4)/2 = 6.5바이트? 뭐 이렇게 풀면 되려나.....? 


저수준출력(Binary 모드)

 

- std::ios::binary 란...

파일을 바이너리모드로 열겠다는 것..! 이게 뭔말이냐..

-> 데이터를 2진수 그대로 저장하겠다는 것.. 이걸 해야 딱 그 메모리만 저장이 됨(쓸데없는 공백같은걸 포함해서 저장을 x)

 

- 저수준 출력.. out.write()를 사용 -> 메모리에 있는 데이터를 그대로 파일에 저장하겠다.. 

데이터를 가공없이, 메모리 그대로! 저장하겠다는 것임.

보통 파일이 저장될때.. 텍스트모드(아스키 코드)로 변환 후 저장이 됨.

그런데 저수준 출력은?! 텍스트변환 없이! 바이너리 그대로. 저장을 한다는 것을 말함!

 

out.write()를 통해 저수준함수로 기록할 수있다.. (텍스트 모드하고싶으면 다른 것 사용하자)

뭐하는애냐? 바이너리 데이터 파일에 직접 쓰는 함수임!

out.write(시작할 메모리주소, 저장할 데이터 크기)

*참고로 write는 char*형식의 포인터를 요구해서 a.data()를 char*형식으로 바꿔준것임.

저기선 4000바이트가 요구되므로 int*a사이즈 만큼(4000)해서 

4000바이트를 파일에 변환없이 저장하게 해준 것임(그래서 열어보면 이상한 문자들이 가득가득ㅎ) 


[문제] 바이너리로 저장된 "진짜 랜덤" 이라는 파일이 존재! 

여기서 가장 큰 값과 작은 값을 출력하라..

교수님이랑 같이 쳤던 코드... 그런데 hello배열에 in에 존재하는 값이 제대로 안들어갔는지ㅠ모든 값이 0으로 찍히길래..

뭐가 문제인가 했다.. 첨에는 스레기값 들어간줄 알고 잘못도 없는 랜덤값만 계속 조정함;; 마루멋쓱;

그건 스레기값이 아니라 바이너리로 저장된 숫자였음을 깨달았다..

알고보니까 copy를 해줄 때.. std::istream_iterator는 텍스트 모드에서 동작..-> 이러니까 바이너리모드로 저장된 in의 값을 못읽어옴

그러니까 모든 값을 0으로 가져와버린 것이다...

아직 해결하는 부분은 진도로 안나갔지만.. 찾아보니 copy대신 read를 사용해주거나,

copy를 사용하되 istreambuf_iterator<char>로 바꿔 사용해주면 된다캄 (얘는 바이너리모드에서도 데이터를 잘 읽는대요)

이렇게하니까 최댓값과 최솟값이 제대로 나왔다!

 

 

너무 오래 앉아있었다..오늘은 여기까지..너무추워요날씨가..