분류 전체보기

Optimus EX용 커널(SmartassV2+Lazy)

2020. 3. 16. 19:56

변경점

  • 백원만님 커널 기반
  • 기본 Governer : Lazy (하지만 init.rc에서 가버너를 바꾸는 듯함)
  • 기타 여러가지

적용법


adb, terminal에서 su dd if=(img 파일 입력) of=/dev/block/mmcblk0p7

KT젤리빈용입니다

boot.img
4.8 MB

'안드로이드 > 옵티머스 EX' 카테고리의 다른 글

Optimus EX용 커널(SmartassV2+Lazy)  (0) 2020.03.16
Optimus EX 롬 백업  (0) 2016.12.28

블로그에 다크모드가 적용되었습니다!

2019. 9. 25. 00:25

추후 강좌도 작성하겠습니다.

사파리의 경우 아래와 같은 개발자 모드 화면에서 다크모드를 강제로 켜거나 끌 수 있습니다.

 

 

크롬에서도 개발자모드를 통해 미적용 상태와 비교가 가능할 것으로 보입니다.

 

 

마크다운 사용 이전의 게시물은 가독성이 현저히 떨어지는 부분이 있습니다.

최대한 옛날 글에서도 가독성을 잃지 않도록 바꿔나갈 예정입니다.

[macOS 한글 호환성 2편] 한글 깨짐 수정법

2019. 8. 29. 15:42

맥을 사용하면서 자주 접하게 될 한글 인코딩 호환성 문제

인코딩이 윈도와 다르다. 맥에서 만든 파일은 윈도에서 자음과 모음이 분리되어 보인다. 많은 사람들이 이를 자소 분리현상이라고 말한다. 또한, 일부 사이트는 한글이 깨지거나, 다운로드한 파일의 이름이 깨지는 경우가 많다.`

이번 글에서 다룰 것은 아니지만, 이 현상은 iOS에서도 나타나는 현상이다. 하지만 지금까지 iOS 사용자들은 이런 불편함을 느끼지 못했다. 파일 공유가 어려워서, 다운로드 받을 파일을 수정하는 경우는 많지만, 파일을 만드는 경우는 거의 없었다. 또한, 주요 클라우드 서비스는 파일을 업로드하면 자소 분리를 해결해주기 때문에 한글 인코딩 문제가 크게 다가오지 않았다. 그런데, 앞으로는 iOS 사용자들도 자주 겪게 될 것이다. 9월 중 정식 공개될 iOS 13에서는 File 앱을 통해 파일 관리를 쉽게 할 수 있다. 문제는 맥과 같은 인코딩을 사용하기 때문에 베타 사용자들 입장에서는 iOS 13에서 한글 처리에 문제가 생긴 것으로 느끼기도 할 수 있다는 것이다.

어쨌든, 이번 글을 통해 두 가지를 다룰 것이다.

  1. 업로드 하는 파일의 자소 분리 문제와 해결법
  2. 다운로드하는 파일의 텍스트 깨짐과 해결법

원인

이 현상의 원인은 인코딩이 달라서가 아니다. 윈도우에서 CP949라는 구식 인코딩 방식을 사용하기 때문이다. CP949는 EUC-KR의 확장 버전이라고 볼 수 있다. 이 인코딩 방식은 MS에서 초기 윈도우를 개발할 때, 한글 지원을 위해 만든 인코딩 방식이다. 따라서 현재는 개량된 인코딩이 많이 나와 있으며, 많은 운영체제에서 사용하지 않는 인코딩 방식이다(지원하지 않는다는 의미는 아니다). 요즘은 영어를 제외한 대부분의 문자를 Unicode로 인코딩한다. 영어도 특수한 문자를 표시하기 위해 유니코드로 인코딩하는 경우가 많다.

그럼에도 불구하고 윈도우는 여전히 기본 인코딩 방식이 CP949이다. 그래서 기본 텍스트 편집기로 작성한 파일이나 Visual Studio에서 작성한 코드들이 다른 운영체제에서 보면 깨져서 보인다. 특이하게도 한글 윈도우만 기본 인코딩이 CP949이다. 한글 지원을 위한 인코딩이니... 당연한 결과다. 영문 윈도우는 기본 인코딩이 CP949가 아니다. 영문 윈도우에서 작성한 한글 텍스트 문서들은 다른 운영체제에서도 잘 보인다는 얘기다.
영문 윈도우가 한글을 지원하지 않는 것도 아닌데, 한글 윈도우는 왜 기본 인코딩이 CP949인지 의문이다.

그래서, 일부 웹페이지들이 CP949로 인코딩되어 있다. 이런 사이트는 일부 운영체제에서 글자가 깨져서 보인다. 앞서 언급했듯이, 한글 윈도우만 기본 인코딩이 CP949이기 때문에 다른 언어의 윈도우나 다른 운영체제에서 작성한 웹페이지는 한글이 깨지지 않는다. 가끔은 웹페이지는 잘 보이지만, 파일을 다운로드하면 파일 이름이 깨져있기도 하는데, 이 또한 파일을 전송하는데 인코딩을 제대로 바꾸지 않아서 그렇다.

증상

글자가 깨진다는 것은 아래와 같은 증상을 말한다.

텍스트파일의 내용 중 한글이 보이지 않는다.
간혹 다운로드한 파일의 이름이 위와 같이 깨지기도 한다.

이 증상은 1편의 자소 분리 현상에 비할 수 없이 불편하다. 자소 분리 현상은 파일을 공유하면 다른 사용자가 겪게 되는 문제이면서도 인코딩을 바꾸지 않더라도 읽고 이해할 수는 있다.

하지만 위의 한글 깨짐 현상은 맥의 사용자가 직접 겪을 문제이고, 인코딩을 바꾸지 않는 한, 사용자는 읽고 이해하기 어렵다.

해결법

저 텍스트를 유니코드 인코딩으로 변환하면 된다.

이번에는 iconv명령을 사용한다. iconv -f cp949 -t UTF-8 "$f"

Automator로 만들기

기존의 터미널은 파일을 직접 입력해야 한다. 하지만 오토메이터를 사용하면 Finder에서 파일을 선택하여 바로 실행할 수 있고, 또한 여러 파일을 자동화할 수도 있다.

실행 가능한 Workflow 파일 다운로드

깨진 한글 파일 변경.workflow.zip
8.5 kB
깨진 한글 txt 변경.workflow.zip
135.5 kB

Finder에서 사용할 수 있게 등록하기

  • 시스템 메뉴(애플 로고)
  • 시스템 환경설정(System Preferences)
  • Extentions
  • Finder
  • 방금 만든 Quick Action 선택

Quick Action에 등록된 서비스를 실행하면 아래처럼 파일 내용이 정상이 된다.

[macOS 한글 호환성 1편] 한글 자소분리 해결법

2019. 8. 28. 20:06

맥을 사용하면서 자주 접하게 될 한글 인코딩 호환성 문제

macOS에서 사용하는 한글 인코딩은 Windows와 다르다. 맥에서 만든 파일은 윈도우에서 자음과 모음이 분리되어 보인다. 많은 사람들이 이를 자소 분리현상이라고 말한다. 또한, 일부 사이트는 한글이 깨지거나, 다운로드한 파일의 이름이 깨지는 경우가 많다. 이 또한 인코딩이 달라서 생기는 문제이다.

이번 글에서 다룰 것은 아니지만, 이 현상은 iOS에서도 나타나는 현상이다. 하지만 지금까지 iOS 사용자들은 이런 불편함을 느끼지 못했다. 파일 공유가 어려워서, 다운로드한 파일을 수정하는 경우는 많지만, iOS 장치에서 파일을 생성하여 공유하는 경우는 거의 없었다. 또한, 주요 클라우드 서비스는 파일을 업로드하면 자소 분리를 해결해주기 때문에 한글 인코딩 문제가 크게 다가오지 않았다. 그런데, 앞으로는 iOS 사용자들도 자주 겪게 될 것이다. 9월 중 정식 공개될 iOS 13에서는 Files 앱을 통해 파일 관리를 쉽게 할 수 있다. 문제는 맥과 같은 인코딩을 사용하기 때문에 베타 사용자들 입장에서는 iOS 13에서 한글 처리에 문제가 생긴 것으로 느끼기도 할 수 있다는 것이다.

어쨌든, 이번 글을 통해 두 가지를 다룰 것이다.

  1. 업로드하는 파일의 자소 분리 문제와 해결법
  2. 다운로드하는 파일의 텍스트 깨짐과 해결법

원인

맥과 윈도우는 인코딩 방식이 다르다.

윈도우는 NFC(Normalization Form Canonical Composition) 방식을, 맥은 NFD(Normalization Form Canonical Decomposition) 방식을 사용한다. 한국어로는 보통 완성형, 조합형이라고 말한다.

조합형은 '콜'을 저장할 때, 'ㅋ' + 'ㅗ' + 'ㄹ'로 저장한다

문자 코드
11
12
13

이라고 하면 실제 저장 내용은 111213으로 저장된다
'ㅋ', 'ㅗ', 'ㄹ'을 입력하는 동안 코드는 11, 1112, 111213으로 바뀐다.

윈도우는 '콜'이라는 문자에 다른 코드를 할당한다.

문자 코드
11
12
13
2032
222355

이라고 하면 실제 저장 내용은 222355가 된다.

'ㅋ', 'ㅗ', 'ㄹ'을 입력하는 동안 코드는 11,2032,222355로 바뀐다.

위는 예시일 뿐이며, 실제로는 완성형 중에도 여러 가지, 조합형 중에도 여러 가지 인코딩 방법이 존재한다.

증상

두 가지 모두 표준 정규화 인코딩 방식이다. 맥은 윈도우에서 만든 파일을 제대로 처리할 수 있으니, 맥은 두 가지 표준을 모두 지원하는 셈이다. 윈도우는 조합형으로 인코딩 된 파일을 제대로 표시할 수 없으니 호환성이 떨어진다고 볼 수 있다.

그러나 일반적인 사용자 입장에서는 유니코드나 인코딩 표준에 대해서 알 겨를이 없으니 맥의 문제라고 착각하기 쉽다. 개인적으로는 현실에서 꽤 많은 사용자가 맥의 문제라고 인식하는 것 같다. 윈도우가 제대로 출력하지 못하는 것인데도 불구하고...

출처 : clien.net

해결법

하지만 점유율 부분에서 이런 문제를 신경 써야 하는 쪽은 맥 사용자다. 다행히도 맥에서는 완성형으로 인코딩 된 파일을 표시할 수 있다. 그래서 파일 명을 완성형으로 인코딩하면 된다.

convmv 설치

우선 convmv를 설치해야 한다. convmv는 CONVerts filenames from one encoding to another and MoVe라는 뜻으로, 인코딩을 바꾸는 툴이다. mv는 파일을 이동하는 명령인데, 이름을 바꾸는 데에도 사용한다. 그러므로 인코딩을 바꾸는 툴이라고 봐도 된다.

터미널을 열고 brew install convmv 를 입력한다. brew가 설치되어 있지 않다면 brew를 먼저 설치해야 한다. brew는 리눅스용으로 컴파일된 프로그램을 실행할 수 있게 해주는 환경을 만들어준다.

convmv 사용법

convmv -f utf8 -t utf8 --nfc --notest <filename>

텍스트 인코딩을 utf8에서 utf8로 바꾸는데, nfc 정규화 방식을 사용한다는 의미이다.

자세한 내용은 man convmv를 참고하면 된다.

Automator로 만들기

기존의 터미널은 파일을 직접 입력해야 한다. 하지만 오토메이터를 사용하면 Finder에서 파일을 선택하여 바로 실행할 수 있고, 또한 여러 파일을 자동화할 수도 있다.

실행 가능한 Workflow 파일 만들기

  • 오토메이터 실행
  • 새로 만들기
  • Quick Action 선택
  • 왼쪽 사이드바에서 Run Shell Script를 선택하고, 오른쪽으로 끌어온다.
  • 오른쪽 패널을 이미지와 같이 바꾸고 입력한다.

for i in "$@"; do
    /usr/local/bin/convmv -f utf-8 -t utf-8 --nfc --notest "$i"
done
  • 파일을 ~/Library/Services에 저장한다.

Finder에서 사용할 수 있게 등록하기

  • 시스템 메뉴(애플 로고)
  • 시스템 환경설정(System Preferences)
  • Extentions
  • Finder
  • 방금 만든 Quick Action 선택

Finder에서 사용하기

이젠 아래 이미지처럼 사용하면 된다.

  1. itda 2020.01.21 20:19

    안녕하세요?

    brew를 설치하라고 나오는데,

    convmv brew를 어디서 다운받고 어떻게 설치하는 건지 상세하게 알려주실 수 있는 지요?

  2. itda 2020.01.21 20:19

    안녕하세요?

    brew를 설치하라고 나오는데,

    convmv brew를 어디서 다운받고 어떻게 설치하는 건지 상세하게 알려주실 수 있는 지요?

    • BlogIcon 친절한 콜홍 2020.01.22 00:58 신고

      이 공식 홈페이지 참고하시면 됩니다
      https://brew.sh/
      영어가 어렵다면 번역기를 사용하시거나 한국 블로그 검색해보세요!!

      그리구 Convmv brew를 설치하는 것이 아니라, brew를 설치하면 이후에 brew를 통해 convmv를 추가로 설치하는 겁니다.
      brew 는 앱스토어 느낌으로 여러가지 커맨드 프로그램을 설치하고 관리해주는 프로그램입니다

  3. neotrue 2020.02.04 19:32

    정말,, 추천 드릴 수 밖에 없는 글이네요. 감사합니다!!

  4. 헥헥 2020.03.02 22:53

    자소 문제로 골치를 썩고 있었는데.. 좋은 팁 감사드립니다^^
    제가 초보라서.. 위 내용 중 궁금한게 있는데요..
    for i in "$@"; do /usr/local/bin/convmv -f utf-8 -t utf-8 --nfc --notest "$i" done
    위 명령은 한글로 된 폴더, 파일 둘다 적용할 수 있는건가요?
    혹은 한글로 된 폴더에 적용하면 하위 폴더(파일)에도 일괄 적용이 가능한가요?
    도움 부탁드립니다. (__)

    • BlogIcon 친절한 콜홍 2020.03.03 00:58 신고

      이 명령을 해석하자면

      파일 이름을 텍스트로 가져와서
      ("&@"부분) 텍스트 인코딩을 바꾸는 거예요(convmv 이하 부분)

      결론은 텍스트로 가져오는 것이기 때문에 하위 폴더에는 사용할 수 없습니다.


      또한 텍스트를 가져오는 것이기 때문에 파일이든 폴더든 상관 없이 인코딩 변경이 됩니다.

  5. 헥헥 2020.03.03 02:17

    하위 폴더 적용은 안되는군요.. 그럼 여러 개의 파일을 동시에 선택한 후 변환하는 것은 가능한가요?
    자꾸 귀찮게 해드려서 죄송합니다. ㅠ

  6. 헥헥 2020.03.11 01:21

    알려주신 팁을 오늘 적용해 봤습니다. 아주 잘되네요!! 감사합니다.^^

  7. workspace 2020.03.21 01:04

    안녕하세요 커맨드를 실행하면 자꾸

    Ready! I converted 0 files in 0 seconds.

    만 뜹니다.. 해결방법이 있을까요?

    • BlogIcon 친절한 콜홍 2020.03.21 14:43 신고

      명령 입력부분의 위쪽을 스크린샷처럼 바꾸셔야 합니다.
      위쪽을 바꿔야 파일 이름이 명령에 전달되거든요

  8. workspace 2020.03.21 21:30

    스크린샷과 동일하게 오토메이터를 설정해두었습니다.
    오토메이터로 해본결과 적용되는것 같지가 않아서 터미널로 입력해보았는데 터미널에서 입력시 똑같은 상황이 발생합니다 ㅜㅜ
    터미널에서 위치도 정확하게 설정해두었는데도 0files in 0seconds 만 출력됩니다.,..

    • BlogIcon 친절한 콜홍 2020.03.21 22:04 신고

      이건 파일 이름을 텍스트로 받는 것이기 때문에 터미널로 실행하면 안될 수도 있습니다.

      터미널로 테스트해보시려면 스크립트 세줄을 복사해서 test.sh로 저장하시고
      터미널에서 ./test.sh "테스트 할 파일" 을 입력해보세요.

  9. workspace 2020.03.21 22:14

    test.sh 를 chmod777 로 권한변경후 실행해본 결과 똑같이 0files in 0seconds 라고 출려됩니다... ㅠㅠ

    • BlogIcon 친절한 콜홍 2020.03.21 22:40 신고

      혹시 첫 줄이 for f in "$@" 로 되어 있진 않으신가요?

      오토메이터에서 Pass input: as arguments로 설정하면 코드 입력 부분에 샘플이 생기는데 그 샘플에서는 f를 사용합니다.
      이걸 i로 바꿔주세요.

  10. workspace 2020.03.21 23:11

    우선 피드백 계속 친절히 주셔서 너무 감사합니다 ㅜㅜㅜ
    오토메이터로 실행: 이미 i로 설정되어있네요... as arguments 가 한글 목록으로는 '변수'인것인거죠?
    test.sh로 실행: 스크립트를 계속 실행해봐도 같은 결과입니다.... 혹시나 하여 sudo 로도 실행해본 결과 똑같습니다...

    • BlogIcon 친절한 콜홍 2020.03.21 23:21 신고

      흠... File or directory not found라고는 안 뜨는거죠?

      혹시 파일 이름이 한글이 아닌건 아닌가요?
      파일명이 utf-8로 인코딩 된 것만 처리하는 것이기 때문에 실행이 안 될 수도 있습니다.
      그런 경우에는 바뀌지 않는 파일 이름을 파인더에서 한 번 바꾸고 실행하는 방법이 있구요. 이름에 무언가 한글을 추가해보세요.
      아니면 스크립트에서 -f utf-8 인 것을 원래 인코딩에 맞춰서 바꾸셔도 됩니다.

      파일 갯수가 적은 경우에는 전자가 편할거예요.

  11. workspace 2020.03.21 23:38

    다 한글 이름 파일들 입니다...
    file -I 커맨드를 돌려본 결과 charset=binary 라고 출력됩니다.
    그래서 -f 을 binary 라고도 해보고 base64라고도 해봤는데 결과는 똑같네요..
    진짜 뭐가 문제인 걸까요 ㅠㅠ
    cannot find directory 문제는 아닌것같습니다.

    • BlogIcon 친절한 콜홍 2020.03.22 11:50 신고

      제가 정상적으로 작동하는 파일도 charset=binary라고 나오네요.

      혹시 맥에서 방금 만든 파일로도 0files in 0 seconds라고 나오나요?

      brew에서 convmv를 업데이트하거나 재설치해보세요.


      파일을 찾지 못했다고 나오지 않는걸 봐서는 convmv명령까지 파일이 제대로 전달되는 것 같습니다.
      그렇다면 convmv에서 인코딩을 제대로 인식하지 못하는 것으로 보입니다.

    • BlogIcon 친절한 콜홍 2020.03.22 11:53 신고

      맥에서 새로 만든 파일로도 제대로 안 된다면

      1. 맥 구성 문제로 한글 인코딩이 이상한 것이거나
      2. convmv의 문제로 인코딩을 인식할 수 없거나
      둘 중 하나밖에 가능성이 없습니다.

      우선 convmv재설치 하시구요.
      가능하다면 다른 맥을 사용해보시고, 그게 어렵다면 다른 사용자계정을 만들어서 시도해보세요.

  12. 맥초보 2020.03.25 01:40

    좋은 정보 정말 감사합니다. 앞으로 맥으로도 과제할때 걱정 없을거 같습니다. 한가지 질문이 있는데요. 확장프로그램 설정에서 설정한 빠른동작이 터치바 항목으로 가 있습니다. 이걸 어떻게 Finder항목으로 옮길 수 있을까요? 저장할때 Finder로 설정했는데 이상하네요 ㅠㅠ

    • BlogIcon 친절한 콜홍 2020.03.25 19:19 신고

      Finder로 설정한 건 파인더에서만 이 오토메이터를 사용할 수 있게 하는거구요, 확장프로그램 설정에 나오는 것과는 관련 없어요.
      저는 파인더와 터치바 항목에 둘 다 나타납니다.

    • 맥초보 2020.03.25 19:56

      감사합니다. 한가지만 더 여쭤도 될까요? ㅠㅠ
      저는 우클릭 했을때 Services항목이 없습니다. 제가 잘못한게 있을까요?

    • BlogIcon 친절한 콜홍 2020.03.25 20:03 신고

      그게 확장 프로그램 설정에서 사용 체크를 해야 나타나는거예요.
      확장프로그램에 나타나지 않는 이유를 모르면 해결할 수 없을 듯합니다

    • 맥초보 2020.03.25 20:08

      됐습니다!!ㅎㅎ 잘 쓰겠습니다 ㅎㅎ

    • BlogIcon 친절한 콜홍 2020.03.25 20:08 신고

      다행이네요! 잘 쓰세요~

  13. Eric 2020.03.31 09:55

    이러한 방법 알려주셔서 감사합니다.
    제가 난독증이 있어서 그러는데요..
    convmv 설치 하고, Automator로 만들기 하고..

    그리고 파인더에서 항상 수정해 줘야 하는건가요??
    이런 질문 드려서 죄송합니다.

    • BlogIcon 친절한 콜홍 2020.03.31 10:26 신고

      오토메이터까지 알맞게 이해 하신거예요!

      그 아랫 단계를 하시면 언제든지
      파인더 - 파일 선택 - 마우스 우클릭 - 서비스 - 한글 파일명 자소분리 수정
      을 클릭해서 윈도에서 자소가 분리되어 보이는 현상을 해결할 수 있습니다!

  14. 디언 2020.04.13 11:09

    안녕하세요
    brew를 아래 명령어로 설치하고
    ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    brew install convmv 로 convmv설치한후
    automator 실행 하고 캡쳐내용대로 넣은후 save한후
    finder에서 쓸수있게 service로 등록하고
    finder에서 한글명의 엑셀파일을 우클릭해서 해당 quick action을 클릭한후
    윈도우 pc에서 해당 파일을 봤는데.. 여전히 자소음이 분리되어 나타납니다 ㅠ
    혹시나해서 convmv를 uninstall 후 install다시했는데도 마찬가지에요..
    혹시 어느 부분을 놓쳤거나 점검해봐야할지요..

    • BlogIcon 친절한 콜홍 2020.04.20 00:15 신고

      어떤 의미인지 모르겠습니다.
      말씀하신 걸 보면 제대로 따라한 것 같습니다.
      처음부터 다시 한 번 차근차근 해보세요.

  15. mansesjh22 2020.04.20 00:13

    안녕하세요! 꿀팁 정말 감사합니다ㅠㅠ
    근데 과정 중에 오토메이터에 셸 스크립트를 쓰고 저장 전에 제가 잘못하고 run을 눌렀었는데요...ㅜㅜ이게 크게 문제되지는 않나요??

  16. 시미간 2020.04.24 16:43

    와우! 자소분리 문제 해결법을 찾던 중... 이 포스트를 발견했습니다!

    잘 작동합니다!

    감사합니다!

  17. ㅇㅇ 2020.05.01 04:19

    최근까지 활발히 댓글 달아주신거 보고 댓글 남깁니다.
    현재 MacOS 10.15.3에서, 정상 작동하지 않습니다. 코드 문제는 아니고요, 위에 어떤 분이 말씀하신 것처럼 제대로 변환이 안됩니다.

    ❯❯❯ convmv 도큐멘트.docx -f utf8 -t utf8 --nfc --notest
    Ready! I converted 0 files in 0 seconds.
    ❯❯❯ convmv -f utf8 -t utf8 --nfc --notest 도큐멘트.docx
    Ready! I converted 0 files in 0 seconds.
    ❯❯❯ convmv -f utf8 -t utf8 --nfd --notest 도큐멘트.docx
    mv "./도큐멘트.docx" "./도큐멘트.docx"
    Ready! I converted 1 files in 0 seconds.

    이런 상황이고요, 정확히 어떤 이슈인지 모르겠습니다. 확실한 것은 어떤 방법을 이용해도 convmv으로는 윈도우에서 한글 깨지는 현상이 없어지지 않아요. 최근까지 이 블로그에서 안내해준 오토메이터로 잘 쓰고 있었는데, Mac Version issue인지 convmv 이슈인지 모르겠어요 (전자같긴한데) 확인 가능한가요?

    • ㅇㅇ 2020.05.01 04:22

      폴더에 적용해도 마찬가지입니다.

      ❯❯❯ convmv -r -f utf8 -t utf8 --nfd --notest ./test
      mv "./test/도큐멘트.docx" "./test/도큐멘트.docx"
      Ready! I converted 1 files in 0 seconds.

      이렇게는 뜨는데, 막상 윈도우에서 보면 그대로 깨져 있어요.

Windows 10 설치 USB 쉽게 만들기

2019. 7. 12. 14:41

UEFI 바이오스에서 윈도 설치 디스크 만들기가 굉장히 쉬워졌다. 그러나 여전히 rufus와 같은 유틸리티를 사용하여 복잡하게 만드는 것이 일반적이다.

이 글에서는 다른 프로그램 없이 바로 부팅 가능한 윈도 설치 USB를 만들어보기로 한다. 방법이 굉장히 간단하기 때문에 본문도 굉장히 짧다.

그래서 서론으로 UEFI는 어떤 특징이 있는지 알아보고, 윈도 설치 ISO를 다운로드하는 방법을 알아본다.

그리고 본문으로 UEFI의 특징을 살려 윈도우 설치 디스크를 만드는 방법을 알아보고자 한다.

UEFI

UEFI의 가장 큰 특징은 기존의 BIOS 시스템에 비해 더 큰 시스템이라는 것이다.

옛날의 BIOS는 기본적인 설정과, POST(Power On Self Test)기능만 제공한다.

하지만 UEFI는 좀 더 많은 기능을 제공한다. 기본 설정과 POST 뿐 아니라, 커서 기능, GUI기능, 빠른 부팅, CLI를 제공한다. 빠른 부팅은 POST 결과를 저장해서 다음에는 POST 단계를 줄이는 기능이다. CLI는 BIOS 단계에서 명령을 실행할 수 있는 환경을 제공한다는 의미이다.

여기서 중요한 게 CLI이다. CLI로 명령을 실행하려면 BIOS가 외부 저장장치에 엑세스 할 수 있어야 한다.
UEFI가 외부 저장장치에 엑세스 할 수 있다는 또 다른 증거가 있다. UEFI는 설정 화면의 스크린샷을 연결된 USB 메모리에 저장할 수 있다는 것이다..

그리고 이런 기능의 지원을 위해 UEFI 바이오스는 FAT32 포맷의 외부 저장장치에 접근할 수 있다.

UEFI 설정 스크린샷

출처 : forum.asrock.com

UEFI는 스크린샷 단축키를 클릭하면 연결되어 있는 FAT32 장치에 스크린샷을 저장한다.

그 외에 여러가지 포맷을 읽을 수 있는 것으로 알고 있지만, 모든 OS에서 사용할 수 있는 포맷은 FAT32와 exFAT 뿐이기 때문에 이 튜토리얼은 FAT32로 진행한다.

FAT32로 윈도우 설치 USB 만들기

우리는 UEFI가 FAT32를 읽고 쓸 수 있고, 윈도우가 FAT32를 읽고 쓸 수 있으며, 윈도우가 ISO파일을 열 수 있다는 것을 알고 있다.

그러면 윈도우 설치 디스크를 만들기는 굉장히 쉽다.
ISO파일을 열고 그 파일을 FAT32 장치에 쓰기 작업을 하면 된다.

ISO 파일 다운로드 하기

MS의 공식 홈페이지에서 다운로드 할 수 있다. 다만, 윈도우에서 접속할 때와 다른 기기에서 접속할 때의 방법이 조금 다르다.

윈도우에서 접속하면 ISO 링크를 주지 않고, 윈도우에서 실행하는 다운로더를 주기 때문이다. 만약 다운로더를 사용하고 싶지 않다면 UA를 변경하면 된다.

프로그램 이용

다운로드 링크 : https://www.microsoft.com/ko-kr/software-download/windows10

다운로드 안내 페이지

위와 같은 사이트가 나타난다. 우리는 컴퓨터를 업데이트 할 것이 아니라, ISO를 만들 것이기 때문에 '지금 도구 다운로드'를 클릭한다. 'MediaCreationTool'이 다운로드 된다.

약관을 반드시 읽어보아야 한다.

프로그램을 실행하고 프로그램 사용권을 자세히 읽은 후 동의한다면 동의 버튼을 눌러 진행한다.

공식 문서이든, 블로그 문서이든, 수많은 튜토리얼을 보면 대부분 게시물들이 위와 같은 약관이나 사용 조건에 대한 동의 화면이 나오면 무조건 동의 버튼을 누르라고 하고 있다.
물론 대부분의 약관은 사용자를 방해하거나 목을 조르려는 용도로 만들지는 않지만, 반드시 읽어보도록 안내 해주었으면 하는 바람이 있다.
이 약관은, 프로그램 제조사와 사용자 사이의 법적으로 유효한 '계약'이며, 소비자의 보호, 제조사의 보호 또는 분쟁시 분쟁 중재를 위한 내용이다.

다운로드 과정

'다른 PC용 설치 미디어 만들기' 를 클릭하고 다음을 누른다.

다운로드 과정

어와 아키텍처를 선택하고 다음을 누른다. 에디션은 통합본으로 나오기 때문에 한 종류 뿐이다. 아키텍처는 Windows 8이나 그 이후 버전이 설치되어 출시된 컴퓨터라면 64비트를 선택하면 된다.

다운로드 과정

ISO 파일을 만들 것이기 때문에 'ISO 파일'을 선택하고 다음을 클릭한다.

USB 플래시 드라이브를 선택하더라도 FAT32로 포맷한다. 따라서 'USB 플래시 드라이브'를 선택하고 진행해도 결과는 같다.
단지 이 튜토리얼은 FAT32로 포맷하는 것이 얼마나 편리한지를 보여주기 위한 것이기 때문에 'ISO 파일'로 진행한다.

파일 위치 선택 대화상자가 나타나면 다운로드할 위치를 설정한다.

다운로드 중

다운로드 중

그러면 다운로드가 시작되고, 미디어를 만드는 작업을 한다.

다운로드 완료

ISO 만들기가 완료됐다. DVD 버너를 사용할 것이 아니기 때문에 '마침'을 눌러 종료한다.

ISO 파일 열기 단계로 넘어가면 된다.

ISO 다운로드 링크 이용

다운로드 링크 : https://www.microsoft.com/ko-kr/software-download/windows10ISO

원하는 윈도우 버전을 선택하고 다운로드 한다.

Windows가 아닌 OS에서 접속할 때 나타나는 ISO 다운로드 페이지

ISO 파일 USB 드라이브로 복사하기

ISO 파일 미리보기

다운로드한 Windows.iso 파일을 실행하면 위와 같은 파일들이 보인다. 이 파일들 모두 FAT32로 포맷된 USB 드라이브에 복사하면 된다.

미립자팁

마지막으로, FAT32의 장점을 활용하는 방법이다. 같은 파일 시스템 안에서는 파일을 이동하는데 걸리는 시간이 굉장히 짧다. 그래서 하나의 USB 안에 여러가지 에디션들을 넣어놓고 필요한 버전을 USB 메모리의 최상단으로 꺼내면 해당 에디션을 설치할 수 있게 된다.

설치 디스크로 부팅하기

윈도우에서 바로 진입

앞서 언급했다시피, UEFI는 빠른 부팅을 지원한다. 빠른 부팅을 할 경우 다른 불필요한 장치에 대해 POST를 진행하지 않는다. 따라서 윈도우 설치 USB 디스크를 삽입하더라도 USB는 확인하지 않고 바로 윈도우로 부팅될 수 있다.

이런 경우에 대비하여 윈도에서 직접 부팅 장치를 선택하거나, UEFI 설정에 진입할 수 있는 방법을 제공한다.

시작 -> 전원 -> (Shift 버튼을 누른 상태로) 다시 시작을 누른다

Use a device를 클릭해서 Windows 설치 디스크를 선택한다.

UEFI 설정에서 부팅 순서 변경

제조사마다 다르므로 제조사 문서를 참고해야 한다. 보통은 부팅 우선순위, Boot Priorities와 같은 표현을 사용한다.

2장-2 변수의 크기와 오버플로우, 언더플로우

2019. 5. 5. 22:01

크흠.... 기존 학교에서 배운 것들을 티스토리에 요약하고, 컴퓨터에서 삭제하려는 목적으로 '컴퓨터공학' 카테고리를 만들었습니다.

그런데 이렇게 3년이 흘러버리니 1학년 때 적어둔 것들이 어떤 순서로 필기된건지 모르겠더군요. 순서가 뒤죽박죽이어서 후에 배울 것들을 앞 장에서 응용하고 있다 보니 게시글의 순서가 뒤죽박죽이 되어 버렸습니다.

티스토리의 경우 게시된 날짜를 기준으로 정렬되는 듯하여 모든 정리가 끝나면 다시 한번 순서를 조절하도록 하겠습니다.

변수의 크기 알아보기

우선 이전 장([컴퓨터공학/C] : 2장-1 자료형)에서 각 자료형이 몇 Bytes의 크기인지 배웠습니다. 실제로 프로그래밍을 할 때 변수들의 크기가 중요합니다. 뒤에 배우게 될 구조체도 크기를 아는 것이 중요합니다.

간단한 정수형이나 실수형 변수의 크기는 외울 수 있다고 하더라도 프로그래머가 직접 구현하는 구조체의 크기까지 외울 수 있을까요? 아마 불가능할겁니다.

그래서 sizeof();연산자가 있습니다.

이 연산자는 함수가 아닙니다. 연산자입니다. 왜냐하면 프로그램이 실행될 때 sizeof();를 실행해서 크기를 계산하는 게 아니고, 프로그램을 컴파일 할 때 컴파일러가 size를 계산해서 상수로 바꿉니다. 그러니까 크기를 외워서 크기를 입력하는 것과 sizeof(); 연산자를 사용하는 것은 성능상에 차이가 없다는 의미입니다.
상수가 뭔지도 추후에 배울 예정입니다. 상수는 코드를 읽기 쉬우면서 프로그램은 가볍게 만들기에 유리합니다.

#include <stdio.h>
void main(){
    char x;
    float y;

    printf("변수 x의 크기  %d\n", sizeof(x));        //<- printf("변수 x의 크기 %d\n", 1); 과 성능 차이 전혀 없음
    printf("변수 y의 크기 %d\n", sizeof(y));
    printf("double의 크기%d\n", sizeof(double));
}

이런 식으로 활용하게 됩니다. sizeof();는 연산자가 아니기 때문에 파라미터의 형식도 상관 없고, 그게 심지어는 자료형이라도 작동합니다.

오버플로우(OverFlow)와 언더플로우(UnderFlow)

변수의 크기를 알 필요가 있는 가장 큰 이유입니다. 제대로 말하자면 조금 다릅니다. 정확한 표현으로는 오버플로우와 sizeof()를 자주 사용해야 하는 이유가 같습니다.

Overflow란, 직역 의미 그대로 넘쳐 흐른다는 의미입니다. 변수의 크기가 너무 커서 변수의 공간 안에 저장할 수 없는 경우이죠. Underflow는 반대의 의미입니다. 너무 작아서 변수의 공간 안에 담을 수 없는 경우입니다.
2장-1에서 배우기로 char형은 1 Byte 크기를 가지고 있고 -128~127의 범위를 갖고 있습니다. 그리고 1 Byte는 8 bits로 구성되어 있습니다.
만약 127을 char형 변수에 저장한다면 실제로는 0111 1111로 저장됩니다. 그리고 여기에 1을 더하면 1000 0000이 되죠. 그 값은 - 128입니다. 이런 것을 Overflow라 합니다. 반대로 -128에서 1을 빼면 127이 되는 현상을 Underflow라고 합니다.

그런데 궁금한게 있습니다! 이전 장에서도 변수의 범위까지는 언급을 했지만 왜 1000 0000이 -127이 되는지는 말하지 않았습니다. 상식적으로 맨 앞이 부호를 표시한다면 1111 1111이 -128이 되어야 하지 않을까요?
컴퓨터는 구조상 뺄셈 연산을 하지 못합니다. 구조를 단순화 하기 위해, 뺄셈은 음수를 더하는 연산을 하죠. 그래서 음수의 표현보다는 음수의 연산에 초점을 맞춰서 개발한 표현방식입니다. 이런 음수의 표현을 '2의 보수'라고 합니다.

127과 -127를 더하면 그 값은 0이 됩니다. 사람이 생각하는 대로 표현했다면 0111 1111 + 1111 1111은 1 0111 1110이라는 이상한 숫자가 나옵니다. 8 Bits 공간을 가지고 있기 때문에 Overflow는 버리고 0111 1110이 됩니다.

하지만 2의 보수를 만들어주면 덧셈이 쉬워집니다. 2의 보수는 양수에서 각 자릿수마다 ~(NOT)연산을 하고 1을 더한다고 보면 됩니다. 그러니까 0111 1111의 2의 보수를 만들면 1000 0001이 -127이 됩니다. 두 수를 덧셈 연산하면 1 0000 0000이 되죠. 위에서와 같이 Overflow를 버리면 0이 됩니다!

변수의 최댓값과 최솟값

변수의 크기는 알았는데, 그럼에도 최댓값과 최솟값은 알아야 Overflow를 방지할 수 있는것 아닌가요? 그래서 몇몇 변수에 대해서 최댓값과 최솟값을 미리 정의해둔 헤더가 있습니다. limits.h인데요, 여기서 CHAR_MIN, CHAR_MAX, UINT_MIN, UINT_MAX 등의 표현으로 정의되어 있습니다. 바로 사용해볼까요?

#include<stdio.h>
#include<limits.h>

void main(){
    char x = CHAR_MAX;
    printf("MAX of CHAR : %d \n", x);
    char y= x+ 1;
    printf("Overflow : %d \n", y);
    printf("127+(-128)  = %d\n", x+y);                 //출력은 -1이 됩니다.
}

이런 식으로 사용할 수 있는겁니다. char의 최댓값을 저장하면 127이 됩니다. 그리고 Overflow된 값(-128)을 y에 저장합니다. 그리고 이 두 수를 더하면 -1이 됩니다.

요약

  • 변수의 크기를 알 수 있다.
  • 오버플로와 언더플로를 이해할 수 있다.
  • 2의 보수를 이해하고, 음수와의 연산에서 오버플로와 언더플로를 활용하는 것을 알 수 있다.
  • 변수의 최댓값과 최솟값이 정의된 헤더를 불러올 수 있다.

변수의 크기를 알아야 하는 이유?

마지막으로 한 가지 더!

오버플로를 설명하면서 변수의 크기를 알아야 하는 이유라고 언급했습니다. 하지만 아무리 생각해봐도 관련성이 없어보입니다. 나중에 배열, 포인터나 주소의 개념을 갖고 나면 이해가 될 부분입니다. C언어는 LowLevel언어이기 때문에 메모리 주소에 직접 접근할 수 있습니다. 그만큼 프로그램이 빠르지만 프로그래머가 메모리를 고려해야 하는 단점이 있습니다.

예를 들어서 char형의 변수가 5개로 구성된 배열 name이 있습니다. 이 변수는 1 Byte 변수가 5개가 있는 것이고, 총 5 Bytes로 구성됩니다. name의 주소가 0x0020이라고 하면, 첫번째 칸은 0x0020이고, 다섯번째 칸은 0x0025가 됩니다.
그런데 프로그래머가 6번째 배열에 접근하려고 하면 C언어는 0x0026에 접근합니다. name을 통해 접근할 수 있는 주소의 범위는 0x0020~0x0025까지인데, 이에 상관없이 0x0026에 접근하는 겁니다. 물론 이런 비정상적인 접근은 OS에서 차단하고 프로그램을 강제 종료합니다. 계속 실행되면 다른 프로그램의 정보를 탈취할 수 있기 때문에 아예 종료해버리는 겁니다.

출처 : reddit.com
그 결과가 이겁니다. 옛날에는 시도 때도 없이 보던 겁니다. 수 년이 지나면서도, Windows가 업데이트 되고 업그레이드 되면서도 꾸준히 보던 경고입니다. 지금 보니 메모리 접근을 고려하는게 얼마나 어려운지 아시겠죠?

물론 다른 고급 언어들도 비슷합니다. 객체 지향 언어들도 배열은 같거든요. 하지만 대부분은 객체를 사용합니다. 그리고 그 객체는 리스트(배열 개념을 객체로 표현한 것이다. C언어는 Linked List(연결리스트)로 구현할 수 있다.)와 리스트의 갯수까지 갖고 있기 때문에 프로그래머는 마지막 변수가 필요할 때, 리스트의 크기를 가져오면 됩니다.

리스트의 개념은 C언어에서도 구조체를 이용해 연결리스트로 표현이 가능합니다. 단지 구현 방법이 좀 다를 뿐이죠. 이는 후에 배열, 포인터 부분에서 학습하게 됩니다.

다음에는 진수의 표현에 대해서 올리도록 하겠습니다.

'컴퓨터공학 > C' 카테고리의 다른 글

2장-2 변수의 크기와 오버플로우, 언더플로우  (0) 2019.05.05
4장-2 비트 연산과 연산 순서  (0) 2019.01.14
4장-1 산술 연산자  (0) 2019.01.14
3장 printf scanf 함수  (0) 2019.01.10
2장-1 자료형  (0) 2019.01.10
1장-1 Hello World  (0) 2018.12.16

Windows 10 코어파킹 (4) 부스트클럭편 노트북편

2019. 1. 19. 23:24

모바일을 위한 코어파킹

코어파킹에 대한 포스트 제목이 "더 조용하게, 더 오래!"였지만 실제로 모바일이나 배터리에 관한 언급은 거의 없었습니다.

오히려 고성능 위주의 HEDT에 적절한 설정값을 공유하거나 추천해드렸습니다.

이번에는 모바일에 대하여 말해보려고 합니다. 클럭이 높을수록 에너지 효율이 떨어지기 때문에 클럭이 낮게 유지될 수 있어야 합니다. 단기적으로는 더 조용하고 오래 사용할 수 있습니다. 발열량이 감소하기 때문에 높은 성능이 필요한 순간에 높은 성능을 낼 수 있고, 장기적으로는 더 높은 성능까지 낼 수 있어야 합니다. 하지만 장기적으로 빠른 처리를 하기 위해 단기적인 관점에서 성능 하락이 크면 안될겁니다.

기존에 코어파킹 강좌에서 언급했거나 설명했던 항목들은 전체적인 부분을 조절하는 항목들입니다.

CPU의 사용량에 따라 설정한 가장 낮은 클럭부터 설정한 가장 높은 클럭 사이를 조절하는 항목이거나, CPU의 사용량에 따라 활성화 된 코어를 설정한 최솟값과 최댓값의 사이에서 조절하는 항목입니다.

이번에는 단순한 클럭 조절을 위한 코어 파킹 설정이 아닙니다. 부스트 클럭을 조절하기 위한 항목에 대해 언급하려고 합니다.

부스트 클럭과 TDP

CPU 제조사들은 코어를 늘리면서 발열을 해소하기 위해 Base Clock을 낮추고, 동시에 특수한 상황에서는 오히려 성능이 낮아지는 단점을 해소하기 위해 Boost Clock이라는 개념을 적용했습니다.

그리고 부스트 클럭과 베이스 클럭의 운영을 조절하기 위해 TDP를 도입합니다.

모바일은 TDP로 발열을 제어합니다. 데스크톱도 발열제어를 하지만 큰 영향을 받지는 않습니다.

TDP에 의한 발열 제어는 CPU만 고려합니다. 그러다보니 CPU의 성능은 남고 GPU의 성능은 부족한데 TDP제한이 작동하지 않았던 경우도 있습니다. 그래서 라이젠 모바일 프로세서의 경우는 TDP를 더 낮춰서(클럭이 더 낮게 유지됨) 더 높은 게이밍 퍼포먼스를 달성하기도 하였습니다. 인텔이든 AMD든 상관 없이 클럭이 높기 때문에 부스트 클럭을 제한함으로써 배터리와 발열은 개선하면서도 체감 차이는 거의 없는 후기가 올라오기도 하였습니다.

데스크톱 프로세서라고 예외는 아닙니다. TDP에 의한 발열 제어는 데스크톱 프로세서와는 관련이 없지만, 부스트 클럭의 조절이 필요합니다. Intel Core i9-9900K의 터보 클럭 스펙은 다음과 같습니다.

출처 : wikichip.org

부스트 클럭으로 작동하는 코어가 많아질수록 최대 클럭은 낮아집니다.
만약 싱글 쓰레드 위주의 프로그램을 실행할 때 모든 코어가 부스트 클럭으로 유지되고 있다면 어떨까요? 해당 쓰레드는 실제로는 4.7Ghz처럼 처리되겠죠. 게다가 파일 탐색기나, 마우스 커서의 움직임처럼 간단한 작업을 처리하는 프로세스들도 불필요하게 4.7Ghz로 처리될겁니다.
하지만 부스트 클럭으로 작동하는 코어를ㄹ 잘 조절하면 높은 성능이 필요한 쓰레드는 5.0Ghz로 작동할 겁니다. 다른 코어에서 실행되는 프로세스들은 베이스 클럭인 3.6Ghz의 속도이지만 체감 차이 없이 처리될 수 있습니다.

코어 수가 많아지면서 베이스 클럭과 부스트 클럭의 차이가 커지는 양상을 보이고 있습니다. 또한 부스트 클럭으로 작동하는 코어의 수에 따라 부스트 클럭도 달라집니다. 클럭이 높을 수록 에너지 효율이 떨어지고 연산량 대비 발열량이 증가합니다. 그렇기 때문에 베이스 클럭은 낮추고, 부스트 클럭도 활성 코어 수에 따라 변하게 하는거죠.

베이스 클럭 자체도 낮은 성능은 아닙니다. 그렇기 때문에 베이스 클럭은 자주 사용되고 부스트 클럭은 덜 사용된다면 발열 제어에 여유가 생겨서 필요할 때에 높은 성능을 낼 수도 있고, 체감 성능 하락도 작아질 것입니다. 그렇기 때문에 부스트 클럭을 적절히 조절하면 높은 성능을 유지할 수 있습니다.

부스트 클럭 설정 조정

윈도우는 작업 관리자에 베이스클럭이 표시됩니다. 즉, 윈도우는 베이스 클럭과 부스트 클럭을 인식할 수 있다는 거죠.(물론 맥이나 리눅스도 마찬가지입니다)

그리고 윈도우는 부스트 클럭에 관한 조절 기능도 제공하고 있습니다. 하지만 기본값이 일반 베이스 클럭과 다를 바 없이 대하도록 되어 있습니다. 그렇기 때문에 웹 브라우저를 실행하고, 웹서핑하는 내내 높은 클럭이 유지됩니다.

반면 MacOS의 경우는 베이스클럭에 있는 시간이 부스트 클럭에 있는 시간보다 깁니다. 웹 브라우저를 실행할 때는 부스트 클럭으로 작동하지만, 웹서핑할 때는 베이스 클럭보다 높은 주파수로 올라가지 않습니다. 그러다가 링크를 클릭하여 다른 웹 페이지로 이동할 때는 부스트 클럭으로 작동합니다.

아래 설정을 통해서 윈도우에서도 부스트 클럭에 머무르는 시간을 줄일 수 있습니다.

Windows 10 코어파킹 더 조용하게, 더 오래!

  • 우선 Windows 10 코어파킹 더 조용하게, 더 오래!편을 참고하여 전원 옵션을 활성화 해주세요.
  • 그리고 제어판 -> 시스템 및 보안 -> 전원 설정에 들어갑니다.
  • 사용 중인 프로필의 오른쪽에 있는 "설정 변경" 버튼을 클릭합니다.

  • 그리고 "컴퓨터를 절전 모드로 설정" 아래에 있는 "고급 전원 관리 옵션 설정 변경"을 클릭합니다.

  • 나타나는 창에서 '프로세서 전원 관리' -> 프로세서 성능 향상 모드(영문OS를 사용 중이기 때문에 한글 표현은 다를 수 있습니다.)로 이동합니다.


그러면 위와 같은 옵션들을 확인할 수 있습니다.

꺼짐
활성
적극적
효율적으로 활성
효율적으로 적극적
보장될 때 적극적
보장될 때 효율적으로 적극적

등의 옵션이 있습니다. 번역이 이해하기 조금 힘들긴 하지만 잘 생각해보면 어려운 표현은 아닙니다.

추가로 Microsoft에서 이와 관련한 설명을 제공하고 있습니다.

Name P-state-based behavior CPPC behavior
0 (Disabled) Disabled Disabled
1 (Enabled) Enabled Efficient Enabled
2 (Aggressive) Enabled Aggressive
3 (Efficient Enabled) Efficient Efficient Enabled
4 (Efficient Aggressive) Efficient Aggressive

출처 : Microsoft

여기서 P-state-based behavior와 CPPC는 CPU 성능에 관한 메시지를 전달하는 방법입니다.

꺼짐 : 부스트 클럭은 사용하지 않습니다.
활성 : (P-state : 활성, CPPC : 효율적으로 활성)
적극적 : (P-state : 활성, CPPC : 적극적)
효율적으로 활성 : (P-state : 효율적, CPPC : 효율적으로 활성)
효율적으로 적극적 : (P-state : 효율적, CPPC : 적극적)
보장될 때 적극적 : (P-state : 효율적, CPPC : 효율적으로 활성)
보장될 때 효율적으로 적극적 : (P-state : 효율적, CPPC : 적극적)

Microsoft 문서에는 "at Guaranteed(보장될 때)"에 대한 설명은 없습니다. 하지만 이 설정을 사용하면 부스트 클럭을 사용하지 않는 것과 다름이 없을 정도라는 커뮤니티 후기가 있습니다.

부스트 클럭 유지 시간 : 적극적 > 활성 > 효율적으로 적극적 > 효율적으로 활성 > 보장될 때 적극적 > 보장될 때 효율적으로 적극적

서버용 Windows의 경우 기본값이 "효율적으로 활성"입니다.

MacOS와 같은 CPU 성능 조절을 원한다면 "효율적으로 활성"이 가장 적절할 것 같습니다.

4장-2 비트 연산과 연산 순서

2019. 1. 14. 19:40

비트 연산, 시프트 연산, 연산 순서

2장 자료형에서 비트에 대한 얘기를 잠깐 하고 지나갔었죠?

컴퓨터는 모든 데이터를 0과 1로 저장합니다. 그걸 bit라고 하죠. 2진수로 볼 수 있습니다.
비트를 이용해 표현할 수 있는 수는 아래와 같습니다.

1비트로는 0, 1.
2비트로는 00, 01, 10, 11.
3비트로는 000, 001, 010, 011, 100, 101, 110, 111.

int는 4bytes(32bits)로 표현되는 정수입니다.

그런데 이런 데이터를 산술 연산이 아닌 bit끼리 비교하는 방법이 있습니다. 그걸 비트 연산이라고 합니다.
뭐랄까, 메모리의 데이터를 그대로 비교한다는 느낌일까요?

그래서 비트 연산은 사칙 연산이 아닌 다른 연산을 할 때 주로 사용합니다. AND, OR, XOR, NOT, 그리고 시프트 연산이 있습니다.

AND, OR, XOR, NOT 연산

비트 연산에 적용하기 전에 이 연산자들이 어떤 연산을 하는지 먼저 알아보도록 하겠습니다.

보통 비트 연산에서는 0이 거짓, 1이 참이라고 생각하면 편하게 계산할 수 있습니다.

AND(&)연산은 두 비트가 모두 1일 경우에 결과값이 1이 됩니다. a & bab 모두 참인지 물어보는 연산이라고 생각하면 됩니다.

0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1

OR(|)연산은 두 비트 중 하나라도 1일 경우에 결과값이 1이 됩니다. a | bab 둘 중 하나라도 참인지 물어보는 연산입니다.

0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1

XOR(^)연산은 두 비트가 같으면 결과값이 1이 됩니다.

0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0

NOT(~)연산은 좀 다릅니다. 두 데이터를 비교하는 게 아닌, 하나의 데이터를 반전하는 연산입니다.

0 = 0
1 = 1
~0 = 1
~1 = 0

컴퓨터에서 비트 연산

변수는 1비트로 이루어져 있지 않습니다. 참과 거짓만을 저장하는 boolean을 제외하고 가장 작은 자료형이 char입니다. 1byte 자료형이고, 비트로는 8bits입니다.

그렇다면 여러 자리의 bits는 어떻게 연산할까요? 이 글의 초반에 메모리의 데이터를 그대로 비교하는 느낌이라고 했던 것 기억하시나요? 비트 연산을 할 때, 컴퓨터는 메모리의 값이 어떤 의미를 가지고 있는지는 상관하지 않습니다. 단지 하나의 bit 끼리만 비교하는 거지요.

여기, 1 byte크기의 데이터가 두 개 있습니다.

각각 a=0010 0101(정수 37), b=1000 0110(정수 -122) 라고 해보지요. 1 byte는 8 bits데이터입니다. 8 bits 크기의 데이터를 하나의 bit 끼리 비교한다면 각 자리별로 총 8번 'bit 연산'을 수행하면 됩니다.

이제 두 데이터 a와 b를 AND, OR, XOR, NOT연산을 해보겠습니다.

AND 연산

a = 0010 0101(37)
&
b = 1000 0110(-122)

A = 0000 0100(4)

OR 연산

a = 0010 0101(37)
|
b = 1000 0110(-122)

A = 1010 0111(-89)

XOR 연산

a = 0010 0101(37)
^
b = 1000 0110(-122)

A = 1010 0011(-93)

NOT 연산

a = 0010 0101(37)
~a = 1101 1010(-38)

b = 1000 0110(-122)
~b = 0111 1001(121)

NOT연산은 정수값을 보니 어떤 의미인지 좀 보이지 않나요?ㅎㅎ

Shift(시프트 연산)

비트 연산은 메모리의 데이터가 의미하는 바에 상관 없이 비트 끼리만 연산하는 거라고 했습니다.

그렇다면 그 비트를 왼쪽이나 오른쪽으로 옮기는 연산도 있지 않을까요?

그것을 Shift 연산이라고 합니다.

#include<stdio.h>
void main(){
    int i = 64;
    i = i << 1;

    printf("%d", i);

    i = i >> 1;

    printf("%d", i);
    return ;  
}

와 같은 형식으로 쓰입니다.

그런데 이 연산의 결과가 재미있습니다.

값이 64인 i를 왼쪽으로 한 번 시프트하면 i는 원래의 두 배인 128이 됩니다. 두 번 시프트 하면 256이 되죠. 반대로 오른쪽으로 시프트하면 128, 그리고 64가 됩니다.

한 번 왼쪽으로 시프트하면 값이 두 배가 됩니다. 오른쪽으로 한번 시프트 연산을 하면 값이 반이 됩니다. 어떻게 이런 결과가 나올까요? 바로 이진법의 원리 때문입니다.

이진법으로 숫자를 써보면 아래와 같습니다.

1 = 0000 0001
2 = 0000 0010
4 = 0000 0100
8 = 0000 1000
32 = 0010 0000
128 = 1000 0000(unsigned char)
-128 = 1000 0000(signed char)

-128인 이유는 '2의 보수' 개념을 사용하기 때문입니다. 2장-2글을 참고하세요

앗, 그러면 두 배를 곱할 때는 i = i * 2; 보다는 i = i << 1;이 빠르지 않을까요? 논리적으로는 맞습니다. 그런데 굳이 그럴 필요는 없습니다. 우리는 컴퓨터에 직접 명령하는 게 아니라, 명령을 적으면 컴파일러가 적절히 최적화 하기 때문이죠.

마지막을 보면 << 연산을 하면 64가 -128이 됩니다. 변수의 크기, 부호의 여부에 따라 음수가 나옵니다. 예상하던 결과와는 다른 값이 나옵니다. 그런데 곱셈 연산도 마찬가지입니다. 컴파일러는 부호가 있는(signed) 변수인 것을 알고 있지만 똑같이 -128이 되죠.

-128을 << 연산을 하면 어떻게 될까요? 비트로 보자면 1 0000 0000입니다. 하지만 8 bits만 할당 된 변수에서는 가장 앞의 1은 버려지고 결과는 0000 0000(0)이 됩니다. 곱셈 연산을 하더라도, 컴파일러는 char 자료형이 8 bits 변수인 것을 알지만 같은 결과가 나타납니다. 똑같이 예상하던 결과와 달른 값이 나오죠.

결국 컴파일러는 같은 연산으로 처리한다는 것을 어림잡아 볼 수 있을 것 같습니다.

3장에서 나누기 연산에 사용되는 두 변수가 모두 정수형이면 정수형으로 결과가 나온다고 했던 것 혹시 기억하시나요?

오른쪽 시프트 연산의 결과는 정수형의 나눗셈 연산과 결과가 같습니다.

변수 0101 0101(85)가 있습니다.

Rsh 1 회 : 0010 1010(42)
Rsh 2 회 : 0001 0101(21)
Rsh 4 회 : 0000 0101(5)
Rsh 6 회 : 0000 0001(1)

오른쪽 시프트를 할 때, 가장 왼쪽의 bit가 다음 bit에 복제됩니다. 그래서 부호를 나타내는 bit는 유지됩니다. 그렇기 때문에 음수에서도 나눗셈의 결과를 볼 수 있습니다.
하지만 음수에 대해서는 시프트 연산과 나눗셈이 다릅니다. 비트연산은 소숫점 자리를 버린다고 했죠? -12.1보다 작은 가장 큰 자연수는 -13입니다. 일반적으로 생각하는 버림과는 조금 다르죠.

음수인 1010 1010(-86)으로 비교해볼까요?

횟수 Bit 연산 정수 연산
1 1010 1010(-86) -86
2 1101 0101(-43) -43
3 1110 1010(-22) -21
4 1111 0101(-11) -10
6 1111 1101(-3) -2
8 1111 1111(-1) 0

비트 연산에서는 소수점 자리를 버립니다. 음수가 더 작은 수가 맞기 때문에 단순한 시프트 연산에서는 맞는 결과이죠. 정수의 나눗셈 연산에서는 사람에게 자연스럽게 소숫점 자리를 버립니다.

1111 1111>> 연산을 아무리 반복해도 -1입니다. 왜냐하면 -1을 2로 나누면 -0.5인데, 이걸 내림연산 하면 -1이 되기 때문입니다.

정수의 나눗셈에서는 -1을 2로 나누면 -0.5이고, 소수점 자리를 버리면 -0 = 0 이 되는 것입니다.

왼쪽 시프트를 얘기하면서 곱셈 대신 시프트를 사용하면 더 빠르다고 말했습니다. 하지만 컴파일러가 최적화를 하기 때문에 시프트 연산을 사용할 필요는 없다고 했죠.
그런데 최적화의 문제만이 아니라 연산의 결과가 달라질 수도 있습니다. 그러니 오류를 무릅쓰고 시프트 연산을 사용할 필요는 없다는 결론을 내릴 수 있습니다.

연산자 순서

산술 연산과 비트 연산들을 소개하면서 연산 순서에 관한 얘기를 몇 번 했습니다.

일단 순서와 관련한 표를 볼까요?

순서 연산자 설명 Associativity (연산자 내 순서)
1 ++a --a Suffix/postfix 증감 연산자 Left-to-right
() Functional forms
[] 배열 지정 연산자
. 구조체와 공용체 접근자
-> 포인터를 통한 구조체와 공용체 접근자
(type) {list} Compound literal
2 a++ a-- Prefix 증감연산자 Right-to-left
+a``-a 단항 연산자 : a를 음수로 만들거나 양수로 만드는 연산자
!``~ 비트연산 NOT, 논리연산 NOT
(type) 형 변환
* Indirection (dereference) (참조)
& 변수의 주소를 가리킴
sizeof Size-of(크기 확인용 연산자)
_Alignof Alignment requirement
3 * / % 곱셈, 나눗셈, 나머지 Left-to-right
4 + - 덧셈, 뺄셈
5 << >> 왼쪽 시프트, 오른쪽 시프트
6 < <= 비교 연산자
> >= 비교 연산자
7 == != 비교 연산자
8 & Bitwise(비트 연산) AND
9 ^ Bitwise XOR (exclusive or)
10 | Bitwise OR (inclusive or)
11 && Logical AND
12 | | Logical OR
13 ? : Ternary conditional(3항 조건 연산자) Right-to-Left
14 = 대입 연산
+= -= 복합 산술 연산
*= /= %= 복합 산술 연산
<<= >>= 복합 비트 연산
&= ^= |= 복합 비트 연산
15 , Comma Left-to-right

출처 : cppreference.com

너무 많죠? 너무 많아요... 하지만 뒤쪽을 배우다 보면 금방 외웁니다. 아니, 외울 필요도 없습니다. 너무 당연한 순서이기 때문이죠.

예시를 하나 볼까요?

#include <stdio.h>
void main(){
    int a = -43, b = ~(6 - 5) - 1 - 3;
}

와우 정말 쓸 데 없는 프로그램입니다.

가 아니고...

int a = -43, b = ~(6 - 5) - 1 - 3;안에 있는 연산자들을 위 표에서 찾아보세요.
Functional Forms (), 대입연산자 =, 단항연산자 -, 콤마 , , 비트 연산 ~, 산술 연산자 -까지 보입니다.
이 연산자들이 어떤 의미일지 한 번 보세요. 그리고 순서를 한 번 보세요. 꽤나 상식적인 부분이 많습니다.

이 중에 첫번째인 것은 ()입니다. 순서에 따라 연산하면 int a = -43, b = ~1 - 1 - 3; 이 되겠네요.

두번째 연산자는 단항 연산자 -~입니다. 그러면 int a = -43, b = -2 - 1 - 3; 가 됩니다. 단항 연산자는 딱히 표시할 방법이 없습니다. 0010 10111101 0101되었다고 보면 될 것 같습니다.

세번째 연산자는 산술 연산자 -입니다. 그런데 -는 연산자 내에서도 순서가 있죠. 처음에는 int a = -43, b = - 3 - 3; 이 되고, int a = -43, b = - 6; 이 됩니다.

네번째 연산자는 =입니다. 각각의 값을 a와 b에 대입합니다. ,의 순위가 가장 낮기 때문에 a와 b를 한 줄에서 선언해도 서로 영향을 주지 않습니다. 또한 ,는 왼쪽 부터 연산을 하기 때문에 a에 먼저 -43을 대입하고 b-6을 대입합니다.

요약

  • AND, OR, XOR ,NOT연산을 이해할 수 있다.
  • <<연산과 >>연산을 이해할 수 있다.
  • 곱셈과 나눗셈, 시프트 연산의 차이를 알 수 있다.
  • 연산의 순서를 이해하고 외울 수 있다.

'컴퓨터공학 > C' 카테고리의 다른 글

2장-2 변수의 크기와 오버플로우, 언더플로우  (0) 2019.05.05
4장-2 비트 연산과 연산 순서  (0) 2019.01.14
4장-1 산술 연산자  (0) 2019.01.14
3장 printf scanf 함수  (0) 2019.01.10
2장-1 자료형  (0) 2019.01.10
1장-1 Hello World  (0) 2018.12.16

4장-1 산술 연산자

2019. 1. 14. 19:40

Computer의 의미는 연산 장치입니다.
그러면 이제 본격적으로 연산을 시켜봐야겠죠?

산술연산자 + - * / % =

사칙연산

기본적으로 C언어는 덧셈 뺄셈 곱셈 나눗셈을 모두 사용할 수 있습니다.
덧셈과 뺄셈은 +, -기호를 사용하면 됩니다.
곱셈과 나눗셈은 키보드에 기호가 없기 때문에 조금 다릅니다. 곱셈은 *, 나눗셈은 / 기호를 사용합니다.

#include <stdio.h>
int main(void){
    printf("20 X 30 = %d\n", 20*30);
    return 0;
}

와 같은 방식으로 사용이 가능합니다. 콘솔에서는 20 X 30 = 600으로 보이겠죠.

앞서 배운 scanf를 활용하면

#include <stdio.h>
int main(void){
    int a, b;
    printf("숫자 입력 : ");
    scanf("%d %d", &a, &b);
    printf("20 X 30 = %d\n", a*b);
    return 0;
}

도 가능합니다. 그런데 나눗셈에서는 주의해야 할 게 있습니다.

#include <stdio.h>
int main(void){
    int a = 10, b = 3;
    printf("%d", a/b);
    return 0;
}

이런 프로그램이 있습니다. 10 / 3의 연산 결과를 출력하는 프로그램이죠.
수학에서 10 / 3 = 3.3333...입니다. 그런데 컴퓨터 언어는 다릅니다.
초등학교 때 배웠던 수학 기억하시나요? 10 을 3으로 나누면 몫은 3이었죠. C언어는 정수와 정수로 나눗셈을 하면 몫도 정수가 됩니다.

printf("%f", a/b);를 사용하면 괜찮지 않을까요? 안타깝게도 그렇지 않습니다.
두 변수가 정수일 경우 컴파일러는 정수연산을 합니다. 그러면 결과값도 정수이기 때문에 %f를 사용하면 결과만 이상해집니다.
그렇기 때문에 나눗셈 결과에 소수점이 필요하다면 변수를 선언할 때부터 실수형으로 선언해야 합니다.

다행히도 두 변수 중 하나라도 실수형 변수라면 컴파일러는 다른 변수도 실수형으로 변환해서 연산할 수 있습니다.

#include <stdio.h>
int main(void){
    float a = 10;
    int b = 3;
    printf("%f", a/b);
    return 0;
}

이 프로그램을 실행하면 b는 정수형으로 선언했음에도 불구하고 제대로 된 결과값이 출력됩니다.

%=연산

%는 나머지 연산입니다.
나머지 연산이 없다면, 나눗셈을 하고 나누는 수와 몫을 곱해서 원래의 수에서 빼야 합니다.
하지만 나머지 연산으로 표현이 간단해졌죠. printf("10 나누기 3 의 나머지 = %d\n", a%b); 처럼 사용할 수 있습니다. 결과는 10 나누기 3의 나머지 = 1이 됩니다

=은 대입 연산입니다.
수학에서는 등호라고 하지만 컴퓨터언어에서는 대입 연산이라고 불립니다. 그 이유는 연산 순서와 방향이 정해져 있기 때문이죠.
대입 연산은 오른쪽의 값을 왼쪽으로 대입하는 연산입니다. 우리는 변수를 선언할 때 a=10;과 같이 사용합니다.
하지만 10=a;라고는 사용할 수 없습니다. 오른쪽의 값을 왼쪽으로 대입하는 연산이기 때문에 10이라는 정수에 a의 값을 대입할 수 없기 때문이죠.

좀 깊게 들어가볼까요?

#include <stdio.h>
int main(void){
    int a= 20, b = 10;
    a = b = 5;
    printf("%d, %d",a, b);
    return 0;
}

이렇게 하면 어떻게 출력될까요?
처음에 a는 20, b는 10입니다.
그런데 다음 줄에서... 갑자기 멍해집니다. 이런 부분 때문에 연산의 순서를 알아둘 필요가 있습니다.

뒤쪽에서 배우겠지만 대입 연산은 오른쪽 부터 연산합니다.
대입 연산이 오른쪽의 값을 왼쪽으로 대입하는 연산이라고 했죠? 그렇기 때문에 ab의 값을 대입해야 합니다. 그 전에, 대입 연산은 오른쪽 부터 연산하기 때문에 b = 5연산을 먼저 하는것이죠. 그러므로 b는 5입니다.
콘솔 출력은 5, 5가 되겠죠.

대입 연산의 특성을 사용한 방법이 하나 더 있습니다. a = a + 5;와 같은 연산이죠. 수학에서는 말도 안되는 식입니다.
하지만 대입 연산에서는 가능합니다. 대입 연산은 오른쪽의 값을 왼쪽에 대입합니다. 그러면 오른쪽의 값을 먼저 알아야겠죠. 오른쪽의 값은 a + 5입니다. 그러니까 원래의 a 값에 5를 더한 값을 a에 대입하는 거죠. 이 연산을 계속 반복하면 a에 5를 더하는 연산을 계속 반복하는 겁니다.

복합대입연산자(Compound Assignment operator)와 증감연산자

이 두 가지 연산은 산술연산을 더 간단히 표현하는 방법입니다.
우선 복합 대입연산자는 대입할 변수에 어떤 연산을 수행해서 그 결과를 대입하는 연산을 간단히 표현하는 겁니다.
바로 위에서 배웠던 a = a + 5;가 그 예가 될 수 있겠죠. 이걸 줄여서 a += 5; 로 표현할 수도 있습니다.
덧셈 뿐 아니라 뺄셈, 곱셈, 나눗셈, 나머지 연산에도 사용할 수 있습니다. +=, -+, *=, /+, %=이렇게요. 뒤에서 배우게 될 비트연산자나 시프트 연산에도 사용할 수 있습니다!

a &= b;
a |= b;
a ^= b;
a <<= b;
a >>= b;

증감연산자는 변수에 1을 더하고 빼는 연산자입니다. a++; 같은 식으로 쓰는 연산자입니다. 이 연산을 하면 a에 1이 더해지죠.
이 연산자는 덧셈과 뺄셈 밖에 없습니다. 1을 곱하거나 나누는 것은 의미가 없으니까요.

증가 연산에도 두 가지 표현이 있습니다. a++;뿐 아니라++a;로도 쓸 수 있거든요. 이번엔 딱 봐도 알겠죠? 연산 순서에 따라 달라진다는 것을요. ++a는 덧셈 연산을 먼저 하고 다음 연산을 하는 겁니다. a++는 다른 연산을 먼저 하고 덧셈을 합니다.

여기서 다른 연산은 한 문장에서 덧셈 외의 연산같은 것들을 말합니다.
예를 들어 a = 5;인 변수가 있을 때 printf("%d",a++);가 있을 수 있습니다. 이 명령은 5가 출력됩니다. 하지만 printf 연산 후에 a는 6이 되죠.
printf("%d",++a);는 6을 출력합니다. 그리고 출력 이후에도 a 값은 6입니다.

내용이 너무 길기도 하고 연산 치고는 성격이 좀 다른 내용이어서 다음 편에서 이어서 하도록 하겠습니다.
다음 편에서는 비트 연산과 시프트 연산, 그리고 연산 순서에 대해 알아보겠습니다.
연산 순서는 여러가지 연산자들 사이에서 어떤 순서로 처리되는지 알아야 원하는 대로 프로그램이 실행되기 때문에 중요합니다.

요약

  • 산술 연산자로 덧셈(+), 뺄셈(-), 곱셈(*), 나눗셈(/)을 할 수 있다.
  • 정수 나눗셈과 실수 나눗셈의 차이를 알 수 있다.
  • 나머지 연산(%)과 대입 연산(=)을 할 수 있다.
  • 대입 연산의 순서를 알 수 있다.
  • +=, -= 같은 복합 대입 연산자를 사용할 수 있다.
  • a++, ++a같은 증감연산자를 사용할 수 있다.

'컴퓨터공학 > C' 카테고리의 다른 글

2장-2 변수의 크기와 오버플로우, 언더플로우  (0) 2019.05.05
4장-2 비트 연산과 연산 순서  (0) 2019.01.14
4장-1 산술 연산자  (0) 2019.01.14
3장 printf scanf 함수  (0) 2019.01.10
2장-1 자료형  (0) 2019.01.10
1장-1 Hello World  (0) 2018.12.16

3장 printf scanf 함수

2019. 1. 10. 00:10

저수준 언어

언어의 수준(Level)은 상대적이지만 요즘은 코볼이나 어셈블리를 배우지 않는 점에서 C언어는 Low-Level 언어에 해당합니다. 코볼이나 어셈블리는 C언어에 대해 상대적으로 더 낮은 수준인 언어입니다.

Level이 낮으면 하드웨어에 직접 엑세스하기 쉬워집니다. 그만큼 처리가 빨리지죠. 반면에 Level이 높아지면 복잡한 구조를 단순하게 만들 수 있다는 점에서 코딩이 편해집니다. 속도는 느려지지만 쉬운 코딩으로 버그가 줄어들고, 복잡한 프로그램을 만들 수 있습니다.
가장 낮은 수준인 어셈블리어는 CPU의 명령어에 맞게 직접 코딩을 해야 합니다. 그러다보니 코딩을 하기 위해선 컴퓨터 구조에 대한 학습은 필수였습니다. 컴퓨터 구조에 맞게 명령을 입력해야 했거든요. 보다 높은 수준인 C언어는 덧셈, 비교, 변수 지정 등을 한 줄로 끝낼 수 있게 되었습니다. 대학교에선 여전히 컴퓨터 구조를 학습하긴 하지만 컴퓨터 언어를 사용하는 데에는 중요하지 않게 되었습니다. 그래서 어셈블리어에 대해 상대적으로 고급 언어입니다.

객체지향 언어는 당연히 객체 개념을 통해 C언어에 비해 고급 언어로 칭해집니다. 객체지향 언어는 메모리에 대한 고려를 거의 하지 않습니다. 그래서 String 형의 변수를 다른 변수에 저장할 때에도 대입 연산을 이용할 수 있습니다. 무엇보다 객체 지향 언어는 객체를 이용하는게 특징입니다. 프로그램 실행에 Stack구조(객체를 계속 쌓는 방식)를 사용하기 때문에 이 전의 코드를 조금 바꾸어 재사용하거나 프로그램 최적화 및 관리가 쉽습니다.
그래서 고급 언어로 사용자와 상호작용을 하기 위한 Front End를 담당하고 저급 언어로 내부의 처리를 담당하기도 합니다. 자바나 코틀린을 사용하는 것으로 잘 알려진 안드로이드도 중요한 시스템 부분은 C언어로 만든 바이너리입니다.

C언어에서 사용하는 scanf는 키보드 입력을 받는 함수인데, 실제 사용자의 입력을 받기 쉽지 않습니다. scanf는 2바이트 문자인 한글을 입력받기 쉽지 않습니다. 또한 키보드로 입력되는 데이터를 버퍼에 저장하는데, 그 버퍼를 자주 비워줘야 프로그램이 의도한 대로 동작합니다. 또한 보안 문제로 대체 함수가 도입되어 있습니다. printf_s, scanf_s이죠. 대부분 보안 프로그램이 scanf를 사용한 경우 프로그램 실행을 차단합니다.

위와 같은 특성으로 인해 printfscanf를 사용자의 입력을 받는 용도로 사용하지 않습니다. 다만 C언어 개발을 배우는 과정에서 콘솔로 입/출력을 받을 때는 가장 자주 사용되는 함수입니다. 실제 프로그램 개발에서는 printf_s를 사용해야 하고, 일반적으로는 객체지향 언어로 프로그래밍 합니다.

예제

보통 C언어 프로그램은 Console(콘솔)로 실행됩니다. Console에서 사용자의 입력 및 출력을 담당하는 함수가 printf, scanf입니다.

int main(void)    //진입함수 main()
{
    int a;    //정수변수 선언
    printf("숫자 입력 : ");
    scanf("%d",&a);    //키보드로부터 값을 입력받아 변수에 저장
    printf("덧셈 결과 %d \n",a+3);     //%d의 숫자와 대응되는 값의 수는 일치
}

printf함수를 통해 숫자 입력 :를 콘솔 화면에 출력합니다. 줄 내림을 하지 않았기 때문에 콘솔의 커서는 줄 내림을 하지 않고 콜론 오른쪽에 있습니다.

숫자를 입력하고 엔터를 누르면 scanf가 입력 값을 받아서 a에 저장합니다. 큰 따옴표 안에 %d가 있고, 큰 따옴표 뒤에 반점으로 구분하여 변수 이름이 적혀 있습니다.

printf함수를 다시 호출합니다. 큰 따옴표 안에 %d\n이 있지만 콘솔에는 보이지 않습니다. 왜 그런지 아래에서 알아보겠습니다.

printf

printf는 단순히 문장만 출력하지 않습니다. 변수를 출력할 수도 있지요. 그래서 같은 문장이라도 변수에 따라 출력이 달라지게 됩니다.
출력할 문장에 변수를 포함하는 방법이 %d를 사용하는 방법입니다. 그리고 그 뒤에 파라미터를 추가하여 %d에 대응하는 값을 출력하는 겁니다.

%d decimal(10진수)
%x hexadecimal(16진수)
%o octal number(8진수)
%e exponentiation(지수형)
%u unsigned(부호가 없는 자료형)
%f float(실수형)
%p pointer(포인터)
%c char(문자형)
%s string(문자열)

변수 여러개 출력하기

printf는 변수를 여러개 출력할 수 있습니다.

printf("아스키코드 %d은 %c입니다.", 97, 97);

%d%c를 두개 넣었습니다. 그리고 파라미터로 두개를 전달했습니다.
그랬더니 아스키코드 97은 a 입니다. 라고 출력됩니다.

2장 자료형에서 살짝 언급했는데, 같은 97을 전달받고도 정수형으로 표현한 것과 문자형을로 표현한 것이 다릅니다.

변수의 자릿수 정렬하기

printf는 자릿수를 정할 수 있습니다.
아래와 같이 입력하면

printf("%d \n",192);
printf("%d",6);
192
6

위와 같이 출력됩니다. 그런데 아래와 같이 입력하면

printf("%3d\n",192);
printf("%3d",6);
192
  6

위와 같이 출력됩니다. 자료형을 나타내는 문자 앞에 숫자를 붙이면 자릿수를 미리 지정할 수 있습니다.

실수형에서는 좀 더 복잡한 정렬도 가능합니다.

#include<stdio.h>
int main(){
    float a = 3.14159;
    int b = 192;
    printf("%6.3f\n",a);
    printf("%.3f\n",a);
    printf("%6d\n",b);
}

위와 같은 프로그램을 실행하면

  3.142
3.142
   192

와 같은 결과를 얻을 수 있습니다.

실수형은 전체 자릿수와 소숫점 아래 자릿수를 제한할 수 있고, 반올림하여 표현할 수 있습니다. 또한, 전체 자릿수는 지정하지 않고 소숫점 아래 자릿수만 제한할 수도 있습니다.

정수형과 실수형을 모두 6자리로 제한하니 출력에서는 마지막 숫자가 같은 위치에 있는 것을 알 수 있습니다.

printf줄 내림을 위해 특별한 표현을 사용합니다.

printf는 한 줄로 명령이 이루어집니다. 게다가 컴파일러는 줄 내림을 무시합니다. 그렇다면 줄 내림을 출력하는 방법은 무엇일까요?

바로 *이스케이프 시퀸스(Escape sequence) *라는 것을 사용하면 됩니다!. 문자열을 입력하고 있는데 \를 통해 escape해서 컴파일러의 처리를 한다고 보면 될 것 같습니다.

printf("줄 내림\n테스트");

라고 입력하면

줄 내림
테스트

라고 뜨게 됩니다.

그 외에도

\t 탭
\r 엔터(carriage return)
\v 수직 탭(vertical tab)
\b 지우기(backspace)
\f 폼 피드, 페이지 피드
\a 경고(beep음 경고)

가 있습니다. 대부분은 직접 입력이 가능하지만 알아두면 좋습니다.

그렇다면 컴파일러가 인식하고 콘솔에 출력하지 않는 문자를 콘솔에 출력하고 싶으면 어떻게 해야 할까요? 큰 따옴표는 문자열을 의미하는 것이어서 큰 따옴표를 입력하면 문자열이 끝나버리고 말죠. %도 %d, %f를 위해 할당된 문자여서 출력이 안됩니다. 도 마찬가지죠.
이러한 문자를 출력하는 것도 Escape Sequence 입니다.

\\
\"
\?
%%

와 같은 방법이죠. 음... Escape Sequence로부터 한번 더 Escape한다는 느낌입니다.

printf("\"큰 따옴표\" \\n %%d");

라고 입력하면

"큰 따옴표" \n %d

라고 출력됩니다.

scanf

scanf의 기본적인 사용법은 같습니다. printf와 다른 부분은 변수를 작성하는 뒤의 변수 이름 부분에 a가 아닌 &a를 사용한다는 것입니다.
추후 포인터를 학습하면서 자세히 다룰 부분인데, 변수의 메모리 주소를 의미합니다. scanf는 입력받은 데이터를 변수에 저장하는 것이 아니라 변수가 저장된 메모리 주소에 저장하기 때문에 &a를 사용합니다.

복습

#include<stdio.h>
int main()
{
    int salary;//월급
    int deposit ;//저금액

    printf("월급을 입력하시오: ");
    scanf("$d",&salary);

    deposit = 10 * 12 * salary;

    printf("10년간 저축액: %d \n", deposit);
    return 0;
}
#include<stdio.h>
int main()

    float radius;
    float area;

    printf("반지름을 입력하십시오: ");
    scanf("%f", %radius);

    area = 3.14 * radius * radius;

    printf("원의 면적: %f\n", area);
    return 0;
}
#include<stdio.h>
int main(){
    int id, pass;
    //ID와 PW자리에 '_'가 4개가 있고, ID 또는 PW를 입력하면 '\'가 없어지는 프로그램

    printf("ID와 PW를 4개의 숫자로 입력하세요:\n");
    printf("id:____\b\b\b\b");
    scanf("%d", &id);
    printf("pass:____\b\b\b\b");
    scanf("%d", &pass);
    printf("\a입력된 아이디는 \"%d\"이고 패스워드는 \"%d\"입니다.\n", id, pass);
    return 0;
}

요약

  • 출력을 위해 printf를 사용할 수 있다. 변수를 출력할 수도 있다.
  • 입력을 받기 위해 scanf를 사용할 수 있다.
  • printf나 scanf에 변수를 포함하도록 할 수 있다.
  • escape squence를 사용하여 원하는 문자열을 출력할 수 있다.

'컴퓨터공학 > C' 카테고리의 다른 글

2장-2 변수의 크기와 오버플로우, 언더플로우  (0) 2019.05.05
4장-2 비트 연산과 연산 순서  (0) 2019.01.14
4장-1 산술 연산자  (0) 2019.01.14
3장 printf scanf 함수  (0) 2019.01.10
2장-1 자료형  (0) 2019.01.10
1장-1 Hello World  (0) 2018.12.16

+ Recent posts