728x90

일반적으로 우분투를 설치하자마자 커맨드창에 python을 입력하면


python2.7 버전이 뜬다.


이를 3버전으로 바꾸고 싶으면


1. vi ~/.bashrc 입력


2. 맨 아래에 


alias python='/usr/bin/python3'


입력


3. 저장 후 source ~/.bashrc 입력


커맨드 창에 python 입력하면 python3.5로 변경 됨



python3이 설치되어 있지 않다면 설치해준 뒤 위의 작업 진행

728x90

'Program > Python' 카테고리의 다른 글

python logger 끄는 법 - turn off logging  (0) 2024.02.20
pip freeze path 문제  (0) 2023.06.22
numpy를 이용한 연속적인 중복값 제거  (0) 2021.01.22
ImportError: cannot import name 'main' pip  (0) 2019.10.08
pip와 pip3 차이  (2) 2018.04.12
728x90

출처 : http://tech.kakao.com/2017/09/27/kakao-blind-recruitment-round-1/


‘블라인드’ 전형으로 실시되어 시작부터 엄청난 화제를 몰고 온 카카오 개발 신입 공채. 그 첫 번째 관문인 1차 코딩 테스트가 지난 9월 16일(토) 오후 2시부터 7시까지 장장 5시간 동안 온라인으로 치러졌습니다. 지원자들의 개발 능력을 잘 검증하기 위해 출제 위원들이 한 땀 한 땀 독창적이고 다양한 문제들을 만들어 냈고 문제에 이상은 없는지, 테스트케이스는 정확한지 풀어보고 또 풀어보며 만반의 준비를 기했습니다.

먼저, 가장 궁금해하실 1차 합격 기준부터 알려드립니다. 1차 합격 기준은 총 7 문제 중 4 문제 이상을 풀이한 분들입니다. 참고로 각 문제는 배점이 동일하므로 어떤 문제를 풀었던지 간에 관계는 없습니다.

문제는 쉬운 난이도에서 어려운 난이도 순으로 풀 수 있도록 차례대로 배치했는데요. 앞서 얘기했듯 모든 문제는 배점이 동일하며 부분 점수는 없습니다. 즉, 채점 테스트케이스를 하나만 틀려도 오답으로 처리가 됩니다. 하지만 입출력 예제에 대부분의 예외 사항을 포함했고 따라서 입출력 테스트를 정상적으로 통과했다면 채점도 무리 없이 통과할 수 있도록 구성했습니다. 아울러 이번 코딩 테스트는 대회가 아니라 채용을 위한 시험인 만큼 ACM-ICPC 같은 어려운 알고리즘 설계 능력을 겨루는 문제가 아닌 업무에서 있을만한 상황을 가정하여 독창적이고 다양한 분야의 문제를 출제했고, 난이도 또한 비교적 쉬운 수준으로 조정하였습니다. 일반적으로 자료구조, 알고리즘 등의 전산학 기초에 대해 충분히 학습하였다면 누구나 풀 수 있을만한 문제들로 구성했습니다.

언어별 통계

참가 언어별로는 자바가 전체의 43%로 가장 많았습니다. 그다음이 C++ 36%, 파이썬 11%, 자바스크립트 8% 순이었는데요. 스위프트는 0.7%의 참가자만이 선택하여 아직 스위프트가 주류로 성장하기엔 좀 더 시간이 필요해 보였습니다.

  • 참가 언어: 자바 > C++ > 파이썬 > 자바스크립트 > 스위프트

4문제 이상을 풀이한 합격자의 비율은 C++이 25%로 가장 높았습니다. 그다음으로 파이썬이 24%로 근소한 차이로 뒤를 쫓고 있고, 참가자가 매우 적었던 스위프트도 20%로 합격률은 비교적 높았습니다. 그러나, 참가자가 가장 많았던 자바는 11%의 합격률 밖에 보여주지 못했으며 아쉽게도 자바스크립트의 경우 합격률이 9%에 불과했습니다.

  • 합격 비율: C++ > 파이썬 > 스위프트 > 자바 > 자바스크립트

풀이한 언어의 평균 코드 라인 수를 알아볼까요?
C++이 평균적으로 가장 긴 라인 수를 자랑했습니다. 4번과 6번 문제는 78라인이나 필요했네요. 그다음은 근소한 차이로 자바입니다. 크게 차이가 나진 않지만 C++에 비해 평균적으로 5 ~ 6라인 정도가 짧았습니다. 그런데 재밌게도 가장 긴 코드는 자바가 차지했네요. 6번 문제의 경우 자바는 무려 80라인을 기록했습니다!

그다음은 자바스크립트입니다. 자바에 비해 10라인 이상이 짧습니다. 역시나 파이썬이 가장 짧은 라인 수를 기록했는데요. 1번 문제는 고작 22라인 밖에 필요하지 않았습니다. 게다가 가장 긴 코드가 필요했던 6번 문제도 48라인으로 자바의 60% 수준에 불과합니다.

  • 코드 라인 수: C++ > 자바 > 자바스크립트 > 파이썬

이외에도 여러 언어를 섞어서 풀이한 분들이 전체의 5%나 되었으며, ‘C++ + 자바 + 자바스크립트 + 파이썬’ 이 4가지 언어를 동시에 섞어서 풀이한 분도 계셨네요.

긴 시간 동안 시험을 치르고, 문제를 풀이하느라 다들 고생 많이 하셨습니다.
자, 그렇다면 많은 분들이 궁금해하실 코딩 테스트 문제를 하나씩 짚어보도록 할까요?

문제 설명

1. 비밀 지도(난이도: 하)

네오는 평소 프로도가 비상금을 숨겨놓는 장소를 알려줄 비밀지도를 손에 넣었다. 그런데 이 비밀지도는 숫자로 암호화되어 있어 위치를 확인하기 위해서는 암호를 해독해야 한다. 다행히 지도 암호를 해독할 방법을 적어놓은 메모도 함께 발견했다.

  1. 지도는 한 변의 길이가 n인 정사각형 배열 형태로, 각 칸은 “공백”(“ “) 또는 “벽”(“#”) 두 종류로 이루어져 있다.
  2. 전체 지도는 두 장의 지도를 겹쳐서 얻을 수 있다. 각각 “지도 1”과 “지도 2”라고 하자. 지도 1 또는 지도 2 중 어느 하나라도 벽인 부분은 전체 지도에서도 벽이다. 지도 1과 지도 2에서 모두 공백인 부분은 전체 지도에서도 공백이다.
  3. “지도 1”과 “지도 2”는 각각 정수 배열로 암호화되어 있다.
  4. 암호화된 배열은 지도의 각 가로줄에서 벽 부분을 1, 공백 부분을 0으로 부호화했을 때 얻어지는 이진수에 해당하는 값의 배열이다.

네오가 프로도의 비상금을 손에 넣을 수 있도록, 비밀지도의 암호를 해독하는 작업을 도와줄 프로그램을 작성하라.

입력 형식

입력으로 지도의 한 변 크기 n 과 2개의 정수 배열 arr1arr2가 들어온다.

  • 1 ≦ n ≦ 16
  • arr1arr2는 길이 n인 정수 배열로 주어진다.
  • 정수 배열의 각 원소 x를 이진수로 변환했을 때의 길이는 n 이하이다. 즉, 0 ≦ x ≦ 2^n - 1을 만족한다.

출력 형식

원래의 비밀지도를 해독하여 "#"공백으로 구성된 문자열 배열로 출력하라.

입출력 예제

매개변수
n5
arr1[9, 20, 28, 18, 11]
arr2[30, 1, 21, 17, 28]
출력["#####","# # #", "### #", "# ##", "#####"]
매개변수
n6
arr1[46, 33, 33 ,22, 31, 50]
arr2[27 ,56, 19, 14, 14, 10]
출력["######", "### #", "## ##", " #### ", " #####", "### # "]

문제 해설

이 문제는 비트 연산Bitwise Operation을 묻는 문제입니다. 이미 문제 예시에 2진수로 처리하는 힌트가 포함되어 있고, 둘 중 하나가 1일 경우에 벽 #이 생기기 때문에 OR로 처리하면 간단히 풀 수 있습니다. 아주 쉬운 문제였던 만큼 if else로 풀이한 분들도 많이 발견되었는데요. 정답으로는 간주되지만 이 문제는 비트 연산을 잘 다룰 수 있는지를 묻고자 하는 의도였던 만큼 앞으로 이런 유형의 문제를 풀 때는 비트 연산을 꼭 기억하시기 바랍니다.

이 문제의 정답률은 81.78%입니다. 첫 번째 문제이고 가장 쉬운 문제였던 만큼 많은 분들이 잘 풀어주셨습니다.

2. 다트 게임(난이도: 하)

카카오톡에 뜬 네 번째 별! 심심할 땐? 카카오톡 게임별~

카카오톡 게임별의 하반기 신규 서비스로 다트 게임을 출시하기로 했다. 다트 게임은 다트판에 다트를 세 차례 던져 그 점수의 합계로 실력을 겨루는 게임으로, 모두가 간단히 즐길 수 있다.
갓 입사한 무지는 코딩 실력을 인정받아 게임의 핵심 부분인 점수 계산 로직을 맡게 되었다. 다트 게임의 점수 계산 로직은 아래와 같다.

  1. 다트 게임은 총 3번의 기회로 구성된다.
  2. 각 기회마다 얻을 수 있는 점수는 0점에서 10점까지이다.
  3. 점수와 함께 Single(S), Double(D), Triple(T) 영역이 존재하고 각 영역 당첨 시 점수에서 1제곱, 2제곱, 3제곱 (점수^1 , 점수^2 , 점수^3 )으로 계산된다.
  4. 옵션으로 스타상(*) , 아차상(#)이 존재하며 스타상(*) 당첨 시 해당 점수와 바로 전에 얻은 점수를 각 2배로 만든다. 아차상(#) 당첨 시 해당 점수는 마이너스된다.
  5. 스타상(*)은 첫 번째 기회에서도 나올 수 있다. 이 경우 첫 번째 스타상(*)의 점수만 2배가 된다. (예제 4번 참고)
  6. 스타상(*)의 효과는 다른 스타상(*)의 효과와 중첩될 수 있다. 이 경우 중첩된 스타상(*) 점수는 4배가 된다. (예제 4번 참고)
  7. 스타상(*)의 효과는 아차상(#)의 효과와 중첩될 수 있다. 이 경우 중첩된 아차상(#)의 점수는 -2배가 된다. (예제 5번 참고)
  8. Single(S), Double(D), Triple(T)은 점수마다 하나씩 존재한다.
  9. 스타상(*), 아차상(#)은 점수마다 둘 중 하나만 존재할 수 있으며, 존재하지 않을 수도 있다.

0~10의 정수와 문자 S, D, T, *, #로 구성된 문자열이 입력될 시 총점수를 반환하는 함수를 작성하라.

입력 형식

“점수|보너스|[옵션]”으로 이루어진 문자열 3세트.
예) 1S2D*3T

  • 점수는 0에서 10 사이의 정수이다.
  • 보너스는 S, D, T 중 하나이다.
  • 옵선은 *이나 # 중 하나이며, 없을 수도 있다.

출력 형식

3번의 기회에서 얻은 점수 합계에 해당하는 정수값을 출력한다.
예) 37

입출력 예제

예제dartResultanswer설명
11S2D*3T371^1 * 2 + 2^2 * 2 + 3^3
21D2S#10S91^2 + 2^1 * (-1) + 10^1
31D2S0T31^2 + 2^1 + 0^3
41S*2T*3S231^1 * 2 * 2 + 2^3 * 2 + 3^1
51D#2S*3S51^2 * (-1) * 2 + 2^1 * 2 + 3^1
61T2D3D#-41^3 + 2^2 + 3^2 * (-1)
71D2S3T*591^2 + 2^1 * 2 + 3^3 * 2

문제 해설

문자열 처리String Manipulation를 묻는 문제입니다. 앞에서부터 한 글자씩 잘라서 처리할 수 있고, 또는 간단한 컴파일러를 만들듯이 토큰화Tokenizing와 의미 분석Semantic Analysis을 통해 어렵지 않게 계산할 수 있습니다.

점수 중에는 한 자리뿐만 아니라 두 자리인 10점도 포함되어 있기 때문에 한 글자씩 잘라서 처리할때는 그 부분에 유의해야겠네요. 토큰화로 처리할 때는 정규식을 사용하면 비교적 쉽게 잘라낼 수 있습니다. S, D, T는 각각 원점수, 제곱, 세제곱으로 처리하고 스타상은 두 배로 계산하면 됩니다. 참, 아차상은 마이너스 점수라는 점에 유의하세요.

이 문제의 정답률은 73.47%입니다. 앞서 비밀지도 보다는 낮지만 그래도 많은 분들이 잘 풀어주셨습니다.

3. 캐시(난이도: 하)

지도개발팀에서 근무하는 제이지는 지도에서 도시 이름을 검색하면 해당 도시와 관련된 맛집 게시물들을 데이터베이스에서 읽어 보여주는 서비스를 개발하고 있다.
이 프로그램의 테스팅 업무를 담당하고 있는 어피치는 서비스를 오픈하기 전 각 로직에 대한 성능 측정을 수행하였는데, 제이지가 작성한 부분 중 데이터베이스에서 게시물을 가져오는 부분의 실행시간이 너무 오래 걸린다는 것을 알게 되었다.
어피치는 제이지에게 해당 로직을 개선하라고 닦달하기 시작하였고, 제이지는 DB 캐시를 적용하여 성능 개선을 시도하고 있지만 캐시 크기를 얼마로 해야 효율적인지 몰라 난감한 상황이다.

어피치에게 시달리는 제이지를 도와, DB 캐시를 적용할 때 캐시 크기에 따른 실행시간 측정 프로그램을 작성하시오.

입력 형식

  • 캐시 크기(cacheSize)와 도시이름 배열(cities)을 입력받는다.
  • cacheSize는 정수이며, 범위는 0 ≦ cacheSize ≦ 30 이다.
  • cities는 도시 이름으로 이뤄진 문자열 배열로, 최대 도시 수는 100,000개이다.
  • 각 도시 이름은 공백, 숫자, 특수문자 등이 없는 영문자로 구성되며, 대소문자 구분을 하지 않는다. 도시 이름은 최대 20자로 이루어져 있다.

출력 형식

  • 입력된 도시이름 배열을 순서대로 처리할 때, “총 실행시간”을 출력한다.

조건

  • 캐시 교체 알고리즘은 LRU(Least Recently Used)를 사용한다.
  • cache hit일 경우 실행시간은 1이다.
  • cache miss일 경우 실행시간은 5이다.

입출력 예제

캐시크기(cacheSize)도시이름(cities)실행시간
3[“Jeju”, “Pangyo”, “Seoul”, “NewYork”, “LA”, “Jeju”, “Pangyo”, “Seoul”, “NewYork”, “LA”]50
3[“Jeju”, “Pangyo”, “Seoul”, “Jeju”, “Pangyo”, “Seoul”, “Jeju”, “Pangyo”, “Seoul”]21
2[“Jeju”, “Pangyo”, “Seoul”, “NewYork”, “LA”, “SanFrancisco”, “Seoul”, “Rome”, “Paris”, “Jeju”, “NewYork”, “Rome”]60
5[“Jeju”, “Pangyo”, “Seoul”, “NewYork”, “LA”, “SanFrancisco”, “Seoul”, “Rome”, “Paris”, “Jeju”, “NewYork”, “Rome”]52
2[“Jeju”, “Pangyo”, “NewYork”, “newyork”]16
0[“Jeju”, “Pangyo”, “Seoul”, “NewYork”, “LA”]25

문제 해설

여기서부터 문제가 좀 어려워졌던 거 같습니다. 정답률이 많이 낮은데요. 이 문제는 ‘조건’에도 나와있지만 LRU 캐시 교체 알고리즘을 구현하는 문제이고, 이미 잘 알고 있다면 또는 검색해봤다면 잘 구현된 LRU 알고리즘 코드는 많이 찾을 수 있습니다.

단, 이 문제에는 입출력 예제에 캐시 사이즈 0이 포함되어 있습니다. 공개된 대부분의 LRU 구현 코드는 0일 때의 비정상적인 상황은 가정하지 않고 있기 때문에 생각 없이 그냥 가져와 붙인다면 에러가 나서 많이 고생했을 거 같네요. 하지만 사이즈 0을 처리하는 예외 처리 자체는 어렵지 않게 구현할 수 있으므로 입출력 예제가 왜 자꾸 틀리는지를 유심히 살펴봤다면 쉽게 풀 수 있는 문제입니다.

아울러 검색해서 가져온 코드는 반드시 사용 가능한지 라이센스를 확인하고, 가져올때는 꼭 출처를 명시해야 한다는 점 잊지 마세요.

이 문제의 정답률은 45.26%입니다.

4. 셔틀버스(난이도: 중)

카카오에서는 무료 셔틀버스를 운행하기 때문에 판교역에서 편하게 사무실로 올 수 있다. 카카오의 직원은 서로를 ‘크루’라고 부르는데, 아침마다 많은 크루들이 이 셔틀을 이용하여 출근한다.

이 문제에서는 편의를 위해 셔틀은 다음과 같은 규칙으로 운행한다고 가정하자.

  • 셔틀은 09:00부터 총 n회 t분 간격으로 역에 도착하며, 하나의 셔틀에는 최대 m명의 승객이 탈 수 있다.
  • 셔틀은 도착했을 때 도착한 순간에 대기열에 선 크루까지 포함해서 대기 순서대로 태우고 바로 출발한다. 예를 들어 09:00에 도착한 셔틀은 자리가 있다면 09:00에 줄을 선 크루도 탈 수 있다.

일찍 나와서 셔틀을 기다리는 것이 귀찮았던 콘은, 일주일간의 집요한 관찰 끝에 어떤 크루가 몇 시에 셔틀 대기열에 도착하는지 알아냈다. 콘이 셔틀을 타고 사무실로 갈 수 있는 도착 시각 중 제일 늦은 시각을 구하여라.

단, 콘은 게으르기 때문에 같은 시각에 도착한 크루 중 대기열에서 제일 뒤에 선다. 또한, 모든 크루는 잠을 자야 하므로 23:59에 집에 돌아간다. 따라서 어떤 크루도 다음날 셔틀을 타는 일은 없다.

입력 형식

셔틀 운행 횟수 n, 셔틀 운행 간격 t, 한 셔틀에 탈 수 있는 최대 크루 수 m, 크루가 대기열에 도착하는 시각을 모은 배열 timetable이 입력으로 주어진다.

  • 0 < n ≦ 10
  • 0 < t ≦ 60
  • 0 < m ≦ 45
  • timetable은 최소 길이 1이고 최대 길이 2000인 배열로, 하루 동안 크루가 대기열에 도착하는 시각이 HH:MM형식으로 이루어져 있다.
  • 크루의 도착 시각 HH:MM은 00:01에서 23:59 사이이다.

출력 형식

콘이 무사히 셔틀을 타고 사무실로 갈 수 있는 제일 늦은 도착 시각을 출력한다. 도착 시각은 HH:MM 형식이며, 00:00에서 23:59 사이의 값이 될 수 있다.

입출력 예제

ntmtimetableanswer
115[“08:00”, “08:01”, “08:02”, “08:03”]“09:00”
2102[“09:10”, “09:09”, “08:00”]“09:09”
212[“09:00”, “09:00”, “09:00”, “09:00”]“08:59”
115[“00:01”, “00:01”, “00:01”, “00:01”, “00:01”]“00:00”
111[“23:59”]“09:00”
106045[“23:59”,”23:59”, “23:59”, “23:59”, “23:59”, “23:59”, “23:59”, “23:59”, “23:59”, “23:59”, “23:59”, “23:59”, “23:59”, “23:59”, “23:59”, “23:59”]“18:00”

문제 해설

쉬워 보이는데 어려운 문제가 바로 이 문제였던 거 같네요. 당초 난이도를 ‘중’으로 두고 문제를 중간 즈음에 배치하였는데, 시간을 계산하는 부분에서 많은 분들이 어려워하셨던 거 같습니다.

예를 들어 2번 입출력 예제의 경우 ["09:10", "09:09", "08:00"]인데 이 경우 두 번째 버스는 9:10분에 출발하기 때문에 9:10분에 오면 되지 않느냐 많이들 혼동하셨을 거 같아요. 하지만 9:00에 오는 버스는 8:00에 대기하는 크루 1명만 탑승할 수 있고, 따라서 9:10 버스에는 남아 있는 두 명이 모두 타게 됩니다. 따라서 좀 더 이른 9:09에 와야 탑승할 수 있습니다.

전체 계산은 어렵지 않지만 이처럼 정확하게 시간 계산을 해야 하는 부분이 많고 마지막 버스 시간까지 빈틈없이 계산해야 해서 많은 분들이 실수를 한 거 같습니다. 이 문제는 정답률이 두 번째로 낮은 26.79%입니다.

5. 뉴스 클러스터링(난이도: 중)

여러 언론사에서 쏟아지는 뉴스, 특히 속보성 뉴스를 보면 비슷비슷한 제목의 기사가 많아 정작 필요한 기사를 찾기가 어렵다. Daum 뉴스의 개발 업무를 맡게 된 신입사원 튜브는 사용자들이 편리하게 다양한 뉴스를 찾아볼 수 있도록 문제점을 개선하는 업무를 맡게 되었다.

개발의 방향을 잡기 위해 튜브는 우선 최근 화제가 되고 있는 “카카오 신입 개발자 공채” 관련 기사를 검색해보았다.

  • 카카오 첫 공채..’블라인드’ 방식 채용
  • 카카오, 합병 후 첫 공채.. 블라인드 전형으로 개발자 채용
  • 카카오, 블라인드 전형으로 신입 개발자 공채
  • 카카오 공채, 신입 개발자 코딩 능력만 본다
  • 카카오, 신입 공채.. “코딩 실력만 본다”
  • 카카오 “코딩 능력만으로 2018 신입 개발자 뽑는다”

기사의 제목을 기준으로 “블라인드 전형”에 주목하는 기사와 “코딩 테스트”에 주목하는 기사로 나뉘는 걸 발견했다. 튜브는 이들을 각각 묶어서 보여주면 카카오 공채 관련 기사를 찾아보는 사용자에게 유용할 듯싶었다.

유사한 기사를 묶는 기준을 정하기 위해서 논문과 자료를 조사하던 튜브는 “자카드 유사도”라는 방법을 찾아냈다.

자카드 유사도는 집합 간의 유사도를 검사하는 여러 방법 중의 하나로 알려져 있다. 두 집합 AB 사이의 자카드 유사도 J(A, B)는 두 집합의 교집합 크기를 두 집합의 합집합 크기로 나눈 값으로 정의된다.

예를 들어 집합 A = {1, 2, 3}, 집합 B = {2, 3, 4}라고 할 때, 교집합 A ∩ B = {2, 3}, 합집합 A ∪ B = {1, 2, 3, 4}이 되므로, 집합 A, B 사이의 자카드 유사도 J(A, B) = 2/4 = 0.5가 된다. 집합 A와 집합 B가 모두 공집합일 경우에는 나눗셈이 정의되지 않으니 따로 J(A, B) = 1로 정의한다.

자카드 유사도는 원소의 중복을 허용하는 다중집합에 대해서 확장할 수 있다. 다중집합 A는 원소 “1”을 3개 가지고 있고, 다중집합 B는 원소 “1”을 5개 가지고 있다고 하자. 이 다중집합의 교집합 A ∩ B는 원소 “1”을 min(3, 5)인 3개, 합집합 A ∪ B는 원소 “1”을 max(3, 5)인 5개 가지게 된다. 다중집합 A = {1, 1, 2, 2, 3}, 다중집합 B = {1, 2, 2, 4, 5}라고 하면, 교집합 A ∩ B = {1, 2, 2}, 합집합 A ∪ B = {1, 1, 2, 2, 3, 4, 5}가 되므로, 자카드 유사도 J(A, B) = 3/7, 약 0.42가 된다.

이를 이용하여 문자열 사이의 유사도를 계산하는데 이용할 수 있다. 문자열 “FRANCE”와 “FRENCH”가 주어졌을 때, 이를 두 글자씩 끊어서 다중집합을 만들 수 있다. 각각 {FR, RA, AN, NC, CE}, {FR, RE, EN, NC, CH}가 되며, 교집합은 {FR, NC}, 합집합은 {FR, RA, AN, NC, CE, RE, EN, CH}가 되므로, 두 문자열 사이의 자카드 유사도 J("FRANCE", "FRENCH") = 2/8 = 0.25가 된다.

입력 형식

  • 입력으로는 str1과 str2의 두 문자열이 들어온다. 각 문자열의 길이는 2 이상, 1,000 이하이다.
  • 입력으로 들어온 문자열은 두 글자씩 끊어서 다중집합의 원소로 만든다. 이때 영문자로 된 글자 쌍만 유효하고, 기타 공백이나 숫자, 특수 문자가 들어있는 경우는 그 글자 쌍을 버린다. 예를 들어 “ab+”가 입력으로 들어오면, “ab”만 다중집합의 원소로 삼고, “b+”는 버린다.
  • 다중집합 원소 사이를 비교할 때, 대문자와 소문자의 차이는 무시한다. “AB”와 “Ab”, “ab”는 같은 원소로 취급한다.

출력 형식

입력으로 들어온 두 문자열의 자카드 유사도를 출력한다. 유사도 값은 0에서 1 사이의 실수이므로, 이를 다루기 쉽도록 65536을 곱한 후에 소수점 아래를 버리고 정수부만 출력한다.

예제 입출력

str1str2answer
FRANCEfrench16384
handshakeshake hands65536
aa1+aa2AAAA1243690
E=M*C^2e=m*c^265536

문제 해설

이 문제는 자카드 유사도를 설명해주고 자카드 유사도를 직접 계산하는 프로그램을 작성하는 문제입니다. 자카드 유사도는 실무에서도 유사한 문서를 판별할 때 주로 쓰이는데요, 몰랐더라도 문제에서 자세히 설명해주기 때문에 이해하는데 어려움은 없었을 거 같습니다. 공식은 매우 간단한데요, 교집합을 합집합으로 나눈 수입니다. 다만, 이 값은 0에서 1 사이의 실수가 되는데, 여기서는 이를 다루기 쉽도록 65536을 곱한 후 소수점 아래를 버리고 정수부만 취하도록 합니다.

문제 설명은 원소의 중복을 허용하는 다중집합multiset으로 되어 있는데, 자주 접하는 자료구조가 아니고, 일부 언어에서는 기본으로 제공하는 자료구조가 아니라 어려워하는 분들이 있었습니다. 하지만 다중집합 자료구조를 쓰지 않더라도, 각 원소를 정렬된 배열에 넣은 후 병합 정렬Merge sort에서 배웠던 코드를 응용, 어렵지 않게 합집합과 교집합 함수를 직접 구현할 수도 있습니다.

다중집합의 교집합, 합집합만 잘 구해낸다면 이 문제는 어렵지 않게 풀 수 있으며, 다만 집합 A와 B가 모두 공집합일 경우에는 나눗셈이 정의되지 않으므로division by zero 따로 J(A,B) = 1로 정의합니다. 즉, 65536을 곱하면 이 경우 1 * 65536 = 65536이 정답이 됩니다. 예제 입출력에도 합집합이 공집합인 경우가 포함되어 있으므로 이 경우만 주의한다면 쉽게 풀 수 있는 문제입니다.

이 문제의 정답률은 41.84%입니다.

6. 프렌즈4블록(난이도: 상)

블라인드 공채를 통과한 신입 사원 라이언은 신규 게임 개발 업무를 맡게 되었다. 이번에 출시할 게임 제목은 “프렌즈4블록”.
같은 모양의 카카오프렌즈 블록이 2×2 형태로 4개가 붙어있을 경우 사라지면서 점수를 얻는 게임이다.

만약 판이 위와 같이 주어질 경우, 라이언이 2×2로 배치된 7개 블록과 콘이 2×2로 배치된 4개 블록이 지워진다. 같은 블록은 여러 2×2에 포함될 수 있으며, 지워지는 조건에 만족하는 2×2 모양이 여러 개 있다면 한꺼번에 지워진다.

블록이 지워진 후에 위에 있는 블록이 아래로 떨어져 빈 공간을 채우게 된다.

만약 빈 공간을 채운 후에 다시 2×2 형태로 같은 모양의 블록이 모이면 다시 지워지고 떨어지고를 반복하게 된다.

위 초기 배치를 문자로 표시하면 아래와 같다.

TTTANT
RRFACC
RRRFCC
TRRRAA
TTMMMF
TMMTTJ

각 문자는 라이언(R), 무지(M), 어피치(A), 프로도(F), 네오(N), 튜브(T), 제이지(J), 콘(C)을 의미한다

입력으로 블록의 첫 배치가 주어졌을 때, 지워지는 블록은 모두 몇 개인지 판단하는 프로그램을 제작하라.

입력 형식

  • 입력으로 판의 높이 m, 폭 n과 판의 배치 정보 board가 들어온다.
  • 2 <= nm <= 30
  • board는 길이 n인 문자열 m개의 배열로 주어진다. 블록을 나타내는 문자는 대문자 A에서 Z가 사용된다.

출력 형식

입력으로 주어진 판 정보를 가지고 몇 개의 블록이 지워질지 출력하라.

입출력 예제

mnboardanswer
45[“CCBDE”, “AAADE”, “AAABF”, “CCBBF”]14
66[“TTTANT”, “RRFACC”, “RRRFCC”, “TRRRAA”, “TTMMMF”, “TMMTTJ”]15

예제에 대한 설명

  • 입출력 예제 1의 경우, 첫 번째에는 A 블록 6개가 지워지고, 두 번째에는 B 블록 4개와 C 블록 4개가 지워져, 모두 14개의 블록이 지워진다.
  • 입출력 예제 2는 본문 설명에 있는 그림을 옮긴 것이다. 11개와 4개의 블록이 차례로 지워지며, 모두 15개의 블록이 지워진다.

문제 해설

게임 요구 사항을 구현해보는 문제입니다. 같은 모양의 카카오프렌즈 블록이 2x2 형태로 4개가 붙어있을 경우 사라지면서 점수를 얻는 게임인데요. 인접한 모든 블록이 사라지는 실제 게임들과 달리 계산을 쉽게 하기 위해 2x2로 제한하고, 사라진 블록 자리에는 새로운 블록이 채워지지 않습니다. 그럼에도 불구하고 인접한 블록을 모두 스캔해야 하는 문제라 짧지 않은 코드가 필요했을 것 같네요. 이번 시험에서 가장 긴 코드가 필요한 문제였습니다. 자바의 경우 무려 80라인이나 필요했네요. 블록 매트릭스를 생성하여 스캔하고 제거해 나가는 작업을 반복하면서 더 이상 제거되지 않을 때 사라진 블록 자리의 수를 계산하면 됩니다.

이 문제의 정답률은 48.01%입니다.

7. 추석 트래픽(난이도: 상)

이번 추석에도 시스템 장애가 없는 명절을 보내고 싶은 어피치는 서버를 증설해야 할지 고민이다. 장애 대비용 서버 증설 여부를 결정하기 위해 작년 추석 기간인 9월 15일 로그 데이터를 분석한 후 초당 최대 처리량을 계산해보기로 했다. 초당 최대 처리량은 요청의 응답 완료 여부에 관계없이 임의 시간부터 1초(=1,000밀리초)간 처리하는 요청의 최대 개수를 의미한다.

입력 형식

  • solution 함수에 전달되는 lines 배열은 N(1 ≦ N ≦ 2,000)개의 로그 문자열로 되어 있으며, 각 로그 문자열마다 요청에 대한 응답완료시간 S와 처리시간 T가 공백으로 구분되어 있다.
  • 응답완료시간 S는 작년 추석인 2016년 9월 15일만 포함하여 고정 길이 2016-09-15 hh:mm:ss.sss 형식으로 되어 있다.
  • 처리시간 T는 0.1s0.312s2s 와 같이 최대 소수점 셋째 자리까지 기록하며 뒤에는 초 단위를 의미하는 s로 끝난다.
  • 예를 들어, 로그 문자열 2016-09-15 03:10:33.020 0.011s은 “2016년 9월 15일 오전 3시 10분 33.010초”부터 “2016년 9월 15일 오전 3시 10분 33.020초”까지 “0.011초” 동안 처리된 요청을 의미한다. (처리시간은 시작시간과 끝시간을 포함)
  • 서버에는 타임아웃이 3초로 적용되어 있기 때문에 처리시간은 0.001 ≦ T ≦ 3.000이다.
  • lines 배열은 응답완료시간 S를 기준으로 오름차순 정렬되어 있다.

출력 형식

  • solution 함수에서는 로그 데이터 lines 배열에 대해 초당 최대 처리량을 리턴한다.

입출력 예제

예제 1

  • 입력: [ “2016-09-15 01:00:04.001 2.0s”, “2016-09-15 01:00:07.000 2s” ]
  • 출력: 1

예제 2

  • 입력: [ “2016-09-15 01:00:04.002 2.0s”, “2016-09-15 01:00:07.000 2s” ]
  • 출력: 2
  • 설명: 처리시간은 시작시간과 끝시간을 포함하므로 첫 번째 로그는 01:00:02.003 ~ 01:00:04.002에서 2초 동안 처리되었으며, 두 번째 로그는 01:00:05.001 ~ 01:00:07.000에서 2초 동안 처리된다. 따라서, 첫 번째 로그가 끝나는 시점과 두 번째 로그가 시작하는 시점의 구간인 01:00:04.002 ~ 01:00:05.001 1초 동안 최대 2개가 된다.

예제 3

  • 입력: [ “2016-09-15 20:59:57.421 0.351s”, “2016-09-15 20:59:58.233 1.181s”, “2016-09-15 20:59:58.299 0.8s”, “2016-09-15 20:59:58.688 1.041s”, “2016-09-15 20:59:59.591 1.412s”, “2016-09-15 21:00:00.464 1.466s”, “2016-09-15 21:00:00.741 1.581s”, “2016-09-15 21:00:00.748 2.31s”, “2016-09-15 21:00:00.966 0.381s”, “2016-09-15 21:00:02.066 2.62s” ]
  • 출력: 7
  • 설명: 아래 타임라인 그림에서 빨간색으로 표시된 1초 각 구간의 처리량을 구해보면 (1)은 4개, (2)는 7개, (3)는 2개임을 알 수 있다. 따라서 초당 최대 처리량은 7이 되며, 동일한 최대 처리량을 갖는 1초 구간은 여러 개 존재할 수 있으므로 이 문제에서는 구간이 아닌 개수만 출력한다.

문제 해설

이번 테스트의 마지막 문제이고, 가장 어려운 문제입니다. 초당 최대 처리량이 되는 구간 윈도우를 찾아야 하는 문제인데요. 당연히 처음부터 끝까지 스캔하기에는 범위가 너무 크고, 게다가 ms 단위로 되어 있기 때문에 첫 로그 시각부터 마지막 로그 시각까지 1ms씩 증가시키면서 1000ms 단위의 슬라이딩 윈도우로 풀면 24 * 3600 * 1000 * n * 1000ms 만큼의 연산이 필요하기 때문에 이렇게는 풀 수가 없습니다.

그렇다고 각 로그의 시작 시각부터 마지막 시각까지 1ms 씩 움직이면 time(ms) * n^2 이 되며, time(ms)의 값은 대부분 천 단위 이상이기 때문에 마찬가지로 타임아웃이 발생하여 풀 수가 없습니다. 그런데 자세히 살펴보면 요청량이 변하는 순간은 각 로그의 시작과 끝뿐임을 알 수 있습니다. 따라서, 각 로그 별 2번의 비교 연산만 수행하면 되며 2 * n^2, 빅오로 정리하면 O(n^2)에 풀 수가 있습니다. 빅오에서 제거된 상수항도 매우 작기 때문에 이 경우 무리 없이 문제를 풀 수 있게 되며 C++ 기준으로 10ms를 넘지 않습니다.

물론, 이 문제는 윈도우를 사용하지 않고도 풀 수 있는 방법이 있습니다. 효율적인 알고리즘을 쓴다면, O(n log n)으로 풀 수 있는 방법도 있으니 한 번 고민해보세요. 이 문제는 가장 어려운 문제였던 만큼 정답률은 가장 낮은 17.99%입니다.

마무리하며

이렇게 모든 문제를 돌아보고 간략한 해설을 곁들여 봤습니다. 어떠신가요?

참여하신 분들 중 미처 풀지 못한 문제가 있었다면 문제 해설을 보면서 ‘조금만 더 시간이 있었더라면…‘라며 안타까움을 느끼는 분들이 많으실 거라 생각합니다. 여타의 코딩 대회와 달리 채용을 위한 시험인 만큼 재밌게 즐기기는 힘들었을 것입니다. 하지만, “천재는 노력하는 사람을 이길 수 없고, 노력하는 사람은 즐기는 사람을 이길 수 없다.”는 말이 있듯이, 끝까지 즐기는 마음 잊지 않고 코딩을 즐긴다면 언젠가 좋은 결과 있으리라 확신합니다. 마지막까지 잘 마무리하여 꼭 카카오에서 여러분들을 만나 뵙게 되길 기대하겠습니다.

그럼, 2차 시험에서 다시 만나도록 할게요. 마지막까지 파이팅!



출처 : http://tech.kakao.com/2017/09/27/kakao-blind-recruitment-round-1/

728x90
728x90

* Rundll 커맨드 라인

RUNDLL.EXE <DLL 명>,<엔트리 포인트> <옵션 아규먼트>


를 이용하여 실행


.lnk (참조 되어 있는 샘플 파일) 의 커맨드라인 분석, 복사


그 후 rundll32.exe와 해당 .dll파일 주소를 샘플 파일과 같이 이동,


ex: C:\Windows\SysWOW64\rundll32.exe C:\Windows\SysWOW64\cb3cacb2418b31f93e8172d12c00fef8bb1bbf0b222f5d2afcf876219926e86b.dll,MXS3



728x90
728x90
요약
윈도우 95는 DLL에서 익스포트된 함수를 실행하는 16비트, 32비트 Rundll.exe과 Rundll32.exe 커맨드-라인 유틸리티를 가진다. 그러나, Rundll과 Rundll32 프로그램이 모든 DLL로 부터의 모든 익스포트 함수에 대해 실행되지는 않는다. 예를 들어 시스템 DLL에서 익스포트되는 Win32 API (Application Programming Interface) 는 콜할 수없다. 작성한 DLL에 존재하는 익스포트 함수에 대하여만 가능하다. 여기에서는 윈도우 NT와 95하에서 Rundll과 Rundll32 사용법을 다룬다. 원래 Rundll과 Rundll32 유틸리티는 마이크로소프트 내부용의로 설계되었다. 그러나 그 기능이 일반적이므로 현재는 공개되었다. 
주 : 윈도우 NT 4.0은 Rundll32만 포함되며 Rundll32만 지원한다.
추가 정보

* Rundll 과 Rundll32 비교

Rundll은16-비트 DLL을 로드하고 실행하며, 반면 Rundll32는32-비트 DLL을 로드하고 실행한다. 잘못된 DLL을 Rundll 나 Rundll32에 사용하는 경우, 오류 메시지 없이 실행에 실패한다.

* Rundll 커맨드 라인

RUNDLL.EXE <DLL 명>,<엔트리 포인트> <옵션 아규먼트>
다음은 예이다:
RUNDLL.EXE SETUPX.DLL,InstallHinfSection 132 C:\WINDOWS\INF\SHELL.INF
다음은 위 명령어 라인에서 주의해야한 3가지 문제이다:
  1. Rundll 이나 Rundll32은 주어진 DLL 파일명을 LoadLibrary() 함수가 사용하는 표준위치에서 찾는다. 정확을 기하기 위해서는 DLL의 풀-패스를 기술하고, 유효한 파일명이 되기 위해서는 긴 파일명 대신 짧은 파일 명을 기술한다. 즉 "C:\Program Files" 폴더는 반드시 짧은 폴더 명으로 변환되어야 한다.
  2. <DLL 명>에는 스페이스, 콤마, 따옴표등이 포함될 수없다. 이것은 Rundll 커맨드 분석기의 한계이다.
  3. 위 커맨드 라인에서, <DLL 명>과 <엔트리 포인트>사이의 컴마(,)는 매우 중요하다. 만약 컴마가 없다면, Rundll이나 Rundll32는 어떤 오류 메시지 없이 실패한다. 또한 <DLL 명>, 컴마와 <엔트리 포인트> 함수 사이에는 스페이스도 없어야만 한다.

* Rundll 동작 방법

  1. 커맨드 라인을 분석한다.
  2. LoadLibrary()로 명시된 DLL을 로드한다.
  3. GetProcAddress()로 <엔트리 포인트> 함수의 어드레스를 얻는다.
  4. <옵션 아규먼트>를 <엔트리 포인트> 함수로 패스하면서 콜한다.
  5. <엔트리 포인트> 함수 리턴시 Rundll.exe는 DLL을 언로드하고 종료한다.

* DLL 작성법

작성하는 DLL에서, 다음같은 함수 원형 <엔트리 포인트> 함수를 만든다:


16-비트 DLL:

void FAR PASCAL __loadds
EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);

32-비트 DLL:

void CALLBACK
EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);
엔트리 포인트 함수는 다음을 고려해야 한다.
  1. "EntryPoint"는 반드시 실제 엔트리 포인트 함수명 이어야 한다. Rundll32의 엔트리 포인트는 프로세스와 쓰레드 어태치/디태치 통보(notifications)를 처리하는 32비트 DLL의 DllEntryPoint함수와 완전히 별개이다.
  2. Rundll32의 엔트리 포인트 함수는 반드시 _stdcall(CALLBACK은 디폴트로 _stdcall 속성을 사용한다)을 정의해야만 한다. 만약 _stdcall이 없으면, 함수는 디폴트로 _cdecl를 사용하며, 이때 Rundll32은 함수 호출 후, 비정상적으로 종료한다.
  3. 반드시 함수 선언에 _stdcall 를 사용해야 하며, 비주얼 C++ 컴파일러는 DLL이 C로 쓰여진 경우는 _EntryPoint@16으로, C++로 쓰여진 경우는 함수명을 장식한다. 그러므로 장식돤 이름을 사용하지 않으려면, .DEF 파일을 사용하고, 이름으로 엔트리 포인트 함수를 익스포트해야 한다.
Rundll 엔트리 포인트의 매개변수는 다음과 같다:
hwnd - DLL에서 사용할 오너 윈도우의 윈도우 핸들
hinst - DLL의 인스턴스 핸들
lpszCmdLine - DLL이 분석해야할 ASCIIZ 커맨드 라인
nCmdShow - DLL의 윈도우를 디스플레이할 방법

다음은 예이다:
RUNDLL.EXE SETUPX.DLL,InstallHinfSection 132 C:\WINDOWS\INF\SHELL.INF
Rundll은 Setupx.dll 내의 InstallHinfSection() 엔트리 포인트 함수를 다음의 매개 변수로 콜한다:
hwnd = (모 윈도우 핸들)
hinst = SETUPX.DLL의 HINSTANCE 
lpszCmdLine = "132 C:\WINDOWS\INF\SHELL.INF"
nCmdShow = (CreateProcess에 전달되는 nCmdShow)
주 : 엔트리 포인트 함수(예제에서는 InstallHinfSection())는 커맨드 라인 (여기에서는 lpszCmdLine)을 분석한다. Rundll.exe는 커맨드 라인에 패스되는 아규먼트중 옵션 아규먼트까지 분석하고 나머지 분석은 엔트리 포인트 함수에 의존한다. 

* 윈도우 95와 윈도우 NT간의 차이점

윈도우 NT에서의 Rundll32.exe동작은 유니코드 커맨드 라인에 적합하도록 되어있다. 윈도우 NT는 먼저 <엔트리 포인트 함수명>W의 GetProcAddress를 얻어내어 엔트리 포인트가 있는 경우 함수 원형을 다음으로 간주한다:
void CALLBACK
EntryPointW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine, int nCmdShow);
이것은 lpszCmdLine이 유니코드 문자열인 점만이 ANSI 엔트리포인트 함수와 다른 점이다. 

만약 <엔트리 포인트 함수명>W이 없으면, 윈도우 NT는 <엔트리 포인트 함수명>을 위하여 <엔트리 포인트 함수명>A의 GetProcAddress를 실행하고 이를 ANSI 엔트리 포인트로 여겨 윈도우 95와 동일하게 처리한다. 그러므로, 만약 작성한 DLL이 윈도우 95에서는 ANSI 지원, 윈도우 NT에서는 UNICODE지원하게 한다면 반드시 두개의 함수: EntryPointW 와 EntryPoint를 익스포트한다. 윈도우 NT에서 EntryPointW 함수는 유니코드 커맨드 라인을 사용하고, 윈도우95에서는 EntryPoint 함수는 ANSI 커맨드 라인을 콜하게 될 것이다.


728x90

'Program > DLL' 카테고리의 다른 글

dll 멀웨어 파일 실행 방법  (0) 2016.11.30
INFO: Windows Rundll 및 Rundll32 인터페이스  (0) 2016.11.30
728x90
요약
Microsoft Windows 95, Windows 98 및 Windows Millennium Edition(Me)에는 16비트나 32비트 DLL에서 내보낸 함수를 호출하는 데 사용되는 Rundll.exe와 Rundll32.exe라는 두 가지 명령줄 유틸리티 프로그램이 포함되어 있습니다. 그러나 Rundll과 Rundll32 프로그램을 통해 임의의 DLL에서 내보낸 함수 모두를 호출할 수 있는 것은 아닙니다. 예를 들어, 이러한 유틸리티 프로그램을 사용하여 시스템 DLL에서 내보낸 Win32 API(응용 프로그래밍 인터페이스) 호출을 수행할 수는 없으며, 이들 프로그램이 호출하도록 명시적으로 작성된 함수만 DLL에서 호출할 수 있습니다. 이 문서에서는 위에서 언급한 Windows 운영 체제에서 Rundll 및 Rundll32 프로그램을 사용하는 방법에 대해 자세히 설명합니다. 

MIcrosoft Windows NT 4.0, Windows 2000 및 Windows XP에는 Rundll32만 제공됩니다. 이러한 플랫폼에서는 Rundll(Win16 유틸리티)을 지원하지 않습니다. 

Rundll 및 Rundll32 유틸리티 프로그램은 원래 Microsoft 내부에서만 사용하도록 설계되었습니다. 그러나 이들 프로그램에서 제공하는 기능이 상당히 일반적이기 때문에 지금은 일반적인 용도로 사용할 수 있습니다. Windows NT 4.0에는 Rundll32 유틸리티 프로그램만 제공되므로 Windows NT 4.0은 Rundll32만 지원합니다.
추가 정보

Rundll과 Rundll32 비교

Rundll은 16비트 DLL을 로드하고 실행하는 반면 Rundll32는 32비트 DLL을 로드하고 실행합니다. 잘못된 유형의 DLL을 Rundll이나 Rundll32로 전달하면 오류 메시지가 표시되지 않고 실행되지 않을 수 있습니다.

Rundll 명령줄

Rundll의 명령줄은 다음과 같습니다.

   RUNDLL.EXE <dllname>,<entrypoint> <optional arguments>
				
예를 들면, 다음과 같습니다.

   RUNDLL.EXE SETUPX.DLL,InstallHinfSection 132 C:\WINDOWS\INF\SHELL.INF
				
위의 명령줄에서 신중하게 고려할 세 가지 사항이 있습니다.
  1. Rundll이나 Rundll32는 표준 위치에서 주어진 DLL 파일 이름을 검색합니다(자세한 내용은 LoadLibrary() 함수에 대한 문서 참조). DLL을 제대로 검색하기 위해 DLL의 전체 경로를 제공하는 것이 좋습니다. 최상의 결과를 얻으려면 잘못된 문자가 나타나지 않도록 긴 파일 이름 대신 짧은 파일 이름을 사용합니다. 특히 "C:\Program Files" 폴더의 DLL이 짧은 이름으로 변환되어야 합니다.
  2. <dllname>에는 공백, 쉼표 또는 따옴표가 포함되지 않을 수 있습니다. 이것은 Rundll 명령줄 파서의 제한 사항입니다.
  3. 위의 명령줄에서 <dllname>과 <entrypont> 함수 이름 사이의 쉼표(,)는 매우 중요합니다. 쉼표 구분 기호가 없으면 Rundll이나 Rundll32는 오류를 표시하지 않고 실패합니다. 또한, <dllname>, 쉼표 및 <entrypoint> 함수 사이에는 공백이 있어서는 안 됩니다.

Rundll의 작동 방식

Rundll은 다음 단계를 수행합니다.
  1. 명령줄 구문을 분석합니다.
  2. LoadLibrary()를 통해 지정된 DLL을 로드합니다.
  3. GetProcAddress()를 통해 <entrypoint> 함수의 주소를 얻습니다.
  4. <entrypoint> 함수를 호출하고 명령줄 끝 정보인 <optional arguments>를 전달합니다.
  5. <entrypoint> 함수가 결과를 반환하면 Rundll.exe는 DLL을 언로드하고 종료됩니다.

DLL을 작성하는 방법

DLL에서 다음 프로토타입을 사용하여 <entrypoint> 함수를 작성합니다. 

16비트 DLL: 


  void FAR PASCAL __loadds
  EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);
				
32비트 DLL:

  void CALLBACK
  EntryPoint(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow);
				
EntryPoint 함수에서 고려할 세 가지 사항이 있습니다.
  1. "EntryPoint"라는 이름을 작성한 진입점 함수의 실제 이름으로 바꿔야 합니다. Rundll32의 진입점은 프로세스와 스레드 연결/분리 알림을 처리하는 32비트 DLL의 DllEntryPoint 함수와는 전혀 관계가 없습니다.
  2. Rundll32의 진입점 함수는 _stdcall 호출 규칙을 사용하여 정의되어야 합니다(콜백은 _stdcall 특성을 사용하도록 기본적으로 설정됨). _stdcall 특성이 없으면 함수는 _cdecl 호출 규칙을 기본적으로 사용하고 Rundll32는 함수를 호출한 후 비정상적으로 종료됩니다.
  3. 위에서 설명한 대로 _stdcall 호출 규칙을 사용하여 함수를 선언해야 하므로 Visual C++ 컴파일러는 DLL이 C로 작성된 경우 이것을 _EntryPoint@16으로 내보내고 DLL이 C++로 작성된 경우 이름 장식을 더 사용합니다. 따라서 명령줄에서 Rundll이나 Rundll32에 대해 제대로 내보낸 이름을 사용하도록 해야 합니다. 장식된 이름을 사용하지 않으려면 .def 파일을 사용하고 이름에 따라 진입점 함수를 내보냅니다. Visual C++ 컴파일러를 사용하는 경우의 이름 장식에 대한 자세한 내용은 제품 설명서와 다음 문서를 참조하십시오.
    140485 INFO: 32비트 DLL에서 PASCAL 형식의 기호 내보내기
Rundll 진입점에 대한 매개 변수는 다음과 같습니다.
   hwnd - DLL이 만든 모든 창에 대해 소유자 창으로 사용되는
          창 핸들
   hinst - DLL의 인스턴스 핸들
   lpszCmdLine - DLL이 구문 분석하는 ASCIIZ 명령줄
   nCmdShow - DLL의 창이 표시되는 방법 설명
				
다음 예제에서

     RUNDLL.EXE SETUPX.DLL,InstallHinfSection 132 C:\WINDOWS\INF\SHELL.INF
				
Rundll은 Setupx.dll에서 InstallHinfSection() Entrypoint 함수를 호출하고 다음 매개 변수를 전달합니다.
   hwnd = (부모 창 핸들)
   hinst = SETUPX.DLL의 HINSTANCE
   lpszCmdLine = "132 C:\WINDOWS\INF\SHELL.INF"
   nCmdShow = (CreateProcess로 전달된 모든 nCmdShow)
				
이것은 자체 명령줄(위의 lpszCmdLine 매개 변수)의 구문을 분석하고 필요에 따라 개별 매개 변수를 사용해야 하는 <entrypoint> 함수(위의 예제에서는 InstallHinfSection())입니다. Rundll.exe는 명령줄로 전달된 선택적 인수의 구문까지만 분석합니다. 나머지 구문 분석은 <entrypoint> 함수가 담당합니다.

Windows 95와 Windows NT의 차이점

Windows NT, Windows 2000 및 Windows XP에서는 유니코드 명령줄을 수용하기 위해 Rundll32.exe의 동작이 약간 다릅니다. 

Windows NT는 먼저 <EntryPoint>W에 대한 GetProcAddress를 실행합니다. 이 진입점을 찾은 경우 프로토타입은 다음과 같습니다.

   void CALLBACK
   EntryPointW(HWND hwnd, HINSTANCE hinst, LPWSTR lpszCmdLine,
               int nCmdShow);
				
이것은 lpszCmdLine 매개 변수가 유니코드 문자열이라는 점을 제외하고는 ANSI EntryPoint와 동일합니다. 

<EntryPoint>W 진입점을 찾지 못하면 Windows NT는 <entrypoint>A 및 <entrypoint>에 대한 GetProcAddress를 실행합니다. 둘 중 하나가 발견되면 ANSI 진입점으로 간주되고 Windows 95/98/Me와 같은 방식으로 처리됩니다. 따라서 ANSI가 지원되는 Windows 95와 유니코드가 지원되는 Windows NT/2000/XP에서 DLL을 실행하려고 하면 두 함수 EntryPointW와 EntryPoint를 내보내야 합니다. Windows NT/2000/Me에서 EntryPointW 함수는 유니코드 명령줄에서 호출되고 Windows 95/98/Me에서 EntryPoint 함수는 ANSI 명령줄에서 호출됩니다.


728x90

'Program > DLL' 카테고리의 다른 글

dll 멀웨어 파일 실행 방법  (0) 2016.11.30
[INF] 윈도우 95의 Rundll과 Rundll32의 사용법  (0) 2016.11.30
728x90


연산자

연산자의 의미

결합성

=

오른쪽에 있는 값을 왼쪽에 대입한다.

Ex) a = 20

+

왼쪽과 오른쪽에 있는 값을 더한다.

Ex) a = 4 + 3

-

왼쪽에 있는 값에서 오른쪽에 있는 값을 뺀다.

Ex) a = 4 – 3

*

왼쪽과 오른쪽에 있는 값을 곱한다.

Ex) a = 4 * 3

/

왼쪽에 있는 값을 오른쪽에 있는 값으로 나눈다.

Ex) 4 / 3

%

왼쪽에 있는 값을 오른쪽에 있는 값으로 나눠서 나머지를 반환한다.

Ex) a = 4 % 3

++a

값을 1 증가 후 연산을 진행(선 증가, 후 연산)

Ex) printf(“%d”, ++a)

a++

연산을 진행한 후 값을 1 증가(선 연산, 후 증가)

Ex) printf(“%d”, a++)

--b

값을 1 감소 후 연산을 진행(선 감소, 후 연산)
ex) printf(“%d”, --b)

b--

연산을 진행한 후 값을 1 감소(선 연산, 후 감소)

Ex) printf(“%d”, b--)

<

Ex) a < b

a가 b보다 작은가?

>

Ex) a > b

a가 b보다 큰가?

==

Ex) a == b

a와 b가 같은가?

!=

Ex) a != b

a와 b가 같지 않은가?

<=

Ex) a <= b

a가 b보다 작거나 같은가?

>=

Ex) a >= b

a가 b보다 크거나 같은가?

&&

피연산자가 모두 참이면 true를 반환(and의 의미)

Ex) a && b

||

피연산자 중 하나라도 참이면 true를 반환(or의 의미)

Ex) a || b

!

피연산자가 true면 false를, false면 true를 반환(not의 의미)

Ex) !a

&

비트 단위 AND

Ex) a & b

|

비트 단위 OR

Ex) a | b

^

비트 단위 XOR

Ex) a ^ b

~

비트 단위 NOT

Ex) ~a

<<

왼쪽으로 이동

Ex) a << 2

>>

오른쪽으로 이동

Ex) a >> 2

 

자료형(data type)

할당되는 메모리 크기

표현 가능한 데이터의 범위

char

  1 바이트

  -128 ~ +127

 short

  2 바이트

  -32768 ~ +32767

 int

  4 바이트

  -2147483648 ~ +2147483647

 long

  4 바이트

-2147483648 ~ +2147483647

 float

  4 바이트

  3.4X  ~ 3.4X 

 double

  8 바이트

  1.7X  ~ 1.7X 

 long double

  8 바이트 혹은 그 이상

  차이를 많이 보임

 

특수 문자

의     미

\a(\a)

경고음 소리 발생

\b

백스페이스(backspace)

\f

폼 피드(form feed)

\n

개행

\r

캐리지 리턴(carriage return)

\t

수평 탭

\v

수직 탭

\\

백슬래시(\)

\’

작은 따옴표

\”

큰 따옴표

 

서식 문자

출력 형태

%c

단일 문자

%d

부호 있는 10진 정수

%i

부호 있는 10진 정수, %d와 같음

%f

부호 있는 10진 실수

%s

문자열

%o

부호 없는 8진 정수

%u

부호 없는 10진 정수

%x

부호 없는 16진 정수, 소문자 사용

%X

부호 없는 16진 정수, 대문자 사용

%e

표기법에 의한 실수(부동소수점 표현 방식)

%E

표기법에 의한 실수(부동소수점 표현 방식)

%g

값에 따라서 %f, %e 둘 중 하나를 선택

%G

값에 따라서 %f, %E 둘 중 하나를 선택

%%

기호 출력

%αd

필드 폭을 α칸 확보하고 오른쪽 정렬해서 출력하라.

%-αd

필드 폭을 α칸 확보하고 왼쪽 정렬해서 출력하라.

%+αd

필드 폭을 α칸 확보하고 오른쪽 정렬한 상태에서 양수는 +, 음수는 –를 붙여서 출력하라.



728x90
728x90

http://blog.naver.com/zacronan?Redirect=Log&logNo=40018174412
http://airtight.yonsei.ac.kr/research/COM/thread_apartment.htm

1-2 스레딩 모델 

먼저 이 부분을 설명하기 위해서는 아파트먼트(Apartment)라는 것에 대해 설명이 필요하다. 아파트먼트는 하나의 프로세스 내에서 여러 개의 스레드를 가지고 각각의 스레드 동기화 문제를 해결하기 위해 나온 것으로 각 오브젝트를 가지고 있는 하나의 방이라는 개념으로 이해하면 된다. 각 아파트먼트당 하나의 스레드가 존재하며 오브젝트는 적당한 아파트먼트 안으로 들어가게 된다. 

이러한 스레딩 모델(Threading Model)은 레지스트리에서 CLSID의 스레딩 모델의 값을 보면 된다. 가능한 경우는 스레딩 모델이 아예 없거나 아파트먼트, 프리(Free), 보스(Both)가 되는 것이다. 아파트먼트는 STA 모델을 가리키며 프리는 MTA 모델을, 보스는 STA, MTA 둘 다 지원한다는 것을 말한다. 이 값이 아예 없다는 것은 main STA에서 동작한다는 것을 말하고 이 main STA는 프로세스가 초기에 주 스레드에서 호출한 CoInitializeEx 값에 의해 결정된다. 




① STA(Single Threaded Apartment) 

STA 내에서 서버는 각각의 아파트먼트 내에 각 오브젝트가 존재하며 하나의 프로세스 내에서 각 아파트먼트 내에 각 오브젝트가 들어가 있게 된다. 이 경우는 CoInitializeEx(NULL,COINIT_APARTMENTTHREADED)를 각각의 스레드당 호출하여 초기화 된다. 이러한 각각의 오브젝트 호출은 메시지에 의해 동기화 된다. 즉 이러한 메시지를 통해 동기화 된다는 것은 메시지 루프를 가져야 한다는 얘기이다. 

하나의 아파트먼트 내에서는 프록시의 개입 없이 직접적으로 호출할 수 있으나 다른 아파트먼트 내에서는 이렇게 될 수는 없다. 즉 하나의 메소드 호출은 클래스 네임이 OleMainThreadWndClass를 가지는 윈도우 클래스가 등록한 WndProc로 가서 적당한 Interface의 메소드를 호출하게 된다. 이러한 모델 내에서의 호출은 그림 5와 같다. 










그림 5 : STA에서의 메시지 큐 


그림 5에서 보는 것처럼 서버로의 모든 호출은 큐(Queue) 속에서 들어가며 GetMessage,DispatchMessage에 의해 해당 오브젝트로 전달된다. 




② .MTA(Multi Threaded Apartment) 

MTA 내에서 하나의 아파트먼트 내에 여러 개의 스레드와 오브젝트가 들어가게 되며 따라서 오직 한 번만 CoInitializeEx(NULL, COINIT_MULTITHREADED)를 호출하면 된다. 이 경우에는 여러 개의 스레드가 동시에 오브젝트의 메소드로 접근할 수 있기 때문에 Reentrant하도록 소스가 작성되거나 동기화 문제를 코드 안에서 해결해야 한다. 하지만 서버 안에서의 스레드간 인터페이스 전달에 프록시가 개입할 필요가 없다. 

또한 STA로 작성하는 것보다 빠른 속도를 보이는 멀티 스레드의 장점을 충분히 활용할 수 

가 있으며 하나의 프로세스 내에 오직 하나의 MTA만 만들어질 수 있다. 




③ 혼합 모델 

이 모델은 프로세스가 한 개의 MTA와 한 개 이상의 STA를 가진다는 것을 의미한다. 




④ STA와 MTA와 혼합 모델에서의 선택 

어떤 오브젝트의 모델을 선택하는 것은 각기 장단점이 존재하기 때문에 상황에 맞게 선택해야 하는데, STA에서는 프로그래머가 스레드간의 동기화를 신경쓸 필요가 없다. 그러나 여기서 다른 아파트먼트로 인터페이스를 전달하기 위해서는 프록시의 개입을 필요로 하므로 느려질 수 있으며, 또한 객체로의 메소드 호출이 메시지 루프(Loop)를 통해 한번에 하나씩 만 처리되기 때문에 멀티 스레드의 장점을 충분히 활용할 수가 없게 된다. 

그러나 MTA를 선택한 경우 서버 객체의 구현자는 여러 개의 스레드가 동시에 메소드 호출을 수행할 수가 있으므로 코드는 Reentrant하게 작성되거나 Mutex, Critical Section, Event를 통해 동기화 코드를 작성해야 한다. 따라서 작성이 어려워지게 되지만 이 경우라고 해도 수많은 사용자가 사용할 수 있는 오브젝트라면 한번 고려해볼 만하다.


출처 : http://broneri.tistory.com/372

728x90
728x90

struct _tagPoint{
     int x; 
     int y;
};

POINTS는 선언되지 않은 심볼이므로 struct _tagPoint POINTS;라고 하면,

POINTS라는 이름의 구조체 변수가 생성됩니다.

당연히 POINTS는 타입으로 선언된 것이 아니므로 POINTS s;라는 구문은 오류입니다.

struct의 임무는 뒤에 나오는 식별자 _tagPoint가

구조체 태그이름임을 나타내는 지시어입니다.

이는 C와의 하위 호환성을 위해 남겨둔 것으로,

C++에서는 선택적으로 사용해도 되고, 사용하지 않아도 상관 없습니다.

C에서 변수선언은 기본적으로

"변수 선언이 가능한 키워드로 시작"될 때만

변수 선언으로 인식하도록 되어 있는 구조입니다.

따라서 한 문장의 시작이 int, char, void 등의 타입을 나타내는

'키워드'여야만 유효한 선언으로 간주하는 구조로 설계되었습니다.

enum이나 union, struct등의 사용자 정의 타입은

그냥 선언한 이름만 쓰면 변수 선언으로 인식하지 못하는 구조이죠.

그래서 해당 타입이 무엇으로 선언되어 있는지를

컴파일러에게 알려주도록 C언어는 설계되었습니다.


 

하지만 C의 슈퍼셋으로 설계된 C++은

사용자 정의 타입 역시 기본 데이터 타입과 통합된 타입 시스템으로 관리하므로,

더이상 사용자 정의 타입의 변수를 생성할 때 그 종류를 알려줄 필요가 없지만,

C와의 하위 호환성을 위해 남겨둔 것 뿐입니다.

C에서 사용자 정의 데이터 타입의 변수를 선언하려면

사용자 정의 타입임을 나타내는 키워드(enum, struct, union 등)와

선언된 타입의 태그 이름을 같이 적어 주어야 했습니다.

하지만 매번 struct를 써주는 것도 번거로운 일이므로,

C에서는 사용자 정의 타입 이름도 typedef 로 재정의 가능하도록 허용했습니다.

그래서 C에서는 사용상의 편의를 위해서 구조체 선언과 동시에

구조체의 태그 이름으로 별 의미없는, 잘 안쓰는 이름을 붙이고

typedef 이름을 잘 쓰이고 읽기 쉬운 이름으로 붙이는 관습이 생겨난 것입니다.

C에서

struct POINTS
{
    int x, y;
};

POINTS s;

라고 변수를 정의하면, 컴파일 에러를 냅니다.

이는 POINTS가 타입이름으로 선언된 이름이 아니라,

사용자 정의 타입의 태그 이름으로만 선언된 이름이기 때문이죠.

태그이름과 타입이름은 엄연히 다른 것이니까요.

하지만 C++ 에서 위의 코드는 아무런 문제가 없습니다.

C++의 타입 시스템은 사용자정의 타입도 기본 데이터 타입과 마찬가지로 취급하므로

구조체 태그 이름을 선언하는 순간, 그 이름이 타입 시스템 내에서

유효한 타입이름으로 등록되어 사용할 수 있게 되므로, C++에서는 사실상

typedef로 타입을 선언하나, 그냥 struct만으로 선언하나 아무런 차이가 없습니다.

단, 여기서 주의할 점은, 다음과 같은 구문에서,

typedef struct
{
    int x, y;
} POINTS;

이와 같은 구문은 컴파일러는 이렇게 해석합니다.

a. 이름없는 구조체를 만들고,

b. 여기에 두 멤버변수 x,y를 추가하고

c. 이 이름없는 구조체의 타입이름을 POINTS로 재정의한다.

여기서 문제가 되는 것은 '이름없는 구조체'를 만드는 것이

컴파일러에 따라 지원될 수도 있고, 안될 수도 있다는 것이죠.

'이름없는 구조체'는 언어 표준에서 명시된 것이 아니므로,

이를 지원하는 컴파일러는 살짝 표준에서 빗겨나가 있긴 하지만

대부분의 컴파일러가 지원하는 기능이므로 대부분 저렇게 쓰기도 합니다.

하지만, 진짜 언어 표준만을 지원하는 컴파일러는

위와 같은 구문은 컴파일시 에러나 워닝을 냅니다.

그래서 그와 같은 컴파일러에서는 구조체를 typedef로 새 타입이름으로 선언하더라도,

임시로 사용할 태그 이름이 필요하게 됩니다.

따라서, 이와 같은 컴파일러에서는 다음과 같이 임시 태그 이름을 사용하여

typedef로 타입 이름을 선언해야 합니다. 

(물론, 번거롭긴 하지만 표준과 일치하는 방법입니다.)

typedef struct _tagPoint{
     int x; 
     int y;
}POINT;

이와 같은 구문은, 어떤 컴파일러를 쓰더라도 정확히 동일한 결과를 내므로

안전한 기법이라고 할 수 있겠습니다.

POINTS라는 이름이 끝에 온다면,

이는 typedef 타입 이름으로 간주되 POINTS라는 이름이 struct 뒤에 바로 온다면

구조체 태그 이름으로 간주된다는 차이가 있습니다.

즉, 첫번째 예제의 POINTS는 typedef 타입 이름이 되며,

두번째 예제의 POINTS는 구조체 태그 이름이 됩니다.

반면, 세번째 예제에서는 typedef구문인데,  POINTS는 구조체 태그 이름만 있고

typedef로 선언할 새 타입 이름이 없으므로 오류입니다.

typedef의 기본 구문은,

typedef (기존타입) (새타입이름);

과 같은 형식입니다.

typedef struct POINT{
     int x; 
     int y;
};

와 같이 쓴다면, struct POINT { ... } 이 부분은 (기존타입)에 해당하지만,

(새타입이름)에 해당하는 부분이 없으므로 컴파일러는 typedef 부분을 무시하고

그냥 POINT라틑 태그이름으로 구조체를 선언하게 되는 것입니다.


728x90
728x90

쉽게 말해 enum 은 열거형 변수 입니다.

"어떻게" 생각하면 struct와 다르냐? 라고 물을 수 있지만.

"전혀" 다릅니다.

 

보통 enum은 상수를 정의하는데에 많이 쓰입니다.

소스의 가독성을 높인다거나 상수에 의미를 부여해서 쓸 수 있습니다.

 

전처리기인 #define 을 사용하거나, 전역 변수를 const로 선언해서 상수처럼 사용이 가능하지만

enum을 상수로 생각해서 처리할때의 이점이 있습니다. (뒷부분에 설명하겠습니다.)

 

우선 이넘(enum)을 선언하는 방법은 다음과 같습니다.

 

enum {mon, tue, wed, thr, fri, sat, sun } day;

 

여기서 day를 열거형 변수라 하고 그 하위의 항목(원소) 들 ( mon, tue, wed, thr, fri, sat, sun)로 구성됩니다.

 

특별하게 값을 지정하지 않는다면 enum의 각 원소들은 순차적인 "정수" 값을 갖게 됩니다.

이때 갖게되는 값은 mon부터 0, 1, 2 ... 6 까지 각 각 가지게 됩니다.

 

특별하게 값을 지정해서 enum을 사용한다면

 

enum {mon=100, tue, wed=200, thr, fri=300, sat, sun } day;

 

이렇게 선언을 하게 되면, mon은 당연히 100일거고,, tue는... 150일까요?

tue는 101을 갖게 됩니다.

 

enum의 값을 정하는 정의는 "이전 원소 값의 + 1" 입니다.

 

 

그럼. "왜 이넘을 사용해야 하는가.." 입니다.

 

사실 enum은 필요없을 지도 모릅니다.

#define 이 있고,

const int 가 있습니다.

 

하지만 C++ 이 enum에게 준 몇가지의 특별한 이유 때문에 enum을 사용합니다.

 

① 기억이 용이하다.

enum대신 정수형 변수를 대신 사용할 수 도 있습니다. 하지만, 이렇게 될때 각 정수의 의미가 무엇인지를 만드는 사람이 기억하고 있어야 하죠. 값이 많아질 수록 혼란스러울겁니다. 보통, 사람은 숫자보다 문자를 더 잘 기억합니다. 그리고, enum의 원소들을에게 의미를 부여한 이름을 준다면 더 기억하기가 쉽겠죠..

 

② 소스의 가독성(Readability)이 높아진다.

enum의 원소만 봄으로써, 그 상수의 의미를 보다 쉽게 파악 할 수 있고, 소스 전체의 가독성을 높이는데 도움이 됩니다. 예를 들어 whatdays = 0; 이라고 표현한다면, 이게 월요일인지,, 일요일인지, 도무지 알 길이 없습니다. 하지만 whatdays = mon; 이라고 한다면, 두말할나위없이 이해할 수 있겠죠. 두명이상의 Project나 팀단위 작업을 할때에는 알고리즘을 아무리 잘 짜도 소스가 X같으면, 프로젝트 진행이 어려워집니다. 따라서 이런 팀단위 작업에는 가독성이 아주 중요시 됩니다.

 

③ 안전하다.

앞서 예를든 days에 대입될수 있는 값은 7개중 하나로 제한이 되기때문에 사용자의 실수를 컴파일러가 미리 예방해줄 수 있습니다. 따라서 변수형을 사용하는것보다 안전하죠.

 

 

필수는 아니지만 있으면 좋다. 이게 이넘(emum)입니다.

 

 

enum을 보다 효율적으로 사용하는 방법은

 

typedef를 사용하는겁니다.

 

바로 예부터 보자면...

 

typedef enum CDays {enum {mon, tue, wed, thr, fri, sat, sun };

 

이제 CDays는 하나의 타입으로 생성된겁니다.

 

CDays WhatDay(); 와 같이 오늘이 몇요일인지 리턴하는 함수를 작성 할 수도 있구요.

 

CDays Day = WhatDay();

 

와 같이 Enum을 효과적으로 처리할 변수를 만들어 사용할 수 있습니다.

[출처] enum 사용법|작성자 다람쥐


enum 사용 예제 입니다. 

  1. #include <stdio.h>  
  2. enum week {sun, mon, tue, wed, thu, fri, sat};  
  3. int main(void)  
  4. {  
  5.     enum week day1;  
  6.     day1=fri;  
  7.     printf("day1 : %d\n", day1);  
  8.     printf("fri : %d\n", fri);  
  9.     day1=mon;  
  10.     printf("day1 : %d\n", day1);  
  11.     printf("mon : %d\n", mon);  
  12.     return 0;  
  13. }  


// 실행 결과


출처 : http://kimgagakk.tistory.com/341

728x90
728x90

UNION

C에서는 공용체라 부르는 특수한 타입이 있다. 공용체의 멤버로 선언된 변수들은 메모리 어드레스를 공유하게 된다. 어찌보면 별 필요없는 기능이라고 생각될 수도 있지만 메시지를 만들어 데이터를 읽고 쓰는데는 아주 유용한 기능이다.

선언 및 사용

union의 선언 방법은 struct와 동일하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
union simple_message {
int a;
int b;
};
 
int main(int argc, char **argv)
{
union simple_message smessage;
smessage.a = 1;
 
printf("smessage.a: %dn", smessage.a);
printf("smessage.b: %dn", smessage.b);
}

출력 결과를 보면 공용체 smessage의 멤버 a의 값과 b의 값이 동일한 것을 볼 수 있다. 멤버 a의 값이 변경된 것이 b에도 적용된 것 처럼 보이지만 사실은 공용체 멤버 a와 b가 동일한 메모리 주소를 공유하고 있는 것이다.

Example


위와 같은 데이터를 읽고 쓴다고 하자. 4 bytes 데이터 이므로 int 값에 bit 연산으로 데이터를 채워 넣는 방법을 쓸 수도 있지만 가독성이 떨어지며 코드길이가 길어져 한참후에 코드를 들여다 봤을 때 이해하는 것이 불가능해 질 수도 있다. 하지만 union을 사용하면 데이터를 다루기도 쉽고 이해하기도 편리하다는 것을 깨닫게 될 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <linux/types.h>
#include <memory.h>
 
struct regdata {
 __u16 opcode:4;
 __u16 prtaddr:5;
 __u16 regaddr:5;
 __u16 ta:2;
 __u16 data;
} __attribute__((packed));
 
union data {
 struct regdata reg0;
 __u32 rdata;
};
 
int main(int argc, char** argv)
{
 union data message;
 
 memset(&message, 0x0, sizeof(union data));
 message.reg0.opcode = 0x4;
 message.reg0.regaddr = 0x3;
 message.reg0.data = 0xE8A3;
 
 printf("message: %08xn", message.rdata);
 
 return 0;
}

실행결과는 message: e8a30604 이다. intel 시스템일 경우 little endian을 사용함으로 big endian으로 읽어보면 제대로데이터가 들어간 것을 알 수 있다.


728x90

+ Recent posts