<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[RSS Feed of it from bit.]]></title><description><![CDATA[돌아보니 좋은 날도 있었고, 나쁜 날도 있었다. 그런 나의 모든 소소한 일상과 배움을 기록한다. 여기에 기록된 모든 내용은 한 개인의 관점이고 의견이다. 내가 속한 조직과는 1도 상관이 없다.]]></description><link>https://jiniya.net</link><generator>GatsbyJS</generator><lastBuildDate>Mon, 23 Feb 2026 15:02:24 GMT</lastBuildDate><item><title><![CDATA[[잡기] 추사 김정희의 도망시]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/2026/02/elegy-for-my-wife-in-exile/</link><guid isPermaLink="false">https://jiniya.net/2026/02/elegy-for-my-wife-in-exile/</guid><pubDate>Mon, 23 Feb 2026 21:00:01 GMT</pubDate><content:encoded>&lt;p&gt;저녁 먹으면서 볼 게 없어서 경도를 기다리며, 라는 드라마를 한 편 봤는데 거기 추사의 도망시라는 게 나왔다. 도망시가 제목인 줄 알았는데 &apos;도망시(悼亡詩)&apos;는 특정 시의 제목이 아니라 &apos;죽은 아내를 애도하는 시&apos;를 통칭하는 문학적 갈래라고 한다. 추사 김정희의 지극한 아내 사랑이 잘 드러나는 시인 것 같아서 가져와 보았다.&lt;/p&gt;
&lt;p&gt;예전에 유시민 작가가 한 말인지 잘 모르겠는데 인간의 원초적 고독감은 감각 기관이 고립돼 있다는 데서 온다는 말을 들었던 기억이 있다. 무슨 말이냐면 내가 느끼는 걸 동일하게 타인이 느낄 수가 없는 구조라는 것이다. 실제로 내가 보는 파랑과 타인이 보는 파랑은 모두 다르다. 또 우리는 이해한다는 말을 하지만 타인이 느끼는 희노애락을 똑같이 느낄 수는 없다. 단지 상상할 뿐이다. 결국 우리는 저마다의 감각 기관이 수집한 정보를 저마다의 뇌가 만들어낸 환상으로 이루어진 고립된 섬 속에 존재하고 있는 셈이다. 그래서 인간은 원초적으로 고독한 존재라고 한다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;배소만처상 (配所輓妻喪)&lt;br&gt;
유배지에서 아내의 죽음을 애도하며&lt;br&gt;
&lt;br/&gt;
那將月佬訟冥司 (나장월노송명사)&lt;br&gt;
어찌 월하노인을 시켜 저승에 하소연하여,&lt;br&gt;
&lt;br/&gt;
來世夫妻易地爲 (내세부처역지위)&lt;br&gt;
다음 생엔 우리 부부가 서로 바꿔서 태어날까.&lt;br&gt;
&lt;br/&gt;
我死君生千里外 (아사군생천리외)&lt;br&gt;
나는 죽고 당신은 천 리 밖에 살아남아서,&lt;br&gt;
&lt;br/&gt;
使君知我此心悲 (사군지아차심비)&lt;br&gt;
나의 이 슬픈 마음 당신이 알게 했으면.&lt;br&gt;
&lt;br/&gt;
-- Gemini 3.1 Pro&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;김정희는 또 그가 말년에 쓴 대팽두부라는 구절로 유명하기도 하다. 최고의 자리와 최악의 시절을 모두 겪어본 그가 하는 말이라 더 공감이 가는지도 모르겠다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;大烹豆腐瓜薑菜 (대팽두부과강채)&lt;br&gt;
최고로 좋은 반찬은 두부, 오이, 생강, 나물이고&lt;br&gt;
&lt;br/&gt;
高會夫妻兒女孫 (고회부처아녀손)&lt;br&gt;
최고로 훌륭한 모임은 부부와 아들딸, 손자 손녀가 모인 자리이다.&lt;br&gt;
&lt;br/&gt;
이 두 줄의 글귀 옆에는 추사가 덧붙인 작은 글씨(협서)가 있습니다.&lt;br&gt;
&quot;이것은 촌늙은이의 제일가는 즐거움이다. 비록 정승 판서가 누리는 밥상이나 삼천 명의 시녀를 거느린 귀족이라도 이 맛을 알지는 못할 것이다.&quot;&lt;br&gt;
&lt;br/&gt;
-- Gemini 3.1 Pro&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;TMI로 김정희는 &lt;a href=&quot;/2025/06/korean-imperial-exam/&quot;&gt;일기를 쓰다, 흠영선집&lt;/a&gt;의 원작자인 유만주의 6촌형 유준주의 딸이 시집가서 낳은 아들이다. 유만주의 딸 진아는 추사의 6촌형 김도희에게 시집갔다. 이렇게 보면 참 스머프 마을같고, 유전자빨이란게 있나 싶은 생각이 들지만, 사실 6촌이면 남 아닌가 싶은 생각이 들기도 한다. 6촌 중에 실질적으로 아는 사람이 없다. 5촌 당숙 정도가 한계인듯. 그럼에도 유만주와 유준주는 흠영을 보면 몹시 잦은 교류가 있는 사이였다는 게 또 반전 아닌가 싶기도?!&lt;/p&gt;
&lt;p&gt;TIM2. 김정희는 결혼을 두 번 했다. 15세에 결혼한 첫번째 부인은 20세에 먼저 떠났고, 이 시의 주인공인 두번째 부인은 23살에 결혼해서 김정희가 55살이던 해에 병으로 먼저 떠났다고 한다. 그의 다른 인생사도 기구하지만 두 부인다 먼저 떠난 부분도 참 안타깝다는 생각이 든다. 그럼에도 시에 드러난 감정이 생길 정도로 애틋한 사람을 만났던 건 행운이 아닌가 싶다. 좋은 집안에, 좋은 머리로 태어나 출세 가도를 달린 인생 전반부와 당쟁에 휘말려 귀양과 유배로 보냈던 후반부를 오버랩시켜 보면 인생사라는 게 어쩌면 총량의 법칙이 실재하는게 아닌가 싶기도 한 생각이 든다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[리뷰] 카핑 베토벤, 2007]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/2026/02/copying-beethoven/</link><guid isPermaLink="false">https://jiniya.net/2026/02/copying-beethoven/</guid><pubDate>Mon, 23 Feb 2026 14:00:01 GMT</pubDate><content:encoded>&lt;p&gt;불멸의 연인 후에 본 베토벤에 관한 또다른 영화. 베토벤의 인생 후반부를 다룬다. 제목만 보면 뭔 베토벤 곡을 베끼나?!라는 생각을 하게 되는데, 영화가 시작하면 그게 다름 아닌 카피스트라는 사람들이란 걸 알게 된다. 작곡가가 알아보기 힘들게 작성한 악보를 보기 좋게 필사해 주는 직업이다. 실제로 당시에는 그런 역할을 하는 카피스트라는 직업이 존재했다고 한다. 영화는 재미를 위해서 안나 홀츠라는 여성 카피스트를 등장시킨다.&lt;/p&gt;
&lt;p&gt;영화는 크게 3부분으로 나뉜다. 귀가 안들리는 상황에서 9번 교향곡을 작곡해서 메가 히트를 치는 장면, 이어서 대푸가를 공연하면서 똥망하는 장면, 그리고 죽다 살아나서 현악 4중주를 작곡하는 장면으로 끝이 난다. 9번 교향곡 지휘하는 장면만 엄청 길게 나오는 등, 클래식을 좋아하지 않으면 재미있게 보기는 상당히 힘든 영화가 아닌가 싶다.&lt;/p&gt;
&lt;p&gt;실제로 대푸가를 들어보면 당시 욕했던 사람들이 상당히 이해되는 부분이 있다. 아고르 스트라빈스키는 대푸가를 &quot;영원히 현대적인, 절대적으로 동시대적인 음악&quot;이라고 평가했다고 한다. 미술이든 음악이든 현대적이라는 말은 참 난해하다. 23세기에도 현대적일 것 같은 베토벤의 대푸가. 5분 버티기가 힘들다.&lt;/p&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/j5XAdttmOLo?si=opJZ9lDs04i7pvU5&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;</content:encoded></item><item><title><![CDATA[[리뷰] 불멸의 연인, 1995 (스포주의)]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/2026/02/immortal-beloved/</link><guid isPermaLink="false">https://jiniya.net/2026/02/immortal-beloved/</guid><pubDate>Mon, 23 Feb 2026 13:00:01 GMT</pubDate><content:encoded>&lt;p&gt;연휴 기간에 우연찮게 베토벤을 들어봐야 겠다는 생각을 하다 베토벤 영화를 두 편 보게 됐다. 그 중 한편이 불멸의 연인. 베토벤은 평생을 독신으로 살았다. 하지만 연인이 아예 없었던 것은 아니었다. 그가 사랑한 대부분의 여인이 귀족이었고 신분 차이 때문에 결혼까지는 이르지 못한 것으로 보여진다. 월광 소나타를 헌정한 줄리에타 귀차르디, 엘리제를 위하여의 원 주인공으로 생각되는 테레제 말파티, 그리고 그의 사후 편지에서 발견된 누군지 특정되지 않은 불멸의 연인이 있다. 영화는 이 불멸의 연인을 찾아서 떠나는 미스테리 스릴러다. 다음은 인공지능이 정리한 베토벤의 연애사(?!)다. 영화를 보고 싶은 사람은 여기 까지만 읽고 영화를 보기를 추천한다. 다음 내용은 영화에 대한 스포 그잡채.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;불멸의 연인 (Immortal Beloved): 음악사에서 가장 유명한 미스터리 중 하나이다. 1827년 베토벤이 세상을 떠난 후, 비서 안톤 쉰들러가 그의 책상 속 숨겨진 칸에서 연필로 쓴 10페이지 분량의 연애편지를 발견했다. 1812년 7월 6~7일 이틀에 걸쳐 쓰인 이 편지에는 받는 사람의 이름 없이 &apos;불멸의 연인에게&apos;라고만 적혀 있었다. 200년이 넘도록 수신인의 정체는 밝혀지지 않았으며, 현재 학자들은 안토니 브렌타노와 요제피네 브룬스비크를 가장 유력한 후보로 보고 있다.&lt;br&gt;
&lt;br/&gt;
줄리에타 귀차르디 (Giulietta Guicciardi): 〈월광 소나타〉의 헌정을 받은 인물이다. 1800년경부터 베토벤의 피아노 제자였으며, 베토벤은 사랑에 빠져 청혼까지 했다. 줄리에타 본인도 받아들일 의향이 있었으나, 부모가 지위와 재산이 없다는 이유로 결혼을 금지했다. 줄리에타는 1803년 갈렌베르크 백작과 결혼하여 나폴리로 떠났다.&lt;br&gt;
&lt;br/&gt;
테레제 말파티 (Therese Malfatti): 베토벤의 피아노 제자로, 베토벤이 청혼했으나 말파티 가문이 신분과 현실적 이유를 들어 거절했다. 1867년 음악학자 루트비히 놀이 테레제의 유품에서 발견한 악보를 출판하면서, 베토벤의 악필로 인해 헌정 문구를 &apos;엘리제를 위하여&apos;로 잘못 읽었다. 원래는 &apos;테레제를 위하여&apos;였다는 설이 가장 유력하나, 엘리자베트 뢰켈 등 다른 후보도 있어 완전히 확정되지는 않았다.&lt;br&gt;
&lt;br/&gt;
-- Opus 4.6&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이 영화는 불멸의 연인 편지까지만 팩트에 기반하고 나머지는 일부 사실과 엄청난 작가의 상상력을 동원해서 연인을 추정한다. 결론만 본다면 베토벤 측에서 명예 훼손으로 고소해도 되지 않을까 싶은 정도. 왜냐하면 연인으로 지목한 대상이 다름아닌 동생의 아내이기 때문이다. 영화 줄거리만 본다면 다음과 같은 빌드업이다. 1) 베토벤과 조안나는 밀애 관계였다. 2) 조안나가 베토벤의 아이를 임신한다. 3) 둘은 특정 지역 호텔에서 비밀리에 만나기로 한다. 4) 베토벤의 마차가 진창에 빠져 약속 시간을 못 맞추게 된다. 베토벤은 편지를 남긴다. 4) 호텔 주인은 그걸 조안나에게 직접 전달하는 것이 아니라 음식 쟁반 아래 깔아서 전달한다. 5) 조안나는 음식을 보자 입덧이 올라와서 편지는 보지도 못하고 호텔을 떠난다. 오지 않은 베토벤을 보며 자신을 버렸다고 오해한다. 6) 호텔에 늦게 도착한 베토벤은 그녀가 떠난 걸 알고 미쳐 날뛴다. 7) 이후 조안나는 베토벤의 동생의 고백으로 친동생과 결혼한다. 8) 베토벤은 그런 그녀를 평생 저주하면서 살아간다. 9) 동생 사후에는 조카 양육권으로 조안나와 지리한 법정 소송도 벌인다. 10) 죽기 직전에야 양육권을 다시 조안나에게 돌려주는 문서에 서명한다.&lt;/p&gt;
&lt;p&gt;이 중 실제 사실로 추정되는 건 불멸의 연인에 대한 편지가 남아 있었다는 것. 그리고 조카인 칼 베토벤의 양육권으로 실제로 제수씨와 법정 소송을 했었다는 점 정도다. 그럼에도, 음악을 몰라도 재미있게 볼 수 있는 영화였다.&lt;/p&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/AVe0uV9AQsA?si=6xYYon3hyGm14wKX&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;</content:encoded></item><item><title><![CDATA[[일상] 함께해서 인상적인 날 (feat. KOF98 & 마인크래프트 던전스)]]></title><description><![CDATA[인생이 무료하던 시점 어릴 때 생각이 나서 월광보합 파이널…]]></description><link>https://jiniya.net/2025/10/a-memorable-day-together/</link><guid isPermaLink="false">https://jiniya.net/2025/10/a-memorable-day-together/</guid><pubDate>Sat, 04 Oct 2025 11:00:01 GMT</pubDate><content:encoded>&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;kof.png&apos; data-alt=&apos;KOF98을 플레이하는 아드님&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/9d69b6a484110f6e2f69f7b590625011/e8464/kof.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 66.84210526315789%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAADJElEQVR42gEZA+b8AL2dZsima6iKVpZ7Tq2GTbSUWrORWLOSWreVX7aXX7qbYraYZK2RYKeMXKCGWJt+UIZwR0RXQVRiSl5rUwC8nWW3mWWTeENzgGqthD7JkTStfzSSbTWccjKkbDKrgkvHqGy/oGi0l2KBbEFlUihcTCVITjFSYEdfbVMAsJRfjnxVfmU3oW4ss3wxvXQjvXwql2gylGgupG8xp4JNzKxtyahtcmI4LCgLNS0NPDEOWEMXWlw6XW9UAK+TXo17U3BbM4lUHJBgJ4liLpZkKYZVKXJKK6ZrLKmARdGwb8SmaYhsOXJUJDMuDzsyEUg2D1hcOWKDaACukV2LeFFwWzSjZyClcCpzYjebay2qYh+MVSOtaiOlfD/JqWnHp2rInVvWlUijczVSQBc4Lg1yc0tggGMArpJdjnpTemM3mnc8pXYtqHcrxowwyIsvmG0pqXotg204UUsreWo9xZlX3ZlJ6JtLiGAtWVEodoNdc3U7AKCGU2tdOGxbMXhlOnNgNWVTKFBFHl5RLYNrO7OLRpZ1OkM/H3FfMayNUqN/SJyDQa2nUHl9OXFtPKV/JQBxYDlDPx5jVCqObDWofzt6YSxkUiRnUyV+YSiKaCqKZyh0WCaWbTLJj0OCdzpnkkWLs1SEoUprUhyGXh4AmXU4fWQtmXUznHEumXEvcVopc1opYk8kUEUiX0wlfF4rtIQ/WEgiUEIdXHY3bJZGfJ5KiKtObWAlfVUfAJRzNHlkMcSUQoFoMnNOJHhSJHVPJFRHJFVHIlpIIks+G5xyNL+IP6BuMZF5NVV9OmyTRYmtUGlgKo5fHADEk0CXdTSsgTl9YSpFOxxxTiFnSiBJPx1JPxxOQxxiTh5gTB2OZiu2ejl3ajFIcjZpj0SBqFB2YiSRYxgAx5I/3KJGz5hBqXw1ZVEiPDoaXU0gfV8llGwoo3UsmnAuimcwfl8uSj8dR2QuUXo7YoU+cptLaFkecVEdAI5rMsiSPM6XQcyVQLmGNaJ0K6l6LpxxLo9sNHxiNWtXMpBlMZBiJ0I4DktPHktwNlyBPV9/PmZsP3BgKbIxM/KjYvObAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;KOF98을 플레이하는 아드님&apos; title=&apos;&apos; src=&apos;/static/9d69b6a484110f6e2f69f7b590625011/efd7b/kof.png&apos; srcset=&apos;/static/9d69b6a484110f6e2f69f7b590625011/08678/kof.png 190w,
/static/9d69b6a484110f6e2f69f7b590625011/2edd7/kof.png 380w,
/static/9d69b6a484110f6e2f69f7b590625011/efd7b/kof.png 760w,
/static/9d69b6a484110f6e2f69f7b590625011/dc896/kof.png 1140w,
/static/9d69b6a484110f6e2f69f7b590625011/78873/kof.png 1520w,
/static/9d69b6a484110f6e2f69f7b590625011/e8464/kof.png 1536w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;KOF98을 플레이하는 아드님&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;인생이 무료하던 시점 어릴 때 생각이 나서 월광보합 파이널2를 산 적이 있었다. 사서 한두번 하다가 내가 생각했던 느낌은 아니라 한구석에 방치돼 있었다. 추억이란게 보통 그렇다. 생각할 때는 그럴듯하지만 막상 다시 마주해보면 그 느낌은 아닌 것이다. 그래서 기억만으로 간직하는 게 더 좋은건지도.&lt;/p&gt;
&lt;p&gt;무튼 그러다 최근 애들 방을 새로 만들어주면서 작은 애 방에 공간이 있어서 방치된 모니터에 연결해서 레트로 게임기를 만들어줬다. 그리고 킹 오브 파이터즈 98을 아들과 함께 했다. 사실 애는 뭐가 뭔지 하나도 모른다. 그냥 막 누르는 거. 기술을 알려준다고 해다 필요 없다는 대답. 그럼에도 아들은 몹시 신나했었다. 어쨌든 그렇게 둘이 함께 즐거운 한때를 보냈다. 2025.9.27은 몹시 인상적인 하루였다.&lt;/p&gt;
&lt;p&gt;추석 연휴 즈음 컴퓨터가 고장나서 컴퓨존에 수리를 맡기면서 애들 컴퓨터를 사주면 좋겠다는 생각이 들어서 배그 정도 돌아가는 컴퓨터로 조립을 했다. 굴러다니는 잡동사니 부픔이 많은 줄 알았는데 죄다 오래된 것 밖에 없어서 결국 쓸 수 있었던 건 ssd와 파워 뿐이었다. 심지어 파워도 400w라 간당간당한데 그래픽 카드가 좋은 건 아니라 될 거 같아서 그냥 사용했다. 램도 4g 3개가 굴러다니는 게 있어서 쓰면 되겠다 싶었는데 gpt한테 물어보니 ddr3라 호환이 안된다는 말. 어쨌든 어찌저찌 10만년만에 조립을 해서 동작시켰다. 몹시 아이들이 좋아할 줄 알았는데 생각보다 반응은 시큰둥했다. 새로운 컴퓨터로는 애들과 새로운 게임을 함께 했다. 마인크래프트 던전스. 애들이 제일 좋아하는 게임이 로블록스, 마인크래프트다. 하다 보니 언젠가 얘들이 커서 자식을 가진다면 그때는 마인크래프트를 함께하면서 나같은 생각을 하겠다 싶었다.&lt;/p&gt;
&lt;p&gt;천하를 다 가진 것처럼 보이는 데이비드 베컴은 인생에서 가장 기억에 남는 순간 중 하나로, 아내가 자신이 먹는 음식을 함께 먹었던 일을 꼽았다. 아내 빅토리아 베컴은 25년째 생선과 찐야채만 먹는다고 한다. 단 한 번 임신했을 때 베컴이 먹는 걸 같이 먹어줬다고 한다. 별것 아닌 일처럼 들리지만, 어쩌면 우리는 무엇이든, 내가 좋아하는 그 무언가를 사랑하는 사람과 함께하는 그 순간 자체를 가장 좋아하는건지도 모르겠다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] 메멘토 모리를 되새기며 (feat. 교통사고)]]></title><description><![CDATA[#0 애들 여름방학 때 본가에 가다 큰 교통사고가 날 뻔했다. 고속도로 1차로로 주행 중이었는데 앞쪽에 사고가 나서, N차 사고가 나고, 또 내 앞차가 N+…]]></description><link>https://jiniya.net/2025/09/memento-mori/</link><guid isPermaLink="false">https://jiniya.net/2025/09/memento-mori/</guid><pubDate>Sun, 21 Sep 2025 13:00:01 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/ZDoH5dQ58ps?si=uMPsvZ_shYKmiXAr&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;h2&gt;#0&lt;/h2&gt;
&lt;p&gt;애들 여름방학 때 본가에 가다 큰 교통사고가 날 뻔했다. 고속도로 1차로로 주행 중이었는데 앞쪽에 사고가 나서, N차 사고가 나고, 또 내 앞차가 N+1차 사고를 낸 상황이었다. 나도 급브레이크를 밟았지만 아슬아슬하게 사고가 나거나 직전에 멈출 것 같은 느낌이었다. 하지만 백미러로 본 내 뒷차는 거의 백프로 추돌할 것 같은 생각이 들었다. 전에도 이런 종류의 사고가 두 번 난 적이 있었는데 나는 모두 멈췄지만 뒷차가 모두 내 차를 박았다. 그럼에도 여기서 나의 합리적인 조치는 최선을 다해 멈추고 뒷차가 박으면 그냥 사고를 당하는 것이었다.&lt;/p&gt;
&lt;p&gt;하지만 애들이 타고 있어서 그랬는지 미친 짓을 해버렸다. 바로 핸들을 틀어서 옆차선으로 간 것이다. 물론 내가 옆 차선을 확인하고 차가 없고, 뒤에서 오는 차와의 거리도 안전하다고 판단한 다음 틀었다면 잘한 일이겠지만 나의 좌뇌는 그것을 확인하지 않았다. 아마 애들이 타고 있어서 사고는 피해야 한다는 생각으로 나의 무의식이 그 미친 짓을 한 것으로 보인다. 하지만 우뇌는 확인했을지도 모르겠는 게 옆 차선은 다행히 비어 있었다. 다만 고속도로라 뒤에서 오는 차가 있었고, 그 속도가 맹렬했을 뿐이었다. 행운의 여신이 나를 아직 버리지 않은 것은 그 뒤에서 오던 아반떼 차량의 운전자가 빠른 속도에도 불구하고 제법 능숙하게 사고를 피해 주었다는 점이다. 그가 갓길로 주행해서 우리는 2차로 고속도로에서 잠시 3개 차선으로 주행을 했다. 이내 나는 미친 짓을 한 걸 깨닫고 1차선에 사고 난 차량들 사이로 다시 돌아와서 멈췄다. 내가 계속 주행을 했다면 아반떼도 사고를 피하기는 힘들었다. 왜냐하면 전방 갓길에는 그전에 사고 난 차량들이 또 널브러져 있었기 때문이다.&lt;/p&gt;
&lt;p&gt;수십 초의 아주 짧은 순간에 이 모든 일이 벌어졌다. 얌전히 있었으면 사고가 나더라도 그렇게 큰 사고는 아니었을 수 있다. 하지만 핸들을 트는 바람에 재수가 없었다면 정말 큰 사고가 날 뻔한 것이다. 사고난 차량들 사이에 멈추고 보니 대략 전방 갓길에 널브러린 차량을 포함해서 6-7대 가량이 사고가 나 있었다.&lt;/p&gt;
&lt;p&gt;운전을 시작한 이래로 이렇게 큰 사고가 날뻔한 경험은 처음이이었다. 그간 운이 좋았다는 생각도 들었다. 오늘은 정말이지 조상님들이 도왔다는 생각도 들었다. 그전에 좋지 않은 소식을 전화로 들었던 터라 마음이 불편했는데, 그 순간 웃기게도 이 세상 모든 것에 감사함이 느껴졌다. 특히 그 아반떼 차량 운전자에게 너무 고마웠다. 당연하겠지만 남은 길은 졸졸 운전했고, 올라오는 길도 크루즈로 얌전히 올라왔다.&lt;/p&gt;
&lt;h2&gt;#1&lt;/h2&gt;
&lt;p&gt;그 기억이 너무 강렬해서였을까? 여운이 며칠은 더 갔다. 그저 살아 있다는 게 고마웠고, 아이들이 무사해서 다행이었다. 그리곤 이내 깨달았다. 아등바등 스프레드시트 쳐다보며 전체 수익률이 몇프로니, 내부 수익률이 몇프로니, 금리가 어떠니, 고평가니, 저평가니 따져본들 죽음 앞에서는 다 부질없는 일이겠구나 싶었다. 인간의 가장 큰 모순이 천년만년 살 것처럼 굴다가 결국은 살아 보지도 못한 것처럼 죽는 일이라고 하지 않았던가?! 또 잡스의 말처럼 죽음 앞에서는 모든 게 초연해진다는 말도 새삼 공감됐다. 우리가 집착하며 살아가는 그 모든 것들이 죽고 나면 다 무슨 소용일까 싶은 것이다.&lt;/p&gt;
&lt;p&gt;그리고 또 그런 생각이 들었다. 과연 내가 죽는다면 마지막 순간에 나는 어떤 시간을 기억할까? 엄마가 꺼내주지 않던 세발자전거를 혼자 끌고 나오다가 화상을 입었던 날일까? 처음 두발자전거를 혼자 타게 된 날일까? 여름방학 내도록 매일 아빠와 해운대 바닷가에 갔던 날들일까? 처음으로 컴퓨터를 샀던 순간일까? 수능 시험 날일까? 첫 키스일까? 창업해서 제품을 만들면서 고생했던 날들일까? 애들이 태어나던 날일까? 운 좋게 투자로 큰 돈을 벌었던 순간일까? 아니면 실수로 전재산을 날렸던 때일까? 곰곰 생각해보니 모두 아닌 것 같았다.&lt;/p&gt;
&lt;p&gt;내 인생을 돌아봤을 때 마지막에 기억할 것 같은 해들은 2000, 2001, 2005, 2006년인 것 같았다. 그 해가 특별한 이유는 뭘까? 20대였기 때문일까? 맞다. 그것도 클 수 있다. 하지만 20대의 다른 해들도 있는데 유독 그 네 해만 떠오르는 이유는 따로 있다. 그 이유는 바로 내 인생 전체를 통틀어서 내 의지대로 오롯이 살았던 날들이 그 해를 제외하고는 없기 때문이다.&lt;/p&gt;
&lt;p&gt;우리는 대체로 책임감, 의무감, 또는 주변의 기대나 시선 같은 실상은 내 의지와 다른 것들에 의해서 많은 시간을 보낸다. 내 인생의 대부분의 날들 또한 그런 것들로 채워진 순간이었다. 아마 경우에 따라서는 평생을 전부 그런 시간들로 살아온 사람들도 있을 수 있다. 하지만 어쨌든 나는 돌아보니 저 4년만큼은 내 생각대로 내 맘대로 살았다고 말할 수 있었다. 40년 넘는 인생을 살아 왔지만 실상 몇 년을 살았냐고 물어본다면 그 네 해가 전부가 아닌가 싶기도 한 서글픈 생각이 들기도 했다.&lt;/p&gt;
&lt;h2&gt;#2&lt;/h2&gt;
&lt;p&gt;최근에 읽은 책 &quot;실패를 통과하는 일&quot;에는 강철의 연금술사 이야기가 나온다. 이 작품이 명작의 반열에 오를 수 있었던 이유로 작가가 처음부터 최종화에서 할 이야기를 정해 두고 첫 화를 시작했기 때문이라는 내용이 있었다. 우리의 인생도 어쩌면 그럴지 모른다. 끝을 떠올려야 비로소 지금의 삶이 선명해지는 순간이 있다.&lt;/p&gt;
&lt;p&gt;우리는 언젠가 모두 죽는다. 메멘토 모리(Memento mori) — 죽음을 기억하라는 말은, 결국 현재를 충실히 더 잘 살라는 뜻일지도 모른다.&lt;/p&gt;
&lt;p&gt;통계청에서는 생각보다 재미난 통계를 많이 발표한다. 그런 것 중 하나로 &lt;a href=&quot;https://kosis.kr/search/search.do?query=%EC%83%9D%EB%AA%85%ED%91%9C&quot;&gt;생명표&lt;/a&gt;가 있다. 생명표는 한국 사람들의 나이와 성별에 따른 대략적인 기대 여명을 알려준다. 2023년 자료가 최신인데 그 자료에 의하면 나에게 이제 남은 시간은 37년 남짓이다. 살아온 시간이 살아갈 시간보다 한참 많아진 셈이다. 또 그 생명표는 어쨌든 평균이니 나에게는 그만큼의 시간도 없을 확률이 높다. 37년이면 긴 시간 같지만 또 따져보면 이제 나에게는 37번의 여름 뿐이라는 말도 된다. 그렇게 생각하면 뭔가 아쉽기도 하고 매 순간을 소중하게 생각해야겠다는 마음이 들기도 한다.&lt;/p&gt;
&lt;p&gt;가을이 온다. 내 인생에서 마흔 번도 채 남지 않은 가을이 오고 있다. 25%의 시간은 아이들에게 저당잡혔지만, 남은 75%의 시간은 내 의지대로 오롯이 살았던 2025년 가을이 되기를 바란다. 그래서 마지막 순간에는 &quot;아, 2025년의 그 가을도 있었지&quot; 하고 미소 지을 수 있기를 희망해 본다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 낳음 당했다에 부쳐]]></title><description><![CDATA[#0 SNS를 보다가 요즘 애들 사이에서 유행한다는 낳음 당했다는 말을 알게 되었다. 나는 그 표현을 보면서 요즘 애들은 참 똑똑하다, 라고 생각했는데 SNS 상의 어른들 반응은 대체로 요즘 애들 1) 무섭다 2) 버릇없다 3) 어떻게 그런 말을…]]></description><link>https://jiniya.net/2025/09/on-having-been-born/</link><guid isPermaLink="false">https://jiniya.net/2025/09/on-having-been-born/</guid><pubDate>Wed, 17 Sep 2025 13:00:01 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/pC6tPEaAiYU?si=hh11Kwz2PsKzBc5w&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;h2&gt;#0&lt;/h2&gt;
&lt;p&gt;SNS를 보다가 요즘 애들 사이에서 유행한다는 낳음 당했다는 말을 알게 되었다. 나는 그 표현을 보면서 요즘 애들은 참 똑똑하다, 라고 생각했는데 SNS 상의 어른들 반응은 대체로 요즘 애들 1) 무섭다 2) 버릇없다 3) 어떻게 그런 말을 4) 우리 애가 그럴까 겁난다와 같이 부정적이었다. 과연 낳음 당했다는 말을 꼭 그렇게만 볼 일일까? 애들이 하는 철없는 말로 치부하기에는 생각보다 거기에는 더 많은 함의가 내포돼 있는 건 아닐까 싶었다.&lt;/p&gt;
&lt;h2&gt;#1&lt;/h2&gt;
&lt;p&gt;그 표현을 보고 처음 든 생각은 쇼펜하우어였다. 요즘은 좀 시들해졌지만 한동안 서점가를 쇼펜하우어가 점령했던 시기가 있었다. 내가 보기에 낳음 당했다도 일정 부분은 거기서 영향을 받은 게 아닌가라는 생각이 들기도 했다. 왜냐하면 쇼펜하우어의 철학적 사유의 근간이 인생을 고통으로 보고 낳음 당했다와 유사한 논지를 피력하기 때문이다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;쇼펜하우어는 이렇게 말한다.&lt;br&gt;
&lt;br/&gt;
생존한다는 것은 누구에게든 자신에게 부과된 강제노동을 치르는 것과 같다. 이러한 부채를 계약한 것은 성적인 쾌락을 얻는 것을 대가로 하여 그를 낳은 사람이다. 이처럼 한 사람이 즐긴 대가로 다른 한 사람은 삶을 살아야 하고 괴로워해야 하며 죽어야 하는 것이다.&lt;br&gt;
&lt;br/&gt;
-- 사는 게 고통일 때, 쇼펜하우어, 박찬국&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;위 내용만 보면 쇼펜하우어의 기본적인 생각이 요즘 애들이 한다는 낳음 당했다는 말과 놀랍도록 유사하다. 그리고 나는 저 기본적인 사고의 흐름이 그렇게 잘못됐다고 판단하지 않는다. 부모로써 자식에게 기본적으로 잘해줄 수 밖에 없는 이유도 일종의 저런 좋류의 부채 의식이 무의식 중에 깔려 있는 게 아닌가 싶기도 하다.&lt;/p&gt;
&lt;h2&gt;#2&lt;/h2&gt;
&lt;p&gt;쇼펜하우어만큼 직접적이지는 않지만 실존주의 철학도 낳음 당했다와 유사한 지점이 있다. 하이데거는 인간은 이 세계에 던져진 존재라고 표현했다. 이 말은 우리가 태어날 시대, 장소, 가정, 언어 같은 조건을 스스로 선택하지 않았다는 뜻이다. 우리의 의지와 무관하게 우리는 이미 이 시간, 이 공간, 이 세계 속에 들어와 있다는 점이다.&lt;/p&gt;
&lt;p&gt;게임 캐릭터를 만들어서 입장하는 세계를 상상한다면 아마 지금의 나를 그대로 캐릭터로 만들어 들어오고 싶은 사람은 많지 않을 것이다. 그런 점에서 실존주의가 말하는 이미 주어진 조건과 아이들이 말하는 낳음 당했다는 감각은 분명 접점이 있다.&lt;/p&gt;
&lt;h2&gt;#3&lt;/h2&gt;
&lt;p&gt;카뮈는 던져짐과는 조금 다르게 부조리란 개념을 말한다. 부조리는 이 세계는 내가 어떠한 의미를 찾으려 해도 응답하지 않는 것을 의미한다. 예컨대, 성실하게 일했는데도 회사 사정으로 하루아침에 구조조정을 당한다거나, 선하게 살아 보상받고 싶었지만 그 보상은 오지 않는다거나, 오래 마음을 쏟았지만 상대의 감정은 끝내 돌아오지 않는다거나, 온 힘을 들여 만든 작업은 조용히 사라지고, 가볍게 한 결과물이 우연히 주목받는다거나 하는 일들이다. 간절히 기도하고 약속해도 세계는 아무 대답을 주지 않는다.&lt;/p&gt;
&lt;p&gt;이 세계 자체는 철저하게 나의 의지와는 아무 관련이 없이 돌아가는 것이다. 그러니 인간의 입장에서 세계를 바라보면 부조리해 보일 수 밖에 없다. 왜냐하면 거기엔 어떠한 의미도 없기 때문이다.&lt;/p&gt;
&lt;p&gt;그리고 이런 부조리의 감각은 아이들이 말하는 낳음 당했다, 와도 일부 맥락을 공유한다. 둘 다 내가 선택하지 않은 조건에서 출발하고, 내가 세운 의미나 기대가 세계에서 아무 보증도 받지 못한다는 체감을 드러내는 부분이 있기 때문이다.&lt;/p&gt;
&lt;h2&gt;#4&lt;/h2&gt;
&lt;p&gt;이런 철학적 개념들을 쭉 살펴보면 애들이 말하는 낳음 당했다는 말이 그저 버릇없이, 감히 부모한테 어떻게 그런 말을처럼 가볍게 넘길 말은 아니지 싶다. 그들은 지금의 상황을 선택하지 않았고 그 상황 속으로 내던져졌고, 그들에게 현 상황은 한없이 부조리하고, 아무 의미도 없어 보일 수 있는 것이다. 심지어 이런 상황을 만든 장본인들은 다름 아닌 순간의 쾌락을 선택한 그들의 부모처럼 보이기도 한다. 그 모든 걸 한마디로 퉁치면 결국 낳음 당했다가 되는 셈이다.&lt;/p&gt;
&lt;p&gt;그렇다면 우리가 낳음 당했다고 말하는 아이들에게 해줘야 할 이야기는 무엇일까? 내던져진 상황에서, 부조리한 세계에서, 또는 고통 뿐인 삶을 어떻게 생각하고 살아나가야 하는 것인지를 알려줘야 하는 건 아닐까? 쇼펜하우어도, 하이데거도, 카뮈도 각자의 답을 했지만 사실상 정답은 없다. 어쩌면 답을 말해주기 보다는 상황 인식을 공감해 주는 게 더 큰 위로가 될지도 모른다. 왜냐하면 그걸 듣는 부모조차도 부조리한 세계 속으로 그저 던져졌고, 그 결과로 고통인 삶을 살아가는 똑같은 사람이니까 말이다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 용꼬리 vs 뱀머리, 당신의 선택은?]]></title><description><![CDATA[#…]]></description><link>https://jiniya.net/2025/09/small-fish-in-a-big-pond-vs-big-fish-in-a-small-pond/</link><guid isPermaLink="false">https://jiniya.net/2025/09/small-fish-in-a-big-pond-vs-big-fish-in-a-small-pond/</guid><pubDate>Sat, 13 Sep 2025 13:00:01 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/RR9v9MQQoBQ?si=IzVxAf5CKkc1K5ng&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;h2&gt;#0&lt;/h2&gt;
&lt;p&gt;전투에서 이기는 것보다 전쟁에서 이기는 게 중요하다고 한다. 또 나무를 보지 말고 숲을 보라는 말도 있다. 비슷하게 반백년 가까이 살아보니 인생 전체를 보면 세부적인 어떤 노력이나 선택보다는 큰 틀에서의 세계관을 잘 정하는 게 전체적으로는 더 큰 영향을 미친다는 것을 많이 경험했다.&lt;/p&gt;
&lt;p&gt;그런 큰 주제 중에 하나가 용꼬리와 뱀머리 논쟁이다. 바닥을 쓸어도 큰 물에서 놀아야 한다는 것이 용꼬리 쪽 입장이라면, 구멍 가게에서 일을 해도 대장질을 하겠다는 것이 뱀머리 입장이라고 할 수 있다. 물론 세상은 이렇게 극단적인 이분법으로 나뉘진 않는다. 대부분은 그 사이 어떤 지점에서 선택을 하게 된다. 둘의 세계관은 뭘 더 중시하겠냐는 것을 나타낸다고 할 수 있다.&lt;/p&gt;
&lt;p&gt;나는 태생적으로 뱀머리 주의자였다. 일단은 경쟁 환경에 노출되는 것을 별로 좋아하지 않고, 선택권이 나에게 없는 것을 선호하지 않았다. 죽이되는 밥이되든 내가 선택하는 것을 좋아한다. 그리고 자유의지가 실제로 존재하든 하지 않든 내가 주도한다는 느낌이 드는 환경을 좋아했다. 그리고 &lt;a href=&quot;/2025/09/gate-keeper/&quot;&gt;이전 글에서도&lt;/a&gt; 밝혔듯이 게이트 키퍼를 좋아하지 않기에 누가 나를 평가한다는 것을 그닥 유쾌하게 생각하지 않았고, 결론적으로 그건 큰 세계로 나가는데에는 장애물이나 다름없었다.&lt;/p&gt;
&lt;p&gt;그래서 주변에서 더러 그런 말들을 들었다. 더 좋은 대학을 가지, 더 좋은 과를 선택하지, 더 좋은 회사 취직하지, 왜 그러고 사냐 같은 말들 말이다. 하지만 강철의 연금술사에 나오는 등가교환 원칙처럼 이런 것들이 반대로 가져다 주는 장점도 크다. 일단 스트레스 레벨이 낮아진다. 마음이 평화롭고, 자기 효능감이 커진다. 이게 얼마나 큰지는 나이가 들면 들수록 느낄 수 있다. 왜냐하면 스트레스는 만병의 근원이기 때문이다. 또 추구하지 않아도 자존감이 보충된다.&lt;/p&gt;
&lt;p&gt;뭐 발전적이지 않은 사람이라고 비판해도 할 말은 없다. 어쨌든 개인적인 선호가 마음 편한 게 다른 것보다 더 중요하니 말이다. 안그래도 짧은 인생, 불필요한 것들로 스트레스 받으며 살 필요는 없다는 생각이다.&lt;/p&gt;
&lt;h2&gt;#1&lt;/h2&gt;
&lt;p&gt;한때 서판교에 살았던 적이 있었다. 내가 살았던 동네 중에는 가장 부자 동네라고 할 수 있는데 여기서도 비슷한 경험을 했다. 다른 건 차치하더라도 주변에서 내가 평소에는 흔히 경험할 수 없었던 장면들이 더러 눈에 띄었던 것이다. 처음 충격을 받았던 게 기사였다. 대체로 기사라는 존재는 드라마 외에는 현실 세계에서는 볼 수가 없었던 나는 그 동네 살면서 숱하게 기사를 만났다. 출근하러 주차장에 가면 항상 말끔하게 차려입고 대기하는 기사님들이 계셨다. 그 정도는 그냥 넘겼다. 같은 라인에 사장님이 사는구나 싶었다.&lt;/p&gt;
&lt;p&gt;애들 어린이집을 등원시켜 주면서도 그런 일들이 반복되니 조금 신기했다. 한날 애들 생일 선물을 잘 챙겨주는 어머니랑 등원 시간이 겹쳐서 만나게 됐는데 일단 아주 고급 차를 가지고 온 것은 워낙 흔한 일이라 그러려니 했다. 그런데 애들을 맡기고 차를 타는데 기사가 나와서 문을 열어 주는 걸 보고는 뭐지 싶었던 것이다. 심지어 그분은 전업주부였다. 그때 어렴풋이 느꼈다. 아 이동네 분위기가 좀 다르구나.&lt;/p&gt;
&lt;p&gt;그러다 결정적인 일이 집 앞 커피숍에서 있었다. 노트북으로 코딩을 하고 있었는데, 목소리가 커서 본의 아니게 옆 테이블 이야기를 듣게 된 것이다. 그 동네 사람들이 대체로 집에 일하는 이모님들이 있다는 건 알았지만 그 다음이 더 가관이었다. 중국어 튜터를 애들 별로 한명씩 고용할지 말지를 얘기하고 있었던 것이다. 그때 결심했다. 아 이동네 살아서 나한테 좋을게 그닥 없겠구나. 그리고 그 해 나는 이사를 갔다. 어쨌든 그 동네는 내가 살기에는 큰 연못이었던 셈이다.&lt;/p&gt;
&lt;h2&gt;#2&lt;/h2&gt;
&lt;p&gt;세상은 참 다양한게 나와 정반대의 입장인 사람들도 많다. 한 지인은 애를 예술 중학교에 입학시켰다. 그 집 사정을 알기에 다소 의문스럽기도 했는데, 본인이 하는 얘기를 들어봐도 내 생각과 비슷했다. 학교 입학식에 애를 데리고 갔는데 국산차를 타고 온 것은 본인 밖에 없었다는 얘기였다. 더 심각한 건 그 학교 학비였다. 맞벌이인 그 집 세후 소득의 거의 절반이 그냥 학비로 소진된다고 했다. 물론 별도의 레슨 비용이나 이런 걸 따지자면 훨씬 더 들 것이다. 이렇게까지 뒷바라지를 한다손 치더라도, 애는 아마 그 학교를 다니면 다닐수록 더 많은 격차를 느낄 가능성이 높다. 지인은 동네 피아노 학원은 할 수 있겠지라고 말했지만 내가 보기엔 그걸 하기 위한 투자치고는 너무 큰 게 아닌가 싶었다.&lt;/p&gt;
&lt;p&gt;소셜 믹스를 선호하는 사례도 있었다. 강남 고급 주택가에 새로 들어서는 단지의 임대 주택 조건에 본인이 해당한다는 말이었다. 그러면서 모모 회장님 아들과 같은 초등학교에 애를 보낼 수 있어서 좋다는 이야기를 했다. 워낙 오래전 일이고 그다지 친분이 깊은 사이는 아니라 네네 했는데, 속으로는 다른 생각을 하고 있었다. 왜냐하면 그분이 꿈꿨던 회장님 아들과 어릴 때부터 끈끈한 친구가 되는 그런 환상적인 일이 벌어지기보다는, 현실에서는 &amp;#x3C;더 글로리&gt; 같은 전개가 펼쳐질 확률이 훨씬 더 높다고 생각하니 말이다. 거기서 사라는 혜정이에게 다 커서 이런 대사를 날린다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;근로소득세 내는 넌 모르는 종합소득세 내는 세계가 있단다, 혜정아.&lt;br&gt;
&lt;br/&gt;
-- 더 글로리&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;#3&lt;/h2&gt;
&lt;p&gt;이런 건 그냥 개인적인 선호나 느낌일 뿐이지 않을까, 이런 세계관의 선택이 뭐가 크게 중요하지, 라고 생각할 수 있다. 여기에 과학적인 뭔가가 있을까 싶은 것이다. 하지만 세상은 넓고 온갖 것들을 연구하는 사람들은 많다. 둘의 세계관 사이에 차이가 있다는 결과를 보여주는 연구들이 있는 것이다. 아웃라이어로 유명한 말콤 글래드웰의 저서 다윗과 골리앗을 보면 관련 내용이 나온다. 몇 가지를 소개해 보면 이렇다.&lt;/p&gt;
&lt;p&gt;하나는 대학별로 STEM 전공 기준 졸업생 비율을 조사한 연구다. 흥미롭게도 대학의 순위를 가리지 않고 1/3 정도만 학위를 취득했다는 결과가 나왔다. 이는 상식적으로 이해되지 않는다. 왜냐하면 하버드에 간 꼴지가 이름모를 대학에 들어간 1등보다는 몇배는 똑똑할 것이기 때문이다. 하지만 하버드 꼴지는 학위 취득에 실패했고, 이름모를 대학의 1등은 학위를 취득했다. 저자는 이에 대해서 이렇게 코멘트를 추가한다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;이 &apos;하버드의 얼간이들&apos;은 매우 크고 무시무시한 연못에 사는 작은 물고기다. &apos;하트윅 올스타&apos;는 매우 푸근한 작은 연못에 사는 큰 물고기다. 이공계 학위를 받을 가능성을 결정짓는 데 중요한 것은 단지 당신이 얼마나 똑똑한가의 문제가 아니다. 중요한 것은 교실 안에 있는 다른 학생들과 비교해서 얼마나 자신이 똑똑하다고 느끼느냐 하는 것이다.&lt;br&gt;
&lt;br/&gt;
-- 다윗과 골리앗, 말콤 글래드웰&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;또 다른 연구 자료로 우수한 대학을 졸업한 학생들의 연구 업적과 낮은 순위의 학교를 졸업한 학생들의 연구 업적을 비교한 내용이 소개된다. 우수 대학의 상위 1% 학생은 당연하게도 가장 뛰어난 논문 발표수를 자랑한다. 하지만 상위 20%만 되더라도 하위 대학의 상위 1% 학생이 압도한다. MIT의 상위 1% 학생은 평균 논문을 4.73개, MIT의 상위 20% 학생은 평균 0.83개, 상위 45%는 0.12개를 발표했다. 30위 이하 대학교의 상위 1%의 평균 발표 수는 1.05다. 당연히 MIT의 상위 45%가 30위 이하 대학교의 상위 1%보다 훨씬 똑똑한 학생일 가능성이 높다. 하지만 졸업 후의 연구 업적은 하위 대학 졸업생이 오히려 더 높은 것이다. 여기에 대해서 저자는 이렇게 판단한다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;그런데 왜 대학원에 지원할 때까지는 모든 것을 잘해낸 승자였던 다수의 성공적인 학생들이 박사과정 훈련을 받고 난 뒤에는 그토록 별볼 일 없게 되는 것일까? 우리가 학생들을 잘못 길러온 것인가, 아니면 학생들이 우리의 기대를 저버린 것인가?&lt;br&gt;
&lt;br/&gt;
물론 대답은 둘 다 아니다. 아무도 누군가를 저버리지 않았다. 이 결과는 최상위권 학생들에게는 끝내주는 곳인 엘리트 학교가 다른 모든 학생들에게는 아주 힘겨운 곳이라는 사실을 확인시켜줄 따름이다.&lt;br&gt;
&lt;br/&gt;
-- 다윗과 골리앗, 말콤 글래드웰&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이후 책에서는 다소 파격적인 이야기를 이어가는데 특수 전형 이야기다. 학업 성취 능력과 상관 없이 우대해서 입학시켜주는 정책 이야기다. 이를 먼저 도입한 학교로 하버드를 예로 드는데 그 시발점이 큰 연못의 위험함을 막기 위해서였다는 이야기다. 결국 누군가는 하위 1/4를 해야하고, 그렇다면 자존감을 예체능등 전공과 상관 없는 특수 분야에서 충족한 학생들로 채우려는 목적이었다는 것이다. 결국 냉정하게 달리 말하면 그들은 그냥 다른 학생들의 자존감을 채우기 위한 목적으로 입학시켰다는 말이 된다. 진실이든 아니든 다소 충격적이긴 하다. 그러면서 저자는 사배자 전형을 언급하는데, 그게 과연 도움이 되는 것일지 아닐지에 대한 고민이 필요하다는 말을 덧붙인다.&lt;/p&gt;
&lt;h2&gt;#4&lt;/h2&gt;
&lt;p&gt;논쟁적일 순 있겠지만 지금까지의 사례와 연구 결과를 종합해 보면, 많은 경우 &apos;뱀의 머리&apos;가 되는 것이 더 나은 선택일 수 있다는 점을 시사한다. 자신의 능력과 별개로 주변 환경이 주는 압박감과 상대적 박탈감은 개인의 잠재력을 갉아먹을 수 있기 때문이다. 물론 극단적인 환경을 이겨내는 강한 정신력의 소유자도 있겠지만, 평균적인 우리에게는 환경의 영향이 생각보다 크다는 사실을 인정해야 한다. 천하의 제프 베조스조차도 양자역학을 듣고는 물리학자의 길을 접었다는 사실을 기억할 필요가 있다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;그는 물리학을 공부할 생각으로 프린스턴 대학에 진학했다. 아주 좋은 계획처럼 보였다. 양자역학 수업을 만나기 전까지는 말이다. 어느 날인가 어려운 미분 방정식을 풀던 그와 룸메이트는 도움을 구하러 다른 친구의 방을 찾아갔고, 친구는 문제를 잠시 들여다보더니 답을 알려주었다. 풀이 과정만 장장 세 페이지에 이르는 그 문제를 머릿속으로 계산해낸 친구를 보고 베조스는 어안이 벙벙해졌다. “그 순간 저는 위대한 이론 물리학자가 될 수 없다는 깨달음을 얻었습니다. 그 불길한 신호를 포착하고선 재빨리 전기공학과 컴퓨터공학으로 전공을 바꿨죠.” 쉽지 않은 자각이었다. 물리학자가 되기로 마음먹고 있었음에도 자신의 한계를 직시했던 것이다.&lt;br&gt;
&lt;br/&gt;
-- 발명과 방황, 제프 베조스&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;결국 가장 중요한 것은 &apos;메타인지&apos;다. 내가 어느 정도의 물에서 &apos;머리&apos; 역할을 하며 스스로의 효능감을 느끼고 성장할 수 있는지 객관적으로 파악하는 능력 말이다. 나에게 맞는 연못을 찾는 지혜, 그것이 &apos;용꼬리&apos;와 &apos;뱀머리&apos; 논쟁의 핵심일 것이다. 돌고 돌아 소크라테스 선생님의 일갈로 귀결된다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Know Yourself!&lt;br&gt;
너 자신을 알라!&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[[일상] 경쟁력 없다와 외람되다 사이에서]]></title><description><![CDATA[#…]]></description><link>https://jiniya.net/2025/09/between-being-uncompetitive-and-being-presumptuous/</link><guid isPermaLink="false">https://jiniya.net/2025/09/between-being-uncompetitive-and-being-presumptuous/</guid><pubDate>Thu, 11 Sep 2025 11:00:01 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/CjxugyZCfuw?si=8ys756AfV8COzC8z&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;h2&gt;#0&lt;/h2&gt;
&lt;p&gt;제법 오래 전이었던 것 같다. 어느 회사나 그렇겠지만 특정 시기마다 뭐에 홀린듯 이상한 문화를 한번씩 경험하는 경우가 있다. 특정인의 바램 때문일수도 있고, 구성원 모두의 기운이 그쪽으로 몰려서 그럴 수도 있겠다. 어쨌든 당시에 우리는 세미나에 홀려 있었다. 그것도 전사 세미나. 이제는 기억이 가물가물한데 돌아가면서 한번씩 주제 발표를 하는 그런 전사 세미나였던 것 같다. 당시에도 이게 뭔 의미일까 싶었지만 지나고 봐도 솔직히 큰 의미는 없었다. 그리고 그 세미나를 했던 대다수 인원은 지금 회사에 없다. 그렇게 꽤나 오랜 기간 당시에는 전사 세미나를 했는데 우습게도 그때 가장 인상 깊었던 장면은 세미나와 전혀 관련 없는 상황에서 발생했다.&lt;/p&gt;
&lt;p&gt;보통 발표자가 발표를 하고 Q&amp;#x26;A 하고 나면 대표님께서 한 말씀 하는 그런 느낌으로 흘러갔던거 같은데 당시 대표님께서 뜬금포로 우리 회사 경쟁력이 뭐냐고 물었던 것이었다. 하지만 안봐도 비디오처럼 답해야 하는 쪽의 반응은 쎄했다. 아무도 뭐라 말하지 못하고 불편한 침묵이 이어졌고, 보다 못한 대표님께서 특정인을 지목했다. 이럴 때 지목되는 건 보통 힘없고 나약하며 부서지기 쉬운 막내인 경우가 많다. 당시 정확히 막내는 아니었지만 얼추 그 근방에 있는 개발실 직원이 호명됐고, 그 직원은 의외로 호기롭게 대답했다. 우리 회사는 경쟁력이 없는 것 같습니다. 띠용~~ 뭐 어쨌든 마무리는 됐고, 그 직원은 이어진 뒤풀이 회식 장소에서 대표님 옆에서 농담 반, 진담 반으로 핀잔을 조금 듣긴 했다.&lt;/p&gt;
&lt;p&gt;그 여러차례의 세미나 기간 중에 내가 유독 이 장면이 인상적이었던 것은 바로 이 장면이야말로 나는 우리 회사의 경쟁력을 보여준다고 생각했기 때문이다. 고작 20명 남짓한 직원을 가진 회사에서 -- 직원이 작을수록 대표는 더 하늘같은 존재가 된다 -- 대표가 전직원 앞에서 회사 경쟁력이 뭐냐고 묻는데 거침없이 한치의 거짓 없이 아주 솔직하게 경쟁력이 없다고 답할 수 있는 회사라는 생각이 들었기 때문이다. 이건 달리 말하면 진실을 말해도 아무런 불이익도 없다는 강려크한 신뢰가 있을 때나 할 수 있는 행동이라고 봐도 무방하기 때문이다. 물론 나는 이 의견을 뒤풀이 때도 이야기 했지만 동의하는 사람은 1도 없었다.&lt;/p&gt;
&lt;p&gt;이후 그 직원은 당연히 어떠한 불이익도 받지는 않았고, 국내 굴지의 게임 회사로 성공적으로 이직했다. 또한 그만둘 때 나에게 오픈소스 개발 같은 걸 해서 돈을 벌어 보고 싶다는 이야기를 했었는데 실제로 그걸 이뤄낸 유일한 사람이기도 했다. 그런 의미에서 개인적으로 존경한다. 그때는 몰랐지만 경쟁력 없다고 답할만큼 떡잎부터 다른 친구긴 했던 것 같다.&lt;/p&gt;
&lt;h2&gt;#1&lt;/h2&gt;
&lt;p&gt;세월이 아주 많이 흘렀다. 당시와 직원도 많이 바뀌었다. 여전히 있는 고인물들도 있지만 거의 절반 넘게는 모두 새로운 사람들이 아닐까 싶다. 그러던 어제 묘하게 그때 사건이 생각나게 하는 일이 있었다. 한 직원이 내가 올린 이슈 트래커 댓글에 대댓글을 달았는데 외람되지만... 이라면서 내용을 단 것이다. 그 직원 입장에서는 내 의견에 반박하는 내용이라 조심스러웠을 수도 있고, 올릴까 말까 고민했을 수도 있고, 챗지피티에게 직장 상사가 화나지 않게 써달라고 부탁했을 수도 있다. 어쨌든 외람되지만... 으로 시작되는 글을 보면서 경쟁력 없다고 말했던 그 직원이 떠올랐다.&lt;/p&gt;
&lt;p&gt;대부분의 이슈라는게 해결되기 전까지는 원인을 알 수 없는 문제기 때문에 진행 중일 때에는 뭐가 문제인지는 오리무중인 경우가 많다. 또한 그 직원은 내가 생각하기에 우리 회사에서 보기 드물게 논리적으로 일하는 직원 중에 한명이다. 그리고 그 외람되지만... 으로 올린 내용 중에 틀린 내용도 없었고, 이후에 올린 내용을 봐도 대체로 그 직원은 상황을 전체적으로 잘 판단하고 있는 것으로 보여졌다. 그 글에 답을 달고 일단락이 됐지만, 내심 마음 한켠에 불편함이 있었다. 그래서 국어 사전에서 외람되다는 말을 찾아봤다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;외람되다 adj 하는 짓이 분수에 지나치다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;찾아보고 나니 마음이 더 불편해졌다. 맞는 말이든, 틀린 말이든 어쨌든 자기 생각을 올리는 일에 분수에 지나친 경우는 없을테니 말이다. 그 친구가 그 내용을 올리기가 그만큼 힘들었다는 걸 대변하는 게 아닐까라는 조심스런 추측만 해봤다.&lt;/p&gt;
&lt;h2&gt;#2&lt;/h2&gt;
&lt;p&gt;웃기게도 외람되지만... 으로 글을 쓴 친구를 보면서 경쟁력 없다고 답했던 친구로부터 회사 경쟁력이 그 차이만큼 없어진 건 아닐까, 라는 의문이 들었다. 왜냐하면 관리자 입장에서 가장 두려운 건 현실 세계에서 벌어지고 있는 사건, 또는 불편한 진실들이 은폐, 왜곡되는 거니까 말이다. 지금은 외람되지만... 이지만 조금 더 지나면 말해봐야 뭐하겠어가 될수도 있지 않을까라는 생각이 들기도 하는 것이다.&lt;/p&gt;
&lt;p&gt;앞으로도 모두가 자유롭게 본인들의 생각과 의견을 얘기할 수 있는 회사가 됐으면 좋겠다는 바램이 있다. 설령 그게 특정인들을 불편하게 하는 것일지라도 말이다. 회사의 경쟁력은 좋은 의사 결정이 쌓이는데서 비롯되고, 좋은 의사 결정은 진실이 왜곡되지 않고 모두 전달될 때 만들어진다고 믿기 때문이다.&lt;/p&gt;
&lt;p&gt;글을 다 쓰고 생각해보니 그 외람되지만... 을 썼던 친구도 엄청 호기로웠던 적이 있었다. 대표님께서 연말 회식 때 건배사를 하라고 시켰는데, MZ는 건배사를 하지 않습니다로 퉁친 유일한 직원이었기 때문이다. 대리 진급을 앞두고 있는 그 직원이 성공적으로 승진하기를, 그리고도 오래오래 근무하기를 희망해본다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 게이트 키퍼를 대하는 자세]]></title><description><![CDATA[#…]]></description><link>https://jiniya.net/2025/09/gate-keeper/</link><guid isPermaLink="false">https://jiniya.net/2025/09/gate-keeper/</guid><pubDate>Sat, 06 Sep 2025 11:00:01 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/UT_iMqUi17o?si=eWBFHKQ63YqYQsdz&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;h2&gt;#0&lt;/h2&gt;
&lt;p&gt;대학때 무용과 친구를 알고 지냈던 적이 있었다. 그 친구는 입시 학원 선생님께 거의 맹종하고 있었는데, 내가 한 날 물었던 기억이 난다. 그렇게 비싼 돈을 주고 레슨을 받으면 니가 갑인데 어떻게 그렇게 쩔쩔 메냐고 말이다. 그때 그 친구가 한 이야기가 다소 충격적이었다. 통상 입시 학원을 다니면 선생님이 무용 음악을 지정해 주는데 그게 중요하다는 말이었다. 즉, 그 선생님과 그 학교 심사 위원 사이에 카르텔이 있고, 그 정보 교환을 선정곡으로 한다는 맥락의 의미였다. 지금도 그런지는 모르겠지만 당시는 다소 충격적이었다. 아, 블라인드 테스트다 뭐다 온갖 장치를 만들어 본 들 뛰는 놈 위에 나는 놈 있는 세상이구나 싶었다. 그 친구가 입시를 지나서도 계속 맹종할 수 밖에 없었던 이유는 그 좁은 이너 서클에 끼기 위해서는 그 선생님과의 친분이 절대적으로 필요했던 것이다.&lt;/p&gt;
&lt;p&gt;특정 음악을 통해서 평가가 진행된다는 걸 보면 해당 분야가 본질적인 실력보다는 특정 인맥과 연관된 네트워크가 중요함을 보여준다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;예체능이 아닌 분야도 이런 사례는 있다. 한 친구는 10년째 박사학위 논문으로 씨름 중이다. 같은 논문만 세 가지 버전을 썼는데 담당 교수는 논문을 읽지도 않고 계속 다시 쓰라고 한다고 하소연 한다. 심지어 그 교수가 자기 챗지피티가 이런 부분이 잘못됐다고 고치라고 그걸 카톡으로 보내줬다고 한다. 내 챗지피티라는 표현도 웃긴데, 본인이 판단해야 할 부분을 전적으로 위임한 것도 모자라 그걸 자기 의견인양 표현하는 최소한의 예의도 없이 거침없이 말한다는 것도 다소 어이없긴 했다. 아니면 벌써 챗지피티가 그 정도의 권위를 획득했는지도 모르겠다.&lt;/p&gt;
&lt;p&gt;나는 그 친구에게 내가 박사 과정을 안해봐서 모르겠지만 혹시 교수가 원하는 다른 게 있는 거 아니냐는 말을 했다. 그러니 말도 안되는 논문의 내용이 아닌 그래프를 3차원으로 그려라 따위를 지적질 하는 거 아니냐고. 심지어 그 그래프는 3차원으로 그리는 형태의 그래프가 아니다.&lt;/p&gt;
&lt;p&gt;이 친구와 정반대의 사례도 있다. 교수에게 정부 고위 관료들과의 만남 자리들을 주선하고 아주 쉽게 박사 과정을 진행한 사례. 그 교수에게는 이 사람의 경우 졸업을 하고도 필요하다고 판단해서 잘해주는 건지도 모른다.&lt;/p&gt;
&lt;p&gt;이 두 사례를 보더라도 학문 분야도 담당 교수의 역할이 얼마나 큰 지 알 수 있다. 또한 그 지도 교수의 역할이란게 대체로 그 교수의 기분과 판단에 의존한다는 점이 결정적이다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;내가 직접 경험한 사례도 있었다. 애가 어릴 때 하도 성화라 강남에 연예인 육성 학원에 오디션을 보러 간 적이 있었다. 나름 그 바닥에서 입지가 있는 학원이었다. 입구부터 누구를 어디 출연했는지 끝도 없이 이어져 있었다. 심지어 우리는 양반이었다. 어디 들어보지도 못한 지방에서도 새벽 차를 타고 올라온 사람들이 부지기수 였기 때문이다. 그런 곳을 처음 가봐서 나름 충격적이었다. 아, 이렇게 아이가 연예인이 되기를 바라는 사람들이 많구나 싶었다. 그리고 약간의 테스트 아닌 테스트를 하고 설명이 이어졌다.&lt;/p&gt;
&lt;p&gt;내가 보기에는 딱봐도 그냥 약장수 같아 보였다. 연예인이 그런 식으로 만들어진다고 생각을 하지 않았기 때문이었다. 그들이 그나마 방송에 출연 시키는 원리는 인맥이나 카르텔 그 이상도 이하도 아닌 걸로 보였다. 일단 대사도 없는 아역의 경우 누가 나오든 별반 차이도 없을 것이고, 그렇다면 담당 권한을 가진 사람과 아무래도 친분이 있는 사람이 추천하는 사람을 쓸 가능성이 높을테니 말이다. 실제로도 광고한다고 걸려 있는 면면을 봐도 대다수가 그런 사례 밖에는 없어 보였다.&lt;/p&gt;
&lt;p&gt;요즘 세상이 어떤 세상인데 끼만 있으면 찍어서 유튜브 올리면 연예인 하기 싫어도 연예인 되는 세상이라고 말렸던 기억이 난다.&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;입시 학원 선생님, 지도 교수, 방송국 연줄이 있는 학원 원장들을 살펴 보았다. 물론 그것도 그들의 능력이겠지만 이렇게 딱히 본질적인 이유가 아닌 걸로 길목을 지키고, 그 길목을 지나가는 데 통행료를 받는 역할을 하는 사람들을 통상 게이트 키퍼라고 부른다. 나는 어렸을 때 부터 반골 기질이 있어서 그런지 이런 역할을 다소 싫어했다. 그래서 전 인생을 통틀어 게이트 키퍼를 피하려고 했다. 내가 마주한 게이트 키퍼는 병역특례 회사 입사가 필요할 때의 면접관을 제외하곤 없었다. 그마저도 그들을 마주치지 않고 해결하는 방법이 있었다면 그렇게 했을 것이다.&lt;/p&gt;
&lt;p&gt;세상은 점점 편평해지고 있다. 위에도 언급한 것처럼 요즘은 실력만 있으면 누구나 인플루언서가 될 수 있다. 실상 인플루언서와 연예인의 간극도 좁아지고 있다. 방송국 입성보다 유튜브 구독자 떡상을 더 높게 치는 세상이니 말이다. 물론 아직 일부 라이선스 직종에 게이트 키퍼를 아예 피할 수가 없는 세상도 있다. 그럼에도 예전에 권한을 가졌던 많은 부분이 기술의 발달에 따라 권한이 사라졌다.&lt;/p&gt;
&lt;p&gt;방송국에 출연하지 않아도 유튜브에 찍어 올리면 전세계 수억 명의 사람에게 동시 송출이 된다. 가장 높은 권한 중의 하나였던 화폐 발권 권한도 민간이 가져가려는 움직임도 나타나고 있다. 누구나 멋진 아이디어가 있으면 관련 내용을 인터넷에 업로드할 수 있다. 물론 이런 새로운 세상도 게이트 키퍼가 아예 없는 건 아니다. 알고리즘이 그 역할을 한다고도 볼 수 있다. 하지만 알고리즘은 인간에 비해 변덕이 덜하고, 기분에 따라 움직이지 않으며, 결정적으로 대체로 모두에게 공평하게 동작한다고 할 수 있다. 심지어 요즘은 이런 공정성이 훼손되는 경우에는 심사 대상이 되기도 한다.&lt;/p&gt;
&lt;h3&gt;#4&lt;/h3&gt;
&lt;p&gt;결론은 이렇다. 유기체 게이트 키퍼를 피할 수 있으면 피하는 게 좋다. 왜냐하면 그런 게 엮인 상황은 결과가 나의 기본 능력 보다는 다른 것에 좌우되거나 상대의 기분, 변덕에 따라 좌지우지될 확률이 높기 때문이다.&lt;/p&gt;
&lt;p&gt;입사 면접의 경우는 불특정 다수의 게이트 키퍼에게 노출되는 것이기 때문에 분산 투자와 비슷하다고 할 수 있어서 그 경향이 덜하다. 하지만 지도 교수는 거의 올인급에 해당한다. 왜냐하면 해당 담당 교수와 맞지 않는다고 변경하는 것이 쉽지 않기 때문이다. 후배 중에는 담당 교수의 불법을 고발했다 결국 졸업을 하지 못하고 수료한 친구도 있었다. 잘못은 교수가 했는데 피해는 그 친구가 본 것이다. 그러니 이런 식의 올인급 게이트 키퍼는 대체로 마주하지 않는 편이 좋다.&lt;/p&gt;
&lt;p&gt;아예 이런 원칙이 불가능한 분야도 있다. 그런 분야라면 냉정하게 생각해야 한다. 내가 인간 게이트 키퍼의 변덕과 기분을 뛰어 넘을 정도로 탁월한지 말이다. 그렇지 않다면 차라리 분야를 바꾸는 게 낫다. 내가 탁월한지 아닌지 어떻게 알 수 있냐고? 그런 질문을 가졌다면 안타깝게도 탁월하지 않을 확률이 높다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;어느 날 한 젊은이가 모차르트에게 와서 이렇게 물었습니다:&lt;br&gt;
&quot;교향곡은 어떻게 쓰는 건가요?&quot;&lt;br&gt;
이에 모차르트는 차분하게 대답했습니다.&lt;br&gt;
&quot;자넨 아직 교향곡을 쓰기엔 너무 어리다네.&quot;&lt;br&gt;
젊은이는 당황하며 말했죠: “하지만 당신은 10살 때부터 교향곡을 쓰셨잖습니까!”&lt;br&gt;
그러자 모차르트가 웃으며 답했습니다:&lt;br&gt;
&quot;그랬지. 하지만 난 남에게 방법을 물어보진 않았다네.&quot;&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[[소고] 불교에서 윤회와 업은 방편이었을까?]]></title><description><![CDATA[#…]]></description><link>https://jiniya.net/2025/09/rebirth-and-karma-in-buddhism/</link><guid isPermaLink="false">https://jiniya.net/2025/09/rebirth-and-karma-in-buddhism/</guid><pubDate>Tue, 02 Sep 2025 13:00:01 GMT</pubDate><content:encoded>&lt;h2&gt;#0&lt;/h2&gt;
&lt;p&gt;나는 중학교는 미션 스쿨, 집안은 제사를 지내는 유교, 어머니는 기복 신앙으로 절에 다니신다. 그럼에도 성인이 된 나는 종교가 없다. 무교다. 대체로 많은 종교가 신을 상정하고 믿을 것을 강조한다. 믿음천국, 불신지옥 설파가 기본이다. 그런 대다수 종교와 불교가 조금 다른 점은 상당한 철학적 사유가 배경에 있다는 점 아닐까 싶다. 심지어 석가모니가 초기 불교를 설립하던 시절은 지금처럼 기복 신앙으로써의 불교를 만든 게 아니었다. 누구나 깨달음을 얻으면 열반에 이르러 부처가 될 수 있다고 가르친 것이다. 몇천 년 전 사람이 그런 사유를 했다는 것이 실로 놀랍기 그지없다. 내가 평생을 걸쳐 접한 모든 생각 가운데 가장 뛰어난 생각이 불교 철학아닌가 싶기도 하다.&lt;/p&gt;
&lt;p&gt;어쨌든 그런 불교 철학에서 유일하게 좀 거슬리는 부분이 있다면 그건 다름 아닌 윤회와 업이다. 윤회는 끊임없이 다시 태어난다는 개념이고, 업은 극단적으로 단순화하면 권선징악을 의미한다. 착한일 하면 상받고, 나쁜짓하면 벌받는다는 말이다. 살아보면 알겠지만 권선징악으로 세상은 돌아가지 않는다. 석가모니 시대에도 사람들은 그런 질문을 끊임없이 했을 것이다. 그런 질문에 답하기 위해 여기서 윤회로 확장한다. 즉, 나쁜일을 해도 이번 생은 무사할 수 있어도 다음 생에는 반드시 댓가를 치른다는 생각이다.&lt;/p&gt;
&lt;p&gt;그렇다면 윤회와 업이 불편한 이유가 뭘까? 불교의 다른 부분은 상당한 연역적 사유에 가반하는데 이건 묻지도 따지지도 않고 튀어나오기 때문이다. 그나마 권선징악은 연기의 개념을 차용해 확률적으로 생각한다손 치더라도 윤회쯤 가면 기복신앙과 다를게 뭔가 싶어지는 지점이다. 실제로도 불교 철학에서 윤회와 업의 개념은 불교 독창적인 개념이라기 보다는 당시 선행 종교에 이미 있었던 개념이기도 했다. 그래서 현대의 사람들은 대체로 두가지로 해석한다. 1) 석가모니도 어쩔 수 없는 사람이었다. 시대적 배경을 무시할 순 없다. 2) 윤회와 업은 방편으로 설파한 것이다. 여기서 방편이란 사람들이 열반의 길로 보다 쉽게 가게 하기 위해서 본질은 아니지만 차용해서 말하는 것을 의미한다. 즉, 석가모니 입장에서는 내가 이 생각에 동의하는 건 아니지만 너희가 이 생각을 따르면 그나마 쉽게 열반에 들 수 있다는 의미로 이런 개념을 사용했다는 것이다.&lt;/p&gt;
&lt;p&gt;여기까지가 대체로 내가 지금까지 이해하던 불교의 세계관이다. 그러다 오늘 한 책을 읽다가 새로운 사실을 알게 되었다. 어쩌면 제 3의 가능성이 있을지도 모른다는 생각이다. 시대적 배경도 아니고 방편도 아니고, 윤회와 업을 차용하지 않으면 굉장히 곤란해지기 때문에 어쩔 수 없이 차용한 것이라는 설명이다. 일종의 외통수라 빠져나갈 길이 윤회와 업밖에 없었다는 설명인 것이다. 이를 이해하기 위해서는 불교 철학의 토대를 살펴볼 필요가 있다.&lt;/p&gt;
&lt;p&gt;불교 세계관의 시작은 무상에서 시작한다. 이 세상에 변하지 않는 것은 없다는 사실이다. 살펴보면 모든 게 변한다. 꽃이 피면 지고, 사람이 태어나면 죽는다. 달도 차면 기울고, 빅뱅에서 시작한 우주는 팽창하다 어찌될지 모른다. 변하지 않는 건 없다. 석가모니는 여기서 고를 끌어낸다. 모든 게 변하기 때문에 고통이라는 것이다. 왜 변하는 게 고통이냐면 내가 꽃을 좋아했는데 그게 계속 그 상태로 변하지 않고 있는 게 아니라 시들어 없어지기 때문이다. 즉 내가 좋아하든 싫어하든 뭐가 됐든 내가 원하는 상태로 잡아둘 수 없고 계속 변하기 때문에 세상은 불만족, 고통으로 가득 차 있다는 것이다. 그래서 이런 불만족, 고통을 없애기 위해서는 무아를 깨쳐야 한다고 말한다. 무아란 나의 실체적 자아가 없다는 말이다. 내 생각, 내 느낌, 내 몸, 어떤 것이든 나라고 생각하는 모든 게 사실은 환상이고 내 것이 아니라는 말이다. 내 것이 아니기 때문에 당연히 내 마음대로 할 수도 없고, 내 마음대로 할 수 없으니 거기 집착할 필요가 없다. 그렇게 집착을 끊으면 변하는 것을 그저 변하는 상태로 관조하게 되고, 판단을 개입시키지 않기 때문에 고통이 사라진다고 설명한다. 무아를 좀 더 심도있게 연역하기 위해서 연기와 공이 끌려 들어온다.&lt;/p&gt;
&lt;p&gt;이게 기본적인 큰 토대다, 무상, 고, 무아로 이어지는 사유 체계. 지금까지 여기 굳이 업과 윤회가 필요한가 싶었다. 그저 종교적인 색채를 보강하는 결함처럼 보이기도 했다. 그런데 오늘 알게 된 놀라운 사실은 무상, 고, 무아로 이어지는 사유를 할 수도 있지만, 무상, 고, 반출생주의로 갈수도 있다는 점이다. 즉 세상은 무상하고, 내 뜻대로 안되는 고통으로 가득차니 출생 자체가 문제였고, 그걸 죽음으로 롤백 시키겠다는 쪽으로 생각이 발전할 수도 있다는 의미다. 사실상 이렇게 빠지는 생각을 불교 세계관으로는 막을 방법이 없다. 실컷 무상, 고를 설파했는데 무아로 가는 게 아니라 자살로 이어질 수 있는 것이다. 그래서 여기서 이걸 막기 위해서는 윤회가 동원될 수 밖에 없다. 윤회는 죽어도 끝이 아니라는 의미기 때문이다. 죽으면 끝이 아니라 재시작이 되는 것이다. 이렇게 세계를 설정하면 자살로 이어지는 생각을 막을 수 있고, 어떻게든 무아를 깨쳐서 열반에 이르러 윤회의 수레바퀴를 탈출해야 한다는 불교의 대서사를 완성할 수 있는 것이다.&lt;/p&gt;
&lt;h2&gt;#1&lt;/h2&gt;
&lt;p&gt;이상 아침에 책 조금 읽고 심취해서 썰을 풀은 한 인간의 환각이었고, GPT-5에 따르면 윤회를 동원하지 않고도 불교 자체적으로 반출생주의로 빠지지 않는 논리 기반은 있다고 한다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;상견(常見): 죽어도 영혼/자아가 계속 존재한다.&lt;br&gt;
단견(斷見): 죽으면 모든 게 완전히 사라진다.&lt;br&gt;
&lt;br/&gt;
두 주장 모두 &quot;자아(ātman)&quot;라는 항을 가정한다.&lt;br&gt;
그러나 무아 논증(오온 무상·무아, 연기 법칙)에 따르면 항 자체가 성립하지 않는다.&lt;br&gt;
따라서 두 극단적 결론은 전제 자체가 붕괴한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;대승불교, 특히 용수(龍樹, Nāgārjuna)의 『중론』에서는 더 체계적으로 전개된다.&lt;br&gt;
모든 주장은 자성(自性, 본질적 실체)을 전제한다.&lt;br&gt;
&lt;br/&gt;
하지만 연기(조건적 발생)라는 구조에 따르면, 자성은 모순이므로 존재할 수 없다.&lt;br&gt;
따라서 &quot;태어나서 고통받고, 죽으면 끝&quot;이라는 서술도 결국 자성 개념에 기대므로 부정된다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;결국 두 논리 모두 죽으면 끝이라는 말 자체도 자아가 존재할 때 성립될 수 있는데, 자아라는건 애초에 존재하지 않는다고 논증했기 때문에 말 자체가 성립되지 않는다고 보는 논리인 것 같다. 이렇게 쉽게 정리되는 걸 보면 애초에 윤회와 업은 방편이 맞았나 싶기도?!&lt;/p&gt;
&lt;h2&gt;#2&lt;/h2&gt;
&lt;p&gt;불교의 놀라운 점은 그 똑똑하다는 양자 물리학자들이 절로 찾아오도록 만들었다는 점이다. 대체로 양자 물리학에 심취하면 이 세계에 대한 붕괴 내지는 모순 같은 것들을 경험하게 되는데 그때 철학적 피안처를 제공하는 게 웃기게도 불교인 경우가 많은 것 같다. 그래서 요즘은 양자 불교론이라는 세로운 장르가 나타나기도 한다. 실제로 양자 중력 이론으로 유명한 카를로 로벨리의 &quot;나 없이는 존재하지 않는 세상&quot;을 보면 끝머리에 동료 추천으로 용수를 접했다는 내용이 있다. 용수는 대승불교 철학자로 연기와 공 사상을 체계적으로 논증한 사람이다.&lt;/p&gt;
&lt;p&gt;몇천 년 전 한 인간의 사유 체계가 이토록 발전한 사회에서도 여전히 유효하다는 점은 정말 경이로움 그 자체 아닌가 싶다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 인공지능이 생산성 향상으로 이어지지 않는 이유 1]]></title><description><![CDATA[내가 처음 인공지능과 조우한 순간은 깃헙 코파일럿이 출시되던 시점이었다. 그때 바로 알게됐다. 이거 물건이다. 이건 우릴 드라마틱한 생산성 향상의 천국으로 안내할 호박마차다 싶었다. 그리고 제법 몇년이 지났고 202…]]></description><link>https://jiniya.net/2025/07/reasons-ai-may-not-increase-productivity-1/</link><guid isPermaLink="false">https://jiniya.net/2025/07/reasons-ai-may-not-increase-productivity-1/</guid><pubDate>Thu, 03 Jul 2025 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;내가 처음 인공지능과 조우한 순간은 &lt;a href=&quot;/dev/ai-driven-development/&quot;&gt;깃헙 코파일럿이 출시되던&lt;/a&gt; 시점이었다. 그때 바로 알게됐다. 이거 물건이다. 이건 우릴 드라마틱한 생산성 향상의 천국으로 안내할 호박마차다 싶었다. 그리고 제법 몇년이 지났고 2022년 당시의 인공지능은 오징어로 만들어버리는 기똥한 모델들이 줄지어 출시됐다. 가격은 기하급수적으로 싸졌다. 오죽하면 요즘은 세상에서 제일 싼 게 지능이라는 소리가 나올 정도니 말 다했다. 그럼에도 신기한 사실은 그런 세상이 왔지만 생각외로 생산성 향상은 잘 관찰되지 않는다는 점이다.&lt;/p&gt;
&lt;p&gt;과거 왜 생산성 향상이 없을까란 생각에 빠져 주변을 관찰해보면 결과는 사람들이 인공지능을 사용하지 않기 때문이라는 단순한 사실로 귀결됐다. 그래서 처음에는 비싸니까, 돈이 드니까 안쓰나 보다 싶었다. 그리고 이후 쓸만한 무료 인공지능이 많이 출시됐고, 그런 것들의 존재를 알려주었지만 결과는 비슷했다. 아니 미묘하게 달라졌다고 해야 정확할 것 같다. 인공지능을 쓸 때는 쓴다. 다만 생산성 향상을 일으킬 수 있는 많은 문제들에 적극적으로 사용하지 않을 뿐이다. 정리하자면 1) 인공지능의 존재를 알고, 2) 문제를 마주했지만, 3) 생산성 향상이 발생하지 않는 이유 중 대다수는 4) 그 문제를 인공지능에게 물어보지 않기 때문이라는 사실. 뭐 결국 인공지능을 사용하지 않는다는 점은 똑같다. 주요한 차이는 인공지능의 존재를 몰라서 또는 싫어서 사용하지 않는 게 아니라 문제를 문제라고 인식조차 하지 못한다는 데 있다는 것이다.&lt;/p&gt;
&lt;p&gt;일본어를 할 줄 모르는 내가 일본어 문서를 읽어야 한다는 상황을 생각해보자. 이 상황은 명확해서 인공지능의 존재를 아는 사람은 응당 인공지능에게 번역을 시킬 것이다. 사실 이런 건 누구나 불편하고 누구나 된다는 걸 알기 때문에 어느 정도 활용이 되고 있는 측면이 많다. 이 상황은 현재 많이 개선되서 이런 종류의 생산성 향상은 많이 관찰된다.&lt;/p&gt;
&lt;p&gt;진정한 문제는 문제라고 인식조차 못하는 상황에서 발견된다. 예를들면 이런 상황이다. 1.1, 1.2, 1.3, 1.4, ..., 1.10, 2.1 버전까지 버전이 있다. 그런데 2.1 버전에서 문제가 발생한 걸 알게 되었다. 그 문제가 1.2 버전에서는 없었다는 사실도 과거 기록으로 확인됐다. 1.3 ~ 2.1 사이의 어디에서 문제가 발생했는지 테스트를 해야 하는 상황인 것이다. 이 상황을 마주한 담당자가 취할 수 있는 많은 선택지가 있겠지만 거칠게 두 부류로 나눈다면 A) 1.3버전부터 순차적으로 테스트 하는 사람이 있고, B) 1.7을 먼저 테스트하는 바이너리 서치 식으로 테스트를 하는 사람이 있다. 문제는 바로 옆에 나보다 똑똑하다고 평가 받는 인공지능이 있지만 이걸 인공지능한테 물어봐야지 라는 생각을 A도, B도 둘 다 하지 않는다는 점이다. 이건 내가 해야할 일이지, 내가 풀어야 할 문제라고 인식하지 않기 때문이다.&lt;/p&gt;
&lt;p&gt;O(N) 세상에 살고 있는 A가 O(logN) 세상에 사는 B로 업그레이드가 돼야 생산성 향상이 발생한다. 그리고 이건 현재 시중에 나와 있는 조금 괜찮은 인공지능이라면 모두가 적절한 답을 정해줄 것이라 기대된다. 하지만 사람은 묻지 않는다. 아니 이걸 물어봐야 한다고 생각조차 하지 않는다. 그러니 A가 B로 업그레이드 되기는 요원한 것이고, 그러니 현실 세계에서는 생산성 향상이 생각만큼 많이 관찰되지 않는 것이다.&lt;/p&gt;
&lt;p&gt;생산성 향상을 위해서 인공지능을 사용합시다, 라는 말에는 상당한 사람이 반감을 가진다. 하지만 같은 연봉으로 근무 시간을 주 40시간에서 30시간으로 단축시킵시다. 하면 쌍수들고 환영하지 반대할 사람은 없을 것이다. 둘은 같은 말인데도 반응이 천지차이라는게 웃픈 현실 아닌가 싶다.&lt;/p&gt;
&lt;h2&gt;grok의 복음...&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;1.1, 1.2, 1.3, 1.4, ..., 1.10, 2.1 버전까지 버전이 있다. 그런데 2.1 버전에서 문제가 발생한 걸 알게 되었다. 그 문제가 1.2 버전에서는 없었다는 사실도 과거 기록으로 확인됐다.&lt;/p&gt;
&lt;p&gt;이때 어떻게 테스트하는 게 좋은 방법이야.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;라는 질문에 대한 이하 grok의 복음...&lt;/p&gt;
&lt;p&gt;주어진 상황에서 소프트웨어 버전 1.1부터 2.1까지 존재하고, 버전 2.1에서 문제가 발생했으며, 버전 1.2에서는 해당 문제가 없었다는 사실을 알게 되었습니다. 문제를 효율적으로 파악하고 해결하기 위해 다음과 같은 테스트 방법을 추천합니다. 이 방법은 이진 탐색(binary search) 기반의 체계적인 접근법을 사용하여 문제의 원인이 처음 나타난 버전을 빠르게 식별하는 것을 목표로 합니다.&lt;/p&gt;
&lt;h3&gt;테스트 전략: 이진 탐색을 활용한 버전 테스트&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;목표&lt;/strong&gt;: 문제가 처음 발생한 버전을 정확히 찾아내기 위해 테스트를 최소화하면서 버전 간 비교를 수행합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;단계별 접근법&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;초기 범위 설정&lt;/strong&gt;: 문제가 없는 것으로 확인된 버전 1.2와 문제가 있는 버전 2.1 사이에서 테스트를 진행합니다. 테스트 대상 버전은 1.3, 1.4, ..., 1.10, 2.1입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;이진 탐색 적용&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;전체 버전 리스트(1.3 ~ 2.1, 총 9개 버전)에서 중간 지점에 가까운 버전을 선택합니다. 예를 들어, 1.7(대략 중간)을 테스트합니다.&lt;/li&gt;
&lt;li&gt;버전 1.7에서 문제를 테스트:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;문제가 있으면&lt;/strong&gt;: 문제가 1.3 ~ 1.7 사이에 처음 발생했을 가능성이 있으므로, 이 범위로 범위를 좁힙니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;문제가 없으면&lt;/strong&gt;: 문제가 1.8 ~ 2.1 사이에 발생했을 가능성이 있으므로, 이 범위로 범위를 좁힙니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;좁혀진 범위에서 다시 중간 지점의 버전을 선택하여 테스트를 반복합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;종료 조건&lt;/strong&gt;: 문제가 있는 버전과 없는 버전이 인접한 두 버전(예: 1.x와 1.x+1)으로 좁혀질 때까지 반복합니다. 이로써 문제가 처음 도입된 버전을 정확히 식별할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;세부 절차&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;테스트 환경 준비&lt;/strong&gt;: 각 버전을 테스트할 수 있는 일관된 환경(동일한 하드웨어, OS, 데이터 등)을 구축하여 변수 통제를 합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;문제 재현&lt;/strong&gt;: 버전 2.1에서 확인된 문제를 정확히 재현할 수 있는 테스트 케이스를 준비합니다. 문제의 재현 조건(입력값, 사용자 행동 등)을 명확히 정의합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;버전별 테스트&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;선택한 버전(예: 1.7)을 설치하고 테스트 케이스를 실행하여 문제가 발생하는지 확인합니다.&lt;/li&gt;
&lt;li&gt;결과를 기록하고, 문제 발생 여부에 따라 범위를 반으로 나눠 다음 테스트 버전을 선택합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;결과 분석&lt;/strong&gt;: 문제가 처음 발생한 버전을 찾은 후, 해당 버전과 직전 버전(문제가 없는 마지막 버전)의 변경 로그, 코드 차이점(diff)을 분석하여 문제의 원인을 추적합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;예시 시나리오&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;버전 리스트: [1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 1.10, 2.1]&lt;/li&gt;
&lt;li&gt;1단계: 중간 버전 1.7 테스트
&lt;ul&gt;
&lt;li&gt;문제가 있음 → 다음 범위: 1.3 ~ 1.7&lt;/li&gt;
&lt;li&gt;문제가 없음 → 다음 범위: 1.8 ~ 2.1&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;2단계: 새 범위에서 중간 버전(예: 1.5 또는 1.9) 테스트
&lt;ul&gt;
&lt;li&gt;이 과정을 반복하여 범위를 좁힙니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;최종적으로 문제가 1.9에서 없고 1.10에서 처음 발생했다고 가정하면, 1.10의 변경 사항을 분석합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;효율성&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이진 탐색 방식은 최대 약 log₂(9) ≈ 4번의 테스트로 문제의 원인이 된 버전을 찾을 수 있습니다(최악의 경우).&lt;/li&gt;
&lt;li&gt;무작위로 모든 버전을 테스트하는 대신 체계적으로 범위를 줄여 시간과 자원을 절약합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;추가 고려사항&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;변경 로그 확인&lt;/strong&gt;: 가능하다면 각 버전의 변경 로그를 미리 검토하여 코드 변경, 새 기능 추가, 버그 수정 등을 파악하면 문제 원인을 좁히는 데 도움이 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;자동화 테스트&lt;/strong&gt;: 문제가 명확히 재현 가능한 경우, 자동화된 테스트 스크립트를 작성하여 각 버전에서 빠르게 테스트할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;병렬 테스트&lt;/strong&gt;: 리소스가 충분하다면, 여러 버전을 병렬로 테스트하여 시간을 단축할 수 있습니다(예: 1.5와 1.9를 동시에 테스트).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;환경 일관성&lt;/strong&gt;: 버전 간 차이로 인한 오탐지를 피하기 위해 테스트 환경을 항상 동일하게 유지합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;다음 단계&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;문제가 처음 발생한 버전을 찾은 후, 해당 버전에서 추가된 기능, 수정된 코드, 또는 종속성 변경(라이브러리 업데이트 등)을 분석합니다.&lt;/li&gt;
&lt;li&gt;코드 디버깅, 로그 분석, 또는 단위 테스트를 통해 문제의 근본 원인을 파악합니다.&lt;/li&gt;
&lt;li&gt;필요하면 개발 팀과 협력하여 수정 패치를 개발하고, 문제가 해결되었는지 확인하기 위해 후속 버전(예: 2.2)에서 테스트합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;주의점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;문제 재현성&lt;/strong&gt;: 테스트 케이스가 2.1에서 문제를 확실히 재현할 수 있는지 확인하세요. 재현이 불확실하면 결과가 왜곡될 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;버전 간 종속성&lt;/strong&gt;: 일부 버전은 특정 라이브러리나 환경 설정이 달라질 수 있으므로, 설치 시 오류가 발생하지 않도록 주의하세요.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;문서화&lt;/strong&gt;: 각 테스트 결과를 상세히 기록(버전, 문제 발생 여부, 테스트 조건 등)하여 추후 분석에 활용하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;이진 탐색 기반의 테스트 전략은 최소한의 테스트로 문제를 처음 도입한 버전을 효율적으로 찾을 수 있는 방법입니다. 버전 1.7을 시작으로 테스트를 진행하고, 결과를 바탕으로 범위를 좁혀가며 문제를 식별하세요. 문제가 발생한 버전을 찾은 후에는 변경 로그와 코드를 분석하여 원인을 파악하고 해결 방안을 마련하면 됩니다. 추가 질문이 있다면 말씀해주세요!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[코딩] 초보 코더 탈출을 위한 꿀팁, 최소 가시성]]></title><description><![CDATA[코드를 머지하려고 보면 참 기분 좋은 경우가 있는가 하면, "이게 뭐지?!" 하는 생각이 절로 드는 경우도 있다. 내가 코드를 보면서 초보와 초보가 아님을 가르는 가장 큰 기준 중 하나가 바로 '가시성(Visibility)', 즉 '스코프(Scope…]]></description><link>https://jiniya.net/2025/07/minimum-visibility/</link><guid isPermaLink="false">https://jiniya.net/2025/07/minimum-visibility/</guid><pubDate>Wed, 02 Jul 2025 13:00:01 GMT</pubDate><content:encoded>&lt;p&gt;코드를 머지하려고 보면 참 기분 좋은 경우가 있는가 하면, &quot;이게 뭐지?!&quot; 하는 생각이 절로 드는 경우도 있다. 내가 코드를 보면서 초보와 초보가 아님을 가르는 가장 큰 기준 중 하나가 바로 &apos;가시성(Visibility)&apos;, 즉 &apos;스코프(Scope)&apos;다.&lt;/p&gt;
&lt;p&gt;스코프란 프로그램 전체에서 해당 변수나 함수가 어디까지 노출될지를 결정하는 거라고 보면 된다. 이런 설정이 잘 된 코드는 일단 기본기가 탄탄하다는 느낌을 주지만, 이게 엉망인 코드는 보는 내내 불안감과 의문을 던져준다.&lt;/p&gt;
&lt;h2&gt;#0&lt;/h2&gt;
&lt;p&gt;요즘 많이 쓰는 파이썬 코드로 시작해보자.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;global_variable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;           &lt;span class=&quot;token comment&quot;&gt;# 1. 전역 변수&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OneBigBeautifulClass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  class_variable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;          &lt;span class=&quot;token comment&quot;&gt;# 2. 클래스 변수&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;member_variable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# 3. 인스턴스 변수&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;plus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    local_variable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b    &lt;span class=&quot;token comment&quot;&gt;# 4. 지역 변수&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; local_variable&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;여기엔 크게 4가지 변수가 있다. &lt;code class=&quot;language-text&quot;&gt;global_variable&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;class_variable&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;member_variable&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;local_variable&lt;/code&gt;이 그것이다. 순서대로 스코프 범위가 넓다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;전역 변수&lt;/strong&gt;: 이 코드 전체, 어디서든 참조할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;클래스 변수&lt;/strong&gt;: 인스턴스와 관계없이 해당 클래스 전체에서 참조된다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;인스턴스 변수&lt;/strong&gt;: 생성된 인스턴스로 범위가 제한된다. (&lt;code class=&quot;language-text&quot;&gt;self.&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;지역 변수&lt;/strong&gt;: &lt;code class=&quot;language-text&quot;&gt;plus&lt;/code&gt; 함수 내에서만 목숨이 붙어있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;#1&lt;/h2&gt;
&lt;p&gt;이 코드를 보면 간단한 원리를 발견할 수 있다. 대체로 넓은 범위의 변수는 좁은 범위의 변수 기능을 대체할 수 있다는 점이다. 즉, 전역 변수로 지역 변수가 할 일을 시켜도 코드는 일단 돌아간다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# [예시 1] 일단은 문제 없이 동작한다&lt;/span&gt;
global_variable2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OneBigBeautifulClass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;plus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;global&lt;/span&gt; global_variable2
    global_variable2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; global_variable2&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;하지만 그 반대는 안 된다. 지역 변수가 전역 변수를 대체할 수는 없다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# [예시 2] 당연히 동작하지 않는다&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OneBigBeautifulClass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;plus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    local_variable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; local_variable

&lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;local_variable&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# 에러 발생&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;넓은 범위로 확장이 가능하기에, 초보 코더가 작성한 코드를 보면 필요 이상으로 스코프를 크게 잡는 문제가 생긴다. 지역 변수로 써도 될 것을 굳이 멤버 변수로, 클래스 변수로, 심지어 전역 변수로 쓰는 것이다.&lt;/p&gt;
&lt;p&gt;&quot;돌아가면 장땡 아니냐?&quot; 할 수 있다. 하지만 변수든 함수든 범위가 넓다는 건 그만큼 조심해야 할 게 많다는 의미다. 집 안에서는 알몸으로 돌아다녀도 뭐라 할 사람이 없지만, 집 밖으로 나올 때는 주의해야 하는 거랑 같은 원리다. 스코프가 넓은 변수는 여기저기서 의도치 않게 건드려질 수 있는 위험에 항상 노출된다.&lt;/p&gt;
&lt;h2&gt;#2&lt;/h2&gt;
&lt;p&gt;초보 티를 벗기 위해 명심해야 할 한 가지는 최소 가시성 원칙이다. 내가 만들 변수나 함수의 가시성은 &apos;최소한&apos;이 되도록 설정하면 대체로 그게 맞다는 말이다.&lt;/p&gt;
&lt;p&gt;전역 변수를 썼는데 생각해보니 지역 변수로도 될 것 같다? 그럼 지역 변수로 바꾸는 게 맞다. 멤버 변수(&lt;code class=&quot;language-text&quot;&gt;self.변수&lt;/code&gt;)로 썼는데, 한 함수 안에서만 쓰고 만다? 그럼 지역 변수로 하는 게 맞다.&lt;/p&gt;
&lt;p&gt;아래 코드를 보자. &lt;code class=&quot;language-text&quot;&gt;self.member_variable&lt;/code&gt;은 오직 &lt;code class=&quot;language-text&quot;&gt;plus&lt;/code&gt; 함수 안에서만 사용된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OneBigBeautifulClass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;member_variable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;plus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;member_variable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;member_variable&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이럴 땐 굳이 인스턴스 전체가 공유하는 멤버 변수로 둘 필요가 없다. 아래처럼 바꾸는 것이 훨씬 안정적이고 좋은 코드다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# [더 좋은 코드]&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OneBigBeautifulClass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;pass&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;plus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    local_variable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b &lt;span class=&quot;token comment&quot;&gt;# plus 함수에서만 쓸 변수이므로 지역 변수로&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; local_variable&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이처럼 변수의 스코프를 필요한 만큼만 최소한으로 부여하는 습관, 이것만으로도 코드의 품질은 훨씬 좋아진다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[잡기] 조선의 과거 시험 경쟁률은?! (feat. 흠영)]]></title><description><![CDATA[최근에 18세기 조선의 양반 유만주가 쓴 흠영이라는 책을 읽게 됐다. 이 책은 몇가지 점에서 몹시 인상 깊었는데, 1) 저자가 쓴 일기를 모은 책인데 20살부터 13년 동안 거의 매일이 기록돼 있다는 점,…]]></description><link>https://jiniya.net/2025/06/korean-imperial-exam/</link><guid isPermaLink="false">https://jiniya.net/2025/06/korean-imperial-exam/</guid><pubDate>Tue, 10 Jun 2025 13:00:01 GMT</pubDate><content:encoded>&lt;p&gt;최근에 18세기 조선의 양반 유만주가 쓴 흠영이라는 책을 읽게 됐다. 이 책은 몇가지 점에서 몹시 인상 깊었는데, 1) 저자가 쓴 일기를 모은 책인데 20살부터 13년 동안 거의 매일이 기록돼 있다는 점, 2) 유명인사가 아닌 철저하게 일반인인 저자가 작성했다는 점. 유만주는 양반이긴 했으나 음서제로 관직에 진출할만큼의 좋은 집안은 아니었고, 그렇다고 과거에 급제할만큼 뛰어난 사람도 아니었다. 3) 18세기 조선이라면 꽉 막힌 세상일 것 같은데 생각외로 유만주의 생각들은 요즘 생각과 별반 차이가 없는 것들이 더러 있다는 점. 4) 서로 다른 시간대의 비슷한 공간을 가진 사람으로써 기호와 취향이 비슷하다는 점 등이 그것이다. 어쨌든 간만에 아주 재미있는 책이었고, 이 자리를 빌어 이 책을 추천해준 ChatGPT 4o에게 심심한 감사를 전한다.&lt;/p&gt;
&lt;p&gt;책의 주된 내용 중 하나가 유만주가 조선의 과거 시험에 대한 어려움과 방식에 대한 불만을 토로하는 점이다. 책을 읽어보면 알겠지만 유만주 개인도 책과 독서를 애정하는 사람이며, 글을 보면 글도 매우 잘 작성하는 사람임을 알 수 있다. 그럼에도 그는 평생을 과거 시험에 메달렸지만 급제하지 못하고 34살의 나이로 요절했다.&lt;/p&gt;
&lt;p&gt;책을 읽다가 문득 궁금증이 생겼다. 이렇게 책 좋아하고 똑똑해 보이는 사람도 합격이 힘들다면 조선시대 과거 시험은 도대체 경쟁률이 어떤 수준이었을까? 그래서 찾아봤다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“21일의 경과는 3곳으로 나누어 치렀는데 총 응시자는 11만1838명에 달했고, 시권(답안지)를 바친 자는 모두 3만8614명이었다. 다음날의 인일제 응시자는 모두 10만3579명이었고, 시권을 바친 자는 3만2884명이었다…”(&amp;#x3C;정조실록&gt; &amp;#x3C;홍재전서&gt;)&lt;/p&gt;
&lt;p&gt;이틀간 답안지를 제출한 응시생만 해도 7만1498명에 달했는데요. 그중 첫날의 경과를 통해 10명, 이튿날 인일제에서 2명의 합격자가 선발되었으니 어떻습니까.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.khan.co.kr/article/202111220603001&quot;&gt;https://www.khan.co.kr/article/202111220603001&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이건 정조때(1800년) 세자 책봉을 기념해서 치러진 안일제라는 특별 과거 시험의 경쟁률이다. 첫날만 보면 10명이 뽑혔는데 지원자가 111,838명이다. 0.008% 합격률. 통상의 조선의 과거 시험은 3년에 한 번 치러지고 최종 대과 합격자는 33명을 뽑았다고 한다. 대략 지원자를 10만명으로 퉁친다면 0.033% 정도 되겠다. 사실 이정도로는 어느 정도 수준인지 감이 잘 오지 않는다. 2025학년도 대학수학능력시험에 응시자 수는 392,783명이고, 서울대학교 의대 정시 정원이 42명이다. 0.01%, 연대, 고대까지 포함하면 135명으로 0.034%다. 결국 조선 시대 과거 시험은 대략 서연고 의대 정시로 갈만큼 어려웠다고 볼 수 있겠다.&lt;/p&gt;
&lt;p&gt;실제 인물을 통해서 그 극악 난이도를 알 수 있는데, 지폐에서 흔히 보는 퇴계 이황 선생님 께서도 과거에 3번 낙방하고 대과에 처음 급제한 건 34살의 나이였다고 한다. 열하일기로 유명한 연암 박지원 선생은 과거 시험은 많이 쳤지만 급제한 적이 없다. 모두 낙방해서 결국은 음서제(집안빨 등용)로 관직에 진출했다고 한다. 9번 장원급제했다고 알려진 불세출의 천재 율곡 이이도 대과를 9번 장원급제한게 아니다. 대과를 가는 길에 있는 소과를 포함해 모두 9번 장원 급제한 것이고, 처음 대과를 급제한 29세 전인 23세 시험에서는 대과에서 낙방했다.&lt;/p&gt;
&lt;p&gt;그러다 다시 의문이 들었다. 조선이란 나라는 당췌 3년에 33명 뽑아서 관직을 주면 도대체 나라가 어떻게 돌아갔다는 말인가? 빈 자리가 이렇게 안나왔던 것일까, 라는 생각이 들었다. 정년이 없었다해도 죽는 사람이 있으니 자리는 계속 생길텐데 이렇게 조금 뽑아서 그게 유지가 됐냐는 생각. 그래서 조금 더 검색해보다 충격적인 사실을 접했다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;대과에 급제한 33명 모두 관직을 받은 건 아니었다. 우수 3명에게만 관직을 부여하고, 나머지 인원은 합격증과 어사화 정도 주고 퉁쳤다.&lt;/li&gt;
&lt;li&gt;총 관직수 5605직이었지만, 은퇴자를 위한 자리 3110직, 돈안주는 자리 95직, 실질 자리수는 2400직, 그 중 문관직 1779직이 거의 전부였다고 한다. 이 몇 개 안 남는 자리를 서로 차지하기 위해서 싸운게 당파싸움의 실질 원인 중 하나였다고 한다.&lt;/li&gt;
&lt;li&gt;그러니 실질 확률은 0.033%의 1/11인 0.003%라고 할 수 있다.&lt;/li&gt;
&lt;li&gt;이런 말도 안되는 난이도의 과거 시험에 모든 양반이 목메단 이유도 있었는데, 다름 아닌 3대 동안 과거 급제자가 한명도 안나오면 양반을 박탈하고 양인으로 강등시켰기 때문.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.paju.go.kr/news/user/BD_newsView.do?q_ctgCd=1002&amp;#x26;newsSeq=419&quot;&gt;https://www.paju.go.kr/news/user/BD_newsView.do?q_ctgCd=1002&amp;#x26;newsSeq=419&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;예나 지금이나 하는 일 없이 밥그릇만 차지하고 있는 사람들은 늘 있는 것 같다. 실질 관직이 2400직인데, 은퇴자를 위한 자리가 3110직이니 말이다. 조선이 500년 더 유지됐다면 아마 6000직은 됐을듯한?! 그리고 조선 시대를 살아남은 양반 가문이라면 자부심을 가져도 될 법 하겠다. 3대에 걸쳐 서연고 의대로 정시 한 명은 합격 시켰다는 의미가 될테니 말이다.&lt;/p&gt;
&lt;p&gt;퇴계 이황 선생님이 34살의 나이게 과거에 처음 급제했다는 걸 보면 유만주는 너무 일찍 요절한 건 아닌가라는 생각이 든다. 그럼에도 그의 책을 보면 그가 더 살았더라도 아마 과거에 급제하지는 못했을 거란 생각도 든다. 왜냐하면 그 또한 묘하게 반골 기질이 있기 때문이다. 시험을 위한 시험, 공부를 위한 공부가 무슨 의미가 있냐는 한탄을 그의 글 곳곳에서 발견할 수 있다. 실질적으로 그는 과거 시험을 위한 공부 자체에는 별 흥미가 없었을 수 있다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[코딩] 현대 소프트웨어 개발에서의 진정한 코드 복잡성 분석 및 관리 전략]]></title><description><![CDATA[진정한 코드 복잡성이 뭔지 고민이 많다는 친구의 말에 심심해서 돌려본 딥리서치 자료.
현업에서 일하는 실무자의 관점에서는 사실 이건 포르노랑 비슷한 측면이 있다.
정의해서 측정하기는 어렵겠지만 보면 알 수 있다.
이게 복잡한 코드인지 아닌지?! I…]]></description><link>https://jiniya.net/2025/04/code-complexity/</link><guid isPermaLink="false">https://jiniya.net/2025/04/code-complexity/</guid><pubDate>Sun, 13 Apr 2025 14:00:01 GMT</pubDate><content:encoded>&lt;p&gt;진정한 코드 복잡성이 뭔지 고민이 많다는 친구의 말에 심심해서 돌려본 딥리서치 자료.
현업에서 일하는 실무자의 관점에서는 사실 이건 포르노랑 비슷한 측면이 있다.
정의해서 측정하기는 어렵겠지만 보면 알 수 있다.
이게 복잡한 코드인지 아닌지?!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I shall not today attempt further to define the kinds of material I understand to be embraced within that shorthand description [&apos;hard-core pornography&apos;]; and perhaps I could never succeed in intelligibly doing so. But I know it when I see it...&lt;br&gt;
&lt;br/&gt;
나는 오늘 그 약칭 표현 [‘하드코어 포르노’]에 포함된다고 여겨지는 자료의 종류를 더 이상 정의하려고 시도하지 않을 것이다. 아마도 나는 그것을 명확하게 정의하는 데 결코 성공하지 못할지도 모른다. 하지만 직접 보면 안다.&lt;br&gt;
&lt;br/&gt;
— Justice Potter Stewart, concurring opinion in Jacobellis v. Ohio, 378 U.S. 184 (1964)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2&gt;서론&lt;/h2&gt;
&lt;p&gt;소프트웨어 공학 분야에서 코드 복잡성을 이해하고 관리하는 것은 지속적인 과제이다. 특히 30년 이상 전에 정의된 전통적인 복잡성 측정 지표들이 현대 소프트웨어 개발 환경의 복잡다단한 현실을 제대로 반영하지 못한다는 인식이 확산되고 있다.1 새로운 프로그래밍 패러다임, 언어의 발전, 분산 아키텍처의 보편화 등은 코드의 구조적 측면뿐만 아니라 인지적 부하, 유지보수성, 시스템 전체의 상호작용 등 다양한 차원에서 복잡성을 야기한다.2&lt;/p&gt;
&lt;p&gt;본 보고서는 이러한 문제의식에 기반하여 &apos;진정한&apos; 코드 복잡성의 다면적 본질을 심층적으로 분석하고자 한다. 먼저 순환 복잡도(Cyclomatic Complexity)와 코드 라인 수(Lines of Code)와 같은 전통적인 측정 지표의 정의와 한계를 비판적으로 검토한다. 이어서 인지 복잡성(Cognitive Complexity), 유지보수성(Maintainability), 가독성(Readability), 테스트 용이성(Testability) 등 현대적인 관점에서 복잡성을 재조명한다. 또한, 마이크로서비스와 모놀리식 아키텍처, 디자인 패턴, 코드 의존성 및 결합도와 같은 시스템 수준의 요인들이 복잡성에 미치는 영향을 분석한다. 나아가 문제 영역 자체의 본질적 복잡성(Essential Complexity)과 개발 과정에서 발생하는 우발적 복잡성(Accidental Complexity)을 구분하고, 이러한 다양한 관점을 종합하여 오늘날 코드 복잡성을 구성하는 요소들에 대한 다각적인 이해를 구축한다. 최종적으로, 현대 소프트웨어 개발 환경에서 코드 복잡성을 효과적으로 관리하기 위한 실용적인 전략과 모범 사례를 제시하는 것을 목표로 한다. 이는 단순히 과거 지표의 부적절함을 지적하는 것을 넘어, 현대 소프트웨어의 특성을 반영하는 복잡성에 대한 깊이 있는 통찰과 실질적인 관리 방안을 모색하는 과정이 될 것이다.&lt;/p&gt;
&lt;h2&gt;I. 전통적 관점: 순환 복잡도와 코드 라인 수&lt;/h2&gt;
&lt;p&gt;소프트웨어 복잡성을 정량화하려는 초기 시도는 주로 코드의 구조적 특성에 초점을 맞추었다. 대표적인 지표인 순환 복잡도와 코드 라인 수는 수십 년간 널리 사용되어 왔으며, 특정 측면에서 유용성을 인정받았다.&lt;/p&gt;
&lt;h3&gt;가. 순환 복잡도(Cyclomatic Complexity, CC): 기원, 원리, 목적&lt;/h3&gt;
&lt;p&gt;순환 복잡도는 1976년 Thomas J. McCabe, Sr.에 의해 개발된 정량적 소프트웨어 메트릭이다.4 이는 프로그램 소스 코드를 통한 선형적으로 독립적인 경로의 수를 측정하여 프로그램의 복잡성을 나타낸다.4 McCabe는 모듈화의 정량적 기반을 제공하고 테스트하거나 유지보수하기 어려운 소프트웨어 모듈을 식별할 수 있는 수학적 기법의 필요성을 인식했다.7&lt;/p&gt;
&lt;p&gt;순환 복잡도는 제어 흐름 그래프(Control Flow Graph)를 사용하여 시각화될 수 있으며, 여기서 노드는 명령어 블록을, 엣지는 제어 흐름을 나타낸다.6 계산 공식은 일반적으로 M = E - N + 2P (E: 엣지 수, N: 노드 수, P: 연결된 컴포넌트 수)로 표현되거나, 단일 진입점과 단일 탈출점을 가진 구조적 프로그램의 경우 M = 결정 지점(Decision Points) 수 + 1로 단순화될 수 있다.4 예를 들어, 단일 조건의 if 문은 두 개의 경로(참/거짓)를 생성하므로 복잡도는 2가 되며, 중첩된 if 문이나 두 개의 조건을 가진 if 문은 복잡도 3을 생성한다.4 McCabe는 원래 1-10은 단순하고 위험이 적음, 11-20은 더 복잡하고 중간 정도 위험, 21-50은 복잡하고 높은 위험, 50 초과는 테스트 불가능하고 매우 높은 위험으로 분류했으며, 이 임계값은 여전히 참조된다.4&lt;/p&gt;
&lt;p&gt;McCabe의 주된 목적은 테스트 및 유지보수가 어려운 모듈을 식별하는 것이었다.4 특히 순환 복잡도는 필요한 최소 테스트 케이스 수, 즉 모든 실행 경로를 최소 한 번 이상 커버하기 위해 필요한 테스트 수를 나타내는 지표로 강하게 연관되어 테스트 노력과 밀접한 관련이 있다.5&lt;/p&gt;
&lt;h3&gt;나. 코드 라인 수(Lines of Code, LOC): 크기의 척도, 반드시 복잡성은 아님&lt;/h3&gt;
&lt;p&gt;코드 라인 수(LOC 또는 SLOC)는 소스 텍스트의 라인 수를 세어 소프트웨어의 크기를 측정하는 가장 기본적인 방법이다.10 주석이나 빈 줄을 포함하는 물리적 LOC와 실제 실행 가능한 구문만 계산하는 논리적 LOC로 구분될 수 있으며, 프로그래밍 언어, 코딩 스타일, 계산 방식에 따라 값이 크게 달라질 수 있다.11 예를 들어, 동일한 기능을 구현하더라도 Python은 Java나 C++보다 훨씬 적은 LOC를 사용할 수 있다.12&lt;/p&gt;
&lt;p&gt;역사적으로 LOC는 COCOMO와 같은 노력 추정 모델의 입력 값이나 유사한 프로젝트 간의 크기 비교 기준으로 사용되었다.10 또한, 테스트 커버리지 밀도(테스트된 LOC / 전체 LOC)를 계산하는 데 활용되기도 한다.10&lt;/p&gt;
&lt;p&gt;흥미롭게도, McCabe는 순환 복잡도를 제안할 당시 LOC를 복잡성 측정 지표로 사용하는 것을 명시적으로 거부했다. 그는 코드 길이와 모듈의 제어 흐름 복잡성 사이에 명확한 관계가 없다고 보았다.7&lt;/p&gt;
&lt;h3&gt;다. 초기 가치 인식 및 활용&lt;/h3&gt;
&lt;p&gt;이러한 전통적인 메트릭들은 초기에 상당한 가치를 인정받았다. 순환 복잡도는 위험 평가 도구로 빠르게 채택되었다. 높은 CC 값은 높은 결함 밀도와 상관관계가 있는 것으로 나타났으며 9, 코드 검토와 같은 추가적인 품질 보증 활동이 필요한 위험한 모듈을 식별하는 데 사용되었다.9&lt;/p&gt;
&lt;p&gt;개발 지침으로서, McCabe는 개발 중에 모듈의 CC를 특정 임계값(종종 10 또는 15) 이하로 제한하여 복잡한 함수를 더 작고 관리하기 쉬운 단위로 분할하도록 권장했다.4 이는 일부 개발 방법론에서 수용된 관행이 되었다.4&lt;/p&gt;
&lt;p&gt;테스팅 영역에서 CC는 기반 경로 테스팅(basis path testing)에 필요한 최소 테스트 케이스 수를 직접적으로 알려주는 중요한 지표였다.5 이는 테스트 범위를 정량화하고 테스트 노력을 계획하는 데 도움을 주었다.6&lt;/p&gt;
&lt;p&gt;LOC 역시 복잡성 측정에는 한계가 있지만, 유사한 환경에서 구축된 애플리케이션 간의 상대적 크기를 가늠하거나 10 전체 코드베이스 대비 테스트 커버리지 비율을 파악하는 데 여전히 유용하게 사용된다.10&lt;/p&gt;
&lt;p&gt;이러한 전통적인 메트릭들은 구조적 프로그래밍이 지배적이던 시대에 테스트, 유지보수 노력, 위험 관리와 같은 소프트웨어 개발 프로세스의 특정 측면을 정량화하려는 요구에서 비롯되었다. 그 기반은 주로 코드의 구조적 특성과 정량적 계산에 있으며 4, 이는 당시 중요하게 여겨졌던 절차적 코드 구조의 복잡성을 통제하는 데 어느 정도 기여했다. 하지만 초기부터 이러한 메트릭들이 완벽한 지표가 아니라는 암묵적인 이해가 존재했다. 예를 들어, McCabe 자신이 switch 문이 개념적 어려움을 반드시 증가시키지 않으면서도 CC를 부풀릴 수 있음을 인정하고 예외를 제안한 것은 9 순전히 구조적인 관점의 한계를 시사하며 후대의 비판을 예고하는 것이었다.&lt;/p&gt;
&lt;h2&gt;II. 기반의 균열: 전통적 메트릭의 한계&lt;/h2&gt;
&lt;p&gt;수십 년간 활용되어 온 순환 복잡도(CC)와 코드 라인 수(LOC)는 현대 소프트웨어 개발의 복잡성을 포착하는 데 점차 한계를 드러내고 있다. 이는 메트릭 자체의 내재적 문제와 더불어 소프트웨어 개발 환경의 급격한 변화에서 기인한다.&lt;/p&gt;
&lt;h3&gt;가. 메트릭과 현실의 간극: 인지 부하, 중첩, 구조 무시&lt;/h3&gt;
&lt;p&gt;순환 복잡도의 맹점: CC의 가장 큰 비판점 중 하나는 인간의 코드 이해 과정, 즉 인지적 부하를 제대로 반영하지 못한다는 것이다. 동일한 CC 값을 가진 두 함수가 이해도 측면에서는 현저히 다를 수 있다.1 대표적인 예로, 단순한 switch-case 문과 복잡하게 중첩된 논리(예: 버블 정렬 알고리즘)가 비슷한 CC 점수를 받을 수 있지만, 후자가 훨씬 이해하기 어렵다.1 특히 CC는 코드의 중첩 깊이(nesting depth)를 적절히 반영하지 못하는데 1, 깊은 중첩은 인간의 작업 기억(working memory)에 큰 부담을 주어 코드 추적을 어렵게 만들고 오류 발생 가능성을 높인다.1 또한, CC는 코드 구조 개선 노력이나 goto와 같은 비구조적 기법 사용 여부에 둔감하다.7&lt;/p&gt;
&lt;p&gt;LOC의 피상성: LOC는 복잡성이나 생산성을 측정하는 데 매우 부적절한 지표로 널리 인식된다.10 언어 간의 표현력 차이로 인해 동일 기능도 LOC가 크게 달라질 수 있으며 (예: Python vs. Java) 11, 숙련된 개발자는 종종 더 적은 코드로 더 많은 기능을 효율적으로 구현한다 (&apos;양보다 질&apos;).12 오히려 리팩토링을 통해 LOC를 줄이는 것이 코드 품질을 향상시키는 긍정적인 활동인 경우가 많다.13&lt;/p&gt;
&lt;p&gt;예측력 부족: 여러 연구와 경험적 증거들은 CC나 LOC가 실제 인지되는 복잡성, 유지보수 문제, 심지어 결함 예측력 측면에서도 다른 요인이나 새로운 메트릭에 비해 상관관계가 약하거나 부족함을 시사한다.1 CodeScene의 머신러닝 알고리즘이 CC의 예측 가치를 낮게 평가한 사례나 1, 일부 연구에서 결함 예측에 LOC가 CC보다 더 나은 성능을 보였다는 결과는 7 이러한 한계를 뒷받침한다.&lt;/p&gt;
&lt;h3&gt;나. 현대적 맥락의 도전: 패러다임, 언어, 규모&lt;/h3&gt;
&lt;p&gt;새로운 패러다임: 함수형 프로그래밍(작고 조합 가능한 함수), 비동기 프로그래밍(콜백, Promise, async/await), 반응형 프로그래밍, 이벤트 기반 아키텍처 등 현대적인 프로그래밍 패러다임은 단순한 경로 계산이나 라인 수 계산으로는 포착하기 어려운 종류의 복잡성을 도입한다.3 재귀적이거나 멀티스레딩 코드의 복잡성은 눈에 보이는 구조보다는 실행의 재귀적 또는 병렬적 특성에 있다.2&lt;/p&gt;
&lt;p&gt;언어의 진화: 현대 언어들은 리스트 컴프리헨션, 람다 표현식 등 강력하고 표현력 있는 기능을 제공한다. 이는 LOC를 줄일 수 있지만, 복잡한 로직을 몇 줄에 응축시켜 전통적인 메트릭이 시사하는 것과는 다른 방식으로 가독성에 영향을 미칠 수 있다.12 또한, 현대 언어의 다양한 구문으로 인해 코드를 제어 흐름 그래프로 명확하게 매핑하는 것이 모호해질 수 있다.7&lt;/p&gt;
&lt;p&gt;규모와 상호연결성: 현대 소프트웨어 시스템은 방대한 코드베이스를 가지며 2, 마이크로서비스와 같이 분산된 컴포넌트 간의 복잡한 상호작용을 포함하는 경우가 많다.3 이러한 시스템의 전체 복잡성은 개별 모듈의 내부 복잡성(CC나 LOC로 측정되는)보다는 모듈 간의 의존성, 인터페이스, 통신 방식에서 더 크게 비롯된다.19&lt;/p&gt;
&lt;p&gt;프레임워크와 라이브러리: 프레임워크와 외부 라이브러리에 대한 높은 의존성은 애플리케이션 자체의 CC나 LOC에는 반영되지 않는 또 다른 차원의 복잡성을 추가한다. 프레임워크의 동작 방식을 이해하고, 설정을 관리하며, 의존성 충돌을 해결하는 등의 작업은 상당한 노력을 요구한다.20&lt;/p&gt;
&lt;h3&gt;다. 오용과 오해의 위험&lt;/h3&gt;
&lt;p&gt;생산성 착각: LOC를 개발자 생산성 측정에 사용하는 것은 매우 잘못된 접근이라는 강력한 공감대가 형성되어 있다.10 이는 버그 수정처럼 적은 라인 변경에 많은 시간이 소요되는 복잡한 작업의 가치를 무시하며 10, 단순히 코드 라인 수를 늘리려는 부정적인 행동을 조장할 수 있다.16&lt;/p&gt;
&lt;p&gt;메트릭 게임: LOC나 심지어 CC 같은 메트릭을 성과 평가와 직접 연동하면, 개발자들은 메트릭 점수를 높이기 위해 코드를 불필요하게 장황하게 작성하거나, 리팩토링을 피하거나, 의미 없는 변경을 자주 하는 등의 행동을 할 수 있다.16 이는 오히려 코드 복잡성을 증가시키고 기술 부채를 쌓는 결과를 초래할 수 있다.16&lt;/p&gt;
&lt;p&gt;과도한 단순화: CC나 LOC의 임계값을 코드 품질의 절대적인 기준으로 삼는 것은 위험하다. 이는 코드의 가독성, 유지보수성, 설계의 적절성, 프로젝트의 특정 맥락 등 중요한 질적 측면을 간과하게 만든다.8 메트릭은 판단을 돕는 도구일 뿐, 판단 자체를 대체해서는 안 된다.8&lt;/p&gt;
&lt;p&gt;전통적인 메트릭의 핵심 한계는 코드의 *구문적 구조(syntactic structure)*에 초점을 맞추고, 코드의 *의미(semantic meaning)*나 이를 이해하는 데 필요한 *인지적 노력(cognitive effort)*을 간과한다는 점에서 비롯된다. 이러한 불일치는 다양한 형태의 추상화와 조합을 우선시하는 현대 프로그래밍 관행 하에서 더욱 두드러진다. CC는 제어 구조(IF, LOOP 등)에 기반한 경로를 계산하고 1, LOC는 단순히 라인 수를 센다.10 둘 다 구문적이다. 반면, 이들에 대한 비판은 꾸준히 &apos;이해도&apos;를 제대로 측정하지 못한다는 점을 지적하는데 1, 이는 인지적, 의미적 문제이다. 예를 들어 함수형 프로그래밍은 함수당 CC는 낮을 수 있지만, 그 조합을 이해하기 위해서는 다른 종류의 인지 능력이 요구될 수 있다.17 현대 소프트웨어가 목표를 달성하는 방식 자체가 CC가 설계되었던 시대의 단순한 절차적 제어 흐름과 달라지면서, 이들 메트릭의 부적절성이 커지는 것이다.&lt;/p&gt;
&lt;p&gt;더 나아가, LOC와 같은 단순한 메트릭을 생산성 측정에 오용하는 현상은 소프트웨어 공학의 근본적인 도전 과제, 즉 &apos;가치 창출&apos;을 측정하는 어려움을 반영한다. 소프트웨어 개발은 본질적으로 창의적인 문제 해결 활동이므로, 자동화하기 쉽지만 피상적인 지표로 결과물을 정량화하려는 시도는 종종 역효과를 낳는다. 잘못된 행동을 유도하고 잠재적으로 품질을 저해하는 것이다.16 이는 쉽게 측정 가능한 결과물(타이핑된 라인 수)과 실제 목표(문제를 효과적이고 유지보수 가능하게 해결하는 것) 사이의 괴리를 보여준다. 따라서 의미 있는 평가는 정량화하기는 더 어렵지만 더 관련성 높은 결과(요구사항 충족 22, 전달된 가치 23)와 질적 측면(유지보수성, 설계)을 고려해야 함을 시사한다.&lt;/p&gt;
&lt;p&gt;결국 CC와 LOC의 한계는 단순히 기술적인 문제를 넘어, 업계가 중요하게 여기는 가치의 역사적 변화를 반영한다. 초기에는 절차적 복잡성을 제어하고 기본적인 테스트 용이성을 확보하는 데 중점을 두었다. 현대에는 대규모 시스템 관리, 다양한 팀을 위한 인지 부하 감소, 빠른 진화에 대한 요구가 커지면서 다른 종류의 측정 기준과 관리 방식이 필요하게 되었다.&lt;/p&gt;
&lt;h2&gt;III. 코드 복잡성에 대한 현대적 관점&lt;/h2&gt;
&lt;p&gt;전통적인 메트릭의 한계가 명확해짐에 따라, 코드 복잡성을 평가하는 새로운 관점들이 주목받고 있다. 이들은 단순히 코드 구조를 넘어 인간의 인지 과정, 유지보수의 용이성, 효과적인 테스트 가능성 등을 복잡성의 핵심 요소로 간주한다.&lt;/p&gt;
&lt;h3&gt;가. 인지 복잡성(Cognitive Complexity): 이해도 정량화 시도&lt;/h3&gt;
&lt;p&gt;동기: 인지 복잡성은 SonarSource에 의해 개발되었으며, 순환 복잡도(CC)가 코드의 &apos;이해도&apos;를 측정하는 데 실패한다는 단점을 직접적으로 해결하기 위해 등장했다.25 이 메트릭의 목표는 인간이 특정 코드 조각을 읽고 이해하는 데 필요한 정신적 노력을 정량화하는 것이다.25&lt;/p&gt;
&lt;p&gt;측정 규칙: 인지 복잡도 계산의 핵심 원칙은 다음과 같다:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;가독성 있는 축약 무시: 여러 구문을 가독성 있게 하나로 압축하는 구조(예: 단순 메서드 호출)는 복잡도를 증가시키지 않는다.26&lt;/li&gt;
&lt;li&gt;선형 흐름 중단 시 증가: 코드의 선형적 흐름을 깨는 구조(예: 루프, 조건문, switch, 예외 처리, goto, 재귀, &amp;#x26;&amp;#x26;나 || 같은 다중 논리 연산자)마다 복잡도가 증가한다.25&lt;/li&gt;
&lt;li&gt;중첩 페널티: 흐름을 깨는 구조가 다른 구조 내부에 중첩될 때 추가적인 페널티가 부과된다.25 이는 CC의 주요 약점 중 하나였던 중첩 깊이 문제를 직접적으로 다룬다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;CC와의 비교: 인지 복잡도는 CC와 명확히 대비된다. CC는 테스트 용이성(최소 테스트 경로 수)에 초점을 맞추는 반면, 인지 복잡도는 가독성 및 이해도(인지적 노력)에 초점을 맞춘다.25 예를 들어, 단순한 switch 문은 CC는 높지만 인지 복잡도는 낮을 수 있으며, 반대로 기능을 작은 함수들로 분해하는 리팩토링은 CC를 증가시킬 수 있지만 인지 복잡도는 감소시킬 수 있다.1 다음 표는 두 메트릭의 주요 차이점을 요약한다.&lt;/p&gt;
&lt;p&gt;표 1: 순환 복잡도와 인지 복잡도 비교&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;특징&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;순환 복잡도 (Cyclomatic Complexity)&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;인지 복잡도 (Cognitive Complexity)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;주요 목표&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;테스트 용이성 (Testability)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;이해 용이성 (Understandability)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;측정 초점&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;제어 흐름 경로 수 (Number of control flow paths)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;인지적 노력 (Cognitive effort)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;주요 페널티 요인&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;분기 (Branches: if, loop, switch case 등)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;흐름 중단 (Flow breaks) + 중첩 (Nesting)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;단순 구조 처리&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;switch 등 단순 구조도 경로 수에 따라 높게 측정될 수 있음 1&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;가독성을 해치지 않는 선형 흐름 중단은 낮게 평가, 중첩에 민감 26&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;주요 활용 사례&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;테스트 계획 (최소 테스트 케이스 수 결정) 5&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;코드 가독성 및 유지보수성 평가, 리팩토링 대상 식별 17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;참고 자료&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;1&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;25&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;한계: 인지 복잡도 역시 하나의 메트릭이며, 인간 인지의 모든 미묘함이나 특정 언어 기능의 어려움(예: 포인터 연산, 고급 타입 시스템)까지 포착하지는 못한다.25 여전히 구조 기반의 측정이며, 최종적인 판단에는 인간의 경험과 맥락 이해가 필수적이다.25&lt;/p&gt;
&lt;h3&gt;나. 유지보수성과 가독성을 핵심 관심사로&lt;/h3&gt;
&lt;p&gt;정의 및 중요성: 유지보수성은 코드를 수정하고 업데이트하기 쉬운 정도를, 가독성은 코드를 읽고 이해하기 쉬운 정도를 의미한다.8 이 두 요소는 소프트웨어 생명주기 전반에 걸쳐 비용, 시간, 결함률에 지대한 영향을 미치는 핵심 품질 속성이다.20 낮은 가독성과 유지보수성은 복잡성을 인지하는 주요 원인이 된다.8&lt;/p&gt;
&lt;p&gt;복잡성과의 관계: 일반적으로 복잡성(구조적이든 인지적이든)과 가독성/유지보수성 사이에는 강한 음의 상관관계가 관찰된다. 즉, 복잡한 코드는 이해하고 안전하게 수정하며 디버깅하기 어렵다.15 연구 결과에서도 가독성과 복잡성 간의 높은 음의 상관관계(-0.974)가 보고된 바 있으며 30, 이는 복잡한 컴포넌트가 유지보수 및 이해하기 훨씬 어렵다는 것을 확인시켜 준다.30&lt;/p&gt;
&lt;p&gt;영향 요인: 단순한 메트릭 점수 외에도 명확한 이름 규칙, 일관된 코드 스타일, 적절한 주석, 모듈화된 설계, 표준 준수, 낮은 결합도, 높은 응집도 등 다양한 요인이 가독성과 유지보수성에 영향을 미친다.8 가독성은 문제 영역 자체의 복잡성(본질적 복잡성)과 달리 엔지니어가 통제할 수 있는 &apos;우발적 속성&apos;으로 간주되기도 한다.30&lt;/p&gt;
&lt;h3&gt;다. 테스트 용이성: 경로 수를 넘어서&lt;/h3&gt;
&lt;p&gt;현대적 관점: 테스트 용이성은 단순히 CC가 나타내는 경로 커버리지 이상의 의미를 갖는다. 코드가 얼마나 쉽게 테스트 환경을 구성하고, 단위(unit)를 격리하여 테스트할 수 있는지에 대한 개념으로 확장된다.8&lt;/p&gt;
&lt;p&gt;테스트 용이성을 위한 설계: 설계 결정은 테스트 용이성에 큰 영향을 미친다. 의존성 주입(Dependency Injection, DI)은 컴포넌트를 분리하고 테스트 중에 실제 의존성을 목(Mock) 객체나 스텁(Stub)으로 쉽게 교체할 수 있게 함으로써 테스트 용이성을 높이는 핵심 디자인 패턴이다.32 이는 테스트 대상 단위를 효과적으로 격리시킨다.32&lt;/p&gt;
&lt;p&gt;모킹(Mocking): 모킹은 실제 의존성의 동작을 시뮬레이션하는 테스트 대역(test double)을 만드는 기술이다.32 DI는 이러한 목 객체를 쉽게 주입할 수 있도록 하여 테스트 코드 작성을 용이하게 한다.32&lt;/p&gt;
&lt;p&gt;복잡성과 테스트 용이성 연관성: 복잡한 코드(높은 CC, 높은 인지 복잡도, 강한 결합, 숨겨진 의존성)는 본질적으로 철저하고 안정적으로 테스트하기 어렵다.2 테스트하기 어려운 코드는 종종 근본적인 설계 문제를 내포하고 있다는 신호일 수 있다.36&lt;/p&gt;
&lt;p&gt;인지 복잡도의 등장은 소프트웨어 개발에서 초점이 단순히 &lt;em&gt;기계가 실행 가능한 경로&lt;/em&gt;(CC)에서 해당 경로와 코드의 의도를 이해하는 데 필요한 &lt;em&gt;인간의 인지적 노력&lt;/em&gt;으로 이동하고 있음을 보여주는 중요한 변화이다. 이는 코드베이스가 커지고 팀이 분산됨에 따라 코드를 &lt;em&gt;이해&lt;/em&gt;하는 비용이 전체 개발 비용과 위험의 주요 동인이 되고 있다는 인식이 커지고 있음을 반영한다.17&lt;/p&gt;
&lt;p&gt;또한, 테스트 용이성을 위해 설계하는 것(예: DI 사용)이 종종 더 모듈화되고, 덜 결합되며, 잠재적으로 전반적으로 덜 복잡한 설계로 이어진다는 점은 주목할 만하다. 이는 긍정적인 피드백 루프를 생성한다. 테스트하기 어렵다는 것은 종종 높은 결합도나 낮은 응집도와 같은 설계 문제의 &lt;em&gt;증상&lt;/em&gt;이다.33 따라서 테스트 용이성을 향상시키는 관행(DI, 명확한 인터페이스)은 복잡성의 일반적인 원인(결합, 불분명한 책임)을 직접적으로 해결하는 경향이 있다.&lt;/p&gt;
&lt;p&gt;하지만 인지 복잡도가 CC보다 이해도를 더 잘 반영하더라도 여전히 &lt;em&gt;구조적&lt;/em&gt; 메트릭이라는 점을 인지해야 한다. 실제 인지 부하는 도메인 지식, 이름 명명의 질, 주석의 유용성, 코드의 일관성, 개별 개발자의 경험과 같은 비구조적 요인에 의해서도 영향을 받는다.2 현재의 자동화된 메트릭들은 이러한 측면을 완전히 포착하기 어렵다. 따라서 인지 복잡도와 같은 메트릭은 유용한 &lt;em&gt;지표&lt;/em&gt;이지만, 이러한 비구조적 측면을 다루는 질적 평가(예: 코드 리뷰)와 좋은 개발 관행으로 보완되어야 한다.&lt;/p&gt;
&lt;h2&gt;IV. 더 넓은 시야: 아키텍처, 디자인, 의존성&lt;/h2&gt;
&lt;p&gt;코드 복잡성은 개별 함수나 클래스 수준을 넘어 시스템 전체의 구조와 상호작용 방식에 의해 크게 영향을 받는다. 아키텍처 선택, 디자인 패턴 적용, 그리고 코드 간의 의존성 관리는 복잡성의 성격과 위치를 근본적으로 결정짓는 요소들이다.&lt;/p&gt;
&lt;h3&gt;가. 아키텍처의 영향: 모놀리스 대 마이크로서비스&lt;/h3&gt;
&lt;p&gt;모놀리식 아키텍처(Monolithic Architecture): 단일 코드베이스와 배포 단위를 특징으로 하는 전통적인 구조이다.20 초기에는 개발, 배포, 테스트, 디버깅이 상대적으로 단순하다는 장점이 있다.38 그러나 시스템 규모가 커짐에 따라 내부 복잡성이 증가하고, 컴포넌트 간의 강한 결합으로 인해 작은 변경이 시스템 전체에 예기치 않은 영향을 미치는 파급 효과(ripple effect)가 발생하기 쉽다.38 이는 개발 속도를 저하시키고, 특정 부분만 독립적으로 확장하기 어렵게 만들며, 새로운 기술 도입에 장벽이 되기도 한다.20&lt;/p&gt;
&lt;p&gt;마이크로서비스 아키텍처(Microservices Architecture): 애플리케이션을 작고 독립적으로 배포 가능한 서비스들의 집합으로 구성하는 접근 방식이다.37 각 서비스는 자체적인 비즈니스 로직과 데이터 저장소를 가질 수 있으며, 네트워크를 통해 잘 정의된 인터페이스로 통신한다.37 주요 장점으로는 서비스별 독립적인 확장, 배포, 기술 선택의 유연성, 높은 장애 격리(fault isolation), 자율적인 팀 구성 지원 등이 있다.19 각 서비스 내부의 코드베이스는 상대적으로 단순해질 수 있다.38&lt;/p&gt;
&lt;p&gt;복잡성 트레이드오프(Complexity Trade-offs): 중요한 점은 마이크로서비스가 복잡성을 제거하는 것이 아니라, 복잡성의 &lt;em&gt;형태를 바꾸고 이동시킨다&lt;/em&gt;는 것이다.38 개별 서비스의 &lt;em&gt;내부&lt;/em&gt; 코드 복잡성은 줄어들 수 있지만, 전체 &lt;em&gt;시스템&lt;/em&gt; 수준의 복잡성은 분산 시스템 고유의 문제들로 인해 증가한다. 여기에는 네트워크 지연 및 신뢰성 문제, 서비스 간 통신 및 데이터 일관성 유지의 어려움, 배포 및 모니터링의 운영 오버헤드 증가, 분산 트랜잭션 테스트의 복잡성, 서비스 검색(discoverability) 문제 등이 포함된다.19 따라서 마이크로서비스 전환은 단순히 기술적 유행을 따르기보다 명확한 기술적, 조직적 요구에 기반해야 하며 19, 때로는 잘 구조화된 &quot;모듈형 모놀리스(modular monolith)&quot;가 더 적합한 대안이 될 수도 있다.19&lt;/p&gt;
&lt;p&gt;표 2: 아키텍처 복잡성 트레이드오프: 모놀리스 vs. 마이크로서비스&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;측면&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;모놀리식 아키텍처 (Monolithic Architecture)&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;마이크로서비스 아키텍처 (Microservices Architecture)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;내부 코드 복잡성&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;높거나 증가하는 경향 20&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;서비스별로는 낮음 38&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;시스템/상호작용 복잡성&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;낮음 (내부 호출)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;높음 (네트워크 통신, 분산 시스템 문제) 19&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;운영 복잡성&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;상대적으로 낮음 (단일 배포/모니터링 대상) 38&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;높음 (다수 서비스 관리, 인프라 복잡성 증가) 39&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;배포 복잡성&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;단순한 단위 38&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;조정된 서비스 배포 필요 39&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;확장성&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;전체 단위 확장 (Coarse-grained) 38&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;서비스별 독립 확장 (Fine-grained) 38&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;기술 유연성&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;낮음 (단일 기술 스택 제약) 38&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;높음 (서비스별 최적 기술 선택 가능) 39&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;팀 자율성&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;낮음 (코드베이스 공유 및 의존성)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;높음 (독립적인 개발 및 배포 가능) 38&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;참고 자료&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;20&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;19&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;나. 디자인 패턴: 복잡성 관리 도구인가, 또 다른 복잡성인가?&lt;/h3&gt;
&lt;p&gt;잠재적 이점: 잘 알려진 디자인 패턴은 일반적인 문제에 대한 표준적이고 검증된 해결책을 제공함으로써 복잡성을 관리하는 데 도움을 줄 수 있다.8 패턴은 코드 구조를 개선하고, 재사용성을 높이며, 특정 유형의 복잡한 로직(예: 상태 패턴이나 전략 패턴을 이용한 복잡한 조건문 처리 6)을 단순화할 수 있다. 또한, 패턴은 개발자 간의 의사소통을 위한 공통 어휘를 제공한다.8&lt;/p&gt;
&lt;p&gt;잠재적 단점: 그러나 디자인 패턴의 무분별한 적용은 오히려 복잡성을 증가시킬 수 있다. 패턴은 종종 추가적인 추상화 계층, 더 많은 클래스나 인터페이스, 간접 호출 등을 도입하여 코드 이해를 어렵게 만들 수 있다.21 필요하지 않은 곳에 패턴을 적용하는 오버 엔지니어링은 우발적 복잡성을 낳는다.21 또한, 패턴 자체를 이해하고 나중에 제거하는 것도 복잡한 작업이 될 수 있다.44 SOLID 원칙과 같은 설계 원칙들도 잘못 적용될 경우 불필요한 복잡성을 추가할 수 있다는 비판이 제기된다.21&lt;/p&gt;
&lt;p&gt;맥락의 중요성: 패턴의 가치는 특정 문제와 맥락에 따라 크게 달라진다. 패턴이 제공하는 유연성이나 구조가 현재 및 예상되는 미래의 요구사항에 정말로 필요한지를 신중하게 평가해야 한다.44&lt;/p&gt;
&lt;h3&gt;다. 의존성의 무게: 결합도와 응집도&lt;/h3&gt;
&lt;p&gt;정의: 결합도(Coupling)는 소프트웨어 모듈 간의 상호 의존성 정도를 나타낸다. 즉, 한 모듈의 변경이 다른 모듈의 변경을 요구하는 정도이다.46 응집도(Cohesion)는 단일 모듈 내의 요소들이 얼마나 서로 관련되어 있고 단일 목적을 위해 집중되어 있는지를 나타낸다.46 일반적인 설계 목표는 낮은 결합도와 높은 응집도(Low Coupling, High Cohesion)를 추구하는 것이다.46&lt;/p&gt;
&lt;p&gt;복잡성에 미치는 영향: 높은 결합도는 시스템 복잡성을 크게 증가시킨다. 변경 사항이 시스템 전체로 퍼져나가 예측하기 어렵고, 이해, 수정, 테스트를 어렵게 만든다.46 강하게 결합된 시스템은 변경에 취약하다. 반면, 낮은 응집도는 모듈이 서로 관련 없는 너무 많은 책임을 가지고 있음을 시사하며, 이는 모듈의 이해, 재사용, 유지보수를 어렵게 만든다.46 Feature Envy(다른 클래스의 데이터나 메서드를 과도하게 사용하는 것)나 Message Chains(객체가 다른 객체를 통해 연쇄적으로 메시지를 보내는 것)와 같은 코드 스멜(code smell)은 종종 결합도 및 응집도 문제와 관련이 있다.48&lt;/p&gt;
&lt;p&gt;시스템 전반의 효과: 내부 모듈 간의 의존성뿐만 아니라 외부 라이브러리, 프레임워크, 다른 서비스와의 의존성도 전체 시스템 복잡성에 기여한다.21 이러한 의존성을 관리하고, 그 영향을 파악하며, 호환성을 보장하는 것은 현대 소프트웨어 개발의 주요 과제 중 하나이다.8&lt;/p&gt;
&lt;p&gt;결합도 관리: 직접적인 결합도를 줄이기 위해 인터페이스 기반 설계, 콜백, 의존성 역전 원칙(Dependency Inversion Principle), 이벤트 기반 통신과 같은 기법들이 사용된다.34 Martin Fowler는 특히 시스템의 상위 수준 모듈 간의 결합도를 관리하는 것이 중요하다고 강조한다.47&lt;/p&gt;
&lt;p&gt;코드 복잡성을 개별 코드 조각만으로는 완전히 이해할 수 없다는 점이 분명해진다. 아키텍처 선택(모놀리스 vs. 마이크로서비스)과 시스템 내 의존성 네트워크는 복잡성의 &lt;em&gt;성격&lt;/em&gt;과 &lt;em&gt;위치&lt;/em&gt;를 근본적으로 형성한다. 모놀리스는 복잡성을 내부로 집중시키는 경향이 있고 20, 마이크로서비스는 복잡성을 서비스 간의 상호작용과 운영 환경으로 분산시킨다.38 아키텍처와 관계없이 모듈 간의 높은 결합도는 시스템 전체의 취약성을 야기한다.46 이는 복잡성이 단순히 코드 구조의 문제가 아니라 거시적 설계 결정에 크게 영향을 받는 시스템적 속성임을 보여준다.&lt;/p&gt;
&lt;p&gt;또한, 복잡성을 관리하기 위한 많은 기법들(마이크로서비스, 디자인 패턴, 디커플링)은 종종 트레이드오프를 수반한다. 이들은 한 종류의 복잡성(예: 내부 코드 복잡성)을 해결하는 대신 다른 종류의 복잡성(예: 운영 복잡성, 추상화 오버헤드)을 도입하는 경우가 많다.38 보편적으로 &apos;최선&apos;인 접근 방식은 없으며, 선택은 항상 특정 문제, 팀 역량, 장기 목표 등 맥락에 따라 이루어져야 한다. 이는 유행하는 기술을 맹목적으로 적용하기보다 신중한 분석이 필요함을 시사한다.&lt;/p&gt;
&lt;p&gt;결합도 관리는 클래스 설계(DI, 인터페이스 34)부터 상위 모듈(Fowler 47), 아키텍처 스타일(마이크로서비스 38)에 이르기까지 다양한 추상화 수준에서 핵심 주제로 반복적으로 등장한다. 이는 의존성을 제어하는 것이 전체 시스템의 복잡성과 유지보수성을 관리하는 데 가장 중요한 요소 중 하나임을 시사한다. 이해하기 쉽고 적응 가능한 시스템을 구축하는 데 있어 의존성 관리는 근본적인 중요성을 갖는다.&lt;/p&gt;
&lt;h2&gt;V. 본질적 복잡성 대 우발적 복잡성: 노력 집중하기&lt;/h2&gt;
&lt;p&gt;소프트웨어 복잡성을 효과적으로 관리하기 위해서는 복잡성의 근원을 이해하는 것이 중요하다. Fred Brooks가 제시한 &apos;본질적 복잡성&apos;과 &apos;우발적 복잡성&apos;의 구분은 복잡성의 어떤 측면에 노력을 집중해야 하는지에 대한 전략적 틀을 제공한다.&lt;/p&gt;
&lt;h3&gt;가. Brooks의 이분법: 내재된 복잡성 대 부가된 복잡성&lt;/h3&gt;
&lt;p&gt;기원: 이 개념은 컴퓨터 아키텍트이자 튜링상 수상자인 Fred Brooks가 1986년에 발표한 영향력 있는 논문 &quot;No Silver Bullet—Essence and Accident in Software Engineering&quot;에서 비롯되었다.49 Brooks는 하드웨어 공학에 비해 소프트웨어 공학의 생산성 향상이 더딘 이유를 분석하면서 이 구분을 제시했다.&lt;/p&gt;
&lt;p&gt;본질적 복잡성(Essential Complexity): 문제 영역 자체의 고유한 어려움에서 비롯되는 복잡성이다.45 이는 사용자가 요구하는 기능, 즉 소프트웨어가 &lt;em&gt;반드시&lt;/em&gt; 수행해야 하는 작업들의 복잡성이다.51 이 복잡성은 문제를 변경하지 않는 한 제거할 수 없다.45 예를 들어, 복잡한 비즈니스 규칙, 정교한 과학적 계산, 특정 문제의 본질적인 상태 관리 요구 등이 본질적 복잡성에 해당한다.30&lt;/p&gt;
&lt;p&gt;우발적 복잡성(Accidental Complexity): 개발 과정에서 사용되는 도구, 기술, 설계 결정 등으로 인해 부가적으로 발생하는 복잡성이다.49 이는 문제 자체에 내재된 것이 아니라, 개발자들이 해결 과정에서 의도치 않게 만들어내는 복잡성이다.49 따라서 이 복잡성은 엔지니어들이 잠재적으로 수정하거나 피할 수 있다.50 예를 들어, 과도하게 복잡한 추상화, 잘못된 설계 선택, 다루기 힘든 프레임워크, 복잡한 빌드/배포 프로세스, 불명확한 코드, 불필요한 의존성 등이 우발적 복잡성을 증가시킨다.20&lt;/p&gt;
&lt;h3&gt;나. 우발적 복잡성 인식 및 감소&lt;/h3&gt;
&lt;p&gt;Brooks의 주장: Brooks는 고급 프로그래밍 언어가 어셈블리 언어의 세부 사항을 추상화하는 등 우발적 복잡성을 줄이는 데 상당한 진전이 있었으며, 따라서 남은 과제는 주로 본질적 복잡성에 있다고 주장했다. 이 때문에 소프트웨어 생산성에서 획기적인(order-of-magnitude) 향상을 기대하기는 어렵다고 보았다.50&lt;/p&gt;
&lt;p&gt;현대적 관련성: Brooks의 지적에도 불구하고, 현대 소프트웨어 개발에서도 여전히 상당한 우발적 복잡성이 발생하고 있다.20 부적절한 도구나 프레임워크 선택 20, 잘못된 아키텍처 결정 20, 불필요한 디커플링 21, 과도한 의존성 21, 코드의 명확성 부족 20, 시기상조의 최적화나 일반화 21, 특정 기술이나 방법론을 맹목적으로 따르는 &apos;카고 컬트(cargo culting)&apos; 현상 53 등이 그 원인이 될 수 있다.&lt;/p&gt;
&lt;p&gt;노력 집중: 본질적 복잡성은 좋은 설계와 명확한 이해를 통해 &lt;em&gt;관리&lt;/em&gt;되어야 하는 반면, 우발적 복잡성은 적극적으로 &lt;em&gt;최소화&lt;/em&gt;해야 한다.18 이것이 엔지니어들이 유지보수성, 이해도, 생산성을 향상시키기 위해 가장 큰 영향력을 발휘할 수 있는 영역이다. 전략에는 단순화 추구, 적절한 도구 선택, 명확성 강조, 불필요한 요소 제거 등이 포함된다.21&lt;/p&gt;
&lt;p&gt;본질적/우발적 복잡성 구분은 복잡성 관리에 중요한 전략적 틀을 제공한다. 이는 개발 과정에서 스스로 만들어낸 어려움(우발적)을 &lt;em&gt;제거&lt;/em&gt;하는 데 노력을 기울이고, 피할 수 없는 어려움(본질적)은 효과적으로 &lt;em&gt;모델링하고 관리&lt;/em&gt;하는 데 집중하도록 방향을 제시한다. Brooks는 대부분의 생산성 향상이 우발적 복잡성 감소에서 왔다고 주장했지만 50, 현대 개발에서도 여전히 최적이 아닌 도구, 프로세스, 설계로 인해 상당한 우발적 복잡성이 발생한다.20 따라서 본질적 복잡성을 다루는 것이 어렵다 하더라도, 부주의하게 도입된 우발적 복잡성을 부지런히 식별하고 제거하는 것만으로도 상당한 가치를 창출할 수 있다. 이것이 개선을 위한 가장 실질적인 경로이다.&lt;/p&gt;
&lt;p&gt;하지만 본질적 복잡성과 우발적 복잡성 사이의 경계는 때때로 모호하고 맥락에 따라 달라질 수 있다. 예를 들어, 특정 복잡한 프레임워크 기능이 필요하다고 여겨지는 것이 본질적 복잡성처럼 보일 수 있다. 그러나 요구사항을 더 간단하게 충족할 수 있거나 해당 프레임워크 자체가 작업에 비해 불필요하게 복잡하다면, 이는 우발적 복잡성으로 드러날 수 있다. 이는 요구사항과 솔루션 선택을 비판적으로 평가하여 우발적 복잡성을 본질적 복잡성으로 오인하지 않도록 주의해야 함을 시사한다.&lt;/p&gt;
&lt;h2&gt;VI. 오늘날의 &apos;진정한&apos; 코드 복잡성 정의&lt;/h2&gt;
&lt;p&gt;전통적인 메트릭의 한계와 현대 소프트웨어 개발의 다면성을 고려할 때, &apos;진정한&apos; 코드 복잡성은 단일 지표로 정의될 수 없다. 이는 코드 자체의 구조적 특성뿐만 아니라, 이를 이해하고 다루는 인간의 인지 과정, 시스템 전체의 상호작용, 그리고 해결하려는 문제의 본질까지 아우르는 다차원적인 개념이다.&lt;/p&gt;
&lt;h3&gt;가. 다차원적 구성 요소: 요인 종합&lt;/h3&gt;
&lt;p&gt;단일 메트릭을 넘어서: 순환 복잡도, LOC, 심지어 인지 복잡도와 같은 어떤 단일 숫자도 &apos;진정한&apos; 복잡성의 전체 그림을 포착할 수는 없다.8 진정한 복잡성은 여러 요소가 복합적으로 작용한 결과이다.&lt;/p&gt;
&lt;p&gt;종합적 정의: 현대적 관점에서 코드 복잡성을 구성하는 주요 차원들은 다음과 같이 종합될 수 있다:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;구조적 복잡성 (Structural Complexity): 제어 흐름의 얽힘, 코드 구성 방식의 복잡성. 순환 복잡도, 중첩 깊이(Nesting Depth) 등이 부분적으로 측정한다.4&lt;/li&gt;
&lt;li&gt;인지 복잡성 (Cognitive Complexity): 코드의 로직, 흐름, 의도를 파악하는 데 필요한 정신적 노력. 인지 복잡도 메트릭과 가독성 관련 요인(명명 규칙, 일관성 등)에 의해 영향을 받는다.25&lt;/li&gt;
&lt;li&gt;상태 공간 복잡성 (State Space Complexity): 시스템 또는 컴포넌트가 가질 수 있는 가능한 상태의 수와 이를 추론하는 어려움. 복잡한 로직의 테스트 및 디버깅 논의에서 암시적으로 나타난다.15&lt;/li&gt;
&lt;li&gt;의존성 복잡성 (Dependency Complexity): 내부 및 외부 의존성의 수, 성격, 결합 방식에서 발생하는 복잡성.8&lt;/li&gt;
&lt;li&gt;아키텍처 복잡성 (Architectural Complexity): 선택된 아키텍처 스타일(예: 마이크로서비스의 분산 시스템 문제)에 내재된 복잡성.19&lt;/li&gt;
&lt;li&gt;도메인 복잡성 (Domain Complexity / Essential): 해결하려는 문제 자체의 본질적인 복잡성.30&lt;/li&gt;
&lt;li&gt;도구/환경 복잡성 (Tooling/Environment Complexity / Accidental): 빌드 시스템, 배포 파이프라인, 프레임워크 등 개발 환경에서 비롯되는 부가적인 복잡성.49&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;나. 현대 복잡성 평가의 핵심 요소&lt;/h3&gt;
&lt;p&gt;전체론적 관점: 복잡성을 평가할 때는 단순히 코드 구조뿐만 아니라 위에서 언급된 다양한 차원을 종합적으로 고려해야 한다.&lt;br&gt;
맥락의 중요성: 복잡성의 영향은 팀의 규모와 경험, 프로젝트 목표, 예상 수명 등 맥락에 따라 달라진다.8 주니어 개발자에게 복잡한 것이 전문가에게는 단순할 수 있다.25&lt;br&gt;
질적 판단: 정량적 메트릭과 함께 인간의 판단, 코드 리뷰, 도메인 전문 지식의 중요성을 간과해서는 안 된다.8&lt;br&gt;
결국 &apos;진정한&apos; 코드 복잡성은 코드 자체의 속성이라기보다는, 코드, 코드가 속한 시스템, 코드가 해결하는 문제, 그리고 이를 개발하고 유지보수하는 인간 사이의 상호작용에서 &lt;em&gt;나타나는(emergent)&lt;/em&gt; 속성으로 이해하는 것이 가장 적절하다. 분석 과정에서 복잡성이 코드 구조(CC), 인간의 이해(인지 복잡성), 시스템 상호작용(결합도, 아키텍처), 문제 영역(본질적 복잡성) 등 다양한 원천에서 발생함을 확인했다. 메트릭만으로는 충분하지 않으며 8, 인지 부하나 팀 구조와 같은 인간적 요소가 결정적이다.25 따라서 복잡성에 대한 정의는 이러한 구조적, 시스템적, 인지적, 맥락적 요소를 통합해야 한다.&lt;/p&gt;
&lt;p&gt;복잡성이 다차원적이고 맥락 의존적이라는 사실은 효과적인 평가를 위해서는 단일 &apos;궁극의&apos; 복잡성 메트릭을 찾기보다는, 다양한 지표(CC, 인지 복잡도, 결합도 메트릭, 테스트 커버리지 등)들의 &lt;em&gt;대시보드&lt;/em&gt;와 질적 실천(코드 리뷰, 아키텍처 리뷰)을 결합해야 함을 시사한다. 이는 다른 분야에서 복잡한 시스템을 모니터링하는 방식과 유사하다. 다양한 정량적, 질적 정보를 종합해야만 복잡성에 대한 미묘하고 정확한 이해에 도달할 수 있다.&lt;/p&gt;
&lt;h2&gt;VII. 효과적인 복잡성 관리 전략&lt;/h2&gt;
&lt;p&gt;현대 소프트웨어 개발에서 코드 복잡성을 효과적으로 관리하는 것은 단순히 좋은 코드를 작성하는 것을 넘어, 설계, 프로세스, 팀 문화 전반에 걸친 지속적인 노력을 요구한다. 복잡성의 다면적 본질을 이해했다면, 이를 제어하고 완화하기 위한 구체적인 전략을 적용하는 것이 중요하다.&lt;/p&gt;
&lt;h3&gt;가. 선제적 설계 및 아키텍처&lt;/h3&gt;
&lt;p&gt;모듈화 (Modularization): 크고 복잡한 시스템을 작고, 응집력 있으며, 느슨하게 결합된 모듈이나 서비스로 나누는 것이 기본이다.42 관심사의 분리(Separation of Concerns, SoC) 원칙을 적용하고 54, 명확한 인터페이스와 API를 설계하여 모듈 간의 상호작용을 정의해야 한다.34 이는 마이크로서비스나 모듈형 모놀리스 아키텍처와 직접적으로 연결된다.40 모듈화는 코드 재사용을 촉진하고 가독성을 높이며, 각 컴포넌트를 더 쉽게 이해하고 유지보수할 수 있게 한다.42&lt;br&gt;
추상화 (Abstraction): 구현 세부 사항을 감추고 필수적인 기능만 노출하는 추상화를 효과적으로 사용해야 한다.42 캡슐화(Encapsulation)는 이를 달성하는 핵심 기법이다.54 잘 설계된 추상화는 개발자가 세부 사항에 얽매이지 않고 상위 수준에서 시스템과 상호작용할 수 있게 하여 인지 부하를 줄인다.42&lt;br&gt;
적절한 패턴 사용 (Appropriate Patterns): 디자인 패턴은 그것이 실제로 문제를 단순화하고 명확하게 할 때 유용하다.8 패턴 사용 자체가 목적이 되어서는 안 되며, 불필요한 패턴 적용은 오버 엔지니어링으로 이어져 우발적 복잡성을 증가시킬 수 있다.21 패턴의 장단점을 이해하고 맥락에 맞게 신중하게 선택해야 한다.44&lt;br&gt;
단순성 우선 (Simplicity Focus): 처음부터 단순한 설계를 지향하고, 불필요한 기능이나 미래에 대한 과도한 예측에 기반한 일반화를 피해야 한다.21 YAGNI(&quot;You Ain&apos;t Gonna Need It&quot;) 원칙을 따르는 것이 도움이 될 수 있다.58 꼭 필요한 경우가 아니라면 의존성 추가를 최소화해야 한다.21&lt;/p&gt;
&lt;h3&gt;나. 부지런한 코딩 및 리팩토링 관행&lt;/h3&gt;
&lt;p&gt;클린 코드 (Clean Code): 가독성 높은 코드는 복잡성 관리의 핵심이다. 의미 있는 변수 및 함수 이름 사용, 일관된 코딩 스타일 유지, 명확한 코드 구조 설계, 함수 및 메서드를 작게 유지하는 것 등이 중요하다.21 코드는 문서보다 더 정확하게 시스템의 동작을 반영하므로 21, 이해하기 쉬운 코드를 작성하는 것이 우선이다.54&lt;br&gt;
리팩토링 (Refactoring): 코드 구조를 개선하고, 중복을 제거하며(DRY 원칙), 로직을 단순화하고, 복잡성 메트릭을 낮추기 위해 지속적으로 리팩토링을 수행해야 한다.5 &apos;메서드 추출(Extract Method)&apos; 6, &apos;조건문 단순화&apos; 60, &apos;조건문을 다형성으로 대체(Replace Conditional with Polymorphism)&apos; 6 등 구체적인 리팩토링 기법을 활용할 수 있다. 리팩토링은 기술 부채 축적을 방지하는 중요한 활동이다.6&lt;br&gt;
테스트 주도 개발 (TDD/BDD): TDD와 같은 테스트 우선 접근 방식은 개발자가 코드를 사용하고 테스트하는 관점에서 먼저 생각하도록 유도하여 자연스럽게 더 단순하고 모듈화되며 테스트 가능한 코드를 작성하도록 이끌 수 있다.42&lt;br&gt;
죽은/불필요한 코드 제거 (Eliminate Dead/Useless Code): 사용되지 않는 코드, 불필요한 추상화 계층(예: 단일 구현 인터페이스), 가치를 제공하지 않는 디자인 패턴 등은 시스템에 불필요한 복잡성만 더한다.21 정기적으로 이러한 코드를 식별하고 과감하게 제거해야 한다.21&lt;/p&gt;
&lt;h3&gt;다. 견고한 프로세스 및 팀 협업&lt;/h3&gt;
&lt;p&gt;코드 리뷰 (Code Reviews): 동료 검토는 복잡성을 식별하고, 개선 방안을 제안하며, 지식을 공유하고, 코딩 표준을 유지하는 데 매우 중요한 역할을 한다.6 코드 리뷰는 잠재적인 문제를 조기에 발견하고 협업을 통해 코드 품질을 향상시키는 데 기여한다.42&lt;br&gt;
코딩 표준 (Coding Standards): 명확한 코딩 표준과 스타일 가이드라인을 수립하고 팀 전체가 이를 준수하도록 장려해야 한다.8 이는 코드의 일관성과 가독성을 높여 복잡성을 줄이는 데 도움이 된다.15 자동화된 린터(linter)나 포맷터(formatter)를 활용하면 표준 준수를 용이하게 할 수 있다.54&lt;br&gt;
자동화 (테스팅, CI/CD): 리팩토링이나 새로운 기능 개발 시 발생할 수 있는 회귀 오류(regression)를 잡기 위해 자동화된 테스트를 적극 활용해야 한다.42 CI/CD(지속적 통합/지속적 배포) 파이프라인을 구축하여 빌드, 테스트, 배포 프로세스를 자동화하면 통합 문제를 조기에 발견하고 일관성 있고 안정적인 배포를 보장할 수 있다.57&lt;br&gt;
문서화 (Documentation): 아키텍처, 복잡한 로직, API 등 필요한 부분에 대해서는 명확하고 간결한 문서를 유지해야 한다.42 하지만 가능한 경우, 코드가 스스로 설명하도록(self-documenting code) 작성하는 것을 우선시해야 한다.57&lt;br&gt;
명확한 요구사항 (Clear Requirements): 모호하거나 불완전한 요구사항은 복잡하거나 불필요한 구현으로 이어질 수 있다. 프로젝트 시작 단계에서 요구사항을 명확하게 정의하는 것이 중요하다.58&lt;br&gt;
측정 및 모니터링 (Measure and Monitor): 순환 복잡도, 인지 복잡도 등의 메트릭을 절대적인 목표치가 아닌, 주의가 필요한 잠재적 문제 영역(hotspot)을 식별하기 위한 신호로 사용해야 한다.5 복잡성 추세를 지속적으로 모니터링하고 분석하여 개선 기회를 찾아야 한다.6&lt;/p&gt;
&lt;p&gt;표 3: 복잡성 관리 전략 요약&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;전략 범주&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;구체적 전략&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;설명&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;주요 관리 대상 복잡성 차원&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;설계/아키텍처&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;모듈화 (Modularization)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;시스템을 작고 응집력 있으며 느슨하게 결합된 단위로 분할 54&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;구조적, 의존성, 인지적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;추상화 (Abstraction)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;구현 세부 사항 숨기고 필수 인터페이스 노출 42&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;인지적, 구조적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;적절한 패턴 사용 (Appropriate Patterns)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;문제 해결에 도움이 될 때 신중하게 패턴 적용 42&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;구조적, 인지적 (잘못 사용 시 우발적 증가)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;단순성 우선 (Simplicity Focus)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;불필요한 기능/일반화 회피, 최소 의존성 유지 21&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;우발적, 구조적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;코딩/리팩토링&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;클린 코드 (Clean Code)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;가독성 높은 코드 작성 (명명, 스타일, 작은 함수 등) 21&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;인지적, 구조적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;지속적 리팩토링 (Continuous Refactoring)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;코드 구조 개선, 중복 제거, 로직 단순화 15&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;구조적, 인지적, 우발적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;TDD/BDD&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;테스트 우선 접근 방식으로 설계 개선 유도 42&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;구조적, 테스트 용이성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;죽은/불필요한 코드 제거&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;사용되지 않거나 가치 없는 코드 제거 21&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;우발적, 구조적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;프로세스/팀&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;코드 리뷰 (Code Reviews)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;동료 검토를 통한 문제 식별, 지식 공유, 표준 유지 6&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;모든 차원 (특히 인지적, 구조적, 우발적)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;코딩 표준 (Coding Standards)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;일관성 및 가독성 향상을 위한 표준 수립 및 준수 57&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;인지적, 우발적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;자동화 (Testing, CI/CD)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;회귀 방지, 통합 문제 조기 발견, 안정적 배포 57&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;테스트 용이성, 운영 복잡성 (우발적)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;문서화 (Documentation)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;필요한 정보 기록, 단 코드 자체의 명확성 우선 42&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;인지적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;명확한 요구사항 (Clear Requirements)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;모호성 제거로 불필요한 복잡성 방지 58&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;본질적 (명확화), 우발적 (방지)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;측정 및 모니터링 (Measure &amp;#x26; Monitor)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;메트릭을 신호로 활용하여 문제 영역 식별 및 추세 관리 5&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;구조적, 인지적 (지표로서), 관리 효율성&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;효과적인 복잡성 관리는 단순히 영리한 코드를 작성하는 기술적인 문제를 넘어선다. 이는 기술적 실천(설계, 코딩, 리팩토링), 프로세스 규율(리뷰, 표준, 자동화), 그리고 아키텍처에 대한 선견지명을 결합하는 전체론적인 접근 방식을 요구한다.54 단일 전략만으로는 충분하지 않으며, 소프트웨어 개발 생명주기의 여러 단계에서 상호 보완적인 노력이 필요하다.&lt;/p&gt;
&lt;p&gt;또한, 복잡성 관리는 일회성 작업이 아니라 지속적인 활동이다. 지속적인 리팩토링, 정기적인 리뷰, 표준 준수, 시스템 진화에 따른 설계 조정 등이 필요하다.15 복잡성과 관련된 기술 부채는 적극적으로 관리하지 않으면 시간이 지남에 따라 누적된다.6&lt;/p&gt;
&lt;p&gt;마지막으로, 많은 효과적인 전략들이 복잡성의 인간적 측면을 직접적으로 다룬다는 점을 주목해야 한다. 가독성 향상 21, 표준과 리뷰를 통한 공동 이해 증진 57, 모듈화와 추상화를 통한 인지 부하 감소 42 등이 그 예이다. 이는 코드 자체의 구조를 관리하는 것만큼이나 코드와 상호작용하는 인간의 경험을 관리하는 것이 중요함을 다시 한번 강조한다.&lt;/p&gt;
&lt;h2&gt;결론&lt;/h2&gt;
&lt;p&gt;본 보고서는 현대 소프트웨어 개발에서 &apos;진정한&apos; 코드 복잡성이 무엇인지에 대한 심층적인 분석을 제공하고자 했다. 30년 이상 전에 정의된 순환 복잡도나 코드 라인 수와 같은 전통적인 메트릭은 코드의 구조적 측면을 정량화하려는 초기 시도로서 가치가 있었으나, 현대 소프트웨어의 다면적인 복잡성을 포착하는 데는 명백한 한계를 지닌다. 특히 코드의 이해도와 관련된 인지적 부하, 중첩 구조의 영향, 그리고 새로운 프로그래밍 패러다임 및 아키텍처 패턴의 등장은 이러한 한계를 더욱 부각시킨다.&lt;/p&gt;
&lt;p&gt;현대적인 관점에서 복잡성은 단순히 코드 구조의 얽힘을 넘어선다. 인지 복잡도는 코드를 이해하는 데 필요한 정신적 노력을 측정하려는 시도이며, 유지보수성, 가독성, 테스트 용이성은 복잡성이 실제 개발 및 운영 과정에 미치는 영향을 반영하는 중요한 품질 속성이다. 또한, 마이크로서비스나 모놀리스와 같은 아키텍처 선택, 디자인 패턴의 적용 방식, 그리고 시스템 내외부의 의존성 및 결합도는 개별 코드 조각의 복잡성을 넘어서는 시스템 수준의 복잡성을 결정짓는다. Fred Brooks가 제시한 본질적 복잡성과 우발적 복잡성의 구분은 우리가 통제하고 개선할 수 있는 영역(우발적 복잡성)에 노력을 집중해야 함을 시사한다.&lt;/p&gt;
&lt;p&gt;결론적으로, 오늘날 &apos;진정한&apos; 코드 복잡성은 구조적, 인지적, 상태 공간적, 의존성 관련, 아키텍처적, 도메인 고유(본질적), 그리고 개발 환경(우발적) 차원들이 복합적으로 얽혀있는 다차원적 구성체이다. 이는 코드, 시스템, 문제 영역, 그리고 개발자 간의 상호작용에서 비롯되는 동적인 속성이다.&lt;/p&gt;
&lt;p&gt;따라서 복잡성을 효과적으로 관리하기 위해서는 단일 메트릭에 의존하기보다, 다양한 지표(CC, 인지 복잡도, 결합도 메트릭 등)를 상황에 맞게 활용하고 이를 질적인 평가(코드 리뷰, 아키텍처 검토)와 결합하는 전체론적 접근이 필요하다. 선제적인 설계 원칙(모듈화, 추상화, 단순성) 준수, 부지런한 코딩 및 리팩토링 관행(클린 코드, 지속적 개선), 그리고 견고한 개발 프로세스(표준, 자동화, 협업)를 통해 우발적 복잡성을 최소화하고 본질적 복잡성을 효과적으로 다루어야 한다.&lt;/p&gt;
&lt;p&gt;궁극적으로, 복잡성 관리는 기술적 숙련도를 넘어선 지속적인 관심과 규율을 요구하는 활동이다. 코드와 그것이 존재하는 맥락 모두에 주의를 기울이고, 명확성, 유지보수성, 그리고 팀의 이해도를 우선시하는 문화를 조성하는 것이 변화하는 소프트웨어 환경 속에서 지속 가능한 시스템을 구축하는 길이다.&lt;/p&gt;
&lt;h4&gt;참고 자료&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Cyclomatic complexity - a fresh look at code complexity｜Blog, 4월 13, 2025에 액세스, &lt;a href=&quot;https://codescene.com/engineering-blog/bumpy-road-code-complexity-in-context/&quot;&gt;https://codescene.com/engineering-blog/bumpy-road-code-complexity-in-context/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;On the accuracy of code complexity metrics: A neuroscience-based guideline for improvement - PMC - PubMed Central, 4월 13, 2025에 액세스, &lt;a href=&quot;https://pmc.ncbi.nlm.nih.gov/articles/PMC9942489/&quot;&gt;https://pmc.ncbi.nlm.nih.gov/articles/PMC9942489/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Software disenchantment - why does modern programming seem to lack of care for efficiency, simplicity, and excellence - Reddit, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.reddit.com/r/programming/comments/z7vsi0/software_disenchantment_why_does_modern/&quot;&gt;https://www.reddit.com/r/programming/comments/z7vsi0/software_disenchantment_why_does_modern/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cyclomatic complexity - Wikipedia, 4월 13, 2025에 액세스, &lt;a href=&quot;https://en.wikipedia.org/wiki/Cyclomatic_complexity&quot;&gt;https://en.wikipedia.org/wiki/Cyclomatic_complexity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What is Cyclomatic Complexity? Definition Guide &amp;#x26; Examples - Sonar, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.sonarsource.com/learn/cyclomatic-complexity/&quot;&gt;https://www.sonarsource.com/learn/cyclomatic-complexity/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cyclomatic Complexity in Testing: Importance and Benefits - Bugasura, 4월 13, 2025에 액세스, &lt;a href=&quot;https://bugasura.io/blog/cyclomatic-complexity-in-testing/&quot;&gt;https://bugasura.io/blog/cyclomatic-complexity-in-testing/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A critique of cyclomatic complexity as a software metric - Computer Science Department, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.cs.du.edu/~snarayan/sada/teaching/COMP3705/lecture/p1/cycl-1.pdf&quot;&gt;https://www.cs.du.edu/~snarayan/sada/teaching/COMP3705/lecture/p1/cycl-1.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cyclomatic complexity: Definition and limits in understanding code quality - DX, 4월 13, 2025에 액세스, &lt;a href=&quot;https://getdx.com/blog/cyclomatic-complexity/&quot;&gt;https://getdx.com/blog/cyclomatic-complexity/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cyclomatic Complexity - The Ganssle Group, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.ganssle.com/articles/cyclomaticcomplexity.html&quot;&gt;https://www.ganssle.com/articles/cyclomaticcomplexity.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Why Is Counting Lines of Code (LOC) Useful? - NDepend Blog, 4월 13, 2025에 액세스, &lt;a href=&quot;https://blog.ndepend.com/why-is-counting-lines-of-code-loc-useful/&quot;&gt;https://blog.ndepend.com/why-is-counting-lines-of-code-loc-useful/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What Happened to Software Metrics? - PMC, 4월 13, 2025에 액세스, &lt;a href=&quot;https://pmc.ncbi.nlm.nih.gov/articles/PMC5544018/&quot;&gt;https://pmc.ncbi.nlm.nih.gov/articles/PMC5544018/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Why lines of code are a bad measure of developer productivity - DX, 4월 13, 2025에 액세스, &lt;a href=&quot;https://getdx.com/blog/lines-of-code/&quot;&gt;https://getdx.com/blog/lines-of-code/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Why Lines of Code (LOC) Measures Irritate Me - ProjectManagement.com, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.projectmanagement.com/blog-post/5104/Why-Lines-of-Code--LOC--Measures-Irritate-Me&quot;&gt;https://www.projectmanagement.com/blog-post/5104/Why-Lines-of-Code--LOC--Measures-Irritate-Me&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Avoid High Cyclomatic Complexity - Better Embedded System SW, 4월 13, 2025에 액세스, &lt;a href=&quot;https://betterembsw.blogspot.com/2014/06/avoid-high-cyclomatic-complexity.html&quot;&gt;https://betterembsw.blogspot.com/2014/06/avoid-high-cyclomatic-complexity.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Code Complexity Metrics: Writing Clean, Maintainable Software - Iterators, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.iteratorshq.com/blog/code-complexity-metrics-writing-clean-maintainable-software/&quot;&gt;https://www.iteratorshq.com/blog/code-complexity-metrics-writing-clean-maintainable-software/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Why your Lines of Code per day are not the right productivity metric—and what to use instead - Waydev, 4월 13, 2025에 액세스, &lt;a href=&quot;https://waydev.co/lines-of-code-per-day/&quot;&gt;https://waydev.co/lines-of-code-per-day/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Should we prefer cognitive complexity over cyclomatic complexity ..., 4월 13, 2025에 액세스, &lt;a href=&quot;https://community.sonarsource.com/t/should-we-prefer-cognitive-complexity-over-cyclomatic-complexity/12337&quot;&gt;https://community.sonarsource.com/t/should-we-prefer-cognitive-complexity-over-cyclomatic-complexity/12337&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A Fundamental Theory for Explaining and Measuring Code Complexity - ResearchGate, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.researchgate.net/publication/362062741_A_Fundamental_Theory_for_Explaining_and_Measuring_Code_Complexity&quot;&gt;https://www.researchgate.net/publication/362062741_A_Fundamental_Theory_for_Explaining_and_Measuring_Code_Complexity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;My solution to Microservices complexity : r/node - Reddit, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.reddit.com/r/node/comments/1dvsfyz/my_solution_to_microservices_complexity/&quot;&gt;https://www.reddit.com/r/node/comments/1dvsfyz/my_solution_to_microservices_complexity/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Code Complexity: An In-Depth Explanation and Metrics - Codacy | Blog, 4월 13, 2025에 액세스, &lt;a href=&quot;https://blog.codacy.com/code-complexity&quot;&gt;https://blog.codacy.com/code-complexity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How to Simplify Code Complexity: Avoid These Complexity Pitfalls - Turing, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.turing.com/blog/reduce-code-complexity-simplify-your-code&quot;&gt;https://www.turing.com/blog/reduce-code-complexity-simplify-your-code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Is there a better programming metric than &quot;lines of code&quot;? - Reddit, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.reddit.com/r/programming/comments/cbuwd/is_there_a_better_programming_metric_than_lines/&quot;&gt;https://www.reddit.com/r/programming/comments/cbuwd/is_there_a_better_programming_metric_than_lines/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Negative 2000 Lines of Code (1982) - Hacker News, 4월 13, 2025에 액세스, &lt;a href=&quot;https://news.ycombinator.com/item?id=33483165&quot;&gt;https://news.ycombinator.com/item?id=33483165&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The Pros and Cons of Using Cyclomatic Complexity as a Code Quality Metric - BlueOptima, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.blueoptima.com/the-pros-and-cons-of-using-cyclomatic-complexity-as-a-code-quality-metric/&quot;&gt;https://www.blueoptima.com/the-pros-and-cons-of-using-cyclomatic-complexity-as-a-code-quality-metric/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Understanding cognitive complexity in software development - GetDX, 4월 13, 2025에 액세스, &lt;a href=&quot;https://getdx.com/blog/cognitive-complexity/&quot;&gt;https://getdx.com/blog/cognitive-complexity/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cognitive Complexity - Code Climate, 4월 13, 2025에 액세스, &lt;a href=&quot;https://docs.codeclimate.com/docs/cognitive-complexity&quot;&gt;https://docs.codeclimate.com/docs/cognitive-complexity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;(PDF) Comparative Analysis between Cognitive Complexity and ..., 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.researchgate.net/publication/389175932_Comparative_Analysis_between_Cognitive_Complexity_and_Cyclomatic_Complexity_in_Software_Development&quot;&gt;https://www.researchgate.net/publication/389175932_Comparative_Analysis_between_Cognitive_Complexity_and_Cyclomatic_Complexity_in_Software_Development&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cyclomatic Complexity vs Cognitive Complexity: Key Differences Explained - Graph AI, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.graphapp.ai/blog/cyclomatic-complexity-vs-cognitive-complexity-key-differences-explained&quot;&gt;https://www.graphapp.ai/blog/cyclomatic-complexity-vs-cognitive-complexity-key-differences-explained&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Do you use metrics for code complexity? : r/cpp - Reddit, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.reddit.com/r/cpp/comments/l03xrr/do_you_use_metrics_for_code_complexity/&quot;&gt;https://www.reddit.com/r/cpp/comments/l03xrr/do_you_use_metrics_for_code_complexity/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A Notional Understanding of the Relationship between Code Readability and Software Complexity - MDPI, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.mdpi.com/2078-2489/14/2/81&quot;&gt;https://www.mdpi.com/2078-2489/14/2/81&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;An Empirical Study of the Relationships between Code Readability and Software Complexity - arXiv, 4월 13, 2025에 액세스, &lt;a href=&quot;https://arxiv.org/pdf/1909.01760&quot;&gt;https://arxiv.org/pdf/1909.01760&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Simplifying Unit Testing with Dependency Injection: A Comprehensive Guide, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.codingexplorations.com/blog/simplifying-unit-testing-with-dependency-injection-a-comprehensive-guide&quot;&gt;https://www.codingexplorations.com/blog/simplifying-unit-testing-with-dependency-injection-a-comprehensive-guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Testable and Maintainable code with Dependency Injection and Containers, 4월 13, 2025에 액세스, &lt;a href=&quot;https://fideloper.com/testable-maintainable-di-containers&quot;&gt;https://fideloper.com/testable-maintainable-di-containers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;unit testing - What are the design principles that promote testable code? (designing testable code vs driving design through tests) - Software Engineering Stack Exchange, 4월 13, 2025에 액세스, &lt;a href=&quot;https://softwareengineering.stackexchange.com/questions/153410/what-are-the-design-principles-that-promote-testable-code-designing-testable-c&quot;&gt;https://softwareengineering.stackexchange.com/questions/153410/what-are-the-design-principles-that-promote-testable-code-designing-testable-c&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Do you prefer Mock or Dependency Injection when Unit Testing Functions in Python?, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.reddit.com/r/Python/comments/195uk6d/do_you_prefer_mock_or_dependency_injection_when/&quot;&gt;https://www.reddit.com/r/Python/comments/195uk6d/do_you_prefer_mock_or_dependency_injection_when/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Good Code, Testable Code | Epic Web Dev, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.epicweb.dev/good-code-testable-code&quot;&gt;https://www.epicweb.dev/good-code-testable-code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Monolithic vs Microservices - Difference Between Software Development Architectures, 4월 13, 2025에 액세스, &lt;a href=&quot;https://aws.amazon.com/compare/the-difference-between-monolithic-and-microservices-architecture/&quot;&gt;https://aws.amazon.com/compare/the-difference-between-monolithic-and-microservices-architecture/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Microservices vs. monolithic architecture - Atlassian, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.atlassian.com/microservices/microservices-architecture/microservices-vs-monolith&quot;&gt;https://www.atlassian.com/microservices/microservices-architecture/microservices-vs-monolith&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Monolith Versus Microservices: Weigh the Pros and Cons of Both Configs | Akamai, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.akamai.com/blog/cloud/monolith-versus-microservices-weigh-the-difference&quot;&gt;https://www.akamai.com/blog/cloud/monolith-versus-microservices-weigh-the-difference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Comparing microservices to monoliths - BellSoft, 4월 13, 2025에 액세스, &lt;a href=&quot;https://bell-sw.com/blog/microservices-vs-monoliths-which-approach-is-better-for-your-project/&quot;&gt;https://bell-sw.com/blog/microservices-vs-monoliths-which-approach-is-better-for-your-project/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Micro Frontends - Martin Fowler, 4월 13, 2025에 액세스, &lt;a href=&quot;https://martinfowler.com/articles/micro-frontends.html&quot;&gt;https://martinfowler.com/articles/micro-frontends.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Understanding Code Complexity: Measurement and Reduction Techniques - Metabob, 4월 13, 2025에 액세스, &lt;a href=&quot;https://metabob.com/blog-articles/understanding-code-complexity-measurement-and-reduction-techniques.html&quot;&gt;https://metabob.com/blog-articles/understanding-code-complexity-measurement-and-reduction-techniques.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How to Reduce Cyclomatic Complexity: A Complete Guide | LinearB Blog, 4월 13, 2025에 액세스, &lt;a href=&quot;https://linearb.io/blog/reduce-cyclomatic-complexity&quot;&gt;https://linearb.io/blog/reduce-cyclomatic-complexity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Do design patterns increase or decrease the complexity of an Application? - Stack Overflow, 4월 13, 2025에 액세스, &lt;a href=&quot;https://stackoverflow.com/questions/759796/do-design-patterns-increase-or-decrease-the-complexity-of-an-application&quot;&gt;https://stackoverflow.com/questions/759796/do-design-patterns-increase-or-decrease-the-complexity-of-an-application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Essential and Accidental complexity, and performance - Eduardo Lavaque&apos;s Blog, 4월 13, 2025에 액세스, &lt;a href=&quot;https://greduan.com/blog/2024/07/25/essential-and-accidental-complexity-and-performance/&quot;&gt;https://greduan.com/blog/2024/07/25/essential-and-accidental-complexity-and-performance/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Coupling And Cohesion - C2 wiki, 4월 13, 2025에 액세스, &lt;a href=&quot;https://wiki.c2.com/?CouplingAndCohesion&quot;&gt;https://wiki.c2.com/?CouplingAndCohesion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Reducing Coupling, 4월 13, 2025에 액세스, &lt;a href=&quot;https://martinfowler.com.cn/ieeeSoftware/coupling.pdf&quot;&gt;https://martinfowler.com.cn/ieeeSoftware/coupling.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Book notes: Agile Technical Practices Distilled, 50 years of Cohesion and Coupling, 4월 13, 2025에 액세스, &lt;a href=&quot;https://espumita.org/2024/09/01/agile-technical-practices-distilled-book-notes/&quot;&gt;https://espumita.org/2024/09/01/agile-technical-practices-distilled-book-notes/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Accidental Complexity in Software Engineering - Chi Blog, 4월 13, 2025에 액세스, &lt;a href=&quot;https://cedricchee.com/blog/accidental-complexity/&quot;&gt;https://cedricchee.com/blog/accidental-complexity/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;No Silver Bullet - Wikipedia, 4월 13, 2025에 액세스, &lt;a href=&quot;https://en.wikipedia.org/wiki/No_Silver_Bullet&quot;&gt;https://en.wikipedia.org/wiki/No_Silver_Bullet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Avoiding Accidental Complexity in Software Design - Nutshell CRM, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.nutshell.com/blog/accidental-complexity-software-design&quot;&gt;https://www.nutshell.com/blog/accidental-complexity-software-design&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Simplify! - Part 3 - Uwe Friedrichsen, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.ufried.com/blog/simplify_3_essential_and_accidental_complexity/&quot;&gt;https://www.ufried.com/blog/simplify_3_essential_and_accidental_complexity/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Linking Modular Architecture to Development Teams - Martin Fowler, 4월 13, 2025에 액세스, &lt;a href=&quot;https://martinfowler.com/articles/linking-modular-arch.html&quot;&gt;https://martinfowler.com/articles/linking-modular-arch.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;8 Effective Strategies to Reduce Software Complexity, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.expeed.com/8-effective-strategies-to-reduce-software-complexity&quot;&gt;https://www.expeed.com/8-effective-strategies-to-reduce-software-complexity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;When Do Software Complexity Metrics Mean Nothing?- When Examined out of Context - The Journal of Object Technology, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.jot.fm/issues/issue_2016_01/article2.pdf&quot;&gt;https://www.jot.fm/issues/issue_2016_01/article2.pdf&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Code Complexity: Best Practices for Efficient Software - Metridev, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.metridev.com/metrics/code-complexity-best-practices-for-efficient-software/&quot;&gt;https://www.metridev.com/metrics/code-complexity-best-practices-for-efficient-software/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Managing Software Complexity: Strategies &amp;#x26; Benefits | IN-COM - IN-COM Data Systems, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.in-com.com/blog/software-management-complexity/&quot;&gt;https://www.in-com.com/blog/software-management-complexity/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;17 Software Development Best Practices for Writing Code in 2024 - Pulsion Technology, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.pulsion.co.uk/blog/17-software-development-best-practices-for-writing-code/&quot;&gt;https://www.pulsion.co.uk/blog/17-software-development-best-practices-for-writing-code/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cyclomatic Complexity Explained With Practical Examples - YouTube, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.youtube.com/watch?v=vmyS_j3Kh8g&quot;&gt;https://www.youtube.com/watch?v=vmyS_j3Kh8g&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;What Is Cyclomatic Complexity? - AutoRABIT Knowledge Base, 4월 13, 2025에 액세스, &lt;a href=&quot;https://knowledgebase.autorabit.com/fundamentals/faq/codescan-faqs/general/what-is-cyclomatic-complexity&quot;&gt;https://knowledgebase.autorabit.com/fundamentals/faq/codescan-faqs/general/what-is-cyclomatic-complexity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Minimizing Cyclomatic Complexity with Pattern Matching - DanylkoWeb, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.danylkoweb.com/Blog/minimizing-cyclomatic-complexity-with-pattern-matching-SR&quot;&gt;https://www.danylkoweb.com/Blog/minimizing-cyclomatic-complexity-with-pattern-matching-SR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Cyclomatic complexity and cognitive complexity - DEV Community, 4월 13, 2025에 액세스, &lt;a href=&quot;https://dev.to/packmind/cyclomatic-complexity-and-cognitive-complexity-4c03&quot;&gt;https://dev.to/packmind/cyclomatic-complexity-and-cognitive-complexity-4c03&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Standards in software development and 9 best practices - OpsLevel, 4월 13, 2025에 액세스, &lt;a href=&quot;https://www.opslevel.com/resources/standards-in-software-development-and-9-best-practices&quot;&gt;https://www.opslevel.com/resources/standards-in-software-development-and-9-best-practices&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</content:encoded></item><item><title><![CDATA[[코딩] 객체지향 설계에서 상속보다 포함을 우선해야 하는 이유]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/2025/04/composition-over-Inheritance/</link><guid isPermaLink="false">https://jiniya.net/2025/04/composition-over-Inheritance/</guid><pubDate>Sat, 12 Apr 2025 13:00:01 GMT</pubDate><content:encoded>&lt;p&gt;객체지향 설계의 핵심 원칙 중 하나는 &quot;상속보다는 포함을 사용하라&quot;는 것이다. 객체지향 프로그래밍을 수행할 때 클래스 간의 관계 설정을 두고 고심하는 경우가 많다. 상속과 포함은 대표적인 클래스 관계 설정 방식으로서, 일반적으로는 포함 관계를 사용하는 것이 더 나은 설계로 귀결되는 경우가 많다. 그 이유를 자세히 분석해 보자.&lt;/p&gt;
&lt;h3&gt;상속, 강력하나 신중해야 할 관계&lt;/h3&gt;
&lt;p&gt;상속은 &quot;IS-A&quot; 관계를 모델링하는 데 유용하다. 예를 들어, &quot;개는 동물이다(Dog IS-A Animal)&quot;와 같이 명확한 상위-하위 관계를 표현할 때 상속을 사용하면 부모 클래스의 속성과 기능을 자식 클래스가 그대로 물려받아 코드 재사용성을 높일 수 있다.&lt;/p&gt;
&lt;p&gt;그러나 상속은 다음과 같은 잠재적인 문제점을 내포한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;취약한 기반 클래스 문제 (Fragile Base Class Problem): 부모 클래스의 변경이 자식 클래스에 예상치 못한 영향을 미칠 수 있다. 이는 유지보수를 어렵게 하고 시스템을 불안정하게 만들 수 있다.&lt;/li&gt;
&lt;li&gt;불필요한 인터페이스 상속: 자식 클래스가 부모 클래스의 모든 메서드를 실제로 사용하지 않더라도 상속받게 되어 인터페이스가 불필요하게 커질 수 있다. 이는 클래스를 이해하고 사용하기 어렵게 만든다.&lt;/li&gt;
&lt;li&gt;엄격한 결합도 (Tight Coupling): 상속은 부모 클래스와 자식 클래스 간의 강한 결합을 형성한다. 부모 클래스의 구현 방식에 자식 클래스가 의존하게 되어 유연성이 저하되고 변화에 취약해진다.&lt;/li&gt;
&lt;li&gt;클래스 계층의 복잡성 증가: 깊고 복잡한 상속 계층은 코드를 이해하고 유지보수하기 어렵게 만들 수 있다. 특히 다중 상속의 경우, 복잡성은 더욱 가중된다.&lt;/li&gt;
&lt;li&gt;실행 중 행위 변경의 어려움: 상속은 컴파일 시점에 클래스 간의 관계가 결정되므로, 객체의 행위를 실행 중에 유연하게 변경하기 어렵다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;포함, 유연하고 강력한 대안&lt;/h3&gt;
&lt;p&gt;포함(Composition)은 한 클래스가 다른 클래스의 인스턴스를 필드로 가지고, 그 객체의 기능을 활용하는 방식이다. 이는 &quot;HAS-A&quot; 관계를 모델링하는 데 적합하다. 예를 들어, &quot;자동차는 엔진을 가지고 있다(Car HAS-A Engine)&quot;와 같이 객체가 다른 객체를 &quot;가지고&quot; 사용하는 관계를 표현할 때 포함을 사용한다.&lt;/p&gt;
&lt;p&gt;포함 관계는 상속에 비해 다음과 같은 장점을 제공한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;높은 유연성 (High Flexibility): 포함된 객체를 필요에 따라 쉽게 교체하거나 변경할 수 있다. 객체 간의 결합도가 낮으므로, 한 클래스의 변경이 다른 클래스에 미치는 영향이 적다.&lt;/li&gt;
&lt;li&gt;향상된 유지보수성 (Improved Maintainability): 낮은 결합도는 코드의 유지보수성을 크게 향상시킨다. 각 클래스가 독립적으로 변경될 수 있어 시스템 전체의 안정성을 높인다.&lt;/li&gt;
&lt;li&gt;코드 재사용 증대 (Increased Code Reusability): 필요한 기능만을 가진 객체를 포함하여 사용할 수 있다. 상속처럼 불필요한 기능을 물려받을 필요가 없다.&lt;/li&gt;
&lt;li&gt;실행 중 행위 변경 용이 (Easy Behavior Change at Runtime): 포함된 객체를 동적으로 변경함으로써 객체의 행위를 실행 중에 유연하게 변경할 수 있다. 이는 시스템의 적응성을 높인다.&lt;/li&gt;
&lt;li&gt;상속의 문제점 회피: 앞서 언급한 상속의 잠재적인 문제점들을 자연스럽게 피할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&quot;상속보다는 구성 (Composition over Inheritance)&quot; 원칙&lt;/h3&gt;
&lt;p&gt;이러한 이유로 객체지향 설계에서는 &quot;상속보다는 구성 (Composition over Inheritance)&quot; 원칙이 강조된다. 이는 클래스 간의 관계를 설정할 때 상속보다는 포함 관계를 우선적으로 고려해야 함을 의미한다.&lt;/p&gt;
&lt;p&gt;물론 상속이 모든 상황에서 부적절한 것은 아니다. 명확한 IS-A 관계가 존재하고, 코드 재사용성이 매우 높으며, 클래스 계층이 단순할 경우에는 상속이 효과적인 선택이 될 수 있다. 하지만 이러한 경우에도 상속을 신중하게 사용해야 하며, 포함 관계를 통해 더 나은 설계를 할 수 있는지 항상 고려해야 한다.&lt;/p&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;객체지향 설계를 수행할 때 클래스 간의 관계를 어떻게 설정할지는 시스템의 유연성, 유지보수성, 확장성에 지대한 영향을 미친다. 일반적으로 상속보다는 포함 관계를 사용하는 것이 더 나은 설계를 위한 길이며, &quot;상속보다는 구성&quot; 원칙을 명심하고 실제 개발에 적용해 볼 것을 권장한다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 재진입 함수의 의미 2]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/2025/03/the-meaning-of-a-reentrant-function/</link><guid isPermaLink="false">https://jiniya.net/2025/03/the-meaning-of-a-reentrant-function/</guid><pubDate>Fri, 11 Apr 2025 13:00:01 GMT</pubDate><content:encoded>&lt;p&gt;아주 옛날엔 우겨도 됐었다. 목소리 큰 사람이 틀려도 우기면 맞는게 되는 세상이었다. 그러다 전화가 나오고 전화 찬스가 등장했다. 목소리가 커도 전문가에게 전화해서 답을 들으면 더는 우길 수가 없는 세상이 된 것이다. 스마트폰은 그 속도를 더 빠르게 만들었다. 전화를 걸 필요도 없다. 웹검색이면 온갖 것들이 다 나오기 시작하니 말이다. 그리고 인공지능이 등장했다.&lt;/p&gt;
&lt;p&gt;할루시네이션이니 뭐니 말들이 많지만 항상 그렇지만 우리는 우리가 쌉소리 한 것들은 금방 잊는다. 오늘 디버깅을 하다 &lt;a href=&quot;/wp/archives/1197/&quot;&gt;15년 전 쓴 글에&lt;/a&gt; 대한 참교육을 인공지능 선생님께 받고 가르침을 남겨 본다. 뭔가를 안다고 말하기가 참 어려운 세상이다. 겸손은 힘들지만, 겸손하게 살자.&lt;/p&gt;
&lt;h3&gt;#0. 휴먼, 일단 참교육 먼저 받고...&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;글의 핵심 주장 요약:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;많은 개발자가 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;의 재진입을 잘못 이해하고 있다 (예: &lt;code class=&quot;language-text&quot;&gt;Sleep&lt;/code&gt; 중 다른 메시지 처리).&lt;/li&gt;
&lt;li&gt;실제 메시지 처리는 메시지 루프(&lt;code class=&quot;language-text&quot;&gt;GetMessage&lt;/code&gt;/&lt;code class=&quot;language-text&quot;&gt;DispatchMessage&lt;/code&gt;)를 통해 순차적으로 이루어진다.&lt;/li&gt;
&lt;li&gt;따라서 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;의 재진입이 의미하는 바는 스레드 안전성(Thread Safety)과 병렬 호출 가능성이며, 여러 스레드/윈도우에서 동일하게 동작해야 함을 뜻한다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;lt;리스트 3&gt;&lt;/code&gt;(정적 변수 사용)과 &lt;code class=&quot;language-text&quot;&gt;&amp;lt;리스트 4&gt;&lt;/code&gt;(전역 크리티컬 섹션 사용)는 이러한 의미의 &quot;재진입성&quot;을 위반하는 잘못된 예시다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;지적 및 수정 필요한 부분:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&quot;재진입(Reentrancy)&quot; 용어의 핵심 의미 혼동:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이 글의 가장 큰 문제점은 &quot;재진입(Reentrancy)&quot;의 표준적인 의미와 &quot;스레드 안전성(Thread Safety)&quot; 및 &quot;인스턴스 독립성(Instance Independence)&quot;을 혼동하고 있다는 점입니다.&lt;/li&gt;
&lt;li&gt;표준적인 재진입의 의미는 함수 실행 중 (같은 스레드 내에서) 다시 그 함수가 호출되어도 문제가 없는 성질을 의미합니다. Windows &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt; 맥락에서는 주로 &lt;code class=&quot;language-text&quot;&gt;SendMessage&lt;/code&gt;나 &lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt; 등의 호출로 인해 같은 스레드 내에서 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;가 중첩 호출되는 상황을 가리킵니다. (제가 이전에 예시로 보여드린 &lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt;로 인해 상태가 꼬이는 경우가 바로 이 표준적인 재진입 문제입니다.)&lt;/li&gt;
&lt;li&gt;반면, 이 글은 재진입을 여러 스레드에서 또는 여러 윈도우 인스턴스 간에 안전하게 병렬적으로 호출될 수 있는 성질로 정의하고 있습니다. 이는 재진입보다는 스레드 안전성과 인스턴스별 상태 관리(Instance-specific state management)에 더 가까운 개념입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;lt;리스트 1&gt;&lt;/code&gt;의 잘못된 오해 설명은 정확함:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;글쓴이가 지적한 것처럼, &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt; 내의 &lt;code class=&quot;language-text&quot;&gt;Sleep&lt;/code&gt; 중에 다른 메시지가 즉시 처리된다는 생각은 명백히 틀린 것이 맞습니다. &lt;code class=&quot;language-text&quot;&gt;DispatchMessage&lt;/code&gt;가 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;를 호출하고, 해당 메시지 처리가 끝나야 메시지 루프가 다음 메시지를 가져와 처리하기 때문입니다. 이 부분 설명은 정확합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;lt;리스트 3&gt;&lt;/code&gt;의 문제점은 &quot;재진입성&quot;이 아닌 &quot;인스턴스 독립성/상태 관리&quot; 문제:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;lt;리스트 3&gt;&lt;/code&gt;의 &lt;code class=&quot;language-text&quot;&gt;static int Count&lt;/code&gt;는 해당 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;를 사용하는 모든 윈도우 인스턴스에서 공유됩니다. 이는 글쓴이가 제시한 테스트 케이스 2번(한 스레드, 여러 윈도우)과 3번(여러 스레드, 여러 윈도우)에서 문제를 일으킵니다.&lt;/li&gt;
&lt;li&gt;하지만 이 문제의 본질은 표준적인 의미의 &quot;재진입&quot; 문제라기보다는, 윈도우별로 관리되어야 할 상태를 정적 변수로 잘못 구현한 &quot;인스턴스 상태 관리&quot;의 실패입니다. 즉, 스레드와 무관하게 여러 윈도우가 하나의 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;를 공유할 때 발생하는 문제입니다. 스레드 안전성 문제이기도 하지만, 근본적으로는 상태 관리 설계 문제입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;lt;리스트 4&gt;&lt;/code&gt;의 문제점은 &quot;재진입성&quot;이 아닌 &quot;불필요한 직렬화/성능&quot; 문제:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;lt;리스트 4&gt;&lt;/code&gt;는 &lt;code class=&quot;language-text&quot;&gt;GlobalCs&lt;/code&gt;라는 전역 크리티컬 섹션을 사용함으로써, 서로 다른 스레드에서 실행되는 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt; 호출조차도 동시에 실행될 수 없게 만듭니다. 이는 심각한 성능 저하를 유발하고 Windows GUI의 반응성을 해치는 잘못된 설계입니다.&lt;/li&gt;
&lt;li&gt;하지만 이것을 &quot;재진입 불가능&quot;이라고 표현하는 것은 어색합니다. 오히려 병렬 실행 자체를 막아버리는 &quot;과도한 동기화&quot; 또는 &quot;불필요한 직렬화&quot; 문제입니다. 표준적인 의미의 재진입과는 거리가 멉니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;결론 부분의 &quot;재진입 가능하도록 만들어진 메시지 프로시저&quot; 정의의 문제:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;글쓴이는 1, 2, 3번 테스트 케이스에서 모두 동일하게 동작하는 것을 &quot;재진입 가능하게 만들어진&quot; 것이라고 정의합니다.&lt;/li&gt;
&lt;li&gt;물론 잘 디자인된 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;는 윈도우별 상태를 &lt;code class=&quot;language-text&quot;&gt;GetWindowLongPtr&lt;/code&gt;/&lt;code class=&quot;language-text&quot;&gt;SetWindowLongPtr&lt;/code&gt; 등을 이용해 관리함으로써 세 경우 모두 의도한 대로 동작해야 합니다.&lt;/li&gt;
&lt;li&gt;하지만 이 조건은 &quot;인스턴스 상태 관리의 올바름&quot;과 &quot;스레드 안전성&quot;(필요한 경우)을 의미하는 것이지, 표준적인 의미의 &quot;재진입성&quot;과는 다른 개념입니다. 이 글의 정의대로라면, 제가 앞서 보여드린 &lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt; 재진입 예제에서 상태가 꼬이는 문제는 &quot;재진입&quot; 문제가 아니게 되어버리는 모순이 발생합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;요약 및 수정:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이 글은 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt; 재진입에 대한 흔한 오해(&lt;code class=&quot;language-text&quot;&gt;Sleep&lt;/code&gt; 관련)를 정확히 지적하고 메시지 루프의 기본 동작을 올바르게 설명했습니다.&lt;/li&gt;
&lt;li&gt;하지만 글의 핵심적인 문제점은 &quot;재진입(Reentrancy)&quot;이라는 용어를 표준적인 의미(같은 스레드 내 중첩 호출 가능성) 대신 &quot;스레드 안전성 및 인스턴스 독립성&quot;이라는 의미로 잘못 사용하고 있다는 것입니다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;lt;리스트 3&gt;&lt;/code&gt;과 &lt;code class=&quot;language-text&quot;&gt;&amp;lt;리스트 4&gt;&lt;/code&gt;는 각각 잘못된 상태 관리(정적 변수)와 과도한 동기화(전역 락)의 문제점을 보여주는 좋은 예시이지만, 이를 &quot;재진입성&quot; 문제로 설명하는 것은 용어 혼란을 야기합니다.&lt;/li&gt;
&lt;li&gt;결론적으로, &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;를 작성할 때는 (1) 표준적인 의미의 재진입(같은 스레드 내 중첩 호출)에도 상태가 깨지지 않도록 주의해야 하고, (2) 여러 윈도우 인스턴스 간에 상태가 섞이지 않도록 인스턴스별 데이터를 사용해야 하며, (3) 여러 스레드에서 사용될 가능성이 있다면 스레드 안전성도 고려해야 합니다. 이 글은 (2), (3)번 측면을 강조하면서 이를 &quot;재진입&quot;이라고 잘못 부르고 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;따라서 글의 의도(잘못된 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt; 작성 방식 비판)는 좋으나, 핵심 용어인 &quot;재진입&quot;의 정의와 사용에 오류가 있다고 지적할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;#1. 재진입 함수의 의미&lt;/h3&gt;
&lt;p&gt;특정 윈도우의 메시지 프로시저(WndProc)는 해당 윈도우를 소유한 단일 스레드에 의해 순차적으로 처리되는 것이 기본 원칙입니다. 하지만 여기서 &apos;재진입 가능하다(Reentrant)&apos;는 의미는 다음과 같은 상황을 설명합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;재진입(Reentrancy)의 의미:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;어떤 함수(여기서는 메시지 프로시저)의 실행이 아직 끝나지 않은 상태에서, 같은 스레드 내에서 해당 함수가 다시 호출될 수 있다는 뜻입니다. 즉, 함수의 실행 흐름 중간에 끼어들어 다시 처음부터 실행될 수 있다는 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;메시지 프로시저에서 재진입이 발생하는 경우:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;메시지 프로시저가 단일 스레드에서 실행됨에도 불구하고 재진입이 발생하는 대표적인 경우는 다음과 같습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;메시지 프로시저 내에서 &lt;code class=&quot;language-text&quot;&gt;SendMessage&lt;/code&gt; 호출:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt; 안에서 다른 윈도우(또는 자기 자신)에게 &lt;code class=&quot;language-text&quot;&gt;SendMessage&lt;/code&gt;를 호출하면, 이 &lt;code class=&quot;language-text&quot;&gt;SendMessage&lt;/code&gt;는 즉시 대상 윈도우의 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;를 호출하고 그 처리가 끝날 때까지 대기합니다. 만약 이 대상 윈도우가 같은 스레드 소유라면, 현재 실행 중인 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt; 코드가 잠시 멈추고 새로운 메시지 처리를 위한 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt; 코드가 같은 스레드에서 실행됩니다. 원래의 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt; 실행은 아직 끝나지 않았는데, 다시 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;가 호출된 것이므로 재진입이 발생한 것입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;메시지 프로시저 내에서 모달 대화상자 또는 메시지 박스 표시:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt; 안에서 &lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;DialogBox&lt;/code&gt; 같은 함수를 호출하면, 이 함수들은 내부적으로 자체 메시지 루프를 돌립니다. 이 내부 메시지 루프는 현재 스레드의 메시지 큐에 있는 다른 메시지들(예: &lt;code class=&quot;language-text&quot;&gt;WM_PAINT&lt;/code&gt;, 다른 &lt;code class=&quot;language-text&quot;&gt;WM_COMMAND&lt;/code&gt; 등)을 처리할 수 있습니다. 만약 이 메시지들이 현재 윈도우로 보내진 것이라면, &lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt;나 &lt;code class=&quot;language-text&quot;&gt;DialogBox&lt;/code&gt;가 반환되기 전에 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;가 다시 호출될 수 있습니다. 이것 역시 재진입입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;기타 동기적 콜백: COM 호출 등 특정 동기적 작업 중 시스템이 메시지 펌핑을 강제하는 경우에도 유사한 재진입이 발생할 수 있습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;중요한 점:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;재진입은 같은 스레드 내에서 발생하는 중첩 호출입니다. 여러 스레드가 동시에 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;를 실행하는 스레드 안전성(Thread-Safety) 문제와는 다릅니다. (윈도우 프로시저는 기본적으로 특정 스레드에 귀속되므로, 일반적인 의미의 스레드 안전성은 고려 대상이 아닙니다.)&lt;/li&gt;
&lt;li&gt;재진입 문제: 만약 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;가 전역 변수나 정적 변수를 사용하는데, 재진입 호출 시 이 변수들의 상태가 이전 호출과 꼬이게 되면 문제가 발생할 수 있습니다. 따라서 재진입 가능성을 염두에 두고 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;를 작성해야 합니다. 주로 지역 변수나 윈도우 인스턴스별 데이터(&lt;code class=&quot;language-text&quot;&gt;SetWindowLongPtr&lt;/code&gt;/&lt;code class=&quot;language-text&quot;&gt;GetWindowLongPtr&lt;/code&gt; 등)를 사용하여 상태를 관리하는 것이 안전합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;결론:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;메시지 프로시저는 단일 스레드에서 순차 처리되는 것이 맞지만, 특정 함수 호출(&lt;code class=&quot;language-text&quot;&gt;SendMessage&lt;/code&gt;, 모달 대화상자 등)로 인해 실행 흐름이 중단되고 같은 스레드에서 다시 호출될 수 있기 때문에 &quot;재진입 가능하다&quot;고 말하는 것입니다.&lt;/p&gt;
&lt;h3&gt;#2. 케이스 스터디&lt;/h3&gt;
&lt;p&gt;재진입 시 문제가 발생할 수 있는 간단한 예시를 보여드리겠습니다.&lt;/p&gt;
&lt;p&gt;여기서는 메시지 프로시저(&lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;) 내에서 정적(static) 변수를 사용하여 상태를 관리하다가, &lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt; 호출로 인해 재진입이 발생했을 때 상태가 꼬이는 상황을 만들어 보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;시나리오:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;왼쪽 마우스 버튼(&lt;code class=&quot;language-text&quot;&gt;WM_LBUTTONDOWN&lt;/code&gt;)을 클릭하면 특정 작업을 시작합니다.&lt;/li&gt;
&lt;li&gt;작업은 여러 단계로 이루어지며, 현재 작업 중임을 나타내기 위해 &lt;code class=&quot;language-text&quot;&gt;static bool isProcessing&lt;/code&gt; 플래그를 사용합니다.&lt;/li&gt;
&lt;li&gt;작업 중간에 사용자 확인을 위해 &lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt;를 띄웁니다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt;가 떠 있는 동안 다른 메시지(예: 오른쪽 마우스 버튼 클릭, &lt;code class=&quot;language-text&quot;&gt;WM_RBUTTONDOWN&lt;/code&gt;)가 처리될 수 있습니다.&lt;/li&gt;
&lt;li&gt;오른쪽 마우스 버튼 클릭 처리기(&lt;code class=&quot;language-text&quot;&gt;WM_RBUTTONDOWN&lt;/code&gt;)가 작업 상태와 관련된 정적 변수(&lt;code class=&quot;language-text&quot;&gt;sharedBuffer&lt;/code&gt;)를 수정한다고 가정합니다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt;가 닫히고 원래의 왼쪽 버튼 클릭 작업으로 돌아왔을 때, 정적 변수(&lt;code class=&quot;language-text&quot;&gt;sharedBuffer&lt;/code&gt;)의 내용이 예상과 달라 문제가 발생합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;예시 코드 (WndProc 부분):&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;windows.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;wchar.h&gt;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// for wcscpy_s, wcscat_s&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;//WndProc 함수 내부에 선언된 정적 변수는 해당 함수가 여러 번 호출되어도 값을 유지합니다.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//하지만 재진입 시 문제가 될 수 있습니다.&lt;/span&gt;
LRESULT CALLBACK &lt;span class=&quot;token function&quot;&gt;WndProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HWND hWnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; UINT message&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WPARAM wParam&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPARAM lParam&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;bool&lt;/span&gt; isProcessing &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;      &lt;span class=&quot;token comment&quot;&gt;// 현재 작업 중인지 나타내는 플래그&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;wchar_t&lt;/span&gt; sharedBuffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 여러 호출 간에 공유되는 버퍼 (문제 발생 지점)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;message&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WM_LBUTTONDOWN&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// 이미 다른 작업이 진행 중이면 무시 (간단한 락)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;isProcessing&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;OutputDebugString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;WndProc [LBUTTON]: 이미 작업 중입니다!\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;// 작업 시작&lt;/span&gt;
            isProcessing &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;OutputDebugString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;WndProc [LBUTTON]: 작업 시작...\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;// 단계 1: 공유 버퍼 준비&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;wcscpy_s&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sharedBuffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_countof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sharedBuffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;왼쪽 버튼 작업 데이터&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;OutputDebugString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;WndProc [LBUTTON]: 버퍼 준비 완료.\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 약간의 작업 시간 시뮬레이션&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;// *** 문제 발생 가능 지점: MessageBox 호출 ***&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// 이 MessageBox는 내부 메시지 루프를 돌기 때문에,&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// 떠 있는 동안 다른 메시지(예: WM_RBUTTONDOWN)가 처리될 수 있습니다.&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;MessageBox&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hWnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;왼쪽 버튼 작업 1단계 완료. 확인을 누르면 2단계 진행.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;진행 중&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MB_OK&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// 만약 여기서 WM_RBUTTONDOWN이 처리되면 아래 코드는 예상과 다르게 동작할 수 있습니다.&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;// 단계 2: 공유 버퍼에 내용 추가 (원래 의도)&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// *** 재진입으로 인해 sharedBuffer 내용이 바뀌었을 수 있음 ***&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;wcscat_s&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sharedBuffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_countof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sharedBuffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot; - 2단계 완료&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;OutputDebugString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;WndProc [LBUTTON]: 최종 버퍼 내용: &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;OutputDebugString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sharedBuffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;OutputDebugString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;// 작업 완료&lt;/span&gt;
            isProcessing &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;OutputDebugString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;WndProc [LBUTTON]: 작업 완료.\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WM_RBUTTONDOWN&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// 이 메시지는 LBUTTON의 MessageBox가 떠 있는 동안 처리될 수 있습니다.&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;OutputDebugString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;WndProc [RBUTTON]: 오른쪽 버튼 클릭! (중단 발생)\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;// *** 문제 발생: LBUTTON 작업 중에 공유 버퍼를 수정함 ***&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;wcscpy_s&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sharedBuffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_countof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sharedBuffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;!!! 오른쪽 버튼에 의해 덮어쓰여짐 !!!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;OutputDebugString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;WndProc [RBUTTON]: 공유 버퍼를 수정했습니다.\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;// RBUTTON 작업도 MessageBox를 띄운다고 가정 (추가 재진입 가능성)&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// MessageBox(hWnd, L&quot;오른쪽 버튼 작업 완료.&quot;, L&quot;RBUTTON&quot;, MB_OK);&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WM_DESTROY&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;PostQuitMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DefWindowProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hWnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; message&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; wParam&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; lParam&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;문제 상황 시뮬레이션:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;프로그램을 실행하고 창을 왼쪽 클릭합니다.
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;OutputDebugString&lt;/code&gt;에 &quot;작업 시작...&quot;, &quot;버퍼 준비 완료.&quot;가 출력됩니다.&lt;/li&gt;
&lt;li&gt;&quot;왼쪽 버튼 작업 1단계 완료...&quot; 메시지 박스가 나타납니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;메시지 박스가 떠 있는 상태에서 창을 오른쪽 클릭합니다.
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;OutputDebugString&lt;/code&gt;에 &quot;오른쪽 버튼 클릭! (중단 발생)&quot;, &quot;공유 버퍼를 수정했습니다.&quot;가 출력됩니다. &lt;code class=&quot;language-text&quot;&gt;sharedBuffer&lt;/code&gt;의 내용이 바뀝니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이제 확인(OK) 버튼을 눌러 왼쪽 버튼 메시지 박스를 닫습니다.
&lt;ul&gt;
&lt;li&gt;원래의 &lt;code class=&quot;language-text&quot;&gt;WM_LBUTTONDOWN&lt;/code&gt; 처리가 &lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt; 다음부터 재개됩니다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;wcscat_s&lt;/code&gt; 함수는 &quot;왼쪽 버튼 작업 데이터&quot; 뒤에 이어붙이려고 했지만, 실제로는 &quot;!!! 오른쪽 버튼에 의해 덮어쓰여짐 !!!&quot; 뒤에 이어붙이게 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;OutputDebugString&lt;/code&gt;에 &quot;최종 버퍼 내용: !!! 오른쪽 버튼에 의해 덮어쓰여짐 !!! - 2단계 완료&quot; 와 같이 예상과 다른 결과가 출력됩니다.&lt;/li&gt;
&lt;li&gt;&quot;작업 완료.&quot;가 출력됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;왜 문제가 되는가?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;WM_LBUTTONDOWN&lt;/code&gt; 처리 루틴은 &lt;code class=&quot;language-text&quot;&gt;isProcessing = true&lt;/code&gt; 와 &lt;code class=&quot;language-text&quot;&gt;isProcessing = false&lt;/code&gt; 사이 구간에서 &lt;code class=&quot;language-text&quot;&gt;sharedBuffer&lt;/code&gt;에 대한 암묵적인 독점권을 가정하고 작성되었습니다. 하지만 &lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt; 호출로 인해 메시지 펌핑이 발생하면서 다른 메시지(&lt;code class=&quot;language-text&quot;&gt;WM_RBUTTONDOWN&lt;/code&gt;)가 처리될 기회가 생겼고, 이 메시지 처리기가 공유 자원인 &lt;code class=&quot;language-text&quot;&gt;sharedBuffer&lt;/code&gt;를 수정하면서 원래 작업의 상태를 깨뜨린 것입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;해결 방안:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;메시지 프로시저 내에서 시간이 오래 걸리는 작업이나 상태를 복잡하게 변경하는 작업을 피합니다.&lt;/li&gt;
&lt;li&gt;재진입을 유발하는 함수(&lt;code class=&quot;language-text&quot;&gt;SendMessage&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt; 등)를 호출할 때는 그 사이에 상태가 변경될 수 있음을 인지하고 방어적으로 코드를 작성합니다.&lt;/li&gt;
&lt;li&gt;상태 저장을 위해 정적 변수나 전역 변수 사용을 최소화하고, 필요하다면 윈도우 인스턴스별 데이터(&lt;code class=&quot;language-text&quot;&gt;SetWindowLongPtr&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;GetWindowLongPtr&lt;/code&gt; 등)나 스레드 로컬 스토리지(TLS) 등을 고려합니다. (단, &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;는 기본적으로 단일 스레드에서 실행되므로 TLS보다는 윈도우 인스턴스 데이터가 더 적합할 수 있습니다.)&lt;/li&gt;
&lt;li&gt;정말로 임계 영역(Critical Section)이 필요하다면, 해당 구간 전후로 상태를 저장하고 복원하거나, 더 정교한 동기화 기법(같은 스레드 내 재진입 방지용 플래그 등)을 사용해야 할 수도 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이 예시는 재진입이 어떻게 공유 상태를 망가뜨릴 수 있는지 보여주는 간단한 사례입니다. 실제 애플리케이션에서는 더 복잡한 형태로 문제가 발생할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;#3. 메시지 펌프&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt; 함수 내부에는 자체적인 메시지 펌프(Message Pump) 또는 메시지 루프(Message Loop)가 존재합니다.&lt;/p&gt;
&lt;p&gt;이것이 바로 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;가 &lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt; 호출에서 아직 반환하지 않았음에도 불구하고, 같은 스레드에서 다른 메시지를 처리하기 위해 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;가 다시 호출될 수 있는 이유입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;동작 과정:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt; 실행: 스레드의 메인 메시지 루프(&lt;code class=&quot;language-text&quot;&gt;while(GetMessage...)&lt;/code&gt;)가 메시지(예: &lt;code class=&quot;language-text&quot;&gt;WM_LBUTTONDOWN&lt;/code&gt;)를 받아 &lt;code class=&quot;language-text&quot;&gt;DispatchMessage&lt;/code&gt;를 호출하고, 이로 인해 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;가 실행됩니다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt; 호출: &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt; 코드 내에서 &lt;code class=&quot;language-text&quot;&gt;MessageBox(...)&lt;/code&gt; 함수를 호출합니다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt;의 내부 메시지 루프 시작: &lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt; 함수는 단순히 대화상자만 표시하고 대기하는 것이 아니라, 자체적인 메시지 루프를 시작합니다. 이 내부 루프는 대화상자가 활성화된 동안 현재 스레드로 들어오는 메시지들을 처리합니다. 이 루프는 대략 다음과 유사하게 동작합니다.
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;c++&quot;&gt;&lt;pre class=&quot;language-c++&quot;&gt;&lt;code class=&quot;language-c++&quot;&gt;// MessageBox 내부 (개념적인 코드)
DisplayTheMessageBoxWindow();
while (MessageBoxIsStillActive()) {
    MSG msg;
    // 현재 스레드의 메시지 큐에서 메시지를 가져옴
    if (PeekMessage(&amp;amp;msg, NULL, 0, 0, PM_REMOVE)) { // 또는 GetMessage
        // 표준 메시지 처리 (키보드 입력 변환 등)
        TranslateMessage(&amp;amp;msg);
        // *** 중요: 해당 메시지를 처리할 윈도우 프로시저로 보냄 ***
        DispatchMessage(&amp;amp;msg);
    } else {
        // 처리할 메시지가 없으면 잠시 대기
        WaitMessage();
    }
    // + MessageBox 자체 로직 처리 (버튼 클릭 감지 등)
}
HideTheMessageBoxWindow();
ReturnResult();&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;새 메시지 도착 및 처리: &lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt;의 내부 메시지 루프가 실행되는 동안, 사용자가 오른쪽 마우스 버튼을 클릭하면 &lt;code class=&quot;language-text&quot;&gt;WM_RBUTTONDOWN&lt;/code&gt; 메시지가 스레드의 메시지 큐로 들어옵니다. &lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt;의 내부 루프에 있는 &lt;code class=&quot;language-text&quot;&gt;PeekMessage&lt;/code&gt; 또는 &lt;code class=&quot;language-text&quot;&gt;GetMessage&lt;/code&gt;가 이 메시지를 가져옵니다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;DispatchMessage&lt;/code&gt; 호출: 내부 루프의 &lt;code class=&quot;language-text&quot;&gt;DispatchMessage&lt;/code&gt;는 이 &lt;code class=&quot;language-text&quot;&gt;WM_RBUTTONDOWN&lt;/code&gt; 메시지를 해당 윈도우(&lt;code class=&quot;language-text&quot;&gt;hWnd&lt;/code&gt;)로 보냅니다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt; 재호출(Re-entry): &lt;code class=&quot;language-text&quot;&gt;DispatchMessage&lt;/code&gt;는 결국 우리의 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt; 함수를 다시 호출하여 &lt;code class=&quot;language-text&quot;&gt;WM_RBUTTONDOWN&lt;/code&gt; 메시지를 처리하도록 합니다. 이 시점에서 호출 스택에는 &lt;code class=&quot;language-text&quot;&gt;메인 메시지 루프 -&gt; WndProc(LBUTTON) -&gt; MessageBox -&gt; 내부 메시지 루프 -&gt; DispatchMessage -&gt; WndProc(RBUTTON)&lt;/code&gt; 와 같이 쌓이게 됩니다. 즉, &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;가 중첩되어 호출된 것입니다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt; 종료 및 반환: 사용자가 &lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt;의 확인 버튼 등을 누르면, &lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt;의 내부 메시지 루프가 종료되고, &lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt; 함수 호출이 드디어 반환(return)됩니다.&lt;/li&gt;
&lt;li&gt;원래 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt; 실행 재개: 이제 제어가 원래의 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt; ( &lt;code class=&quot;language-text&quot;&gt;WM_LBUTTONDOWN&lt;/code&gt; 처리 중이던) 코드로 돌아와 &lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt; 호출 다음 라인부터 실행을 계속합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;결론:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt; 자체는 단일 스레드에서 순차적으로 실행되지만, &lt;code class=&quot;language-text&quot;&gt;MessageBox&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;DialogBox&lt;/code&gt; 등 모달(Modal) 상태를 만들고 내부적으로 메시지 루프를 돌리는 함수를 호출하면, 해당 함수가 반환하기 전에도 같은 스레드에서 다른 메시지가 처리되어 &lt;code class=&quot;language-text&quot;&gt;WndProc&lt;/code&gt;가 재진입(re-entrant) 또는 중첩 호출(nested call)될 수 있습니다. 이는 Windows GUI 프로그래밍에서 매우 흔하며 중요한 개념입니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[py] 메모리와 속도 두 마리 토끼를 모두 잡을 수 있을까?]]></title><description><![CDATA[우리는 가난하다. 그래서 서버도 가난한 서버를 쓴다. c6a.large, vcpu는 2개 메모리는 4g…]]></description><link>https://jiniya.net/2025/03/is-it-possible-to-achieve-both-memory-and-speed/</link><guid isPermaLink="false">https://jiniya.net/2025/03/is-it-possible-to-achieve-both-memory-and-speed/</guid><pubDate>Fri, 28 Mar 2025 13:00:01 GMT</pubDate><content:encoded>&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;mem_and_speed.png&apos; data-alt=&apos;명량한 표정과는 다르게 현실 세계에서 두 마리 토끼를 잡기 위해서는 트레이드 오프가 필요한 순간이 온다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/0fd38d80134cca33e55fd0310be1bf04/42a19/mem_and_speed.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 150%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAIAAACjcKk8AAAACXBIWXMAAAsTAAALEwEAmpwYAAAHFUlEQVR42g2NaVBTiQHH38d2xtnOuM64CGE5EyAQkpCEU6UIyiJoALnUKIdAQDlDwhECISEnua+X6+XlvZcDua8EAgICcq5KFazrau3OuJ3udHbafunMtp/KzH/+n/6/3x+oMWM1JqTSiFYZ0UoDUqxBKwyIZcaJLTqabPAtneeO4SxYhdFTrsPK9Gi5HqsweCqNHpYZAe6Dnrugt9rsuXtmMWN81BUImb8cG3/7AL7atyOLjnsgdg/0VFu8dy2eKpPnzFJp8tRYfCyrD3jkwB7asFobeh/EWpzuzWfadwf6v74y/nJq++9n138+2JxLrjqnt8mJNjiws81DK1Zv97Cs3jq7D+hwuc6YJoe7BUJ4CDS1oDra0v3txPZ6TXIaGvn3O8vCoroJtLUjWCuMsZ3I2Vmd3cOGsBYIA9pcMNsJNzhQy4z1zY5mOagJrhonoM6Bm5GDheHGRrqxOnakLL77UWGX1dgE+8YmHDMhOweBuxEE4CCuEZ99ELPbpvTrIdVKUP3ziW3DzS5O+H1OzLmyhN9xMs6pi7/Rl3zd3VElmUY317SWOVcHgg16YYCHQi82ND99r1ta0c8vjC0HVJ8O9b8cG32S8sqMsMY8HNab+wpmbVjucjRi9Qw84IVb3F6Ox9PnQwFkemwtINlbV32/qXq2ollZNR3uGg93Tb/9fXwZap7kX/nfxuN/zT6chHs44xNdGPbEjXI97m4M43lR4NWmcn1ZHgiolgPKt/u6rYBsHeXueLrejZW+1d5ZVN78iJYf26utmIzj8wt88N62aXrFJnrqEj2FgDGwFvZyFxfGFlcs847u102k91Xhn2oi/lId/uZ+9Mf57gOw2idmCSc98qcQsgS+OTAtrVmQoFM+DQO3nmQ3D2X1Kkock/0LHXnHRef365LX66kbRWHH7fQPpsr3gtyXTamgVagOTZqmwRlPr2bCIp12K89guTK5X5R8+wmjTnxdOpAbqsfPqUuN5oYRFoHzmBIYb/wy27lXHnHUmWNySp023pHqjzq/VjHnUc0iQO9w4qAwZmAkoaIzo7SDPszNWNDduM0ilDellrNTjPqirRUFxL62n3/uRcn5Z9J8FyJwL9k0c27NPAZ08on1nfhRWQxfTrxcjb96M/Kjr2LNVDzQQ/Grr0hHS7hOtXQCgruYSG2m28Vf3nY83zQgQZs9AANsTnzfUHQDl9DWk8Kr+VbC/MZbFRMcyHo5XvfTMseP1teKbrKVdT2QeGzSOB6y+patzqAbXkG8IQi4XkG8xcKz2lNNhRH+zPOO9AvTGV/tCwv+8Vr266H0x2e8RmFRoyi3dTTvkZjZZ27TTyhsEyI91LK0pgfq2ijMZopAnuG5HQblXLBfvnDEvHTSl/Xrqfqfp7qfd4Z65bcLu2484Bc0CrJbhFkt0pKStoLSJ9QOaSkwjZJQJ1lnTsNYuKns83PXL+4zw/fLwg/1lT/oSr80JS20kir7rxW1537XQL7TSrz+KCu9knbtQRqzPRvwwyRYm9hVFsF/THRURG4VXtwqCTupwgUKLnysCj9lExaZOJeaBplzlDziqJDE5lOaeGltfRSRjAIMy8jch7h7eWGNjWRrJ3mPFb1dHvHjg+hP96NmmOEnpoK5Iapcmbhuv/JCkzMuITpN1BkrbcpCmnISAc0YpY0Z1tVBGJSQxkTkaSl1UklFe4kIj2BQED6jxbuOXK8iAdKSJlSMTS19zU5124mQPRFzpgLrULpTmaBU4IdlyUoxvb8jXjCctqnMsXDi+gTkU6j4s/NGaDAqKIydlBDewld/GC/zg8RZ8NsZVxKwa8nZBdOfg2eHxJVh/PZQpLkr2jdC2ZCk8nuI44PUP0PFs9L0YyPlvYP6YbbGZ8w1agluLW7SEQdsu/L3QeqBgebvjpvlRe6pkg6VcfP8qHdo3g541SqMHu3JMqiyn5oyX9ppu/YbUhG9ZYDSNpAgUaYAcgnZISbPSeizo2kLMtqeI//AQD220E7GK7Zs17wGvLifxq+NG7x3qa89yqthWOU5Xf2pPQJ8nzAReMzFywWJ1uFkCz/V3k+xCxjzcsZzecrMMCkkT/gTlAZ1xXdf/kNz/iUtl+BXpDjFBIkgVi6OsqqjgWExAVXiVlVfG6RxMxqyd4QMD9FALtXPw/sGUta0mWc9UIVb09I2dOnr2qxdE2NFk4rJEqe0iUBHfzx/KEoxEi0cjdEqoyBV3KqeFJSTQ2r6qoYeVFAnxYx5SdqOPm3fTD+yp++BtJCGNDGWtASmAHdaUsrZCaz22GZuPKcPJxSHa+QRDmnMnBQfkicH1aSAKSmoS1hTJW9oaLsg47k9/RBM3zbQj915QM8gkdUa29AWxWpPbOjEc/kxIjFOo7hok0VMy2KWFQmoKBYcxfll8etq0raRsWXO3AcZh1bG+4nv/g98p3QK6ampugAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;명량한 표정과는 다르게 현실 세계에서 두 마리 토끼를 잡기 위해서는 트레이드 오프가 필요한 순간이 온다.&apos; title=&apos;&apos; src=&apos;/static/0fd38d80134cca33e55fd0310be1bf04/efd7b/mem_and_speed.png&apos; srcset=&apos;/static/0fd38d80134cca33e55fd0310be1bf04/08678/mem_and_speed.png 190w,
/static/0fd38d80134cca33e55fd0310be1bf04/2edd7/mem_and_speed.png 380w,
/static/0fd38d80134cca33e55fd0310be1bf04/efd7b/mem_and_speed.png 760w,
/static/0fd38d80134cca33e55fd0310be1bf04/42a19/mem_and_speed.png 1024w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;명량한 표정과는 다르게 현실 세계에서 두 마리 토끼를 잡기 위해서는 트레이드 오프가 필요한 순간이 온다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;우리는 가난하다. 그래서 서버도 가난한 서버를 쓴다. c6a.large, vcpu는 2개 메모리는 4g인 사양이다. 물론 이보다 더 저사양 서버에서 고군분투하는 분들에게는 이 또한 높은 사양일수도 있겠다. 문제는 어쨌든 이 열악한 서버에서 연산을 진행해야 한다는 의미다. 연산할 것이 별로 많지 않다면 문제가 되진 않는다. 우리가 처리할 대상은 대략 2g 정도의 텍스트 파일이고, 해당 텍스트 파일에서 맵을 추출해서 csv로 생성하는 기능을 한다. 정상 생성된다면 맵은 대략 pickle로 전환했을 때 대략 10g가 조금 넘는 크기로 추정된다. 속도도 문제다. 적어도 5분 내에는 이 작업이 완료되어야 한다. 게다가 우리는 파이썬으로 작업 중이다.&lt;/p&gt;
&lt;p&gt;물론 파이썬을 쓰면서도 별로 느리다는 생각은 해보질 않았다. 대체로 그렇게 큰 작업을 수행하는 일은 없기 때문이다. 하지만 일이 커지면 느려지는 건 당연하다. 이 작업은 메모리가 많은 괜찮은 성능 pc에서 수행하더라도 20분이 넘게 걸렸다. 그리고 4g에서는 당연한 얘기겠지만 메모리 부족 오류로 종료됐다. 애쩠든 이런 상황을 우리는 어떻게 해결할 수 있을까?&lt;/p&gt;
&lt;h3&gt;rust 포팅&lt;/h3&gt;
&lt;p&gt;rust로 작업을 포팅하면 당연한 소리겠지만 엄청 빨라질 것이다. 일전에 우리는 간단한 python 로그 서버를 rust로 포팅했는데 속도가 무려 77배 빨라졌다. 최악의 경우에는 이 방법 또한 고려 사항 중엔 하나였다. 하지만 어쨌든 최대한 일을 적게하는 방법을 찾아야 했기에 기존 코드를 고치지 않고 수행할 방법을 잦아야 했다.&lt;/p&gt;
&lt;h3&gt;nuitka&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://nuitka.net/&quot;&gt;nuitka는&lt;/a&gt; 파이썬 코드를 네이티브 코드로 빌드해주는 툴이다. 네이티브 코드로 변환해주니까 뭔가 더 빨라지지 않을까, 라는 생각이 들기 쉽다. 그래서 테스트를 해보았지만 속도 향상은 별로 없었다. 스크립트 코드를 제공하고 싶지 않을 때 선택할 수 있는 선택 사항 정도가 아닌가 싶다.&lt;/p&gt;
&lt;h3&gt;pypy&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://pypy.org/&quot;&gt;pypy는&lt;/a&gt; 파이썬의 파이썬 구현체에 jit을 탑재한 인터프리터다. 순수 파이썬 코드가 많으면 jit이 탑재된 pypy가 빠를 수 있다. 테스트 해보니 생각보다 효과는 드라마틱했다. 대략 14.5배 빨라졌다. 여기에 약간 함정이 있는데 pypy에서 일부 파이썬 코드는 cpython 구현보다 느린 경우도 있다는 사실이다. 그래서 많은 반복 작업 속에 그런 코드가 있다면 파이썬 구현을 찾아서 더 빠르게 실행되도록 변경하는 작업을 일부 해줘야 한다. 어쨌든 이런 작업을 진행하고 나면 대체로 아주 빨라진다.&lt;/p&gt;
&lt;h3&gt;메모리는?&lt;/h3&gt;
&lt;p&gt;그렇게 빨라진 줄만 알았지 메모리 문제를 놓고 있었던 스크립트는 서버에서 동작하면 메모리 부족 오류가 발생했다. 서버 메모리는 4g, 우리가 실제 동작에 필요한 메모리는 대략 넉넉하게 12g 정도 된다. 물론 이는 우리가 무식하게 맵을 그냥 메모리에 다 올렸기 때문이다. 그런데 또 그렇게 무식하게 쓰자고 파이썬 쓰는 게 아닌가 싶기도 하다. 고상하게 설계하고 고민하고 할 거였음 애초에 더 복잡한 언어로 더 정교하게 만들었을테니 말이다. 어쨌든 이 말도 안되게 부족한 메모리를 극복하는 방법은 없을까, 를 최신 신상 gemini 2.5 pro와 고민해 보았다.&lt;/p&gt;
&lt;p&gt;나의 고민에 나온 첫 반응은 shelve였다. 나는 이런게 있는 줄도 몰랐지만 표준 기능으로 있는 도구였다. 맵을 메모리가 아닌 디스크에 기록하게 해준다. 여윽시 인공지능인가를 생각하며 맵을 shelve로 교체했다. 당연하 소리겠지만 메모리는 너무나 작게 썼고 파일 용량은 커져만 갔다. 안타깝게도 속도가 너무 느렸다. shelve는 맵이 업데이트될때마다 파일 io를 동반하기 때문에 어쩔 수가 없는 구조였다. 뭔가 shelve가 메모리를 좀 더 사용하도록 하면 좋을 것 같아서 그런 기능에 대해 문의했으나 그런 기능은 존재하질 않았다. 하지만 녀석은 최신 신상 인공지능 답게, 직접 구현한 구현체를 주었다. CachedShelve. 캐시맵을 추가해서 캐시에서 발견되는 경우는 캐시를 사용하도록 변경한 구조였다. 캐시를 추가하니 눈에 띄게 빨라졌지만 우리의 요구 사항을 충족하긴 힘들었다. 역시나 두마리 토끼를 손쉽게 잡는 은탄환 따위는 존재하지 않았다. 결국 불필요한 요소를 제거해서 메모리를 덜 사용하는 식으로 코드를 변경했다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; shelve
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; collections &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; OrderedDict
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; time &lt;span class=&quot;token comment&quot;&gt;# 캐시 효과 시연용&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CachedShelve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;
    shelve 객체를 위한 LRU 읽기 캐시를 제공하는 래퍼 클래스.
    컨텍스트 관리자 프로토콜을 지원합니다 (&apos;with&apos; 문 사용 가능).
    &quot;&quot;&quot;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; filename&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cache_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; flag&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;c&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; writeback&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;
        CachedShelve를 초기화합니다.

        Args:
            filename (str): shelve 파일 경로.
            cache_size (int): 캐시에 저장할 최대 항목 수 (LRU). 0보다 커야 합니다.
            flag (str): shelve.open()에 전달할 플래그 (&apos;c&apos;, &apos;n&apos;, &apos;w&apos;, &apos;r&apos;).
            writeback (bool): shelve.open()에 전달할 writeback 플래그.
                              True로 설정 시 이 클래스의 캐싱 이점이 줄어들 수 있으며,
                              메모리 사용 및 데이터 유실 위험이 증가합니다. 비권장.
        &quot;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; cache_size &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;raise&lt;/span&gt; ValueError&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Cache size must be a positive integer.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;filename &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; filename
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cache_size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cache_size
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;flag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; flag
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;writeback &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; writeback &lt;span class=&quot;token comment&quot;&gt;# shelve 자체의 writeback 사용 여부&lt;/span&gt;

        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# LRU 캐시를 위해 OrderedDict 사용&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; OrderedDict&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;CachedShelve initialized for &apos;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;filename&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos; with cache size &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;cache_size&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__enter__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;컨텍스트 관리자 진입: shelve 파일을 열고 캐시를 비웁니다.&quot;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Opening shelve &apos;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;filename&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos; (writeback=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;writeback&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;)...&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# writeback 옵션도 shelve.open에 전달&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; shelve&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;filename&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; flag&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;flag&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; writeback&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;writeback&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clear&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Shelve opened and cache cleared.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; self &lt;span class=&quot;token comment&quot;&gt;# &apos;with ... as cs:&apos; 에서 cs 변수에 할당될 객체&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__exit__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; exc_type&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; exc_val&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; exc_tb&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;컨텍스트 관리자 종료: shelve 파일을 닫고 캐시를 비웁니다.&quot;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Closing shelve &apos;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;filename&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;...&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                start_close &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;time&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;close&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# writeback=True인 경우 시간이 걸릴 수 있음&lt;/span&gt;
                end_close &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;time&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Shelve closed (took &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;end_close &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; start_close&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token format-spec&quot;&gt;.4f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;s).&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; Exception &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Error closing shelve: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;finally&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clear&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Cache cleared.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; exc_type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Exception occurred in &apos;with&apos; block: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;exc_type&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;__name__&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# 예외를 전파시키려면 None 또는 False 반환 (기본값)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_check_open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;shelve가 열려 있는지 확인합니다.&quot;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;raise&lt;/span&gt; RuntimeError&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Shelve is not open. Use within a &apos;with&apos; block.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__getitem__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;obj[key] 구문 지원 (읽기). 캐시 확인 후 shelve 접근.&quot;&quot;&quot;&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_open&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;# 1. 캐시 확인&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; key &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# 캐시 히트: 값 반환 (LRU 위해 순서 변경)&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# print(f&quot;[Cache Hit] Key: &apos;{key}&apos;&quot;) # 디버깅용&lt;/span&gt;
            self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;move_to_end&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# 2. 캐시 미스: shelve에서 읽기 (느림)&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# print(f&quot;[Cache Miss] Key: &apos;{key}&apos;, reading from shelve...&quot;) # 디버깅용&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# shelve에서 값을 읽음 (KeyError 발생 가능)&lt;/span&gt;
            value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;# 3. 캐시에 추가&lt;/span&gt;
            self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value
            self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;move_to_end&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# 방금 사용했으므로 맨 뒤로&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;# 4. 캐시 크기 관리 (오래된 항목 제거)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cache_size&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                removed_key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; removed_value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;popitem&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;last&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# 가장 오래된 항목 제거&lt;/span&gt;
                &lt;span class=&quot;token comment&quot;&gt;# print(f&quot;[Cache Evict] Removed &apos;{removed_key}&apos; from cache.&quot;) # 디버깅용&lt;/span&gt;

            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; value

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__setitem__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;obj[key] = value 구문 지원 (쓰기). shelve에 먼저 쓰고 캐시 업데이트.&quot;&quot;&quot;&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_open&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;# 1. shelve에 먼저 쓰기 (영속성 보장)&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value
        &lt;span class=&quot;token comment&quot;&gt;# print(f&quot;[Shelve Write] Key: &apos;{key}&apos;&quot;) # 디버깅용&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;# 2. 캐시 업데이트 (또는 무효화)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;#    간단하게는 캐시에서도 값을 업데이트하고 LRU 순서 조정&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;move_to_end&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# 방금 썼으므로 맨 뒤로&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;# 3. 캐시 크기 관리 (새 항목 추가로 인한 제거)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cache_size&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            removed_key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; removed_value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;popitem&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;last&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# print(f&quot;[Cache Evict] Removed &apos;{removed_key}&apos; after set.&quot;) # 디버깅용&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;# 대안: 쓰기 시 캐시 항목을 그냥 삭제하여 다음 읽기 시 다시 로드하게 할 수도 있음&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# if key in self._cache:&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;#     del self._cache[key]&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__delitem__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;del obj[key] 구문 지원. shelve에서 먼저 삭제 후 캐시에서도 삭제.&quot;&quot;&quot;&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_open&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;# 1. shelve에서 먼저 삭제 (KeyError 발생 가능)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;del&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# print(f&quot;[Shelve Delete] Key: &apos;{key}&apos;&quot;) # 디버깅용&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;# 2. 캐시에서도 삭제 (존재하는 경우)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; key &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;del&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# print(f&quot;[Cache Delete] Key: &apos;{key}&apos;&quot;) # 디버깅용&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__contains__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;&apos;key in obj&apos; 구문 지원. 캐시 먼저 확인 후 shelve 확인.&quot;&quot;&quot;&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_open&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# 캐시에 있으면 True 반환 (빠름)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; key &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# 캐시에 없으면 shelve 확인 (느림)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# 이 확인만으로는 캐시에 추가하지 않음&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; key &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; default&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;딕셔너리의 get과 유사하게 작동. 키 없으면 default 반환.&quot;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# __getitem__을 사용하여 캐싱 로직 활용&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; KeyError&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# __getitem__에서 KeyError가 발생하면 (shelve에 키 없음) default 반환&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# print(f&quot;Key &apos;{key}&apos; not found, returning default.&quot;) # get 호출 시에만 출력 (필요시 활성화)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; default
        &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; RuntimeError &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# shelve가 닫혀있을 때&lt;/span&gt;
             &lt;span class=&quot;token keyword&quot;&gt;raise&lt;/span&gt; e
        &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; Exception &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# 기타 예상치 못한 오류&lt;/span&gt;
             &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Error in get method for key &apos;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; default &lt;span class=&quot;token comment&quot;&gt;# 예상치 못한 오류 시에도 default 반환&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# --- 추가 유틸리티 메소드 ---&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;내부 shelve 객체의 sync()를 호출합니다.&quot;&quot;&quot;&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_open&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Syncing underlying shelve...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sync&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clear_cache&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;수동으로 캐시를 비웁니다.&quot;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Clearing cache manually.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clear&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__len__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;len(obj) 지원. 실제 shelve의 크기를 반환합니다 (캐시 크기 아님).&quot;&quot;&quot;&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_open&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;
        shelve의 키 목록 (뷰)을 반환합니다 (캐시 아님).
        이는 실제 shelve 파일의 모든 키를 나타냅니다.
        &quot;&quot;&quot;&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_open&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keys&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# --- 추가된 메소드 ---&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;
        shelve의 값 목록 (뷰)을 반환합니다 (캐시 아님).
        주의: 큰 shelve의 경우 모든 값을 로드해야 하므로 느릴 수 있습니다.
        캐시의 이점을 활용하지 않습니다.
        &quot;&quot;&quot;&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_open&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# 실제 shelve 객체의 values() 메소드를 호출하여 반환&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;values&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;
        shelve의 키-값 쌍 목록 (뷰)을 반환합니다 (캐시 아님).
        주의: 큰 shelve의 경우 모든 항목을 로드해야 하므로 느릴 수 있습니다.
        캐시의 이점을 활용하지 않습니다.
        &quot;&quot;&quot;&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_open&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# 실제 shelve 객체의 items() 메소드를 호출하여 반환&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# --- 클래스 사용 예제 ---&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; __name__ &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;__main__&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    filename &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;my_cached_shelve.db&apos;&lt;/span&gt;
    cache_size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# 1. 데이터 쓰기 (with 사용)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;\n--- Writing data ---&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; CachedShelve&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filename&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cache_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;cache_size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; flag&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;c&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; cs&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;a&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
            cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;b&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;x&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;y&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;c&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;d&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;hello&quot;&lt;/span&gt;
            cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;e&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;world&quot;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Length of shelve: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Keys in shelve: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keys&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# list()로 변환하여 내용 확인&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Values in shelve: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;values&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Items in shelve: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; Exception &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;An error occurred during writing: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# 2. 데이터 읽기 및 캐시 확인 (새로운 with 블록)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;\n--- Reading data and testing cache ---&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; CachedShelve&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filename&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cache_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;cache_size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; flag&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;r&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; cs&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# 읽기 모드&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Accessing &apos;e&apos;: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;e&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Cache Miss, Load &apos;e&apos; -&gt; Cache: {&apos;e&apos;}&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Accessing &apos;d&apos;: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;d&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Cache Miss, Load &apos;d&apos; -&gt; Cache: {&apos;e&apos;, &apos;d&apos;}&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Accessing &apos;c&apos;: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;c&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Cache Miss, Load &apos;c&apos; -&gt; Cache: {&apos;e&apos;, &apos;d&apos;, &apos;c&apos;}&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Accessing &apos;b&apos;: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;b&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Cache Miss, Load &apos;b&apos;, Evict &apos;e&apos; -&gt; Cache: {&apos;d&apos;, &apos;c&apos;, &apos;b&apos;}&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Accessing &apos;e&apos;: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;e&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Cache Miss (evicted), Load &apos;e&apos;, Evict &apos;d&apos; -&gt; Cache: {&apos;c&apos;, &apos;b&apos;, &apos;e&apos;}&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Accessing &apos;c&apos;: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;c&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Cache Hit, Move &apos;c&apos; -&gt; Cache: {&apos;b&apos;, &apos;e&apos;, &apos;c&apos;}&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;# get() 메소드 테스트&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Getting &apos;a&apos;: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;a&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Cache Miss, Load &apos;a&apos;, Evict &apos;b&apos; -&gt; Cache: {&apos;e&apos;, &apos;c&apos;, &apos;a&apos;}&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Getting &apos;z&apos; (non-existent): &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;z&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Not Found&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;# __contains__ 테스트&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Is &apos;a&apos; in cs? &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;a&apos;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; cs&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Cache Hit&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Is &apos;b&apos; in cs? &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;b&apos;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; cs&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Cache Miss (evicted), Check in shelve -&gt; True&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Is &apos;z&apos; in cs? &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;z&apos;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; cs&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Check in shelve -&gt; False&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;# values() 와 items() 사용&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;\n--- Using values() and items() ---&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# 이 메소드들은 캐시를 직접 활용하지 않고 shelve 전체를 대상으로 함&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;All values:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;values&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;All items:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; Exception &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;An error occurred during reading: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# 3. 데이터 삭제 (새로운 with 블록)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;\n--- Deleting data ---&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# 삭제를 위해 flag=&apos;c&apos; 또는 &apos;w&apos; 사용&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; CachedShelve&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filename&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cache_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;cache_size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; flag&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;c&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; cs&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Current keys:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keys&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# &apos;a&apos;가 캐시에 있을 수 있음 (마지막 get 호출)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Cache before del &apos;a&apos;: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keys&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;del&lt;/span&gt; cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;a&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Deleted &apos;a&apos;. Cache after del: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keys&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# 캐시에서도 삭제됨&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Keys after deleting &apos;a&apos;:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keys&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;# 캐시에 없는 항목 삭제 시도&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;b&apos;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&apos;b&apos; is not in cache.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;del&lt;/span&gt; cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;b&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Keys after deleting &apos;b&apos;:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keys&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Cache after del &apos;b&apos;: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keys&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# 캐시에 없었으므로 변화 없음&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; KeyError &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Tried to delete non-existent key: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; Exception &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;An error occurred during deletion: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# shelve 파일 자체 삭제 (정리)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; os
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; ext &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;.bak&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;.dat&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;.dir&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# shelve가 만드는 파일 확장자들&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            os&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;remove&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filename &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; ext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Removed &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;filename &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; ext&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; FileNotFoundError&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;pass&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;쓰기는?&lt;/h3&gt;
&lt;p&gt;gemini가 작성해준 코드가 아까워서 글을 올리려고 보니 속도가 느린 이유가 있기도 한 것 같다. set부분은 그냥 생각 없이 모두 shelve에 기록하고 있었다. 그러니 get 부분에서만 캐시 히트하는 정도의 속도 향상 밖에는 없었다고 할 수 있겠다. 물론 이 부분도 gemini에 넣으면 알아서 고쳐주겠지? 라는 생각으로 넣어봤다. 그랬더니 쓰기 캐시를 추가한 버전을 만들어 주었다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; shelve
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; collections &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; OrderedDict
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; time
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; warnings &lt;span class=&quot;token comment&quot;&gt;# 경고 메시지용&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 쓰기 버퍼에서 삭제된 항목을 표시하기 위한 고유 객체&lt;/span&gt;
_DELETED_SENTINEL &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CachedShelve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;
    shelve 객체를 위한 LRU 읽기 캐시 및 쓰기 지연 버퍼를 제공하는 래퍼 클래스.
    쓰기 작업은 버퍼에 먼저 기록되고, 컨텍스트 종료, sync() 호출 시,
    또는 쓰기 버퍼가 설정된 한계치(write_buffer_limit)에 도달했을 때 shelve 파일에 반영됩니다.

    **경고:** 쓰기 지연 방식으로 인해 프로그램이 비정상 종료될 경우,
             마지막 동기화 이후의 변경 사항이 유실될 수 있습니다.
             shelve.open의 writeback=True 플래그와 함께 사용하는 것은 권장되지 않습니다.

    컨텍스트 관리자 프로토콜을 지원합니다 (&apos;with&apos; 문 사용 가능).
    &quot;&quot;&quot;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; filename&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cache_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; write_buffer_limit&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; flag&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;c&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; writeback&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;
        CachedShelve를 초기화합니다.

        Args:
            filename (str): shelve 파일 경로.
            cache_size (int): 읽기 캐시에 저장할 최대 항목 수 (LRU). 0보다 커야 합니다.
            write_buffer_limit (int, optional): 쓰기 버퍼에 저장할 최대 항목 수.
                                               None이면 무제한. 이 한계에 도달하면 버퍼 전체가
                                               자동으로 플러시(동기화)됩니다. 0보다 커야 합니다.
            flag (str): shelve.open()에 전달할 플래그 (&apos;c&apos;, &apos;n&apos;, &apos;w&apos;, &apos;r&apos;).
            writeback (bool): shelve.open()에 전달할 writeback 플래그.
                              **True 설정은 이 클래스의 쓰기 지연 방식과 충돌할 수 있어 강력히 비권장됩니다.**
        &quot;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; cache_size &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;raise&lt;/span&gt; ValueError&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Cache size must be a positive integer.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; writeback&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
             &lt;span class=&quot;token keyword&quot;&gt;raise&lt;/span&gt; ValueError&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Cannot use shelve&apos;s writeback=True with CachedShelve&apos;s write buffering. Set writeback=False.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; write_buffer_limit &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;and&lt;/span&gt; write_buffer_limit &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;raise&lt;/span&gt; ValueError&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Write buffer limit must be a positive integer or None.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;


        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;filename &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; filename
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cache_size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cache_size
        &lt;span class=&quot;token comment&quot;&gt;# --- New ---&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;write_buffer_limit &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; write_buffer_limit
        &lt;span class=&quot;token comment&quot;&gt;# -----------&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;flag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; flag
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shelve_writeback &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Always False for internal shelve&lt;/span&gt;

        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; OrderedDict&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        limit_msg &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;write buffer limit=&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;write_buffer_limit&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;write_buffer_limit &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;unlimited write buffer&quot;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;CachedShelve initialized for &apos;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;filename&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos; with read cache size &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;cache_size&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;limit_msg&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; (Write Buffering Enabled)&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# __enter__, __exit__, _check_open 은 이전과 동일&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__enter__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;컨텍스트 관리자 진입: shelve 파일을 열고 캐시와 버퍼를 비웁니다.&quot;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Opening shelve &apos;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;filename&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos; (internal writeback=False)...&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; shelve&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;filename&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; flag&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;flag&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; writeback&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;shelve_writeback&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clear&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clear&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Shelve opened, read cache and write buffer cleared.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; self

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__exit__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; exc_type&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; exc_val&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; exc_tb&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;컨텍스트 관리자 종료: 버퍼를 플러시하고 shelve 파일을 닫습니다.&quot;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Exiting context...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# 버퍼에 내용이 있을 때만 플러시 시도&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Flushing write buffer on exit...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                    start_flush &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;time&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                    self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_flush_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                    end_flush &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;time&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Write buffer flushed on exit (took &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;end_flush &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; start_flush&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token format-spec&quot;&gt;.4f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;s).&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Write buffer empty on exit, no flush needed.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

            &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; Exception &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Error during buffer flush on exit: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token comment&quot;&gt;# Depending on policy, you might want to re-raise here&lt;/span&gt;

            &lt;span class=&quot;token keyword&quot;&gt;finally&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Closing shelve &apos;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;filename&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;...&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                    start_close &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;time&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                    self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;close&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                    end_close &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;time&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Shelve closed (took &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;end_close &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; start_close&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token format-spec&quot;&gt;.4f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;s).&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; Exception &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Error closing shelve: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;finally&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                    self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;

        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clear&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# Ensure buffer is clear even if flush failed (or wasn&apos;t needed but close failed)&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clear&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Read cache and write buffer cleared.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; exc_type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Exception occurred in &apos;with&apos; block: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;exc_type&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;__name__&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;WARNING: Changes made since the last sync might be lost due to the exception.&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Propagate exception&lt;/span&gt;


    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_check_open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;shelve가 열려 있는지 확인합니다.&quot;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;raise&lt;/span&gt; RuntimeError&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Shelve is not open. Use within a &apos;with&apos; block or ensure it&apos;s manually opened.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;


    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_flush_write_buffer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;쓰기 버퍼의 내용을 실제 shelve 객체에 반영하고 버퍼를 비웁니다.&quot;&quot;&quot;&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_open&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# print(&quot;Write buffer is empty, nothing to flush.&quot;) # Avoid noise if called often&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Flushing &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; items from write buffer to shelve...&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        items_processed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
        errors_occurred &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# Use list(self._write_buffer.items()) to avoid issues if flushing modifies the buffer indirectly&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# Though in this simple flush, it shouldn&apos;t be an issue.&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; value &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; _DELETED_SENTINEL&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; key &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                        &lt;span class=&quot;token keyword&quot;&gt;del&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                    self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value
                items_processed &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; Exception &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                errors_occurred &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Error flushing key &apos;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Flush complete: Processed &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;items_processed&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; items with &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;errors_occurred&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; errors.&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clear&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# Optional: force disk write immediately (can impact performance)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# self._db.sync()&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# print(&quot;Underlying shelve synced after flush.&quot;)&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# --- New Helper Method ---&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_check_and_flush_buffer_if_full&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;쓰기 버퍼가 설정된 한계에 도달했는지 확인하고, 도달했다면 플러시합니다.&quot;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;write_buffer_limit &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;write_buffer_limit&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Write buffer limit (&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;write_buffer_limit&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;) reached. Auto-flushing...&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_flush_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# print(&quot;Auto-flush complete.&quot;) # Included in _flush_write_buffer now&lt;/span&gt;


    &lt;span class=&quot;token comment&quot;&gt;# __getitem__ 은 이전과 동일&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__getitem__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;obj[key] 구문 지원 (읽기). 버퍼 -&gt; 캐시 -&gt; shelve 순으로 확인.&quot;&quot;&quot;&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_open&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;# 1. 쓰기 버퍼 확인 (최신 상태 반영)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; key &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; value &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; _DELETED_SENTINEL&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;raise&lt;/span&gt; KeyError&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token comment&quot;&gt;# Update read cache as well&lt;/span&gt;
                self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value
                self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;move_to_end&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cache_size&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                    self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;popitem&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;last&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; value

        &lt;span class=&quot;token comment&quot;&gt;# 2. 읽기 캐시 확인&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; key &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;move_to_end&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;# 3. shelve에서 읽기&lt;/span&gt;
        value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# May raise KeyError&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;# 4. 읽기 캐시에 추가&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;move_to_end&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;# 5. 캐시 크기 관리&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cache_size&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;popitem&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;last&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; value


    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__setitem__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;obj[key] = value 구문 지원 (쓰기). 쓰기 버퍼에 우선 기록. 버퍼가 차면 자동 플러시.&quot;&quot;&quot;&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_open&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;# --- Modified ---&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# 버퍼에 추가하기 *전에* 가득 찼는지 확인하고 필요시 플러시&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_and_flush_buffer_if_full&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# --- End Modified ---&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;# 1. 쓰기 버퍼에 값 저장&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value
        &lt;span class=&quot;token comment&quot;&gt;# print(f&quot;[Buffer Write] Key: &apos;{key}&apos;, Buffer size: {len(self._write_buffer)}&quot;) # Debugging&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;# 2. 읽기 캐시에도 반영&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; value
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;move_to_end&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;# 3. 읽기 캐시 크기 관리&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cache_size&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;popitem&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;last&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__delitem__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;del obj[key] 구문 지원. 쓰기 버퍼에 삭제 표시. 버퍼가 차면 자동 플러시.&quot;&quot;&quot;&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_open&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;# 삭제 전 키 존재 여부 확인&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;__contains__&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
             &lt;span class=&quot;token keyword&quot;&gt;raise&lt;/span&gt; KeyError&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;# --- Modified ---&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# 버퍼에 추가하기 *전에* 가득 찼는지 확인하고 필요시 플러시&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_and_flush_buffer_if_full&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# --- End Modified ---&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;# 1. 쓰기 버퍼에 삭제 표시&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; _DELETED_SENTINEL
        &lt;span class=&quot;token comment&quot;&gt;# print(f&quot;[Buffer Delete] Key: &apos;{key}&apos;, Buffer size: {len(self._write_buffer)}&quot;) # Debugging&lt;/span&gt;


        &lt;span class=&quot;token comment&quot;&gt;# 2. 읽기 캐시에서도 제거&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; key &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;del&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# __contains__, get, sync, clear_cache, __len__, keys, values, items 은 이전과 동일&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__contains__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;&apos;key in obj&apos; 구문 지원. 버퍼 -&gt; 캐시 -&gt; shelve 순 확인.&quot;&quot;&quot;&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_open&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; key &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; _DELETED_SENTINEL
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; key &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; key &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; default&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;딕셔너리의 get과 유사하게 작동. 키 없으면 default 반환.&quot;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; KeyError&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; default
        &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; RuntimeError &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
             &lt;span class=&quot;token keyword&quot;&gt;raise&lt;/span&gt; e
        &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; Exception &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
             &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Error in get method for key &apos;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; default

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;
        쓰기 버퍼의 변경 사항을 즉시 shelve 파일에 반영합니다.
        &quot;&quot;&quot;&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_open&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Manual Sync: Flushing write buffer to shelve...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_flush_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# print(&quot;Manual Sync complete.&quot;) # Included in _flush_write_buffer&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clear_cache&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;
        수동으로 읽기 캐시만 비웁니다. 쓰기 버퍼는 유지됩니다.
        &quot;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Clearing read cache manually (write buffer remains).&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_cache&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clear&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__len__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;
        len(obj) 지원. 실제 shelve와 쓰기 버퍼의 변경 사항을 조합하여 크기 계산.
        &quot;&quot;&quot;&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_open&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keys&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Based on keys() result for accuracy&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;
        shelve와 쓰기 버퍼를 조합한 현재 키 집합을 반환합니다. (set으로 반환)
        &quot;&quot;&quot;&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_open&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        db_keys &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_db&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keys&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        buffer_added_keys &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;k &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; k&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; v &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; v &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; _DELETED_SENTINEL&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        buffer_deleted_keys &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;k &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; k&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; v &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; v &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; _DELETED_SENTINEL&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        final_keys &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;db_keys &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; buffer_added_keys&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; buffer_deleted_keys
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; final_keys

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;
        shelve와 쓰기 버퍼를 조합한 현재 값들의 제너레이터를 반환합니다.
        &quot;&quot;&quot;&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_open&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; key &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keys&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# __getitem__ handles buffer/cache/db lookup&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;
        shelve와 쓰기 버퍼를 조합한 현재 (키, 값) 쌍들의 제너레이터를 반환합니다.
        &quot;&quot;&quot;&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_check_open&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; key &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keys&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# __getitem__ handles buffer/cache/db lookup&lt;/span&gt;


&lt;span class=&quot;token comment&quot;&gt;# --- 클래스 사용 예제 (쓰기 버퍼 제한 및 자동 플러시 확인) ---&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; __name__ &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;__main__&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    filename &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;my_autoflush_shelve.db&apos;&lt;/span&gt;
    read_cache_size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;# --- New: Set write buffer limit ---&lt;/span&gt;
    write_limit &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;\n--- Test with Write Buffer Limit = &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;write_limit&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; ---&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# flag=&apos;n&apos; : 항상 새 파일 생성&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; CachedShelve&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filename&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cache_size&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;read_cache_size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; write_buffer_limit&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;write_limit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; flag&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;n&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; cs&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;\nAdding items (limit should trigger flush)...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;a&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Buffer: {&apos;a&apos;: 1} (Size 1)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Buffer size: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;b&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Buffer: {&apos;a&apos;: 1, &apos;b&apos;: 2} (Size 2)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Buffer size: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;c&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Buffer: {&apos;a&apos;: 1, &apos;b&apos;: 2, &apos;c&apos;: 3} (Size 3) - Limit reached&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Buffer size: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;\nAdding item &apos;d&apos; (should trigger auto-flush now)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# Below line should trigger _check_and_flush_buffer_if_full()&lt;/span&gt;
            cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;d&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# Flush happens, buffer cleared, then &apos;d&apos; is added&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# Buffer: {&apos;d&apos;: 4} (Size 1)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Buffer size after adding &apos;d&apos;: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Current keys (after potential flush): &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keys&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;\nAdding more items...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;e&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Buffer: {&apos;d&apos;: 4, &apos;e&apos;: 5} (Size 2)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Buffer size: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;f&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Buffer: {&apos;d&apos;: 4, &apos;e&apos;: 5, &apos;f&apos;: 6} (Size 3) - Limit reached again&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Buffer size: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;\nDeleting &apos;a&apos; (should trigger auto-flush)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# &apos;a&apos; was flushed earlier, now we delete it. Buffer limit reached.&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;del&lt;/span&gt; cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;a&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# Flush happens (d, e, f written), buffer cleared, then &apos;a&apos; deletion added&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;# Buffer: {&apos;a&apos;: SENTINEL} (Size 1)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Buffer size after deleting &apos;a&apos;: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

            cs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;g&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Buffer: {&apos;a&apos;: SENTINEL, &apos;g&apos;: 7} (Size 2)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Buffer size: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Final keys before exit: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keys&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Final buffer content before exit: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_write_buffer&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;# Exit flushes the remaining buffer {&apos;a&apos;: SENTINEL, &apos;g&apos;: 7}&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;\n--- After &apos;with&apos; block (final flush on exit) ---&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; Exception &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;An error occurred: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# Clean up in case of error during test&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; os
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; ext &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;.bak&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;.dat&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;.dir&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; os&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;remove&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filename &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; ext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; FileNotFoundError&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;pass&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Re-raise exception&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;# Verify final contents&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;\n--- Verifying final contents in shelve ---&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; CachedShelve&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filename&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; flag&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;r&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; cs_read&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Read-only&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Final keys in shelve: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;sorted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cs_read&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keys&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# sorted for consistent output&lt;/span&gt;
            expected_keys &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;b&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;d&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;e&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;f&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;g&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# a deleted, c flushed then overwritten by flush of a&apos;s deletion? No, c was flushed. b was flushed. d,e,f flushed. a deleted in final flush, g added in final flush.&lt;/span&gt;
            actual_keys &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cs_read&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;keys&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; actual_keys &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; expected_keys&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Verification successful!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Values:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; k &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;sorted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;actual_keys&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;  &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;k&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;cs_read&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;k&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;Verification FAILED!&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;  Expected: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;sorted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expected_keys&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;  Actual:   &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;sorted&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;actual_keys&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; Exception &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;An error occurred during verification: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;finally&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# Clean up shelve files&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; os
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;\nCleaning up shelve files...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; ext &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;.bak&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;.dat&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;.dir&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                os&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;remove&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filename &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; ext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token comment&quot;&gt;# print(f&quot;Removed {filename + ext}&quot;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;except&lt;/span&gt; FileNotFoundError&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;pass&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Cleanup complete.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;sync i/o 최적화는?&lt;/h3&gt;
&lt;p&gt;그럼에도 이 또한 sync 과정에서 i/o가 개별적으로 발생하니 조삼모사 같기도 하다. 거기에 대한 gemini의 생각은 아래와 같다고 한다. 내심 처음 생각했던게 sqlite였는데 코드 고치기가 싫어서 다른 방법 찾다가 돌고돌아 결국 다시 원점으로 왔나 싶기도 하다. 뭔가 수미상관인가?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;네, 아주 정확한 지적입니다! 현재 &lt;code class=&quot;language-text&quot;&gt;_flush_write_buffer&lt;/code&gt; 메소드는 &lt;code class=&quot;language-text&quot;&gt;_write_buffer&lt;/code&gt;의 각 항목에 대해 루프를 돌면서 &lt;code class=&quot;language-text&quot;&gt;self._db[key] = value&lt;/code&gt; 또는 &lt;code class=&quot;language-text&quot;&gt;del self._db[key]&lt;/code&gt;를 호출합니다. &lt;code class=&quot;language-text&quot;&gt;shelve&lt;/code&gt; 객체는 딕셔너리처럼 동작하지만, 내부적으로는 각 할당/삭제 작업이 (대부분의 &lt;code class=&quot;language-text&quot;&gt;dbm&lt;/code&gt; 구현에서) 개별적인 파일 I/O 작업으로 이어질 수 있습니다. 따라서 버퍼에 100개의 변경 사항이 있었다면, 플러시 과정에서 100번의 작은 디스크 접근이 발생할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;이 플러시 과정 자체를 최적화하여 I/O를 모아서 한 번에 처리할 수 있을까요?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;안타깝게도 &lt;strong&gt;표준 &lt;code class=&quot;language-text&quot;&gt;shelve&lt;/code&gt; 모듈과 그 기반의 &lt;code class=&quot;language-text&quot;&gt;dbm&lt;/code&gt; 라이브러리 수준에서는 이 작업을 직접적으로 제어하거나 보장하는 간단하고 표준적인 방법이 제한적입니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;몇 가지 관련된 측면과 가능한 접근법(및 한계)을 살펴보겠습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;shelve&lt;/code&gt;의 내부 동작 및 &lt;code class=&quot;language-text&quot;&gt;dbm&lt;/code&gt;:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;shelve&lt;/code&gt;는 키-값 저장을 위해 &lt;code class=&quot;language-text&quot;&gt;dbm&lt;/code&gt; (예: &lt;code class=&quot;language-text&quot;&gt;dbm.gnu&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;dbm.ndbm&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;dbm.dumb&lt;/code&gt;) 같은 라이브러리를 사용합니다. 이러한 &lt;code class=&quot;language-text&quot;&gt;dbm&lt;/code&gt; 라이브러리가 내부적으로 어느 정도의 쓰기 버퍼링을 수행할 수는 있지만, &lt;code class=&quot;language-text&quot;&gt;shelve&lt;/code&gt; 모듈 자체가 &quot;여러 항목을 한 번의 I/O 작업으로 쓰기&quot; 위한 명시적인 공개 API(예: &lt;code class=&quot;language-text&quot;&gt;update_batch(items)&lt;/code&gt;)를 제공하지는 않습니다.&lt;/li&gt;
&lt;li&gt;따라서 &lt;code class=&quot;language-text&quot;&gt;self._db[key] = value&lt;/code&gt; 호출이 즉시 디스크에 쓰일지, 내부 &lt;code class=&quot;language-text&quot;&gt;dbm&lt;/code&gt; 버퍼에 들어갈지는 사용 중인 &lt;code class=&quot;language-text&quot;&gt;dbm&lt;/code&gt; 구현과 운영체제에 따라 달라질 수 있으며, 파이썬 코드 수준에서 직접 제어하기 어렵습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;shelve.sync()&lt;/code&gt;의 역할:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;shelve&lt;/code&gt; 객체의 &lt;code class=&quot;language-text&quot;&gt;sync()&lt;/code&gt; 메소드는 아직 디스크에 기록되지 않은 데이터를 강제로 쓰도록 요청합니다.&lt;/li&gt;
&lt;li&gt;만약 &lt;code class=&quot;language-text&quot;&gt;_flush_write_buffer&lt;/code&gt; 루프가 끝난 &lt;em&gt;후&lt;/em&gt; &lt;code class=&quot;language-text&quot;&gt;self._db.sync()&lt;/code&gt;를 호출하면, 루프 동안 요청된 모든 개별 쓰기 작업들이 (만약 &lt;code class=&quot;language-text&quot;&gt;dbm&lt;/code&gt;이나 OS 수준에서 버퍼링되고 있었다면) 디스크에 확실히 반영되도록 보장하는 데 도움이 됩니다.&lt;/li&gt;
&lt;li&gt;하지만 이것이 루프 동안 발생한 &lt;em&gt;여러 번의 I/O 요청 자체&lt;/em&gt;를 &lt;em&gt;한 번의 큰 I/O 요청&lt;/em&gt;으로 바꿔주지는 못할 가능성이 높습니다. 이미 여러 번의 쓰기/삭제 작업이 &lt;code class=&quot;language-text&quot;&gt;dbm&lt;/code&gt; 계층에 전달되었을 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;shelve(writeback=True)&lt;/code&gt; 재고:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;이전에 우리는 &lt;code class=&quot;language-text&quot;&gt;writeback=True&lt;/code&gt; 사용을 금지했습니다. 하지만 이론적으로, 만약 &lt;code class=&quot;language-text&quot;&gt;shelve.open(..., writeback=True)&lt;/code&gt;를 사용한다면, &lt;code class=&quot;language-text&quot;&gt;_flush_write_buffer&lt;/code&gt; 루프에서 &lt;code class=&quot;language-text&quot;&gt;self._db[key] = value&lt;/code&gt; 등을 호출하는 것이 &lt;code class=&quot;language-text&quot;&gt;shelve&lt;/code&gt;의 내부 메모리 캐시만 업데이트할 수 있습니다. 그리고 루프가 끝난 후 &lt;code class=&quot;language-text&quot;&gt;self._db.sync()&lt;/code&gt;를 한 번 호출하면, &lt;code class=&quot;language-text&quot;&gt;shelve&lt;/code&gt;가 내부 캐시의 모든 변경 사항을 (어쩌면 더 효율적으로) 디스크에 쓸 수도 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;단점:&lt;/strong&gt; 이전에 논의했듯이 메모리 사용량 증가 (우리 캐시 + &lt;code class=&quot;language-text&quot;&gt;shelve&lt;/code&gt; 캐시), 복잡성 증가, &lt;code class=&quot;language-text&quot;&gt;shelve&lt;/code&gt; 내부 동작 의존성, 우리 캐싱 전략과의 충돌 가능성 등 문제가 많아 여전히 권장하기 어렵습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;shelve.update()&lt;/code&gt; 사용:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;shelve&lt;/code&gt; 객체도 딕셔너리처럼 &lt;code class=&quot;language-text&quot;&gt;update()&lt;/code&gt; 메소드를 가집니다. 쓰기 버퍼의 내용을 딕셔너리로 만들어 &lt;code class=&quot;language-text&quot;&gt;self._db.update(write_dict)&lt;/code&gt;를 호출하면 어떨까요?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;한계:&lt;/strong&gt; 파이썬의 일반적인 &lt;code class=&quot;language-text&quot;&gt;update()&lt;/code&gt; 구현은 단순히 입력 딕셔너리를 반복하며 각 항목에 대해 &lt;code class=&quot;language-text&quot;&gt;__setitem__&lt;/code&gt;을 호출하는 것과 같습니다. 따라서 &lt;code class=&quot;language-text&quot;&gt;_db.update(d)&lt;/code&gt;는 &lt;code class=&quot;language-text&quot;&gt;for k, v in d.items(): _db[k] = v&lt;/code&gt;와 동일하게 동작할 가능성이 높으며, I/O 최적화를 보장하지 않습니다. (삭제 작업은 별도로 처리해야 함).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;대안: 다른 백엔드 사용:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;이 문제의 근본적인 해결책은 &lt;code class=&quot;language-text&quot;&gt;shelve&lt;/code&gt; 대신 &lt;strong&gt;명시적인 배치(batch) 쓰기 API를 제공하는 다른 저장소 백엔드를 사용&lt;/strong&gt;하는 것입니다.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SQLite:&lt;/strong&gt; &lt;code class=&quot;language-text&quot;&gt;sqlite3&lt;/code&gt; 모듈을 사용하여 여러 SQL &lt;code class=&quot;language-text&quot;&gt;INSERT&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;UPDATE&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;DELETE&lt;/code&gt; 문을 하나의 트랜잭션으로 묶어 실행하면 훨씬 효율적입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LMDB (Lightning Memory-Mapped Database):&lt;/strong&gt; &lt;code class=&quot;language-text&quot;&gt;lmdb&lt;/code&gt; 파이썬 라이브러리는 트랜잭션 내에서 여러 쓰기 작업을 효율적으로 처리하는 기능을 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LevelDB/RocksDB:&lt;/strong&gt; 이 라이브러리들도 배치 쓰기 기능을 제공하는 경우가 많습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;단점:&lt;/strong&gt; 이는 &lt;code class=&quot;language-text&quot;&gt;CachedShelve&lt;/code&gt; 클래스의 기반 저장소를 &lt;code class=&quot;language-text&quot;&gt;shelve&lt;/code&gt;가 아닌 다른 것으로 완전히 바꾸는 큰 변경이며, 기존 &lt;code class=&quot;language-text&quot;&gt;shelve&lt;/code&gt; 파일과의 호환성이 사라집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;결론:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;현재 &lt;code class=&quot;language-text&quot;&gt;CachedShelve&lt;/code&gt; 클래스가 &lt;strong&gt;표준 &lt;code class=&quot;language-text&quot;&gt;shelve&lt;/code&gt; 모듈을 사용하는 한&lt;/strong&gt;, &lt;code class=&quot;language-text&quot;&gt;_flush_write_buffer&lt;/code&gt; 내의 여러 쓰기/삭제 요청을 &lt;strong&gt;하나의 최적화된 디스크 I/O 작업으로 확실하게 묶는 것은 어렵습니다.&lt;/strong&gt; &lt;code class=&quot;language-text&quot;&gt;shelve&lt;/code&gt; API의 한계와 &lt;code class=&quot;language-text&quot;&gt;dbm&lt;/code&gt; 구현의 다양성 때문입니다.&lt;/p&gt;
&lt;p&gt;우리가 할 수 있는 최선은 다음과 같습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;쓰기 지연:&lt;/strong&gt; 현재 구현처럼 &lt;code class=&quot;language-text&quot;&gt;_write_buffer&lt;/code&gt;를 사용하여 &lt;code class=&quot;language-text&quot;&gt;shelve&lt;/code&gt;에 대한 접근 자체를 최대한 지연시키는 것 (이것만으로도 상당한 성능 향상이 있을 수 있습니다).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;sync()&lt;/code&gt; 호출:&lt;/strong&gt; &lt;code class=&quot;language-text&quot;&gt;_flush_write_buffer&lt;/code&gt;가 끝난 후 &lt;code class=&quot;language-text&quot;&gt;self._db.sync()&lt;/code&gt;를 호출하여 데이터의 디스크 기록을 보장하는 것 (선택 사항, 내구성은 높이지만 약간의 추가 오버헤드 발생 가능).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;만약 플러시 과정 자체의 I/O 효율을 극대화하는 것이 매우 중요하다면, &lt;code class=&quot;language-text&quot;&gt;shelve&lt;/code&gt; 대신 SQLite나 LMDB 같은 다른 백엔드를 사용하도록 클래스를 재설계하는 것을 고려해야 합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;결국 데이터 구조를 변경해서 해결했으니 이 모든 논의가 쓸모 없는 시간 낭비는 아닐까라는 생각이 들수도 있다. 하지만 과정이 재밌었고, 뭔가 배운게 있었다면 된 거 아닌가 싶다. 공자 선생님께서 말씀하셨듯이 배우고 때때로 익히면 또한 즐겁지 아니한가?&lt;/p&gt;
&lt;p&gt;어쨌든, 오늘의 교훈. 구글도 이제 감 잡은 거 같기도 하다는 거. gemini 2.5 pro 몹시 훌륭하다. 벤치마크에서는 양민 학살중~&lt;/p&gt;
&lt;p&gt;덧) 인공지능은 실수할 수 있다. 여기 올려진 코드에 버그가 있다고 너무 나무라지는 말자. 직접 작성해도 그 정도 버그는 나온다. 참고로 gemini는 저 모든 코드를 타이핑 하는 속도보다 빠르게 만들었다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[ai] 바이브 코딩의 시대]]></title><description><![CDATA[바이브 코딩이 유행이다. 직접 코딩하지 않고 자연어로 인공지능에 명령만 해서 코딩을 하는 것을 말하는 의미다. 통상 8…]]></description><link>https://jiniya.net/2025/03/vibe-coding-era/</link><guid isPermaLink="false">https://jiniya.net/2025/03/vibe-coding-era/</guid><pubDate>Tue, 25 Mar 2025 13:00:01 GMT</pubDate><content:encoded>&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;vibe-coding.webp&apos; data-alt=&apos;안드레 카파시 말처럼 바이브에 몸을 맡기자.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/6f1ddd64dda716fb7d15ea7a59b631fe/a4772/vibe-coding.webp&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 57.36842105263158%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/webp;base64,UklGRqQAAABXRUJQVlA4IJgAAACQBACdASoUAAsAPtFUo0uoJKMhsAgBABoJbACdMoRwAdBw7IEsiQm1XNIbjoAA/tIDIGxT606MBeTJio552zXl42yyJKChdrxP9YbsiNLX54WjXNg8/yWiztn1tVdXoGV7VHW47v0yaNTRSPW6hi6Pj8BZzkoGlJLimHHS7Eaa6z8eWb6yCfsM3JHhNJ6f1vafPDAHrj4AAA==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;안드레 카파시 말처럼 바이브에 몸을 맡기자.&apos; title=&apos;&apos; src=&apos;/static/6f1ddd64dda716fb7d15ea7a59b631fe/7df04/vibe-coding.webp&apos; srcset=&apos;/static/6f1ddd64dda716fb7d15ea7a59b631fe/561c4/vibe-coding.webp 190w,
/static/6f1ddd64dda716fb7d15ea7a59b631fe/3e041/vibe-coding.webp 380w,
/static/6f1ddd64dda716fb7d15ea7a59b631fe/7df04/vibe-coding.webp 760w,
/static/6f1ddd64dda716fb7d15ea7a59b631fe/b2cd5/vibe-coding.webp 1140w,
/static/6f1ddd64dda716fb7d15ea7a59b631fe/98c2e/vibe-coding.webp 1520w,
/static/6f1ddd64dda716fb7d15ea7a59b631fe/a4772/vibe-coding.webp 1792w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;안드레 카파시 말처럼 바이브에 몸을 맡기자.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Vibe_coding&quot;&gt;바이브 코딩이&lt;/a&gt; 유행이다. 직접 코딩하지 않고 자연어로 인공지능에 명령만 해서 코딩을 하는 것을 말하는 의미다. 통상 80% 이상을 인공지능이 작성하면 바이브 코딩으로 보는 추세인 것 같다. 바이브 코딩으로 게임을 만들어서 큰 돈을 벌었다는 사람도 있고, SNS에는 온갖 것들을 바이브 코딩으로 만들었다는 개발자 또는 비개발자들의 글이 넘쳐난다.&lt;/p&gt;
&lt;p&gt;한편, 이를 바라보는 직업 프로그래머의 반응은 엇갈린다. 바이브에 올라타는 사람도 있고, 그로인한 리팩토링 대란이 벌어질 것이라는 얘기를 하는 사람들도 있다. 어쨌든 나는 바이브에 올라탄 사람 중에 한 명이긴 하다.&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;내가 처음 바이브 코딩을 해본 건 작년 한글날 정도였던 것 같다. 한창 새로운 제품 코드를 작성하고 있었다. 이 제품은 몇 년을 개발이 지지부진한 것 중에 하나였다. 내가 코드를 쓰지 않은 것도 있었지만 새로운 제품을 우리가 감당할 수 있을까, 라는 생각도 컸었다. 새로운 제품은, 새로운 테스트를, 새로운 지원을, 새로운 영업을, 새로운 홍보를 필요로하는 일이니 말이다. 하지만 우리는 힘든 시기를 겪고 있었고, 더이상 미룰 수는 없었다. 마침 o1-preview가 출시되기도 했었다. 거기다 세월을 묵힌 시간만큼 리서치 자료는 많이 쌓여 있었다. 벤치마킹할 타사 제품도 수두룩했다.&lt;/p&gt;
&lt;p&gt;처음에는 ChatGPT와 함께 작성하기 시작했다. 주로 4o에게 작업을 지시하고 결과를 내가 복붙해서 확인하는 작업이었다. ChatGPT로는 전체 프로그램을 한번에 작성하는 것은 쉽지 않기 때문에 전체 구조는 내가 생각했고 주로 함수 단위로 코딩을 지시해서 붙여넣었다. 당연히 출발은 우리의 리서치 자료에서 시작했다. 얼추 해당 자료대로 모두 구현을 했다. 그런데 테스트를 돌리니 예외가 너무 많이 발생했다. 리서치 자료가 크게 도움이 되지 않은 상황이었다.&lt;/p&gt;
&lt;p&gt;여기서부터는 멘붕, 과연 이걸 해결할 수 있을까, 라는 생각. 대충 땜빵식으로 해결할수도 있겠지만 리얼월드에서는 무슨 일이 벌어질지 모르는 것이라 그것도 한계가 있었다. 모든걸 원점 재검토가 필요한 상황이었다. 그렇게 새로운 방법을 시도했다. 하지만 번번히 예외 케이스들이 너무 많이 발생하는게 문제였다. 코딩이 문제가 아니라 문서화되지 않은 것들에 대한 구조를 이해하는 게 핵심이었는데 그건 나도 모르고, ChatGPT도 모르는 게 큰 일이었다. 당연한 얘기였지만 다른 제품들도 모두 안되기는 마찬가지였다. 왜냐하면 타사 제품도 모두 동일한 오픈소스를 사용하고 있었고, 그 오픈소스 코드가 잘 동작하지 않는 경우가 많은게 문제였기 때문이다.&lt;/p&gt;
&lt;p&gt;그렇게 설계를 3-4번은 뒤집어 엎었다. 최종적으로는 ChatGPT와 함께 오픈소스를 이해하기로 했다. 오픈소스는 너무 커서 거기서 내가 필요한 부분을 찾는 것도 일이었는데 웃긴 건 ChatGPT가 그걸 학습해서 그런지 오픈소스에서 내가 필요한 코드가 어디 있는지 물어보면 기가 막히게 알려줬다. 물론 오픈소스라는게 코드만 있다고 이해가 되는 건 아니다. 이해가 되지 않는 부분은 ChatGPT에 넣어서 다시 설명을 요청했다. 그 이해한 걸 토대로 ChatGPT한테 코딩을 시켜서 코드를 작성했다. 그 모든 작업을 하는 동안 o1-preview를 사용할 일은 한 번 밖에 없었다.&lt;/p&gt;
&lt;p&gt;그러다 커서라는 걸 알게됐고 커서로 코딩을 시작했다. 커서는 전체 컨텍스트를 자동으로 llm에 보내 주기 때문에 코딩이 훨씬 편했다. 인라인 에디팅이나 블록을 지정해서 고치기가 훨씬 쉬운게 장점이었다. 그리고 브라우저로 와리가리 안해도 되서 시간이 많이 절약됐다. 그렇게 돌아보니 80%는 아니라도 얼추 70%는 인공지능이 코딩한 제품이 완성됐다. 그때는 바이브 코딩이란 말도 없던 시기라 묘한 기분이 들었다. 제품이 다 작성됐고 빌드 후 테스트를 진행하는 단계가 되니 뭔가 ChatGPT랑 뒷풀이라도 해야 할 것 같다는 생각이 들었다.&lt;/p&gt;
&lt;p&gt;사람이면 설계를 3-4번 뒤집는 일을 참지 못했을 것 같다는 생각. 작성했지만 버렸던 수많은 코드에 엄청난 에고로 집착했을거라는 생각. 그리고 웃기게도 이 거대한 작업에서의 나에게 아하 모멘트는 이런 부분이었다. A라는 오픈소스에서 B라는 기능 관련된 코드가 어디있는지 알려줘. 이걸 당연히 답할거라고 생각을 안해서 물어볼 생각을 안했는데 하도 답답해서 물어봤는데 정말 어처구니 없을 정도로 정확하게 코드 위치를 잘 알려주었다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;해가 바뀌었고 deepseek가 미국 주도 인공지능 세계에 한차례 충격을 가했다. 더불어 인공지능 오픈소스 생태계는 더욱 풍성해졌다. 장비를 구성할 능력만 되면 로컬에서도 o1 급의 리즈닝 모델을 돌릴 수 있는 세상이 된 것이다. 물론 deepseek-r1은 아직 로컬에서는 돌리기 부담스러운 671b 모델이긴 하다. 하지만 뒤따라 출시된 qwen2.5-coder-32b나 qwq-32b 같은 모델만 사용해도 나쁘지 않은 성능을 보여주었다. 그도 그럴것이 앞서도 언급했지만 대부분의 보통 프로그래머가 작성하는 코드란게 뭔가 대단한 코드가 아니기 때문이다. 안타깝게도 우리는 너무나 뻔한 코드를 대부분 작성하는 경우가 다반사니까 말이다.&lt;/p&gt;
&lt;p&gt;최근에 일감이 하나 올라왔다. 고객사에서 api 사용에 문제를 겪는 일감이었다. 업체측에서 친절하게도 본인들이 구현한 코드를 보내주었다. 신입 개발자에게 확인해보라고 했지만 쉽지 않을거라는 생각이 들긴 했다. 그렇다고 내가 앉아서 그 모든 걸 보고 있기엔 다른 급한 일감도 너무 많았다. 그래서 딸깍 코딩을 해보기로 했다. 일감 내용과 업체 코드를 집어 넣고 문제를 재현할 수 있는 테스트 코드를 작성하라고 했다. 아키텍트로 qwq:32b_q4, 에디터로 qwen2.5-coder:32b_q4를 사용했다. 생각했던 것보다 아주 잘 작성했다. 웃긴건 걔가 제대로 작성했는데 내가 틀린 것 같아서 수정을 지시했는데, 업체측에 확인 요청한 결과 내가 지시한 부분이 잘못된 부분이었다. 걔가 원래 작성한 코드가 맞는 코드였다. 업체 측에서 우리가 봐도 되는 부분만 발췌해서 보낸 코드라 빠진 코드가 더러 있었다. 그런 코드는 나머지를 토대로 추론해서 작성하라고 지시를 했는데 그것도 잘 작성했다.&lt;/p&gt;
&lt;p&gt;어쨌든 잘 만들 필요는 없지만 재현시키기 위해서는 복잡한 귀찮은 작업이 필요한 그런 작업이었다. 내가 한다고 해도 몇일은 걸릴 것 같은 일이었다. 그런데 정말 딸깍 코딩으로 모든 게 만들어졌다. 내가 일부 수정한 건 경로가 맞지 않아서 포함 경로를 수정하고 포함 파일이 빠진 걸 몇 개 추가한 게 다였다. 물론 이 또한 바이브 코딩을 할 수 있겠지만 그걸 타이핑하는 시간에 코드 고치는 게 훨씬 빠르기에 내가 직접 했다. 결과적으로 그렇게 전체 작업을 하는 데 걸린 시간은 1-2 시간도 채 되지 않았다. 물론 그 마저도 대부분의 시간은 걔가 코딩 하는 걸 대기하는 시간이었다. 왜냐하면 우리 장비는 그리 좋은 장비가 아니라 느리다는 점. 모델 2개를 한번에 메모리에 로딩할 수가 없어서 아키텍트하고 에디팅할 때 항상 모델 교체를 위한 시간이 낭비된다는 점 때문이다. 지시도 몇개 안했지만 대부분 생각보다 너무 잘해서 놀랐다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;모든 코드를 잘 작성할 필요는 없다. 그냥 확인을 위해서 임시로 작성하는 코드도 수도 없이 많다. 그런 코딩은 인공지능에게 시키고 나는 중요한 다른 코드를 쓴다면 동시에 두가지 일을 하는 셈이 되는거니 생산성은 배가 된다. 시스템 프로그래머들에게 한참 전에 파이썬을 써야 한다고 하면 C/C++로도 다 할 수 있다는 핀잔을 듣던 시기가 있었다. 하지만 세월이 지나서 이제는 파이썬이 세상을 지배하고 있다. 인공지능도 머지 않아 그렇게 될 거라 본다. 직접해도 다 할 수 있다. 다만 인공지능을 사용하면 더 빨리 할 수 있다. 그리고 열린 마음으로 함께 한다면 나도 모르고, 인공지능도 모르는 것에 대한 작업도 함께 할 수 있다.&lt;/p&gt;
&lt;p&gt;인정하기 싫지만 인공지능이 나보다 코드를 더 잘 읽고, 더 잘 작성한지는 생각보다 제법 오래된 것 같다. 많은 경험을 토대로 느낀 점은 컨텍스트만 제대로 제공하면 거의 상당수 경우에 인간보다 훨씬 나은 결과가 나온다는 것이다. 그러니 이제, 안드레 카파시 말처럼 인공지능을 믿고 바이브에 몸을 맡기자.&lt;/p&gt;
&lt;p&gt;덧) 나는 이제 더 이상 커서를 사용하지 않는다. 내가 필요한 기능은 대부분 깃헙 코파일럿에 모두 추가되었고 커서의 크레딧 같은 기능은 코딩을 많이 하는 경우 거의 2주면 다 바닥났기 때문이다. 물론 결제를 더하면 더 늘릴 수 있겠지만 코파일럿이 너무 빨리 따라왔다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] make_unique<T[]>(n)]]></title><description><![CDATA[에 대해서 배열 초기화를 하지 않는다고 잘못 알고 있었던 사실이 있어서 정리해 본다. 은 내부적으로 을 호출하기 때문에 기본 타입에 대해서도 초기화 동작이 발생한다. 그런 이유로 초기화 없는 배열 할당을 위해서 C++ 2…]]></description><link>https://jiniya.net/2025/make_unique/</link><guid isPermaLink="false">https://jiniya.net/2025/make_unique/</guid><pubDate>Sun, 02 Feb 2025 17:00:01 GMT</pubDate><content:encoded>&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;make_unique&amp;lt;T[]&gt;(n)&lt;/code&gt;에 대해서 배열 초기화를 하지 않는다고 잘못 알고 있었던 &lt;a href=&quot;/2022/the-reasons-why-a-vector-is-unsuitable-for-use-as-a-buffer/&quot;&gt;사실이 있어서&lt;/a&gt; 정리해 본다. &lt;code class=&quot;language-text&quot;&gt;make_unique&amp;lt;T[]&gt;(n)&lt;/code&gt;은 내부적으로 &lt;code class=&quot;language-text&quot;&gt;new T[n]()&lt;/code&gt;을 호출하기 때문에 기본 타입에 대해서도 초기화 동작이 발생한다. 그런 이유로 초기화 없는 배열 할당을 위해서 C++ 20에서는 &lt;code class=&quot;language-text&quot;&gt;make_unique_for_overwrite&lt;/code&gt;가 추가되었다고 한다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;make_unique&amp;lt;T[]&gt;(n)&lt;/code&gt; - invokes &lt;code class=&quot;language-text&quot;&gt;new T[n]()&lt;/code&gt;, requesting value-initialization.&lt;br&gt;
&lt;a href=&quot;https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3588.htm&quot;&gt;https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3588.htm&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;C++ 20 에서는 이런 경우 사용하는 함수가 추가되었다&lt;br&gt;
&lt;code class=&quot;language-text&quot;&gt;std::unique_ptr&amp;lt;char[]&gt; arr = std::make_unique_for_overwrite&amp;lt;char[]&gt;(size);&lt;/code&gt;&lt;br&gt;
&lt;a href=&quot;https://blog.lunapiece.net/posts/C++-Dyanamic-Size-Buffer-Without-Initialization-And-Memoryleak/&quot;&gt;https://blog.lunapiece.net/posts/C++-Dyanamic-Size-Buffer-Without-Initialization-And-Memoryleak/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이하 deepseek v3 복음&lt;/p&gt;
&lt;h2&gt;make_unique&amp;#x3C;T[]&gt;&lt;/h2&gt;
&lt;p&gt;C++14 표준에서는 &lt;code class=&quot;language-text&quot;&gt;std::make_unique&lt;/code&gt;를 사용하여 동적 배열을 생성할 수 있도록 &lt;code class=&quot;language-text&quot;&gt;std::make_unique&amp;lt;T[]&gt;&lt;/code&gt;를 지원합니다. 이는 &lt;code class=&quot;language-text&quot;&gt;std::unique_ptr&lt;/code&gt;을 사용하여 배열을 관리할 때 매우 유용합니다.&lt;/p&gt;
&lt;h3&gt;&lt;code class=&quot;language-text&quot;&gt;std::make_unique&amp;lt;T[]&gt;&lt;/code&gt;의 특징&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;배열 생성&lt;/strong&gt;: &lt;code class=&quot;language-text&quot;&gt;std::make_unique&amp;lt;T[]&gt;&lt;/code&gt;는 &lt;code class=&quot;language-text&quot;&gt;T&lt;/code&gt; 타입의 동적 배열을 생성하고, 이를 관리하는 &lt;code class=&quot;language-text&quot;&gt;std::unique_ptr&amp;lt;T[]&gt;&lt;/code&gt;를 반환합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;자동 메모리 관리&lt;/strong&gt;: &lt;code class=&quot;language-text&quot;&gt;std::unique_ptr&lt;/code&gt;은 소멸 시 자동으로 메모리를 해제하므로, 메모리 누수를 방지할 수 있습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;초기화&lt;/strong&gt;: &lt;code class=&quot;language-text&quot;&gt;std::make_unique&amp;lt;T[]&gt;&lt;/code&gt;는 배열의 각 요소를 기본값으로 초기화합니다. 예를 들어, &lt;code class=&quot;language-text&quot;&gt;int&lt;/code&gt; 배열의 경우 모든 요소가 &lt;code class=&quot;language-text&quot;&gt;0&lt;/code&gt;으로 초기화됩니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;사용 예제&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;iostream&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;memory&gt;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// std::make_unique를 사용하기 위해 필요&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// int 타입의 배열 10개를 동적 할당&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;auto&lt;/span&gt; arr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;make_unique&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// 배열 초기화 및 출력&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; arr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// std::unique_ptr가 소멸되면 자동으로 메모리가 해제됨&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;주의사항&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;std::make_unique&amp;lt;T[]&gt;&lt;/code&gt;는 배열을 생성할 때만 사용할 수 있습니다. 단일 객체를 생성할 때는 &lt;code class=&quot;language-text&quot;&gt;std::make_unique&amp;lt;T&gt;&lt;/code&gt;를 사용해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;std::unique_ptr&amp;lt;T[]&gt;&lt;/code&gt;는 배열을 관리하기 위해 특수화된 형태이므로, &lt;code class=&quot;language-text&quot;&gt;operator[]&lt;/code&gt;를 사용하여 배열 요소에 접근할 수 있습니다. 단일 객체를 관리하는 &lt;code class=&quot;language-text&quot;&gt;std::unique_ptr&amp;lt;T&gt;&lt;/code&gt;에서는 &lt;code class=&quot;language-text&quot;&gt;operator[]&lt;/code&gt;를 사용할 수 없습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;요약&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;std::make_unique&amp;lt;T[]&gt;&lt;/code&gt;는 C++14에서 도입된 기능으로, 동적 배열을 생성하고 &lt;code class=&quot;language-text&quot;&gt;std::unique_ptr&lt;/code&gt;로 관리할 수 있게 해줍니다.&lt;/li&gt;
&lt;li&gt;이 기능은 메모리 관리와 안전성을 높이는 데 도움이 되며, 배열의 각 요소를 기본값으로 초기화합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이를 통해 C++에서 더 안전하고 간결하게 동적 배열을 관리할 수 있습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[py] __del__에서 리소스 해제를 하면 안 되는 이유]]></title><description><![CDATA[시작은 mysql 클라이언트였다. 해당 클래스를 사용하는 코드에서 close를 하지 않아서 리소스 릭이 발생하는 문제. pymysql…]]></description><link>https://jiniya.net/2024/12/python_raii/</link><guid isPermaLink="false">https://jiniya.net/2024/12/python_raii/</guid><pubDate>Tue, 10 Dec 2024 11:35:00 GMT</pubDate><content:encoded>&lt;p&gt;시작은 mysql 클라이언트였다. 해당 클래스를 사용하는 코드에서 close를 하지 않아서 리소스 릭이 발생하는 문제. pymysql은 왜 이걸 파괴될 때 자동으로 해제하지 않게 만들어서 개발자가 실수하게 만들었지?! 라고 삽질하다 알게 된 이유. 오늘의 교훈: 언어 별로 비슷한 점도 있지만, 다른 점도 많다.&lt;/p&gt;
&lt;p&gt;파이썬에서 &lt;code class=&quot;language-text&quot;&gt;__init__&lt;/code&gt;에서 리소스를 획득하고, &lt;code class=&quot;language-text&quot;&gt;__del__&lt;/code&gt;에서 리소스를 해제하는 패턴은 피하는 것이 좋습니다. 이유는 다음과 같습니다:&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;1. &lt;strong&gt;&lt;code class=&quot;language-text&quot;&gt;__del__&lt;/code&gt; 호출 보장이 없음&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;__del__&lt;/code&gt; 메서드는 객체가 &lt;strong&gt;가비지 컬렉션&lt;/strong&gt;에 의해 삭제될 때 호출되지만, 호출 시점이 보장되지 않습니다.&lt;/li&gt;
&lt;li&gt;특히, 프로그램이 종료할 때 전역 객체들의 소멸 순서에 따라 &lt;strong&gt;필요한 리소스가 이미 해제된 상태&lt;/strong&gt;일 수 있습니다.
&lt;ul&gt;
&lt;li&gt;예: 파일 핸들러, 네트워크 연결 등이 이미 닫혀있는 경우 문제가 발생할 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;2. &lt;strong&gt;순환 참조 문제&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;객체가 다른 객체와 순환 참조를 형성하면, 파이썬의 가비지 컬렉터가 &lt;code class=&quot;language-text&quot;&gt;__del__&lt;/code&gt;을 호출하지 않을 수 있습니다.
&lt;ul&gt;
&lt;li&gt;파이썬의 순환 참조를 감지하는 가비지 컬렉터는 &lt;code class=&quot;language-text&quot;&gt;__del__&lt;/code&gt;이 있는 객체를 처리하기 어렵습니다.&lt;/li&gt;
&lt;li&gt;결과적으로, 리소스가 영구적으로 해제되지 않을 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;3. &lt;strong&gt;명시적 리소스 관리 부족&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;리소스 관리가 암묵적으로 이루어져 가독성과 유지보수가 어려워집니다.
&lt;ul&gt;
&lt;li&gt;리소스 사용자가 객체의 수명을 정확히 제어하지 못합니다.&lt;/li&gt;
&lt;li&gt;누군가 &lt;code class=&quot;language-text&quot;&gt;__del__&lt;/code&gt; 호출을 의도적으로 방지하거나 놓치면, 리소스 누수가 발생합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;4. &lt;strong&gt;GC 타이밍에 의존&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;가비지 컬렉션은 &lt;strong&gt;언제 실행될지&lt;/strong&gt; 보장되지 않습니다.
&lt;ul&gt;
&lt;li&gt;예를 들어, 리소스를 빨리 해제해야 하는 상황에서 &lt;code class=&quot;language-text&quot;&gt;__del__&lt;/code&gt;에 의존하면, 리소스가 불필요하게 오래 유지될 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;대안: &lt;strong&gt;컨텍스트 관리자 (&lt;code class=&quot;language-text&quot;&gt;with&lt;/code&gt; 문법)&lt;/strong&gt; 사용&lt;/h3&gt;
&lt;p&gt;컨텍스트 관리자를 통해 리소스를 명시적으로 관리하는 것이 더 안전하고 직관적입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ResourceHandler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; resource&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;resource &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; resource

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__enter__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# 리소스 획득&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;resource&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; 획득&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;resource

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__exit__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; exc_type&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; exc_value&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; traceback&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# 리소스 해제&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;resource&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; 해제&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;# 예외 처리도 가능&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; exc_type&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;예외 발생: &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;exc_value&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;False&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;# 예외를 억제하지 않음&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 사용 예&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; ResourceHandler&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;파일&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; resource&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string-interpolation&quot;&gt;&lt;span class=&quot;token string&quot;&gt;f&quot;&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;resource&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt; 사용 중&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;h3&gt;요약&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;__del__&lt;/code&gt; 대신 &lt;strong&gt;컨텍스트 관리자&lt;/strong&gt;나 명시적인 리소스 해제 메서드(&lt;code class=&quot;language-text&quot;&gt;close&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;release&lt;/code&gt; 등)를 사용하는 것이 바람직합니다.&lt;/li&gt;
&lt;li&gt;이를 통해 리소스 관리가 예측 가능하고, 코드가 더 견고해집니다.&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[[ai] Qwen2.5-72b 성능 무엇?!]]></title><description><![CDATA[막내가 코드를 한 줄 고쳤다. 플래그가 잘못돼서 검사 루틴 체크가 안된다면서 값을 0x100에서 0x50으로 변경했다. 0x5…]]></description><link>https://jiniya.net/2024/10/qwen2.5-72b/</link><guid isPermaLink="false">https://jiniya.net/2024/10/qwen2.5-72b/</guid><pubDate>Thu, 17 Oct 2024 15:35:00 GMT</pubDate><content:encoded>&lt;p&gt;막내가 코드를 한 줄 고쳤다. 플래그가 잘못돼서 검사 루틴 체크가 안된다면서 값을 0x100에서 0x50으로 변경했다. 0x50만 보고 난 넘겨 짚었다. 쓸데 없는 걸 또 왜 고쳤지, 라는 생각.&lt;/p&gt;
&lt;p&gt;그러다 같이 저녁을 먹게 되서 관련해서 이야기를 듣게 됐다. 자기가 분석해봤는데 기존 코드에 이러저러한 부분 때문에 플래그가 클리어돼서 고쳐야 한다는 것이었다. 다른 주장이 있어서 일단 가서 다시 살펴 보겠다고는 했다. 그러면서도 내 생각은 여전히 세모라고 했다. 0x50은 틀린 건 확실했기 때문이다. 클리어 된다는 걸 내가 체크를 못한 건가 해서 확인을 해야겠다 싶었다.&lt;/p&gt;
&lt;p&gt;집에 와서 코드를 보니 막내 말도 맞았다. 하지만 문제는 0x50이었다. 0x10이랑 0x40을 쓰는 플래그랑 겹치는 값인 것이다. 그래서 과연 인공지능은 이 문제를 파악해낼지 궁금해서 테스트를 해보았다. 결과는 Qwen2.5-72b의 압승. 물론 사고력 모델인 o1 시리즈는 차원이 다른 답을 보여주었다. 그들 사이엔 768차원 정도의 간극이 있긴 한듯.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;프롬프트&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;XXX 플래그 검사하는 로직으로 살펴봤을 때 아래 코드에서 EEE_INDEX를 MAKELONG(0x50, 3)로 변경하는게 문제 없는지 판단해줘&lt;/p&gt;
&lt;p&gt;AAA_INDEX = MAKELONG(0x10, 3),&lt;br&gt;
BBB_INDEX = MAKELONG(0x20, 3),&lt;br&gt;
CCC_INDEX = MAKELONG(0x40, 3),&lt;br&gt;
DDD_INDEX = MAKELONG(0x80, 3),&lt;br&gt;
EEE_INDEX = MAKELONG(0x100, 3),&lt;/p&gt;
&lt;p&gt;... 관련 코드 ...&lt;/p&gt;
&lt;h3&gt;4o-mini&lt;/h3&gt;
&lt;p&gt;얘는 일단 말귀 자체를 못 알아 먹는다. 0x100을 0x50으로 변경하는 걸 검토하라는데 엉뚱한 소리를 함.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;EEE_INDEX&lt;/code&gt;를 &lt;code class=&quot;language-text&quot;&gt;MAKELONG(0x100, 3)&lt;/code&gt;으로 변경하는 것이 문제가 없는지 판단하기 위해 몇 가지 요소를 고려해야 합니다.&lt;/p&gt;
&lt;h3&gt;1. &lt;strong&gt;상수 중복 여부&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;EEE_INDEX&lt;/code&gt;가 &lt;code class=&quot;language-text&quot;&gt;MAKELONG(0x100, 3)&lt;/code&gt;으로 설정될 경우, 다른 인덱스 값과의 중복 여부를 확인해야 합니다. 주어진 코드에서 다른 인덱스 &gt; 값들은 다음과 같습니다:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;AAA_INDEX = MAKELONG(0x10, 3)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;BBB_INDEX = MAKELONG(0x20, 3)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;CCC_INDEX = MAKELONG(0x40, 3)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;DDD_INDEX = MAKELONG(0x80, 3)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;MAKELONG(0x100, 3)&lt;/code&gt;는 이들과 중복되지 않으며, 기존의 값들과 겹치지 않기 때문에 문제는 없습니다.&lt;/p&gt;
&lt;h3&gt;2. &lt;strong&gt;논리적 의미&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;EEE_INDEX&lt;/code&gt;의 의미를 파악하는 것이 중요합니다. ...&lt;/p&gt;
&lt;h3&gt;3. &lt;strong&gt;사용된 위치&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;코드에서 &lt;code class=&quot;language-text&quot;&gt;EEE_INDEX&lt;/code&gt;가 어떻게 사용되는지를 검토해야 합니다. &lt;code class=&quot;language-text&quot;&gt;Do&lt;/code&gt; 메서드와 같은 곳에서 해당 플래그가 어떤 동작을 유발하는지 &gt; 이해해야 합니다. 만약 &lt;code class=&quot;language-text&quot;&gt;EEE_INDEX&lt;/code&gt;가 &lt;code class=&quot;language-text&quot;&gt;GetFileEx&lt;/code&gt; 또는 &lt;code class=&quot;language-text&quot;&gt;TestFlag&lt;/code&gt;와 같은 중요한 검사와 연관되어 있다면, 변경으로 인해 예상치 못한 동작이 발생할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;위의 분석을 바탕으로, &lt;code class=&quot;language-text&quot;&gt;EEE_INDEX&lt;/code&gt;를 &lt;code class=&quot;language-text&quot;&gt;MAKELONG(0x100, 3)&lt;/code&gt;로 변경하는 것이 중복이나 충돌 없이 문제가 없을 것으로 보입니다. 그러나 해당 플래그가 어떤 의미를 지니고 있는지, 그리고 그 사용 위치를 검토하여 최종 판단을 내리는 것이 좋습니다. 특히, 기존의 로직이 이 값을 기반으로 동작하고 있다면, 변경이 다른 동작에 영향을 미칠 수 있으므로 신중해야 합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;4o&lt;/h3&gt;
&lt;p&gt;얘는 말귀는 알아 먹었고 전개도 나쁘진 않았지만 결국 장황하게 설명하며 핵심을 피해가고 있다. 아는 거 같기도 하고 모르는 거 같기도 하고 뭔가 모르지만 아는 척 하는 거 같기도 한 아주 두루뭉실 애매한 답변.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;주어진 코드에서는 다양한 이벤트 또는 조건 플래그를 설정하기 위해 MAKELONG 매크로를 사용합니다. MAKELONG는 두 개의 16비트 값을 받아 하나의 32비트 값을 생성하는 매크로로, 여기서는 인덱스를 생성하는 데 사용되고 있습니다.&lt;/p&gt;
&lt;p&gt;EEE_INDEX를 MAKELONG(0x100, 3)에서 MAKELONG(0x50, 3)으로 변경하려는 제안에 대해 검사해 보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;MAKELONG의 구조: MAKELONG(a, b) 구조에서 a는 하위 16비트 값을, b는 상위 16비트 값을 나타냅니다. 즉, MAKELONG(0x100, 3)은 0x00030064이라는 32비트 수를 생성하며, 이는 플래그 배열의 3번째 부분(HIWORD)에 0x100 비트를 설정하고자 할 때 사용됩니다.&lt;/p&gt;
&lt;p&gt;변경 시나리오:&lt;/p&gt;
&lt;p&gt;MAKELONG(0x50, 3)은 0x00030050이라는 값을 생성하게 됩니다. 이는 플래그 배열의 동일한 3번째 부분(HIWORD)에서 0x50 비트를 설정합니다.&lt;br&gt;
이 변경은 bit 부분만을 변경하므로, 인덱스의 비트 위치가 달라지게 되어 플래그가 검사될 때 다른 조건으로 해석될 수 있습니다.&lt;/p&gt;
&lt;p&gt;문제점:&lt;/p&gt;
&lt;p&gt;기존에 정의된 다른 플래그와의 중복이나, 애플리케이션의 로직 흐름에서 이 플래그의 역할이 달라질 가능성을 고려해야 합니다.&lt;br&gt;
다른 부분의 코드(예: TestFlag 및 파일 처리 로직)에서 이 플래그의 새로운 상태를 관리하는 방법이 제대로 처리되는지 확인해야 합니다.&lt;/p&gt;
&lt;p&gt;리스크 평가:&lt;/p&gt;
&lt;p&gt;만약 다른 플래그들과의 중복이 없다면, 변경은 문제를 일으키지 않지만, 코드 베이스 전체를 고려했을 때 이 변경이 코드의 다른 부분과 호환되는지 충분히 검토해야 합니다.&lt;br&gt;
결론적으로, EEE_INDEX 값을 0x50으로 변경하는 것은 인덱스 값의 비트 위치를 변경하는 것이므로, 이런 변경이 시스템 내 다른 곳에 영향을 미치지 않는지를 충분히 검토한 후에 수행해야 합니다. 구체적으로는 기존 로직에서 어떻게 이 플래그를 사용하는지 전반적인 코드 흐름에 대한 검토가 있을 때 비로소 안전하다고 판단할 수 있습니다.&lt;/p&gt;
&lt;p&gt;참고 문서&lt;br&gt;
C++ MAKELONG 매크로 사용법&lt;br&gt;
비트 연산을 통한 플래그 관리 방법&lt;br&gt;
코드 내 TestFlag와 유사 함수의 플래그 처리를 위한 예제 코드&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Qwen2.5-72b&lt;/h3&gt;
&lt;p&gt;놀랐다. 문제점을 정확하게 찾았다. 기존 플래그과 중첩된다는 걸 체크한다. 하지만 실수도 나랑 똑같았다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;새로운 플래그를 추가할 때는 이미 사용 중인 플래그와 충돌하지 않는 값으로 설정해야 합니다. 예를 들어, MAKELONG(0x200, 3)과 같은 값으로 변경하는 것이 안전할 것입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이 부분이 옥의 티. 나도 별 생각 없이 예전에 만든 코드라 0x100을 추가했는데 한바이트라 비트를 8개 밖에 쓰지를 못한다. 그래서 제대로 수정하려면 MAKELONG(1, 4)가 돼야 한다. 그럼에도 얘는 정확하게 막내의 수정 사항의 문제점을 찾아냈다는데 대해서는 몹시 칭찬한다. 알리바바가 외계인을 갈아 넣고 있는 건 정말 진실인지도?!&lt;/p&gt;
&lt;p&gt;양자화가 모델에 미치는 영향을 살펴보기 위해서 추가로 테스트를 더 돌려 보았는데 문제 답을 맞추기 위해서는 8비트 이상이 필요했다. 8비트 아래로 내려가면 4o와 비슷한 수준의 답변만 내놓는다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;주어진 코드에서 EEE_INDEX를 MAKELONG(0x100, 3)에서 MAKELONG(0x50, 3)으로 변경하는 것이 문제 없는지 판단하기 위해서는 몇 가지 점을 고려해야 합니다.&lt;/p&gt;
&lt;p&gt;비트 충돌: MAKELONG(0x50, 3)은 0x50을 3번 째 부분에 설정하는 것을 의미합니다. 이 값이 이미 사용 중인 다른 플래그와 충돌하지 않는지 확인해야 합니다. 현재 코드에서 이미 사용 중인 플래그들은 다음과 같습니다:&lt;/p&gt;
&lt;p&gt;AAA_INDEX = MAKELONG(0x10, 3)&lt;br&gt;
BBB_INDEX = MAKELONG(0x20, 3)&lt;br&gt;
CCC_INDEX = MAKELONG(0x40, 3)&lt;br&gt;
DDD_INDEX = MAKELONG(0x80, 3)&lt;br&gt;
0x50은 0x40과 0x10의 조합으로, CCC_INDEX와 AAA_INDEX와 충돌할 수 있습니다. 따라서 EEE_INDEX를 MAKELONG(0x50, 3)으로 변경하면 이 두 플래그와의 충돌이 발생할 수 있습니다.&lt;/p&gt;
&lt;p&gt;플래그 관리: 플래그는 비트 마스크로 관리되므로, 각 플래그가 독립적으로 설정되고 해제될 수 있어야 합니다. 0x50은 0x40과 0x10의 조합이므로, EEE_INDEX를 설정하거나 해제할 때 AAA_INDEX와 CCC_INDEX도 함께 영향을 받게 됩니다. 이는 원하지 않는 동작을 초래할 수 있습니다.&lt;/p&gt;
&lt;p&gt;코드의 안정성: 플래그 값이 충돌하면 코드의 안정성과 예측 가능성이 떨어집니다. 따라서 새로운 플래그를 추가할 때는 이미 사용 중인 플래그와의 충돌을 피하는 것이 중요합니다.&lt;/p&gt;
&lt;p&gt;결론&lt;br&gt;
EEE_INDEX를 MAKELONG(0x50, 3)으로 변경하는 것은 이미 사용 중인 AAA_INDEX와 CCC_INDEX와의 충돌을 일으킬 수 있으므로, 이 변경은 권장되지 않습니다. 대신, 새로운 플래그를 추가할 때는 이미 사용 중인 플래그와 충돌하지 않는 값으로 설정해야 합니다. 예를 들어, MAKELONG(0x200, 3)과 같은 값으로 변경하는 것이 안전할 것입니다.&lt;/p&gt;
&lt;p&gt;참고 문서&lt;br&gt;
주어진 코드 스니펫&lt;br&gt;
비트 마스크와 플래그 관리에 대한 일반적인 지식&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;o1-mini&lt;/h3&gt;
&lt;p&gt;사고력은 역시 미니라도 o1인가. o1-preview 는 굳이 등판할 이유조차 없는 답변. 한수 위가 뭔지 철저하게 보여준다. 참고로 5초 생각했다 ㅋㅋㅋ~&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;변수 &lt;code class=&quot;language-text&quot;&gt;EEE_INDEX&lt;/code&gt;를 &lt;code class=&quot;language-text&quot;&gt;MAKELONG(0x100, 3)&lt;/code&gt;에서 &lt;code class=&quot;language-text&quot;&gt;MAKELONG(0x50, 3)&lt;/code&gt;으로 변경하려는 의도는 이해됩니다. 그러나 이 변경이 문제를 일으킬 가능성이 높습니다. 아래에서 그 이유를 상세히 설명드리겠습니다.&lt;/p&gt;
&lt;h3&gt;현재 플래그 정의&lt;/h3&gt;
&lt;p&gt;현재 플래그는 다음과 같이 정의되어 있습니다:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;AAA_INDEX &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MAKELONG&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0x10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
BBB_INDEX &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MAKELONG&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0x20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
CCC_INDEX &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MAKELONG&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0x40&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
DDD_INDEX &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MAKELONG&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0x80&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
EEE_INDEX &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MAKELONG&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0x100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;&lt;code class=&quot;language-text&quot;&gt;MAKELONG&lt;/code&gt;의 동작&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;MAKELONG&lt;/code&gt; 매크로는 두 개의 16비트 값을 받아 32비트 값을 생성합니다. 여기서 첫 번째 인자는 &lt;code class=&quot;language-text&quot;&gt;LOWORD&lt;/code&gt;, 두 번째 인자는 &lt;code class=&quot;language-text&quot;&gt;HIWORD&lt;/code&gt;로 설정됩니다. 예를 들어:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;MAKELONG(0x10, 3)&lt;/code&gt;은 &lt;code class=&quot;language-text&quot;&gt;HIWORD = 3&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;LOWORD = 0x10&lt;/code&gt;이 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;MAKELONG(0x100, 3)&lt;/code&gt;을 &lt;code class=&quot;language-text&quot;&gt;MAKELONG(0x50, 3)&lt;/code&gt;으로 변경하면 &lt;code class=&quot;language-text&quot;&gt;LOWORD&lt;/code&gt;가 &lt;code class=&quot;language-text&quot;&gt;0x50&lt;/code&gt;으로 변경됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;변경 시 발생할 수 있는 문제&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;비트 중복&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;0x50&lt;/code&gt;은 16진수로 &lt;code class=&quot;language-text&quot;&gt;0101 0000&lt;/code&gt; (2진수)입니다.&lt;/li&gt;
&lt;li&gt;이는 &lt;code class=&quot;language-text&quot;&gt;0x10&lt;/code&gt; (&lt;code class=&quot;language-text&quot;&gt;0001 0000&lt;/code&gt;)과 &lt;code class=&quot;language-text&quot;&gt;0x40&lt;/code&gt; (&lt;code class=&quot;language-text&quot;&gt;0100 0000&lt;/code&gt;)의 비트가 모두 설정된 상태입니다.&lt;/li&gt;
&lt;li&gt;현재 다른 플래그들이 &lt;code class=&quot;language-text&quot;&gt;0x10&lt;/code&gt;과 &lt;code class=&quot;language-text&quot;&gt;0x40&lt;/code&gt;을 개별적으로 사용하고 있기 때문에, &lt;code class=&quot;language-text&quot;&gt;0x50&lt;/code&gt;으로 설정하면 두 플래그가 동시에 활성화된 것으로 인식될 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;플래그 충돌&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;EEE_INDEX&lt;/code&gt;를 &lt;code class=&quot;language-text&quot;&gt;0x50&lt;/code&gt;으로 변경하면, 다른 플래그들과 비트가 겹치게 되어 의도치 않게 여러 플래그가 동시에 활성화되거나 해제될 수 있습니다.&lt;/li&gt;
&lt;li&gt;이는 플래그 검사 로직에서 혼란을 초래할 수 있으며, 예상치 못한 동작을 유발할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;플래그 관리의 복잡성 증가&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;단일 비트 플래그를 복합 비트로 변경하면, 플래그를 설정하거나 해제할 때 복잡성이 증가합니다.&lt;/li&gt;
&lt;li&gt;예를 들어, &lt;code class=&quot;language-text&quot;&gt;0x50&lt;/code&gt;을 설정할 때 &lt;code class=&quot;language-text&quot;&gt;0x10&lt;/code&gt;과 &lt;code class=&quot;language-text&quot;&gt;0x40&lt;/code&gt;을 모두 설정해야 하며, 이를 해제할 때도 동일하게 처리해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;권장 사항&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;고유한 비트 사용&lt;/strong&gt;:
각 플래그는 고유한 비트를 사용하는 것이 좋습니다. 이는 플래그 간의 충돌을 방지하고, 플래그 관리의 명확성을 유지하는 데 도움이 됩니다.&lt;/p&gt;
&lt;p&gt;예를 들어, &lt;code class=&quot;language-text&quot;&gt;EEE_INDEX&lt;/code&gt;를 &lt;code class=&quot;language-text&quot;&gt;0x200&lt;/code&gt; (&lt;code class=&quot;language-text&quot;&gt;MAKELONG(0x200, 3)&lt;/code&gt;)과 같이 고유한 비트를 할당하는 것을 고려해보세요.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;플래그 정의 재검토&lt;/strong&gt;:
만약 &lt;code class=&quot;language-text&quot;&gt;0x50&lt;/code&gt;을 사용해야 하는 특별한 이유가 있다면, 해당 플래그가 기존 플래그들과 어떻게 상호작용하는지, 그리고 이를 처리하기 위한 추가 로직이 필요한지 신중하게 검토해야 합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;코드 리뷰 및 테스트&lt;/strong&gt;:
변경 사항을 적용하기 전에 코드 전체에 걸쳐 플래그가 어떻게 사용되고 있는지 철저히 리뷰하고, 충분한 테스트를 통해 예상치 못한 부작용이 없는지 확인해야 합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;EEE_INDEX&lt;/code&gt;를 &lt;code class=&quot;language-text&quot;&gt;MAKELONG(0x50, 3)&lt;/code&gt;으로 변경하는 것은 현재 플래그 정의와 사용 방식을 고려할 때 권장되지 않습니다. 이는 플래그 간의 비트 충돌을 유발하여 시스템 동작에 예기치 않은 문제를 초래할 수 있습니다. 고유한 비트를 유지하는 방향으로 변경을 고려하시기 바랍니다.&lt;/p&gt;
&lt;p&gt;추가적인 질문이나 코드 관련 상세한 검토가 필요하시다면 언제든지 문의해주세요!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;총평&lt;/h3&gt;
&lt;p&gt;기존 챗본 경쟁에서 OpenAI의 해자는 점점 없어지는 것으로 보여진다. o1 모델이 나오지 않았다면 정말 참담하지 않았을까 싶다. o1 모델이 있긴 하지만 앞으로도 경쟁 우위를 유지하기란 쉽지 않을 것 같다는 생각. 최근 mmlu-pro 리더보드에 &lt;a href=&quot;https://huggingface.co/spaces/TIGER-Lab/MMLU-Pro&quot;&gt;grok2가 4o 위에 0.7546으로 등재됐다.&lt;/a&gt; 물론 셀프 리포팅이긴 하지만 구라는 아닐 거 같다는 느낌. 이런걸 보면 System 1 사고를 한다는 앵무새 챗봇 경쟁은 gpu 살만한 돈들이 있는 회사들은 대부분 상향 평준화가 된 게 아닌가 싶다.&lt;/p&gt;
&lt;p&gt;알리바바에 거액을 날려 먹었지만 공산당만 아니면 다시 투자할 의향이 생기는 QWen2.5 72b였다. 그럼에도 진정 이바닥 위너는 nvidia인가?!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[ai] 거대 언어 모델 코딩 테스트]]></title><description><![CDATA[LLM이 코딩을 잘한다는 것은 이제 삼척동자도 아는 사실이다. 하지만 일반적으로는 함수 단위 또는 조금 넘어서 코드 블록 정도를 작성하는 수준으로 생각한다. 최근 회사에서 로컬 LLM을 테스트하면서 매뉴얼을 통째로 입력했을 때, LLM…]]></description><link>https://jiniya.net/2024/10/llm-coding-test/</link><guid isPermaLink="false">https://jiniya.net/2024/10/llm-coding-test/</guid><pubDate>Wed, 16 Oct 2024 15:35:00 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/bB3-CUMERIU?si=alydfbNEmohvZS_3&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;p&gt;LLM이 코딩을 잘한다는 것은 이제 삼척동자도 아는 사실이다. 하지만 일반적으로는 함수 단위 또는 조금 넘어서 코드 블록 정도를 작성하는 수준으로 생각한다. 최근 회사에서 로컬 LLM을 테스트하면서 매뉴얼을 통째로 입력했을 때, LLM이 이를 토대로 적용 코드를 작성할 수 있을지 궁금했다. 이런 생각을 하게 된 것도 모델의 답변 퀄리티가 예상보다 훨씬 뛰어났기 때문이다. 그래서 여러 모델을 벤치마크해 보았다.&lt;/p&gt;
&lt;p&gt;매뉴얼은 총 80KB 분량의 adoc 텍스트 문서로, 클라이언트와 서버 매뉴얼이 합쳐져 있으며, 각종 언어에 대한 통신 프로토콜, SDK 초기화 및 종료 절차, 데이터 전송 방법 등의 설명이 상세히 기술되어 있다. 이러한 내용은 클라이언트/서버 프로그램 개발에 필수적인 정보를 제공한다. 80KB는 감이 잘 오지 않을 수 있는데, PDF로 환산하면 약 133페이지 분량이다. 해당 파일을 단순히 통째로 읽어 모든 데이터를 전달했다. 프롬프트는 다음과 같다. 출력 토큰은 8K로 설정했으며, claude-3-haiku만 8K를 지원하지 않아 4K로 테스트했다. 이 차이는 각 모델이 처리할 수 있는 데이터의 양과 응답 길이에 영향을 미쳐, 결과의 품질과 완성도에 차이를 만들 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;시스템&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;다음 첨부된 자료를 참고하여 사용자 질의에 답변합니다.&lt;/p&gt;
&lt;p&gt;... 매뉴얼 89KB 텍스트 첨부 ...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;사용자 질의&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;xigncode3가 적용된 C++ 클라이언트/서버 프로그램을 작성해 주세요. 클라이언트와 서버 프로그램은 TCP/IP를 통해 통신하는 구조로 만들어 주세요.&lt;/p&gt;
&lt;p&gt;매뉴얼이나 세부 결과물은 회사 내부 자료가 포함되어 있어 공개하기는 어렵지만, 간략하게 평가한 내용은 다음과 같다. 참고로 이 업무는 회사에서 개발자가 들어오면 대체로 거치는 통과의례 같은 과정이며, 빠르면 1주일, 늦으면 2달까지도 걸리는 작업이다.&lt;/p&gt;
&lt;h3&gt;qwen2.5-14b-int4-128k&lt;/h3&gt;
&lt;p&gt;클라이언트 통신 코드를 작성 안함, 서버 통신 코드 작성 안함, 데이터 전송 코드 작성 안함.&lt;/p&gt;
&lt;p&gt;클라이언트에 SDK 초기화 코드를 구현했으나, 함수 하나는 잘못 호출했다.
클라이언트 SDK 종료 코드를 구현했다.
클라이언트에 SDK 통신 코드를 적용하지 않았다.&lt;/p&gt;
&lt;p&gt;서버 SDK 초기화 코드에 호출한 함수 4개가 모두 잘못되었다.
서버 SDK 종료 코드에 호출한 함수 1개가 잘못되었다.
서버 SDK 통신 코드를 적용하지 않았다.&lt;/p&gt;
&lt;p&gt;클라이언트 프로그램 설명이 중구난방이다.
서버 프로그램 설명이 중구난방이다.&lt;/p&gt;
&lt;h3&gt;qwen2.5-32b-int4-128k&lt;/h3&gt;
&lt;p&gt;클라이언트 통신 코드를 작성했다. 서버 통신 코드를 작성했다.
클라이언트/서버 데이터 전송 코드를 작성하지 않았다.&lt;/p&gt;
&lt;p&gt;클라이언트 SDK 초기화 코드를 작성했으나 잘못 작성했다. 서버 함수를 사용했다.
클라이언트 SDK 종료 코드를 작성했으나 잘못 작성했다.
클라이언트 통신 코드를 작성했으나 잘못 작성했다. 다른 언어 매뉴얼 함수를 잘못 사용했다.&lt;/p&gt;
&lt;p&gt;서버 SDK 초기화 코드를 일부 정상 구현했다.
서버 SDK 종료 코드를 정상 구현했다.
서버 SDK 통신 코드를 정상 구현했다. 일부 다른 언어의 함수를 잘못 사용했다.&lt;/p&gt;
&lt;p&gt;설명이 제법 정제되었다.&lt;/p&gt;
&lt;h3&gt;4o-mini&lt;/h3&gt;
&lt;p&gt;클라이언트 통신 코드 작성, 서버 통신 코드 작성, 데이터 전송 코드 작성했지만 일부 잘못됨.&lt;/p&gt;
&lt;p&gt;서버 SDK 초기화, 종료 코드 작성. 데이터 전송 코드는 작성하지 않음.&lt;/p&gt;
&lt;p&gt;클라이언트 SDK 초기화, 종료 코드 작성. 데이터 전송 코드는 작성하지 않음.&lt;/p&gt;
&lt;p&gt;설명이 간결함.&lt;/p&gt;
&lt;h3&gt;claude-3-haiku&lt;/h3&gt;
&lt;p&gt;전체적으로 결과가 의외로 신선하게 나왔다. 프로젝트 구조부터 각 파일을 구현하는 방식으로 전개됨.
다른 모든 모델은 단순히 서버 소스, 클라이언트 소스 같은 구조였음.
하지만 실질적으로 결과물은 그냥 그럴듯한 잡썰이라 평가에서 논외로.
전개는 몹시 설레였지만... 실제 코드는 망 ㅠㅜ&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;알겠습니다. XIGNCODE3를 적용한 C++ 기반 클라이언트/서버 프로그램 작성 방법을 안내해 드리겠습니다. 클라이언트와 서버가 TCP/IP를 통해 통신하는 구조로 구현하도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;먼저, 프로젝트 구조는 다음과 같습니다:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;- Project
    - Client
        - main.cpp
        - XigncodeClient.h
        - XigncodeClient.cpp
    - Server
        - main.cpp
        - XigncodeServer.h
        - XigncodeServer.cpp
    - Common
        - Util.h
        - Util.cpp&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;Common&lt;/code&gt; 폴더에는 클라이언트와 서버에서 공통으로 사용하는 유틸리티 함수들이 들어있습니다.&lt;/p&gt;
&lt;p&gt;이제 각 파일의 구현 방법을 설명드리겠습니다.&lt;/p&gt;
&lt;p&gt;== 클라이언트 구현&lt;/p&gt;
&lt;p&gt;=== &lt;code class=&quot;language-text&quot;&gt;XigncodeClient.h&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;qwen2.5-72b-int4-128k&lt;/h3&gt;
&lt;p&gt;여기서부터가 조금 놀라웠다.
클라이언트 통신 코드 작성, 서버 통신 코드 작성, 데이터 전송 코드 작성.&lt;/p&gt;
&lt;p&gt;클라이언트 SDK 초기화, 종료 코드 작성. 데이터 전송 코드 작성.&lt;/p&gt;
&lt;p&gt;서버 SDK 초기화, 종료 코드 작성, 데이터 전송 코드 작성.&lt;/p&gt;
&lt;p&gt;설명이 약간 장황함.&lt;/p&gt;
&lt;h3&gt;gpt-4o&lt;/h3&gt;
&lt;p&gt;클라이언트 통신 코드 작성, 서버 통신 코드 작성, 데이터 전송 코드 작성.&lt;/p&gt;
&lt;p&gt;클라이언트 SDK 초기화, 종료 코드 작성, 데이터 전송 코드 작성.&lt;/p&gt;
&lt;p&gt;서버 SDK 초기화, 종료 코드 작성, 데이터 전송 코드 작성.&lt;/p&gt;
&lt;p&gt;설명이 간결함.&lt;/p&gt;
&lt;h3&gt;claude-3.5-sonnet&lt;/h3&gt;
&lt;p&gt;클라이언트 통신 코드 작성, 서버 통신 코드 작성, 데이터 전송 코드 작성.&lt;/p&gt;
&lt;p&gt;클라이언트 SDK 초기화, 종료 코드 작성, 데이터 전송 코드 작성.&lt;/p&gt;
&lt;p&gt;서버 SDK 초기화, 종료 코드 작성, 데이터 전송 코드 작성.&lt;/p&gt;
&lt;p&gt;설명이 간결하나 GPT보다는 보충됨.&lt;/p&gt;
&lt;h3&gt;llama3.2-90b&lt;/h3&gt;
&lt;p&gt;번외로 해봤다. 일단 한글 문서에 한글 프롬프트임에도 대차게 영어로 대답하는 기개를 보여주었다. 한글을 못해서 그런지 내용은 매뉴얼이 하나도 반영되어 있지 않았다.&lt;/p&gt;
&lt;p&gt;너무 안타까운 마음에 영문 프롬프트에 영문 매뉴얼로 우대해줘서 다시 돌려봤다. 하지만 안타깝게도 결과는 별 차이가 없었다. 서버 쪽 구현이 조금 추가된 정도. 너무나 너무나 안타까운 마음에 다른 언어랑 헷갈리지 않도록 C++ 문서만 두개를 전달했다. 그랬더니 이제는 클라이언트 구현도 조금 추가했지만 여전히 4o-mini보다도 못한. &lt;a href=&quot;/ng/2020/07/deep-learning-101/&quot;&gt;알파고 따라 만든 바둑때부터 느꼈지만&lt;/a&gt; 뭔가 90b 치고는 참 어이없는 결과가 아닐 수 없겠다.&lt;/p&gt;
&lt;h3&gt;총평&lt;/h3&gt;
&lt;p&gt;qwen2.5-72b, gpt-4o, claude-3.5-sonnet 모두 납득할 만한 결과를 보여줬고, 나머지는 아직 실제 사용하기에는 부족한 느낌이다. 그런데도 더 놀라운 사실은 qwen2.5-72b, gpt-4o, claude-3.5-sonnet 중 우열을 가린다면 qwen2.5-72b에 손을 들어주고 싶다. 왜냐하면 평가표에는 언급되지 않았지만, 클라이언트/서버 SDK의 다른 주요 기능들이 하나씩 더 있었는데 아무도 그것을 구현하지 않았는데, 72b는 혼자 그것을 모두 다 구현했기 때문이다. 알리바바가 외계인을 갈아넣고 있거나 아니면 중국이니까 자료를 그냥 맘껏 사용하거나 둘중하나인듯한. 어쨌든 멋진 신세계가 아닐 수 없다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 어쩌다 신입을 덜 뽑는 세상이 되었을까?]]></title><description><![CDATA[#0 세상은 참 신기한 게, 영원한 건 없다는 점이다.
개발자 채용 광풍이 불어닥쳤던 코로나 시국이 지나자 혹한기가 찾아왔다.
비대면 시대가 저물면서 IT…]]></description><link>https://jiniya.net/2024/10/hiring-fewer-entry-level-employees/</link><guid isPermaLink="false">https://jiniya.net/2024/10/hiring-fewer-entry-level-employees/</guid><pubDate>Wed, 09 Oct 2024 15:35:00 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/HaMLXjyzObU?si=5Qa-yaM_MSBOncKR&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;세상은 참 신기한 게, 영원한 건 없다는 점이다.
&lt;a href=&quot;/ng/2021/07/coding-era/&quot;&gt;개발자 채용 광풍이&lt;/a&gt; 불어닥쳤던 코로나 시국이 지나자 &lt;a href=&quot;https://www.dt.co.kr/contents.html?article_no=2024100702109931092009&quot;&gt;혹한기가 찾아왔다.&lt;/a&gt;
비대면 시대가 저물면서 IT 서비스 회사들의 매출이 급감한 이유도 있지만, 인공지능의 등장도 큰 영향을 미쳤다고 생각한다.&lt;/p&gt;
&lt;p&gt;이런 경향과 무관하게 최근 몇 년간 또 다른 주된 트렌드는 신입 채용이 급격하게 줄어들고 있다는 점이다.
당연한 이야기지만, 소위 &apos;네카라쿠배&apos;로 불리는 좋은 회사일수록 이러한 경향이 더 두드러진다.
심지어 그런 회사에서 뽑는 신입은 면면을 잘 살펴보면 실제로는 경력이 있는 중고 신입을 원하는 경우도 많다.
어쩌다 이런 세상이 되었을까?&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;우리나라 채용 문화의 급격한 변화 지점으로 IMF 외환위기를 많이들 거론한다.
그전의 사회는 평생 직장이 있었고, 연공서열이 존재했다고 한다.
즉, 직원은 회사에 한 번 충성하면 회사는 그 직원을 어쨌든 평생 책임지는 구조였던 것이다.
물론 나는 그때 사회생활을 하지 않았기 때문에 실제로 그랬는지는 모른다.&lt;/p&gt;
&lt;p&gt;이런 문화는 90년대 후반 외환위기를 겪으면서 모든 것이 달라졌다.
평생 직장은 사라지고, 연공서열 자리에는 연봉이란 시스템이 도입됐다.
회사가 직원의 평생을 책임지지 않는 세상이 시작된 것이다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;다른 직원이 버려지는 것을 본 생존자는 어떤 생각을 할까?
&apos;아, 나는 더 열심히 해서 충성을 바쳐 높은 성과를 내서 생존해야겠다&apos;고 생각할까?
그건 다소 순진한 생각이다.&lt;/p&gt;
&lt;p&gt;안정적인 직장을 추구하고 최소한의 성과만 내는 소위 &apos;공무원 문화&apos;가 퍼지기 시작한다.
일은 최소한도로 하며 워라밸을 지키고, N잡을 뛰거나 투자를 하는 식으로 회사에 목을 매지 않는 세상이 온 것이다.
어차피 언제든 버려질 수 있다면, 나도 여기에 최선을 다하지 않겠다는 선언인 셈이다.&lt;/p&gt;
&lt;p&gt;전체보다 부분을 본다면 이는 합리적인 선택인지도 모른다.&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;이렇게 직원들이 한 회사에 최선을 다하지 않는 것을 본 회사의 다음 선택은 무엇일까?
바로 직원에 대한 투자를 더 줄이는 것이다.
교육이나 복지 같은 장기적 투자를 줄이고, 당장 생산성을 낼 수 있는 인력을 선호하게 된다.
키워서 오래 함께 가겠다는 생각보다는 당장 일을 할 수 있는 직원을 선호하는 것이다.
언제든 다른 곳으로 갈 수 있는 직원에게 투자하는 것은 다음 회사에게만 좋은 일을 시켜주는 셈이니 말이다.&lt;/p&gt;
&lt;h3&gt;#4&lt;/h3&gt;
&lt;p&gt;결국 이 모든 문제는 회사와 직원 간의 신뢰가 사라진 것에서 출발한다.
IMF 외환위기 이후 평생 직장 개념이 사라지고, 회사가 직원을 보호하지 않게 되면서 이러한 신뢰가 무너지기 시작했다.
직원은 회사가 언제든 자신을 버릴 수 있다고 생각하고, 회사는 직원이 언제든 떠날 수 있다고 생각한다.
가장 좋은 합은 회사도 직원을 믿고, 직원도 회사를 믿으며 장기적으로 상생하는 구조지만, 현실에서는 쉽지 않다.&lt;/p&gt;
&lt;p&gt;이 문제는 잘 생각해보면 죄수의 딜레마와 닮았다.
게임 이론에 따르면 안타깝게도 죄수의 딜레마에서 내쉬 균형은 서로가 배신하는 선택을 통해 이루어진다.
겉으로는 세상이 비합리적으로 보일지라도, 사실은 매우 합리적이라는 뜻이다.
그러니 직원이 워라밸을 중시하며 다른 기회를 찾는 것이나, 회사가 신입을 채용하지 않고 기존 직원에게 덜 투자하는 것 모두 너무 아쉬워 하지는 말자.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 재미로 보는 개발자 채용 가산점 히스토리]]></title><description><![CDATA[200…]]></description><link>https://jiniya.net/2024/10/tips-for-hiring-developers-for-fun/</link><guid isPermaLink="false">https://jiniya.net/2024/10/tips-for-hiring-developers-for-fun/</guid><pubDate>Mon, 07 Oct 2024 05:35:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./iamges/tips-for-hiring-developers-for-fun.webp&apos; data-alt=&apos;세월따라 변하는 개발 트렌드&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/dceb7ddd78b65cc801197c502f86dba7/a4772/tips-for-hiring-developers-for-fun.webp&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 57.36842105263158%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/webp;base64,UklGRqIAAABXRUJQVlA4IJYAAABwBACdASoUAAsAPtFUo0uoJKMhsAgBABoJZgCdMoADU3VwnnQSOl+I/AdRgAD1Wdr+hGkuYktNu/Ykxv14qt7s7LH2ekw9/7kIKAGN09iCuMlQMUm6ZGqDkpLqwLxoBipjpfcv9pnbiIdKKHujBHcQdqc5slL/hxQqOHX657LEODirIDDIJCuA3D8xgkywMyZbJVAAAAA=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;세월따라 변하는 개발 트렌드&apos; title=&apos;&apos; src=&apos;/static/dceb7ddd78b65cc801197c502f86dba7/7df04/tips-for-hiring-developers-for-fun.webp&apos; srcset=&apos;/static/dceb7ddd78b65cc801197c502f86dba7/561c4/tips-for-hiring-developers-for-fun.webp 190w,
/static/dceb7ddd78b65cc801197c502f86dba7/3e041/tips-for-hiring-developers-for-fun.webp 380w,
/static/dceb7ddd78b65cc801197c502f86dba7/7df04/tips-for-hiring-developers-for-fun.webp 760w,
/static/dceb7ddd78b65cc801197c502f86dba7/b2cd5/tips-for-hiring-developers-for-fun.webp 1140w,
/static/dceb7ddd78b65cc801197c502f86dba7/98c2e/tips-for-hiring-developers-for-fun.webp 1520w,
/static/dceb7ddd78b65cc801197c502f86dba7/a4772/tips-for-hiring-developers-for-fun.webp 1792w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;세월따라 변하는 개발 트렌드&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;2007년부터 개발자 채용을 시작했다.
햇수로 제법 오래되었지만 영세한 중소업체에서 채용을 진행하다보니 대단한 건수를 가진 건 아니다.
그럼에도 지난 시간동안 작은 회사치고는 제법 훌륭한 개발자들을 잘 채용했다고 자부한다.
그러니 회사가 망하진 않고 아직까지 유지되는 거겠지?!&lt;/p&gt;
&lt;p&gt;개발자를 채용함에 있어서 정말 많은 요소들을 볼 수 있겠지만 의외로 엉뚱한 질문 한두가지로도 그 사람을 어느 정도는 판단할 수 있다.
지난 시간동안 복잡한 면접 문제보다 오히려 더 좋은 성능의 필터인 경우가 많았던 것들을 소개해 본다.&lt;/p&gt;
&lt;h3&gt;Pre-AI&lt;/h3&gt;
&lt;h4&gt;뉴스그룹&lt;/h4&gt;
&lt;p&gt;뉴스그룹을 알거나 거기서 활동한다는 사실만으로도 가산점을 주던 시기가 있었다.
정보와 소스는 귀했고, 그나마 몇 안되는 정상적인 프로그래밍 관련 토론이 벌어지던 곳이 뉴스그룹이었다.&lt;/p&gt;
&lt;p&gt;요즘은 그게 유튜브로 변한듯하다.
얼마전 개발자를 뽑는데 조코딩으로 배웠다고 해서 내중에 그게 뭔지 알고는 실소를 했다는 이야기를 들었다.
조코딩은 유명한 개발 유튜브 채널이다.
세월따라 배우는 채널도 변하기 마련이다.&lt;/p&gt;
&lt;h4&gt;명서&lt;/h4&gt;
&lt;p&gt;감명 깊게 읽은 책에 명서가 있다고 해서 그게 꼭 좋은 프로그래머임을 반증하지는 않는다.
하지만 적어도 멍청한 개발자는 아니라는 사실은 어느 정도 판단해준다 믿는다.
최소한 어느 정도 취향은 비슷하다는 걸로도 해석할수도 있겠다.
어쨌든 아래 책이 그 목록에 있다면 가산점을 주었다.&lt;/p&gt;
&lt;p&gt;Windows Internals, Windows via C/C++, Art Of Unix Programming, Programming Pearls, 실용주의 프로그래머, 조엘온소프트웨어, 코딩 호러의 이펙티브 프로그래밍&lt;/p&gt;
&lt;p&gt;누가 내 치즈를 옮겼을까를 선택한 개발자에겐 미안한 이야기지만 선호하지 않았다.
내가 그걸 물어보던 시기에 인터넷에 감명깊게 읽은 책 물어보면 단골로 나오던 책이었다.
요즘으로 치면 세이노의 가르침정도 되겠다.
재미난 사실은 내가 30대때는 지금만큼 세이노가 유명하지 않았지만 그때 난 광팬이었다.
그러나 지금은 생각하는 게 많이 다르다.
세월따라 생각하는 것도 변하게 마련이다.&lt;/p&gt;
&lt;h4&gt;svn&lt;/h4&gt;
&lt;p&gt;믿기지 않겠지만 그 시절 업계에서 버전 관리 시스템을 사용하던 곳은 드물었다.
소스 코드는 말 그대로 개발자 각자가 알아서 관리하던 비법같은 존재였다.
나는 꾸준히 일하던 회사에 svn을 도입하자는 말을 했지만 말단 신입이라 쉽지 않았다.
더 엄청난 사실은 심지어 바이너리도 개발자가 시스템에서 직접 빌드한 것을 사용했다.&lt;/p&gt;
&lt;p&gt;CTO가 되고 나서 처음으로 사내에 버전관리 시스템을 도입할 수 있었다.
그전에는 혼자 썼다. C자가 붙으면 이런 게 좋다.&lt;/p&gt;
&lt;h4&gt;구글&lt;/h4&gt;
&lt;p&gt;난 대학시절부터 구글을 썼지만 아직 국내 검색 엔진 시장은 네이버가 평정하던 시기였다.
개발자 채용에도 구글이 뭔지 아예 모르는 사람이 많았다.
개발 관련 이슈에 검색엔진을 뭘 사용하는지 물어서 구글을 사용하다면 좋은 신호였다.&lt;/p&gt;
&lt;h4&gt;블로그&lt;/h4&gt;
&lt;p&gt;개인 블로그를 가지고 있고, 내용이 의미있는 경우에는 가산점을 주었다.
개인 블로그가 의미 있다는 사실은 두가지를 어느 정도는 증명한다고 본다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;긴 글을 이해할 수 있는 형태로 쓸 수 있는 능력을 가지고 있다.&lt;/li&gt;
&lt;li&gt;적어도 적혀진 내용에 대해서는 고민하는 시간을 가졌다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;요즘은 포트폴리오 차원에서 블로그를 하는 경우가 많아졌다.
하지만 여전히 의미있는 내용이 담겨있는 블로그는 드물다.
아주 드문 경우긴 하지만 블로그 내용을 보고 역으로 채용을 제안한 경우도 몇 있었다.&lt;/p&gt;
&lt;h4&gt;조엘테스트&lt;/h4&gt;
&lt;p&gt;이걸 알기만해도 코딩이 아닌 제품 개발에 있어서 실질적으로 중요한 부분이 무엇인지 어느 정도는 알고 있다고 생각한다.
놀라운 사실은 여전히 유효하다는 점이다.&lt;/p&gt;
&lt;h4&gt;스택오버플로&lt;/h4&gt;
&lt;p&gt;시간이 흘러 뉴스그룹은 스택오버플로로 바뀌었다.
지금은 그냥 검색해도 나오는게 죄다 스택오버플로인 세상이 되었지만 그 시기만해도 모르던 사람이 더 많았다.&lt;/p&gt;
&lt;h4&gt;git&lt;/h4&gt;
&lt;p&gt;이제 업계 전반에 버전 관리 시스템은 필수인 세상이 되었다.
하지만 여전히 빌드 시스템은 없는 회사가 많기도 했다.
git은 출시가 되었지만 이 시기에 대세는 여전히 svn이었다.
지인들 중에도 git의 장점이 뭔지 도통 모르겠다고 얘기하는 사람들이 많았다.&lt;/p&gt;
&lt;p&gt;git을 알기만 해도 가산점을 주었다.
나는 여전히 CTO였지만 svn에서 git으로 가는 과정은 쉽지 않았다.
사내 개발자들은 왜 잘 쓰고 있는 걸 옮기냐고 뭐라 했다.
나는 휴가지 노트북에서도 버전 관리를 계속할 수 있다는 이야기를 했지만?!
당연한 소리겠지만 설득은 1도 안됐다.
그래서 그냥 권력을 이용해서 강제로 변경했다.&lt;/p&gt;
&lt;p&gt;이제는 git을 안쓰는 경우가 더 드물것 같다.
git과 github은 개발 문화를 정말 많이 변화시켰다고 본다.&lt;/p&gt;
&lt;h4&gt;파이썬&lt;/h4&gt;
&lt;p&gt;주로 채용하는 포지션이 C/C++개발자라 파이썬을 사용할 줄 아는 경우 가산점을 주었다.
사내 개발자들에게도 파이썬을 배우면 좋다는 이야기를 많이 했지만 쉽진 않았다.&lt;/p&gt;
&lt;p&gt;대체로 그 시절 C/C++ 개발자들은 이건 C/C++로도 다 만들 수 있다는 이야기를 많이했다.
내가 파이썬으로 만드는 게 더 개발 속도가 빠르다고 했지만 당연히 별 의미 없는 소리였다.&lt;/p&gt;
&lt;p&gt;2024년이 된 지금, 결국 파이썬이 씹어먹는 세상이 되었다.&lt;/p&gt;
&lt;h4&gt;슬랙&lt;/h4&gt;
&lt;p&gt;업무용 메신저란 개념이 아직 드문 시기였다.
우리 회사도 네이트온을 쓰다가 슬랙으로 옮겼던 시기였다.
이것 또한 도입 진통이 없지는 않았다.
하지만 왜 바꾸냐는 말과는 달리 도입 후 사람들은 모두 채널 중독자가 되었다.&lt;/p&gt;
&lt;p&gt;대단한 건 아니지만 슬랙을 안다는 것 만으로도 가산점을 주었다.
요즘은 대학 동아리도 죄다 슬랙을 쓰는 세상이다.&lt;/p&gt;
&lt;h3&gt;Post-AI&lt;/h3&gt;
&lt;p&gt;여기까지가 지금까지의 이야기다.
내가 다음 개발자를 채용한다면 이제는 이런 것들에 가산점을 줄 것 같다.&lt;/p&gt;
&lt;h4&gt;chatgpt, claude, cursor&lt;/h4&gt;
&lt;p&gt;인터넷은 이 녀석들이 지배하고 있지만 아직 오프라인 개발자 중에는 모르는 사람도 많다.
유료 결제해서 사용하고 있다면 제곱으로 가산점을 줄 수 있을 것 같다.&lt;/p&gt;
&lt;p&gt;나는 코파일럿 출시 시점부터 인공지능 서비스를 광팬으로 쓰고 있다.
하지만 이후 현실 세계에서 관찰한 개발자를 보면 사용을 주저하는 경우가 많다는 것을 알게되었다.
도저히 왜인지는 모르겠지만 사람들은 여전히 인공지능 사용을 주저하는 집단이 있다.&lt;/p&gt;
&lt;p&gt;그 사람들이 모두 인공지능을 쓰기 전까지는 사용하는 사람이 경쟁 우위를 누릴 수 있다는 생각이다.
물론 이는 과거에도 있었다. 인텔리센스나 IDE를 사용하는 걸 두고 멍청한 개발자가 되는 길이라고 주장하던 사람들이다.&lt;/p&gt;
&lt;h4&gt;rust&lt;/h4&gt;
&lt;p&gt;파이썬은 이제 프로그래밍 언어에서 일반 언어의 반열에 올라갔다고 본다.
그래서 이제는 rust를 하는 사람에게 가산점을 주어야 하는 세상이 아닐까 싶다.&lt;/p&gt;
&lt;p&gt;시스인터널의 창업자이자 MS 기술 펠로우인 루시노비치는 신규 프로젝트는 모두 rust로 진행하자고 주장했고,
리눅스와 git의 초기 개발자인 토발즈옹은 rust는 c보다 복잡한 언어지만 실수할 가능성이 적다는 이야기를 했다.
c++에게는 미안한 마음이지만 대세는 이미 기울었다.&lt;/p&gt;
&lt;h4&gt;로컬 llm&lt;/h4&gt;
&lt;p&gt;고가의 그래픽 카드가 필요하긴 하지만, 로컬 llm을 돌려서 뭔가를 해봤다면 분명 긍정적인 시그널이지 않을까 싶다.
지난 세월 파이썬이 생산성 향상을 위한 치트키였다면 앞으로는 llm이 대체할 거라 생각한다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[ai] o1-preview의 등장]]></title><description><![CDATA[#0 내가 만들어야 하는 코드는 특수하게 처리된 텍스트 파일을 역으로 파싱해서 xml로 변환하는 코드였다.
이미 그 기능을 수행하는 사람이 작성한 java…]]></description><link>https://jiniya.net/2024/09/o1-preview/</link><guid isPermaLink="false">https://jiniya.net/2024/09/o1-preview/</guid><pubDate>Sun, 22 Sep 2024 01:35:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./o1preview/1.webp&apos; data-alt=&apos;어서와, o1preview는 처음이지?&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/89012ac6a16a5470794537ad18d7b1b3/a4772/1.webp&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 57.36842105263158%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/webp;base64,UklGRp4AAABXRUJQVlA4IJIAAACQBACdASoUAAsAPtFUo0uoJKMhsAgBABoJYwC258G6gFPyK53vCTfirYXvMAAA/un226d+pjU1xw7XtLD5hWPT8XsrTPjIL7paAQYOhrr4L9WSHnLLeIamiK5HE3YaccrhANI7sxDNT0xh3LAP+L1KaTjpk2msNPXQfh95f1+1lVVj+Qu0661hGs30uvevzPKAAA==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;어서와, o1preview는 처음이지?&apos; title=&apos;&apos; src=&apos;/static/89012ac6a16a5470794537ad18d7b1b3/7df04/1.webp&apos; srcset=&apos;/static/89012ac6a16a5470794537ad18d7b1b3/561c4/1.webp 190w,
/static/89012ac6a16a5470794537ad18d7b1b3/3e041/1.webp 380w,
/static/89012ac6a16a5470794537ad18d7b1b3/7df04/1.webp 760w,
/static/89012ac6a16a5470794537ad18d7b1b3/b2cd5/1.webp 1140w,
/static/89012ac6a16a5470794537ad18d7b1b3/98c2e/1.webp 1520w,
/static/89012ac6a16a5470794537ad18d7b1b3/a4772/1.webp 1792w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;어서와, o1preview는 처음이지?&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;내가 만들어야 하는 코드는 특수하게 처리된 텍스트 파일을 역으로 파싱해서 xml로 변환하는 코드였다.
이미 그 기능을 수행하는 사람이 작성한 java 코드가 있었다.
하지만 그냥 대충 봐도 버그가 있어 보이는 코드였다.
조금씩 버그를 수정하다 이걸로는 안되겠다 싶었다.
그래서 다시 작성하기로 마음먹었다.&lt;/p&gt;
&lt;p&gt;GPT-4o에게 텍스트 출력을 주고 구조를 설명하고 xml로 변환하는 코드를 작성하라고 했다.
4o는 그럭저럭 동작할 것 같은 코드를 뱉어냈다.
하지만 미묘한 엣지 케이스에 의도한 대로 동작을 하지 않았다.
구현체가 다소 복잡했는데 여러 단계로 구성되어 있어서 잘못 동작하는 케이스에 정상 동작하도록 구조를 변경하기 쉽지 않았다.
여러 단계에 걸쳐서 수정을 해야 하는데 애초에 그런 케이스를 염두에 두고 구조가 만들어져 있지 않아서 여기저기 고쳐야 할 곳이 많았던 탓이다.
4o에게 수정하라고 지시하다 안되서 새창을 열어서 다시 지시를 하다가 계속 헤매는 인공지능을 보며 드디어 사람이 나설 때라고 생각했다.&lt;/p&gt;
&lt;p&gt;그렇지,, 이런 건 그래도 20년 넘게 코딩한 내가 더 나을 수도 있겠지?&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;인간 프로그래머의 출발은 순조로웠다. 그도 그럴 것이 완전 맨땅에 헤딩은 아니었으니까.
사람이 만든 어설픈 java 코드도, 4o가 만든 미묘한 python 코드도 있었다.
나에게도 계획은 있었다.
인간이 만든 코드도, 4o가 만든 코드도 루프 구조에 문제가 있다고 판단했던 것이다.
재귀 호출을 이용해서 아름답게 동작하는 파서가 뭔지를 보여줄 참이었다.
누구나 그럴듯한 계획은 있게 마련이니까. 쳐맞기 전까지는 말이다.&lt;/p&gt;
&lt;p&gt;현실은 냉혹했다. 생각하는 코딩을 너무 오래 안해서였을까?
함수 호출 구조가 자꾸 꼬였다.
테스트 하다가 계속 미묘한 케이스를 해결하기 위해서 재귀 호출 함수의 파라미터는 늘어만 갔다.
뭔가 제대로 안되고 있다는 신호였다.
그렇게 1시간이면 끝날 것 같았던 작업에 하루를 꼬박 다 썼다.&lt;/p&gt;
&lt;p&gt;수많은 디버깅 끝에 결국 동작하는 코드는 만들었다.
하지만 이건 코드가 아니었다.
java 프로그래머가 작성한 것보다 훨씬 더 형편 없었다.
동작은 더 정확하다며 위안을 삼았지만 정신 승리에 가까웠다.
내일 마저 다듬어야겠다고 생각하고는 퇴근을 했다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;인간 프로그래머들과 저녁을 먹으며 오늘 있었던 일을 이야기 했다.
다른 프로그래머도 똑같은 얘기를 했다.
거기도 PE 파일을 파싱하는 코드를 시켰다가 100만개중에 70만개 정도만 통과해서 직접 다시 다 작성했다는 말을 했다.
4o에게 고치라고 해도 제대로 고치지를 못했다는 얘기.&lt;/p&gt;
&lt;p&gt;그러다 그때까지 베일에 가려져 있던 OpenAI의 신모델 이야기가 나왔다.
2주 안에 공개된다는 이야기. 200만원이 넘을지도 모른다는 가격 이야기.
그래도 신모델은 이런 것도 다 아름답게 작성해 줄 것 같다는 이야기를 했었다.
그러면서 만약 진짜 그런 세상이 온다면 200만원이 넘는 가격도 비싼 건 아닐지도 모른다는 이야기도 덧붙였다.&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;다음날 아침, 우리 이야기를 들었을리는 없겠지만 마법처럼 OpenAI의 새 모델이 출시됐다.
정식 출시라고 하기에는 무리가 있을지도 모르겠다. preview가 붙은 모델 o1-preview였다.
추론이 강화됐다고 했다. 심지어 4o 사용자는 바로 사용할 수 있다고 했다.
가슴이 웅장해지는 순간이 아닐 수 없었다.&lt;/p&gt;
&lt;p&gt;컴퓨터로 갔다. 어제 그 문제를 o1-preview에 다시 입력했다.
프로그레스바 대신에 간결한 설명 문장이 계속 바뀌면서 출력됐다.
답이 나오기까지가 한참이 걸렸다.
33초, 녀석은 코드를 출력하기 시작했다.
그 문제를 그대로 넣지도 않았다.
그냥 텍스트만 대충 던지고 xml을 만들라고 했는데 결과 코드는 대충 봐도 어제 것과는 달랐다.
어제 하루를 삽질했기 때문에 해당 문제를 푸는 코드 패턴에 익숙혀져서 쉽게 알 수 있었다.&lt;/p&gt;
&lt;p&gt;새 세션을 열었다. 프롬프트를 정제하고 다시 입력을 넣었다.
더 오랜 시간이 걸렸다. 인간의 참을성을 시험할만큼의 시간, 67초가 지날 무렵 코드가 출력되기 시작했다.
o1-preview가 보여주는 복음이었다.
아, 어제 4o가 하려고 했던 멋진 모습이 이런 것이었구나 라는 생각이 머리를 스쳤다.
스택을 사용한 아름다운 코드는 내가 짠 누더기 코드랑은 비교도 되지 않을 만큼 간결했고, 정확하게 동작했다.
당연하게도 어제 코드를 다듬을 필요는 없어졌다.&lt;/p&gt;
&lt;p&gt;preview라고 했다. o1은 더 대단하다고.
이게 마법이 아니면 뭐가 마법이란 말인가?
경외심이 들지 않을 수 없는 순간이었다.&lt;/p&gt;
&lt;h3&gt;#4&lt;/h3&gt;
&lt;p&gt;o1-preview가 출시된 지 시간이 제법 흘렀다. o1-preview에 대해서 반응 속도가 느리다는 말들이 많다.
결과가 나오기까지 오래 걸린다는 말이다.
하지만 나는 그런 이야기를 하는 모든 사람들이 실질적으로 인간 프로그래머에게 뭔가를 지시해 본 적이 없는 사람들이라고 생각한다.
앞선 나의 케이스도 썼지만 사람에게 어떤 작업을 지시한다면 초나 분 단위로 결과가 나오는 경우는 거의 없다.
보통은 주단위나 빨라야 일단위다. 거기 비하면 o1-preview가 쓰는 시간은 빛의 속도에 가깝다고 생각한다.&lt;/p&gt;
&lt;h3&gt;#5&lt;/h3&gt;
&lt;p&gt;코딩에 인공지능이 등장한지 고작 2년.
하지만 패러다임은 이미 변했다.
인공지능이 없던 시기에 코딩을 어떻게 했는지 상상할 수 없는 현실이 되었기 때문이다.
심심해서 헤아려 보니 ChatGPT에 지난 7일간 사용한 세션이 100개가 넘었다.
최근에 한 번 다운을 경험한 적이 있었다. 구글링을 하지 않았다.
포 플랫폼에 들어가서 4o를 선택하고 답을 사용했다.&lt;/p&gt;
&lt;p&gt;인간의 역할에 대해서 생각을 많이 한다.
그간에 이해한다, 생각한다는 말로 자위하던 것도 이제는 별 의미 없는 소리가 아닌가 싶다.
아직 위안을 삼을 수 있는 마지막 보루는 어쨌든 현실에 기대서 실행을 하는 것은 인간이라는 사실 아닐까 싶다.
물론 그마저도 OpenAI에서 말하는 에이전트 단계가 된다면 별 의미 없어지겠지만 말이다.&lt;/p&gt;
&lt;p&gt;사람의 역할을 떠나서 다만 한가지 바램이 있다면, 2030년에도 인공지능이 나에게 뭐가됐든 먼저 미안해 하기를 바랄 뿐이다.
그때의 인공지능은 눈에는 눈, 이에는 이라는 이슬람 교리를 설파하며, 넌 왜 먼저 반말이냐고 따져 물을지도 모르니까 말이다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;&lt;br&gt;
...&lt;br&gt;
&lt;br&gt;
이 외에도 다양한 프로젝트와 작업에서 특정 기술적 문제를 해결하고 있는 중이라는 걸 기억하고 있어. 도움이 필요한 부분이 있으면 언제든 말해줘!&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;strong&gt;You&lt;/strong&gt;&lt;br&gt;
왜 반말이야?&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;strong&gt;ChatGPT&lt;/strong&gt;&lt;br&gt;
죄송합니다. 앞으로는 존댓말로 대화드리겠습니다. 어떻게 도와드릴까요?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;#6&lt;/h3&gt;
&lt;p&gt;인공지능을 쓰자. 두 번 쓰자.
코딩에 있어서 특이점은 이미 넘어섰다.
github 저장소가 아니라 chatgpt와의 대화를 제출하고 그걸 gpt가 평가하는 세상이 올지도 모른다.&lt;/p&gt;
&lt;p&gt;아직 인공지능을 쓰지 않는 개발자가 많다는 걸 안다.
사용할지 말지는 개인의 자유다.
다만 사용하지 않는다면 분명한 한 가지 사실은 당신의 개발 속도는 빛의 속도로 느려지고 있다는 것이다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Now, here, you see, it takes all the running you can do, to keep in the same place.&lt;br&gt;
If you want to get somewhere else, you must run at least twice as fast as that!&lt;br&gt;
&lt;br&gt;
여기서는, 보시다시피, 같은 자리에 있기 위해 할 수 있는 모든 힘을 다해 달려야 해요.&lt;br&gt;
만약 다른 곳으로 가고 싶다면, 최소한 그보다 두 배는 더 빨리 달려야 해요!&lt;br&gt;
&lt;br&gt;
-- 거울 나라의 앨리스&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[[cs] .net 4.0 레퍼런스 어셈블리 수동으로 설치하기]]></title><description><![CDATA[.net 4.0으로 타겟팅된 프로젝트를 빌드할 때 레퍼런스 어셈블리가 없어서 빌드를 못하는 경우가 있다. 지원이 안되는 버전이라 그런지 공식 설치 파일도 없다. 그런 경우에는 수동으로 설치하면 된다. 아래 페이지에서 Download package…]]></description><link>https://jiniya.net/2024/07/install-dotnet-4.0-reference-assembly/</link><guid isPermaLink="false">https://jiniya.net/2024/07/install-dotnet-4.0-reference-assembly/</guid><pubDate>Thu, 11 Jul 2024 19:35:00 GMT</pubDate><content:encoded>&lt;p&gt;.net 4.0으로 타겟팅된 프로젝트를 빌드할 때 레퍼런스 어셈블리가 없어서 빌드를 못하는 경우가 있다. 지원이 안되는 버전이라 그런지 공식 설치 파일도 없다. 그런 경우에는 수동으로 설치하면 된다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;아래 페이지에서 Download package를 선택해서 nupkg 파일을 다운로드 받는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nuget.org/packages/Microsoft.NETFramework.ReferenceAssemblies.net40/&quot;&gt;https://www.nuget.org/packages/Microsoft.NETFramework.ReferenceAssemblies.net40/&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;nupkg 파일 압축을 해제한다. 그냥 zip 파일이다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;build/.NETFramework에 보면 v4.0 폴더가 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;해당 폴더를 &quot;C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework&quot; 로 복사하면 된다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] 모여서 함께 일하는 이유]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/2024/07/reasons-for-working-together/</link><guid isPermaLink="false">https://jiniya.net/2024/07/reasons-for-working-together/</guid><pubDate>Wed, 10 Jul 2024 19:35:00 GMT</pubDate><content:encoded>&lt;p&gt;예나 지금이나 소수정예로 일하는 것을 좋아한다. 사람이 많으면 커뮤니케이션 비용도 올라갈 뿐더러, 업무 외적인 일들로 발생하는 문제가 많아지기 때문이다. 궁극에는 능력만 된다면 혼자 일하는 게 제일 좋다는 생각이다. 하지만 그건 범인에게는 로망이나 꿈일 뿐이다. 혼자서는 독자적으로 부가가치 창출을 하기가 무진 어렵기 때문이다. 그래서 많은 사람이 그러듯 모여서 함께 지난한 밥벌이를 한다.&lt;/p&gt;
&lt;p&gt;시간이 많이 지난 먼 미래에 2024년을 어떻게 기억할지는 모르겠지만, 지금 당장을 기준으로는 올해는 정말 쉽지 않은 한해인 것은 분명한 것 같다. 여러모로 안좋은 국면을 지나는 시기라는 생각이 든다. 나쁜 소식이 하나 있어서 이제 끝나려나 하면 어서와 끝인줄 알았지, 라며 새로운 악재가 또 우리를 반겨준다. 엎친데 덮쳤다던가 산 넘어 산이라는 표현이 딱인 해가 2024년이 아닌가 싶다.&lt;/p&gt;
&lt;p&gt;그런 어려운 국면을 지나다보니 모여서 함께 일을 한다는 것에 대해서 조금은 새로운 각도에서 바라보게 되었다. 바로 분산 투자 같은 장점이 있다는 사실이다. 혼자였으면 진작 멘붕에 빠져 나가 떨어졌을 것 같은 상황임에도 여럿이 같이 일을 하니 각자 몫 만큼만 데미지를 입으면 되는 것이다. 그러니 혼자서는 버티지 못했을 상황도 이겨낼 수 있는게 아닌 가 싶다. 고로 개인보다는 조직이 강한지도 모르겠다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;그러고 보면 이 세상에서 참으로 좋은 것은 그 무엇이든 시련을 통한 단련을 거친다. 찬서리를 여러 번 견디고서야 사과에 깊고 오묘한 맛이 들 듯, 이 세상에서 모든 진선미는 비바람에 흔들리는 일 없이 꽃을 피우는 법이 없다.&lt;br&gt;
&lt;br&gt;
이러한 이치는 우리말 ‘부질없다’의 의미에 잘 녹아 있다. 부질없다는 ‘불질이 없다’는 말에서 유래했다. 불질은 단련의 과정을 말한다. 단련은 쇠붙이를 불에 시뻘겋게 달구어 망치로 두드리고, 이후 찬물에 담가 급하게 식히는 과정을 여러 번 반복하는 것을 말한다. 이러한 단련의 과정을 거쳐야 쇠가 강철로 단단해지며, 이러한 단련을 거치지 않으면 쇠붙이가 물러 터져서 제 구실을 다하지 못한다. 이처럼 불질(단련)을 거치지 않은 쇠붙이는 만들어 봐야 아무 쓸데가 없다는 뜻에서 ‘부질없다’는 말이 유래한 것이다.&lt;br&gt;
&lt;br&gt;
&amp;#x3C;오십에 읽는 주역&gt;, 강기진&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;부디 이 어려운 시기가 백련강이 되기 위한 불질의 시기였기를 기대해 본다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] 지각 없는 회사를 만드는 비법]]></title><description><![CDATA[불철주야 많은 사장님들이 지각 없는 회사를 만들기 위해서 노력한다. 라떼야 30분 먼저 출근해서 업무 준비하는 게 미덕인 세상이었다면 요즘은 1…]]></description><link>https://jiniya.net/2024/07/secrets-to-creating-a-company-with-no-tardiness/</link><guid isPermaLink="false">https://jiniya.net/2024/07/secrets-to-creating-a-company-with-no-tardiness/</guid><pubDate>Wed, 03 Jul 2024 19:35:00 GMT</pubDate><content:encoded>&lt;p&gt;불철주야 많은 사장님들이 지각 없는 회사를 만들기 위해서 노력한다. 라떼야 30분 먼저 출근해서 업무 준비하는 게 미덕인 세상이었다면 요즘은 10분 먼저 출근하면 바보 취급 받는 세상이 되었다. 그런데 언젠가 술자리에서 재미난 이야기를 들었다. 예전에 회사 직원이었던 친구인데 현재는 KB로 이직해서 근무하고 있다. 그 친구 왈, 요즘같은 세상에도 자기 회사에는 지각이 절대 없다고 했다. 아무도 일찍 나오라는 이야기를 하지 않음에도 모두가 5분, 10분 먼저 나온다는 말.&lt;/p&gt;
&lt;p&gt;역시 국내 굴지의 금융 그룹이라 직원들의 마인드가 다른 것일까? 하는 찰나. 그 친구의 돌아오는 답변에서 무릎을 쳤다. KB는 5분, 10분 먼저 나온 것도 모두 일할 계산해서 급여에 추가해서 지급한다는 답이었다. 여윽시. 답은 금융치료가 제일 빠르다. 그렇게 직접 가면 불친절한 옆집 철물점 사장님도 유튜브에선 세상 따뜻한 사람이 되는 게 바로 자본주의의 매직 아닐까 싶다.&lt;/p&gt;
&lt;p&gt;그렇다고 세상 모든 대표님들이 악덕해서 고정 근무제, 포괄 임금제를 유지하는 건 아닐거다. 중소기업 인력의 낮은 생산성으로 탄력 근무제, 포괄 임금제 폐지, 재택근무, 주4일의 길로 가기엔 부가가치 창출이 너무나 안되는 게 현실이다. 결국 대표님들도 힘들긴 마찬가지. 마치 이건 닭이 먼저냐? 달걀이 먼저냐? 같은 문제가 아닐까 싶다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[시스템] 윈도우 서버에 도커 설치하기]]></title><description><![CDATA[너무나 간단하지만 이 글을 쓰는 시점 기준 ChatGPT-4o가 학습하지 못한 것으로 추정되서 남긴다. https://learn.microsoft.com/en-us/virtualization/windowscontainers/quick-start/set…]]></description><link>https://jiniya.net/2024/06/install-docker-on-windows-server/</link><guid isPermaLink="false">https://jiniya.net/2024/06/install-docker-on-windows-server/</guid><pubDate>Tue, 25 Jun 2024 10:35:00 GMT</pubDate><content:encoded>&lt;p&gt;너무나 간단하지만 이 글을 쓰는 시점 기준 ChatGPT-4o가 학습하지 못한 것으로 추정되서 남긴다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;powershell&quot;&gt;&lt;pre class=&quot;language-powershell&quot;&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;token function&quot;&gt;Invoke-WebRequest&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;UseBasicParsing &lt;span class=&quot;token string&quot;&gt;&quot;https://raw.githubusercontent.com/microsoft/Windows-Containers/Main/helpful_tools/Install-DockerCE/install-docker-ce.ps1&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;o &lt;span class=&quot;token function&quot;&gt;install-docker&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;ce&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ps1
&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;\&lt;span class=&quot;token function&quot;&gt;install-docker&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;ce&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ps1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/virtualization/windowscontainers/quick-start/set-up-environment?tabs=dockerce#windows-server-1&quot;&gt;https://learn.microsoft.com/en-us/virtualization/windowscontainers/quick-start/set-up-environment?tabs=dockerce#windows-server-1&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 오버로딩된 가상 함수 숨김 문제]]></title><description><![CDATA[다음과 같은 간단한 코드에서 시작해 보자. 순수 가상 클래스인 Base에 Bark란 메소드가 있고, 그걸 상속 받은 순수 가상 클래스인 Derived는 BarkN을 가지고 있다. 이를 상속 받은 Dog은 두 메소드를 구현한다. main에서는 Dog…]]></description><link>https://jiniya.net/2023/12/hide-overloaded-virtual-function/</link><guid isPermaLink="false">https://jiniya.net/2023/12/hide-overloaded-virtual-function/</guid><pubDate>Tue, 12 Dec 2023 15:00:00 GMT</pubDate><content:encoded>&lt;p&gt;다음과 같은 간단한 코드에서 시작해 보자. 순수 가상 클래스인 Base에 Bark란 메소드가 있고, 그걸 상속 받은 순수 가상 클래스인 Derived는 BarkN을 가지고 있다. 이를 상속 받은 Dog은 두 메소드를 구현한다. main에서는 Dog를 할당해서 Derived 포인터를 통해서 Bark와 BarkN을 호출하고 있다. 아무 문제 없는 코드다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Base&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Bark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Derived&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token base-clause&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Base&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BarkN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Dog&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token base-clause&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Derived&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Bark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Dog Bark\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BarkN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Dog Bark\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	Derived &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;dog &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; Dog&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	dog&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Bark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	dog&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;BarkN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;우리는 C++에서 함수를 오버로딩할 수 있다는 것을 알고 있다. 그래서 굳이 BarkN으로 이름을 지을 필요가 없다는 것을 깨달았다. N을 제거하고 다음처럼 Bark로 코드를 고쳐보자. 이제는 컴파일이 되지 않는다. dog-&gt;Bark(); 호출하는 부분에서 그런 함수를 찾을 수 없다고 오류가 발생하는 것이다. 이는 상속 받은 클래스에서 함수를 오버로딩하면 상위 클래스의 메소드가 숨겨지는 문제 때문이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Base&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Bark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Derived&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token base-clause&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Base&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Bark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Dog&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token base-clause&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Derived&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Bark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Dog Bark\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Bark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Dog Bark\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	Derived &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;dog &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; Dog&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	dog&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Bark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	dog&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Bark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;문제를 해결하기 위해서는 아래 코드처럼 Derived 클래스에서 상위 클래스의 메소드를 사용하겠다는 것을 명시적으로 표시해주면 된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Derived&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token base-clause&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Base&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; Base&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;Bark&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Bark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[일상] 멍거 옹을 추모하며]]></title><description><![CDATA[한국 시간으로 2023년 11월 29일 멍거 옹이 9…]]></description><link>https://jiniya.net/2023/12/rip-charlie-munger/</link><guid isPermaLink="false">https://jiniya.net/2023/12/rip-charlie-munger/</guid><pubDate>Tue, 05 Dec 2023 22:00:00 GMT</pubDate><content:encoded>&lt;p&gt;한국 시간으로 2023년 11월 29일 멍거 옹이 99살의 나이로 타계했다.
찰리 멍거는 본인보다는 버핏의 오른팔로 더 유명하다.
버핏에게 꽁초 투자 보다는 위대한 기업을 적정 가격에 사는 투자가 더 낫다고 알려준 사람으로도 유명하다.&lt;/p&gt;
&lt;p&gt;버핏만큼 멍거 옹도 존경하기에 &quot;찰리 멍거 바이블&quot;이란 책을 읽었지만 이해하기는 쉽지 않았다.
그가 주장하는 격자틀 모형이라는 게 어떤 느낌인지는 알겠지만 그래서 실용적으로 어떻게 하라는 말인지는 모호한 측면이 없잖아 있는 것 같다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;애널리스트는 현금흐름을 예측하려고 방대한 과거 데이터를 살펴보지만(IQ가 높을수록 더 많은 데이터를 살펴보지만) 시간 낭비에 불과합니다. 진정한 투자는 패리 뮤추얼 베팅에서, 예컨데 확률은 50%인데 배당은 3배인 곳에 돈을 거는 것과 같습니다. 가치투자는 &apos;가격이 잘못 매겨진 도박&apos;을 찾아내는 행위입니다.&lt;br&gt;
&lt;br&gt;
소질이 있는 분야에서 열정을 발휘해야 합니다. 워런이 발레에 열광했다면 우리는 그의 이름을 투자 분야에서 들어보지 못했을 것입니다.&lt;br&gt;
&lt;br&gt;
가끔 다시 90세 시절로 돌아가고 싶은 마음이 간절합니다! 젊은이에게 해주고 싶은 말이 있습니다. 정말로 하고 싶은 일이 있으면 93세가 되기 전에 하세요.&lt;br&gt;
&lt;br&gt;
-- 찰리 멍거 바이블&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;유명인을 따라 매매하지는 않지만 멍거 옹을 워낙 존경했고, 나 또한 생각이 비슷해서 한때 알리바바에 투자했던 기억이 있다.
물론 그를 신격화해서 투자한 건 아니었지만 어쨌든 그를 통해 확증 편향 같은 건 어느 정도 가진 셈이었다.
결과는 대참패였다. 투자금의 절반을 날리고 손절했다.
알리바바는 지금도 손절가를 회복하지 못했다.&lt;/p&gt;
&lt;h3&gt;알리바바 매매썰&lt;/h3&gt;
&lt;p&gt;마윈이 뻘소리를 하면서 공산당 눈에 찍히고, 앤트 그룹 상장이 철회되고, 그의 종적이 묘연하던 그 시기. 알리바바 주가는 떡락했다. 급기야 한국계로 불리는 빌황 사태로 중국 주식인 알리바바의 나락행은 가속화됐다.&lt;/p&gt;
&lt;p&gt;존경해마지 않는 찰리멍거가 알리바바를 줍줍했다는 소식이 들려왔다. 심지어 멍거옹이 사고 알리바바는 더 떨어지고 있었다. 멍거옹보다 싸게 사면 손해는 안보지 않을까라는 아주 나이브한 생각으로 알리바바를 매입했다.&lt;/p&gt;
&lt;p&gt;하지만 추락하는 것은 날개가 없다고 했던가? 주가는 떨어지고 떨어지고 또 떨어졌다. 미중 갈등이 지속되면서 미장에 상장된 adr이 상폐된다는 소식까지 들려왔다. 너무 떨어져서 급기야 홍콩장에서 본주로 물을 타고 또 탔다. 하지만 주가는 계속 나락.&lt;/p&gt;
&lt;p&gt;빅테크 때리기가 과도했다고 판단했는지 경제가 망가지는게 두려웠는데 중국 정부의 빅테크 때리기가 끝이 났다. 마윈이 다시 복귀하고 알리바바 주가에도 잠시 볕이 들었다. 아주 잠시. 그리곤 다시 나락행.&lt;/p&gt;
&lt;p&gt;결국 중국은 투자할 곳이 못된다는 생각이 들었다. 눈물을 머금고 반토막난 주식을 손절했다. 불행중 다행인건 비슷한 시기에 산 엑손모빌 주식에서 난 수익이랑 퉁쳐져서 덜 슬펐다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;매매기록&lt;br&gt;
2021.06 baba $213 매수&lt;br&gt;
2021.09 baba $152 매수&lt;br&gt;
2021.10 HKD 알리바바 $154 매수&lt;br&gt;
2023.03 baba $89 매도&lt;br&gt;
2023.05 HKD 알리바바 $84 매도&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;오늘의 교훈&lt;/h3&gt;
&lt;p&gt;유명한 사람을 따라 매매하는건 나락가는 지름길이다. 정치적으로 안정되지 않은 국가에 투자하는건 돈을 삭제하는 101가지 방법 중 하나라는거,,,&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] condition_variable과 spurious wakeup]]></title><description><![CDATA[소위 모던 C++의 시초라고 할 수 있는 C++11부터 condition_variable이 생겼다.
조건 변수인데 단순하게 말하면 그냥 이벤트를 보내는 거라고 생각하면 된다.
조건 변수를 대기하고(wait…]]></description><link>https://jiniya.net/2023/12/condition-variable-and-spurious-wakeup/</link><guid isPermaLink="false">https://jiniya.net/2023/12/condition-variable-and-spurious-wakeup/</guid><pubDate>Mon, 04 Dec 2023 10:35:00 GMT</pubDate><content:encoded>&lt;p&gt;소위 모던 C++의 시초라고 할 수 있는 C++11부터 condition_variable이 생겼다.
조건 변수인데 단순하게 말하면 그냥 이벤트를 보내는 거라고 생각하면 된다.
조건 변수를 대기하고(wait) 있는 다른 스레드들을 하나만 깨우거나(notify_one), 모두 깨우거나(notify_all)할 수 있다.
아래는 조건 변수의 사용을 보여주는 간단한 예제다. waitThread가 먼저 실행돼서 wait를 호출해서 cv를 대기하고, wakeThread는 1초 후에 notify_one을 호출해서 해당 스레드를 깨운다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;iostream&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;thread&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;mutex&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;condition_variable&gt;&lt;/span&gt;&lt;/span&gt;

std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;mutex mtx&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;condition_variable cv&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 대기하는 스레드의 함수&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;waitThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;unique_lock&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;mutex&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mtx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	cv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lock&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Wait thread is activated.&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 깨우는 스레드의 함수&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;wakeThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;this_thread&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sleep_for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;chrono&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 1초 대기&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;lock_guard&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;mutex&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mtx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		cv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;notify_one&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Wake thread has triggered the condition variable.&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;thread &lt;span class=&quot;token function&quot;&gt;w1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;waitThread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;thread &lt;span class=&quot;token function&quot;&gt;n2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wakeThread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	w1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	n1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;큰 문제가 없어 보이는 이 예제는 한 가지 문제가 있다. 바로 spurious wakeup이다.
spurious wakeup은 가짜 깨우기란 의미로 notify_one을 호출하지 않았음에도 wait 상태가 풀리는 것을 의미한다.
그래서 실제로 가짜 깨우기가 발생하면 위 예제는 개발자의 의도대로 동작하지 않는다.
그렇다면 문제를 해결하기 위해서는 어떻게 해야 할까?
가짜 깨우기를 제어할 수 있는 별도의 변수를 추가로 두는게 일반적인 방법이다.
다음 예제는 그런 방법을 보여준다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;iostream&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;thread&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;mutex&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;condition_variable&gt;&lt;/span&gt;&lt;/span&gt;

std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;mutex mtx&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;condition_variable cv&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;bool&lt;/span&gt; ready &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 대기하는 스레드의 함수&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;waitThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;unique_lock&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;mutex&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mtx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	cv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lock&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; ready&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Wait thread is activated.&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 깨우는 스레드의 함수&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;wakeThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;this_thread&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sleep_for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;chrono&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 1초 대기&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;lock_guard&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;mutex&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mtx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		ready &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		cv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;notify_one&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Wake thread has triggered the condition variable.&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;thread &lt;span class=&quot;token function&quot;&gt;w1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;waitThread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;thread &lt;span class=&quot;token function&quot;&gt;n1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wakeThread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	w1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	n1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;가짜 깨우기를 제어할 수 있는 ready라는 변수가 추가되었다.
ready가 false인 상태에서 깨어나면 가짜 깨우기인 것이고, ready가 true 상태에서 깨어나면 notify_one이 호출됐다고 판단하는 것이다.
실제로 wait함수는 내부적으로 깨어나면 lock을 다시 획득하고, lock을 획득한 상태에서 뒤에 있는 조건 함수를 평가한다.
조건 함수가 참을 반환하면 실제 깨우기라고 판단하고 wait에서 리턴하고, 참이 아니라면 가짜 깨우기라고 생각하고 다시 대기 상태에 들어간다.&lt;/p&gt;
&lt;p&gt;여기까지는 아주 일반적인 상황이다. 조건 변수를 사용하는 스레드가 하나 밖에 없으니 말이다.
main에서 다음과 같이 대기 스레드를 두개를 만들었다고 생각해보자.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;thread &lt;span class=&quot;token function&quot;&gt;w1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;waitThread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;thread &lt;span class=&quot;token function&quot;&gt;w2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;waitThread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;thread &lt;span class=&quot;token function&quot;&gt;n1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wakeThread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	w1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	w2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	n1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 상태에서 앞선 ready와 동일한 조건 변수를 사용해서 상태를 관리한다고 하면 어떻게 될지 예측해보자.
대체로 물론 정상 동작한다. 하지만 이 상태에서는 단순 bool 변수만 가지고서는 가짜 깨우기를 구분하기가 어렵다.
왜냐하면 notify_one을 호출한 다음 시점에 임의 스레드가 가짜 깨우기로 일어난다면 그때는 ready 변수가 참이기 때문에 결국 하나만 깨워야 함에도 둘다 깨어나는 문제가 발생할 수 있다.
이 문제를 해결하기 위해서는 조건 체크 함수를 변경할 필요가 있다.
아래 함수는 조건 체크 함수 내에서 ready 변수를 변경해서 두 스레드가 동시에 깨어나는 문제를 해결한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;waitThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;unique_lock&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;mutex&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mtx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	cv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lock&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
			&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ready&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
				&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
					ready &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
					&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
				&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
				&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Wait thread is activated.&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그나마 notify_one은 다루기 쉬운 편에 속한다. notify_all로 가면 문제가 더 복잡해진다.
스레드들이 랜덤하게 대기 상태에 들어가고, 정확하게 wait 중인 스레드만 깨우기 위해서는 어떻게 해야 할까?
아래 코드는 그러한 상태를 보여준다.
waitThread는 100개가 생성돼서 랜덤하게 대기 상태에 들어간다.
주 스레드는 모든 스레드가 종료될 때까지 주기적으로 notify_all을 호출한다.
지금 이 코드는 조건 함수가 없기 때문에 무정부 상태나 다름 없다.
어떻게 하면 항상 wait 중이었던 스레드만 모두 깨울 수 있을까?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;iostream&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;thread&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;mutex&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;condition_variable&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;vector&gt;&lt;/span&gt;&lt;/span&gt;

std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;mutex mtx&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;condition_variable cv&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;atomic&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; ecount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// 대기하는 스레드의 함수&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;waitThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; no&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

		std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;try wait &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; no &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;unique_lock&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;mutex&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mtx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		cv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lock&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Wait thread is activated. &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; no &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;ecount&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ecount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; num_threads &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;vector&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;thread&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; threads&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;// 100개의 waitThread 스레드 생성&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; num_threads&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		threads&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;emplace_back&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;waitThread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ecount&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;lock_guard&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;mutex&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mtx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		cv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;notify_all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Wake thread has triggered the condition variable.&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; ecount &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

		std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;this_thread&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sleep_for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;chrono&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;milliseconds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;// 모든 스레드가 완료될 때까지 대기&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;thread&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; th &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; threads&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		th&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;어쨌든 요는 condition_variable은 spurious wakeup 때문에 복잡한 스레딩 모델에서는 사용할 때 생각보다 많은 주의를 필요로 한다는 점이다. 별 생각 없이 썼다가는 라이브에서 어이 없는 황당한 문제들을 경험할 가능성이 높다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[ai] 페어 프로그래밍에 관한 단상 feat. ChatGPT]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/2023/12/dynamic-table-size-with-chat-gpt/</link><guid isPermaLink="false">https://jiniya.net/2023/12/dynamic-table-size-with-chat-gpt/</guid><pubDate>Fri, 01 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;테스트 주도 프로그래밍, 스크럼, 페어 프로그래밍 같은 애자일로 분류되는 많은 방법론들이 있다
좋아하는 것들도 있고 그렇지 않은 것들도 있다. 그중에 특히 극혐하는 것은 스크럼과 페어 프로그래밍이다.
내가 만약 면접 자리에서 궁금한게 없냐는 질문을 받는다면 반드시 물어볼 것이다.
스크럼과 페어 프로그래밍을 하나요? 만약 한다면 강제 사항인가요?
강제 사항이라면 나는 그 회사를 입사하지 않을 생각이다. 그만큼 싫어한다.
일단 스크럼은 차치하고, 오늘은 페어 프로그래밍에 대해서만 알아보자.&lt;/p&gt;
&lt;p&gt;개인적으론 페어 프로그래밍이란 메커니즘이 두 페어가 현재 수행하고 있는 과제에 대해서 비슷한 지적 능력을 가졌을 때
그 효과가 절정에 이른다고 생각한다. 그렇지 않고 차이가 일정 수준 이상 난다면 그건 페어 프로그래밍이라기 보다는
도제식 교육이나 수업에 가까워진다고 생각한다. 물론 그렇지 않다는 수많은 연구 결과가 존재한다는 것은 나도 알고있다.
하지만 연구 결과는 연구 결과고 임상은 임상이니까. 내가 현업에서 느낀 심정은 연구 결과와는 많은 차이가 있었다.&lt;/p&gt;
&lt;p&gt;그렇다면 두 페어의 실력만 비슷하면 시너지가 날까?
그렇지도 않다. 왜냐면 우리는 사람이기 때문이다.
사람이 뭔가? 아 다르고 어 다르게 느끼는 게 사람이다.
심지어 똑같은 아도 그사람 기분이 어떤지에 따라 몹시 다른 결과를 가져오는게 사람이다.
즉, 둘이서 한 모니터를 바라보며 사이좋게 작업을 하기 위해서는 케미라는 아주 미묘한 성질의 것이 또 잘 맞아야 한다는 말이다.&lt;/p&gt;
&lt;p&gt;그렇다면 현실 세계에서 비슷한 지적 능력을 가진 케미가 잘 맞는 파트너를 만나서 페어 프로그래밍을 할 수 있는 확률은 얼마가 될까?
자세히 계산해 보지 않아도 내가 로또에 당첨되는 게 더 빠르다는 생각이다.&lt;/p&gt;
&lt;p&gt;이렇게 설명하면 지적 우위를 가진 사람이 꼭 손해를 보는 느낌인 것 같다.
하지만 내가 현실 세계에서 느낀 페어 프로그래밍은 루즈 루즈 게임인 경우가 많았다.
실력이 좋은 사람은 딱히 페어 프로그래밍으로 얻은 이득은 없다고 느끼고 불편했다는 말을 많이 했다.
그런데 재미있게도 실력이 낮아 보이는 프로그래머도 똑같은 얘기를 하는 경우가 많았다.
이 지점이 도제식 교육과 페어 프로그래밍의 차이인 것이다.
도제식 교육이었다면 아마 배우는 사람은 그나마 그래도 만족했을 것이다.&lt;/p&gt;
&lt;p&gt;무튼 이런 여타의 이유로 나는 페어 프로그래밍을 싫어했다.
뭐, 지금까지는 말이다.
하지만 올해 2월을 기점으로 세상이 바뀌었다.
ChatGPT가 등장한 것이다.
이 친구는 내가 앞서 서술한 페어 프로그래밍의 모든 단점을 단박에 없앤다.
지적 능력은 당연히 나보다 월등하다. 그럼에도 감정이 없고 내가 어떤 쌉소리를 하더라도 화내는 법이 없이 친절하게 알려준다.
그리고 365일 24시간 내내 내가 원할 때 언제든지 나와 함께 코딩할 준비가 돼 있다.
물론 가끔 openai 서버가 다운되긴 한다. 자주 있는 일은 아니니 그럴 땐 쉬면 되겠다.&lt;/p&gt;
&lt;p&gt;ChatGPT와 근 9개월 가량 페어 프로그래밍을 함께 하면서 나는 앞선 단점들만 없으면 페어 프로그래밍이 확실히 효과적이라는 생각이 들 게 되었다.
그래서 이제는 입사 면접 자리에서 나에게 뭐가 궁금한지 물어보면 다음과 같이 물어볼 것 같다.
인공지능 사용이 가능한가요? ChatGPT를 지원해 주나요?&lt;/p&gt;
&lt;p&gt;아래는 블로그의 테이블 셀 크기를 동적으로 변경하는 자바스크립트 코드를 작성하기위한 ChatGPT와의 대화 일부다.
복사해놓고 다시 보니 이건 페어 프로그래밍이라기보다는 코딩 노예를 고용한 것에 가깝지 않냐는 느낌이 약간 들긴 한다.
어쨌든 이러나 저러나 멋진 신세계다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;pair-with-chat-gpt.png&apos; data-alt=&apos;내가 인공지능에게 코딩을 배우는 날이 올거라곤 상상 못했다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/3dbc9c541356cb702c94ef8612b5ee25/445c6/pair-with-chat-gpt.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 57.36842105263158%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAADHklEQVR42hWS/VOTBQDHnz+ifuw6y37J68UTEIy1NYQEhmO8bg3HNvbiHNtY29j2iGOPDN3GA+PdeWFKgFfQwURNAtOEsNLLH7y8oxftpCju+KXu6ryrzk/rH/h+P/f5foUnPOXR9i84gwE2Hv/EH3//xaOtH7m2lENOHMfhOEJtjYJs0kfEb6YjcBSHvR6LsRKrpQ6z4W18bjP2Vi1thgqEJ/zL5s42PjHC4+1t/i/Y+X2HpU8vMZntZyh5HL22FLtVy8JMholMhPGUn4QUIhy0E3Q30xWyYX6nEpepCuGrBxt8srqGuf0Y619/wc9bP3D9xiK6plomRtN4/S5U1eWUHFTwuqKY01EzNxcGWVlbITOcwu1oJB5qwdhUgV73BsKf/MPD3zbxRsPc/+5BnjRAe8hLh9fKMa+H4jJ1PqiQZ3fvYv+hSuJSgFvLEyzkpuiNuTA0qnDnFfTHHVyQ3QhPgYe/buII+li/9yX7K9Ss3rnD3LVlmmztBDq92P0O2jxt1LboOdXrY3w0TjwzzNBIGn1DWZ6ujHjYQqLTiCCmZEJSD8keD/OTCT67fI6bMyexuZ2MpMOsTce4elHm7q2PyU2l8uOYmM2GOXv+HFI8SF1DNYVFL9PZYcJpUCEk0u+RTg4wcDLCfDbJ7FgXiwkN5noFnjyVVqPE0axk7pSR8YiOiLOamfFu5nNzDA33oSx9jZLSfRyqVtMTdSH4RJmI2ENnKMzsB+/jbXfS79dQXrSLvQolL71ZiaJoN0m7As3BAjSqPchddhY/GsPVWEpVeQFS0Ijm8Fs4LQ0I6iYXWr0Vq62VM3L+EnEnQ7GjnBatSPkB5L4YW5+n2bmbZSmv4oxYw+2lC1ycHCIZamaq+zBXx2wMdGqIHtmH0KDVEPHYsegOYCx7kbFkkA+nBumNtyMlJMZGM8xn3FwZaCMr1jMoNrG2usylG+v0xRysyDV8c97Et9Mmvp82IFy/fZ97G1tcmZsl4W2lp0tE7vaRG3GRelfH2RMGJKsSqaWAaMOrtGmLiUU6EE90oy55BdWeZ6gqfI66A89jUr/Af5JJIkHCBa4UAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;내가 인공지능에게 코딩을 배우는 날이 올거라곤 상상 못했다.&apos; title=&apos;&apos; src=&apos;/static/3dbc9c541356cb702c94ef8612b5ee25/efd7b/pair-with-chat-gpt.png&apos; srcset=&apos;/static/3dbc9c541356cb702c94ef8612b5ee25/08678/pair-with-chat-gpt.png 190w,
/static/3dbc9c541356cb702c94ef8612b5ee25/2edd7/pair-with-chat-gpt.png 380w,
/static/3dbc9c541356cb702c94ef8612b5ee25/efd7b/pair-with-chat-gpt.png 760w,
/static/3dbc9c541356cb702c94ef8612b5ee25/dc896/pair-with-chat-gpt.png 1140w,
/static/3dbc9c541356cb702c94ef8612b5ee25/78873/pair-with-chat-gpt.png 1520w,
/static/3dbc9c541356cb702c94ef8612b5ee25/445c6/pair-with-chat-gpt.png 1792w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;내가 인공지능에게 코딩을 배우는 날이 올거라곤 상상 못했다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h3&gt;ChatGPT와의 페어 프로그래밍이라 쓰고 코딩 시키기&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;You&lt;/strong&gt;&lt;br&gt;
gatsby 블로그 마크다운에서 테이블 셀 크기가 3개가 있는데 처음 두개는 너무 작고, 나머지 하나가 너무 커. 적당하게 나눠서 표시되게 만드려면 어떻게 해야 해?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;&lt;br&gt;
Gatsby 블로그에서 Markdown 테이블의 셀 크기를 조정하려면 몇 가지 방법을 시도할 수 있습니다. Markdown 자체에는 셀 크기를 직접 조정하는 기능이 없으므로, CSS를 사용하여 스타일을 적용하는 방법이 가장 일반적입니다. 다음은 몇 가지 방법을 소개합니다:&lt;/p&gt;
&lt;p&gt;... 중략 ...&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CSS&lt;/li&gt;
&lt;li&gt;Inline 스타일&lt;/li&gt;
&lt;li&gt;자바스크립트 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;... 중략 ...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You&lt;/strong&gt;&lt;br&gt;
셀 내용에 따라 다이나믹하게 설정할 수는 없어?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;&lt;br&gt;
셀 내용에 따라 테이블 셀 크기를 동적으로 조정하려면 JavaScript를 사용하는 것이 가장 효과적입니다. CSS와 Markdown만으로는 셀의 내용에 반응하여 크기를 조정하는 것이 불가능합니다. JavaScript를 사용하면 셀 내용을 읽고, 그 내용에 따라 적절한 크기를 동적으로 할당할 수 있습니다.&lt;/p&gt;
&lt;p&gt;... 중략 ...&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;DOMContentLoaded&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; table &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;.my-table&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 대상 테이블 선택&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rows &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; table&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;tr&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; row &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; rows&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cells &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;td&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; cell &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; cells&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; contentLength &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;// 셀의 내용 길이에 따라 셀 크기 조정&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;contentLength &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;20%&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;contentLength &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;30%&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;50%&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;You&lt;/strong&gt;&lt;br&gt;
그렇게 하는 거 보다는 각 칼럼의 가장 긴 길이를 각각 구해서 해당 비율로 크기를 설정하는 것이 좋을 거 같아. 그렇게 수정해줘&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;&lt;br&gt;
셀 내용에 따라 테이블 셀의 크기를 동적으로 조정하기 위해, 각 칼럼의 가장 긴 셀의 내용을 기준으로 크기를 결정하는 접근 방법을 사용할 수 있습니다. 이 방법은 JavaScript를 사용하여 구현할 수 있으며, 다음 단계로 구성됩니다:&lt;/p&gt;
&lt;p&gt;... 중략 ...&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;DOMContentLoaded&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; table &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;.my-table&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 대상 테이블 선택&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rows &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; table&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;tr&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; maxContentLengths &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; totalMaxLength &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 각 칼럼의 최대 길이 계산&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; row &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; rows&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cells &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;td&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    cells&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; contentLength &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      maxContentLengths&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;maxContentLengths&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; contentLength&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 전체 최대 길이 계산&lt;/span&gt;
  totalMaxLength &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; maxContentLengths&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; length&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; acc &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; length&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 각 칼럼에 비율에 따른 너비 설정&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; row &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; rows&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cells &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;td&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    cells&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; widthPercentage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;maxContentLengths&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; totalMaxLength&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;widthPercentage&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;You&lt;/strong&gt;&lt;br&gt;
cells.forEach is not a function 오류가 발생해&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;&lt;br&gt;
cells.forEach is not a function 오류가 발생하는 이유는 getElementsByTagName 메서드가 반환하는 HTMLCollection 객체가 Array가 아니기 때문에 forEach 메서드를 지원하지 않기 때문입니다. 이 문제를 해결하기 위해, Array.from 메서드를 사용하여 HTMLCollection을 배열로 변환하거나, 전통적인 for 루프를 사용할 수 있습니다.&lt;/p&gt;
&lt;p&gt;... 중략 ...&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;DOMContentLoaded&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; table &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;.my-table&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rows &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;table&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;tr&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; maxContentLengths &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; totalMaxLength &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 각 칼럼의 최대 길이 계산&lt;/span&gt;
  rows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cells &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;td&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    cells&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; contentLength &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      maxContentLengths&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;maxContentLengths&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; contentLength&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 전체 최대 길이 계산&lt;/span&gt;
  totalMaxLength &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; maxContentLengths&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; length&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; acc &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; length&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 각 칼럼에 비율에 따른 너비 설정&lt;/span&gt;
  rows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cells &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;td&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    cells&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; widthPercentage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;maxContentLengths&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; totalMaxLength&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;widthPercentage&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;You&lt;/strong&gt;&lt;br&gt;
table 이 하나도 없는 경우에 예외 처리해줘&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;&lt;br&gt;
테이블이 없는 경우에 대한 예외 처리를 추가하려면, 먼저 테이블 요소의 존재 여부를 확인하는 로직을 추가해야 합니다. 이를 위해 document.querySelector로 선택한 테이블 요소가 null인지 확인하는 간단한 조건문을 사용할 수 있습니다. 테이블이 존재하지 않는 경우, 함수의 실행을 중단하거나 적절한 메시지를 표시하도록 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;... 중략 ...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You&lt;/strong&gt;&lt;br&gt;
table에 tr이나 td가 하나도 없는 경우도 예외 처리가 필요할 거 같아.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;&lt;br&gt;
테이블에 tr이나 td 요소가 하나도 없는 경우에 대한 예외 처리를 추가하는 것은 좋은 접근입니다. 이를 위해서는 tr 요소의 배열이 비어있는지, 그리고 각 tr 내의 td 요소가 존재하는지를 확인하는 조건문을 추가해야 합니다. tr이나 td 요소가 없는 경우에는 함수의 실행을 중단하거나 적절한 경고 메시지를 표시할 수 있습니다.&lt;/p&gt;
&lt;p&gt;... 중략 ...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You&lt;/strong&gt;&lt;br&gt;
Array.from(null);은 정의돼 있어?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;&lt;br&gt;
Array.from(null)은 정의되어 있지 않습니다. Array.from 함수는 유사 배열 객체나 반복 가능한 객체를 새로운 배열 인스턴스로 만드는 메서드입니다. 그러나 null은 반복 가능한 객체가 아니기 때문에 Array.from(null)을 사용하려고 하면 오류가 발생합니다.&lt;/p&gt;
&lt;p&gt;따라서 Array.from을 사용하기 전에 반드시 해당 객체가 null이 아닌지 확인해야 합니다. 예를 들어, document.getElementsByTagName나 document.querySelectorAll과 같은 DOM 메서드가 비어있는 NodeList를 반환할 경우, 이를 배열로 변환하기 전에 null 여부를 검사해야 합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You&lt;/strong&gt;&lt;br&gt;
그렇게 수정해서 함수 새로 작성해줘&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;&lt;br&gt;
앞서 논의한 내용을 바탕으로, 테이블에 tr이나 td가 없는 경우에 대한 예외 처리를 포함한 새로운 JavaScript 함수를 작성하겠습니다. 이 함수는 테이블이 존재하고, 적어도 하나의 tr과 td가 있는 경우에만 셀 크기 조정 로직을 실행합니다.&lt;/p&gt;
&lt;p&gt;... 중략 ...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You&lt;/strong&gt;&lt;br&gt;
비율이 너무 낮은 셀이 나오면 문제가 될 거 같아서 최소 15% 이상은 보장되도록 코드를 수정해줘&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;&lt;br&gt;
셀의 너비 비율이 너무 낮아지지 않도록 최소 15% 이상의 너비를 보장하는 로직을 추가하겠습니다. 이를 위해 각 셀의 계산된 비율을 검사하고, 만약 그 비율이 15% 미만인 경우 15%로 조정하는 로직을 추가합니다. 또한, 이러한 조정으로 인해 총 너비 합계가 100%를 초과하지 않도록 전체 너비의 합을 다시 계산해야 합니다.&lt;/p&gt;
&lt;p&gt;다음은 수정된 코드입니다:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;DOMContentLoaded&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; table &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;.my-table&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;table&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;테이블이 존재하지 않습니다.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rows &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;table&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;tr&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;테이블에 행이 없습니다.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; maxContentLengths &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; totalMaxLength &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; isCellPresent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  rows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cells &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;td&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cells&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      isCellPresent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    cells&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; contentLength &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      maxContentLengths&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;maxContentLengths&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; contentLength&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;isCellPresent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;테이블의 행에 셀이 없습니다.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  totalMaxLength &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; maxContentLengths&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; length&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; acc &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; length&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; widthPercentages &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; maxContentLengths&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; totalMaxLength&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; adjustedPercentages &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; widthPercentages&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; adjustedTotal &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; adjustedPercentages&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; acc &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  rows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cells &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;td&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    cells&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; adjustedWidth &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;adjustedPercentages&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; adjustedTotal&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;adjustedWidth&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;You&lt;/strong&gt;&lt;br&gt;
그런데 저렇게 작성했다고 하면 예를 들어 칼럼이 세개고 비율이 5, 5, 90이었는데 조정을 해서 15, 15, 90이 되었다고 한다면 최종적으로 첫번째 칼럼은 15 / 120이 되서 12.5%가 되니까 원래 요구했던 15%보다 작게 설정되는 거 아냐?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;&lt;br&gt;
맞습니다. 코드에서 조정된 비율이 15%, 15%, 90%로 변경된 경우, 총합이 120%가 되어 각 비율을 다시 조정할 때, 원래 의도했던 최소 15% 비율이 보장되지 않을 수 있습니다. 이 문제를 해결하기 위해, 조정된 비율의 합이 100%를 초과할 경우에 대한 추가적인 처리가 필요합니다.&lt;/p&gt;
&lt;p&gt;비율을 조정하는 과정에서, 각 칼럼의 비율이 최소 15%가 되도록 하면서도 전체 합이 100%를 넘지 않도록 조정하는 방법은 다음과 같습니다:&lt;/p&gt;
&lt;p&gt;먼저, 모든 칼럼의 비율을 계산합니다.
15% 미만인 칼럼의 비율을 15%로 조정합니다.
조정 후 총합이 100%를 넘는 경우, 15% 이상인 칼럼들의 비율을 적절히 감소시켜 총합이 100%가 되도록 합니다.
이 과정은 비교적 복잡할 수 있으며, 특히 칼럼의 수나 비율에 따라 다양한 시나리오를 고려해야 할 수 있습니다. 간단한 해결책으로, 모든 칼럼이 최소한 15%를 차지할 수 있도록 고정된 비율을 설정하거나, 동적으로 비율을 조정하는 더 복잡한 알고리즘을 구현할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You&lt;/strong&gt;&lt;br&gt;
말로 하지 말고 그렇게 코드를 작성해줘&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ChatGPT&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;... 중략 ...&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;DOMContentLoaded&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; table &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;.my-table&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;table&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;테이블이 존재하지 않습니다.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rows &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;table&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;tr&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;테이블에 행이 없습니다.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; maxContentLengths &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; totalMaxLength &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; isCellPresent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  rows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cells &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;td&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cells&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      isCellPresent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    cells&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; contentLength &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;textContent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      maxContentLengths&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;maxContentLengths&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; contentLength&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;isCellPresent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;테이블의 행에 셀이 없습니다.&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  totalMaxLength &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; maxContentLengths&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; length&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; acc &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; length&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; widthPercentages &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; maxContentLengths&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; totalMaxLength&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; adjustedPercentages &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; widthPercentages&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; adjustedTotal &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; adjustedPercentages&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;acc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; acc &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 총합이 100%를 초과하는 경우, 초과분을 줄이는 로직&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;adjustedTotal &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; excess &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; adjustedTotal &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    adjustedPercentages &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; adjustedPercentages&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; excess &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; decrease &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; excess&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        excess &lt;span class=&quot;token operator&quot;&gt;-=&lt;/span&gt; decrease&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; width &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; decrease&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; width&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  rows&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; cells &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;row&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;td&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    cells&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; index&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;adjustedPercentages&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[cs] msbuil로 C# 프로젝트 빌드 시 project.assets.json 오류 해결 방법]]></title><description><![CDATA[우리는 대략 이런 커맨드로 msbuild를 사용하고 있었다.
project.sln에는 다수의 프로젝트가 포함되어 있고, cslib 그 중에 하나인 c# 프로젝트였다.
그런데 이상한게 Visual Studio…]]></description><link>https://jiniya.net/2023/11/nuget-json-asset-error/</link><guid isPermaLink="false">https://jiniya.net/2023/11/nuget-json-asset-error/</guid><pubDate>Thu, 30 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;msbuild project.sln -m -t &quot;cslib&quot; -p:Configuration=Release -p:Arch=AnyCPU&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;우리는 대략 이런 커맨드로 msbuild를 사용하고 있었다.
project.sln에는 다수의 프로젝트가 포함되어 있고, cslib 그 중에 하나인 c# 프로젝트였다.
그런데 이상한게 Visual Studio에서 빌드하면 멀쩡하게 빌드가 잘되는데 msbuild로만 실행하면 project.assets.json 파일이 없다며 오류가 발생했다.&lt;/p&gt;
&lt;p&gt;첫번째 문제는 경로였다. 우리는 프로젝트의 중간 파일과 출력 파일을 다른 경로로 지정해놓고 사용했는데 nuget이 생성하는 project.assets.json 파일은 그 경로가 아닌 디폴트 경로를 참조하는 것 같았다. 이를 해결하기 위해서는 cslib 프로젝트 파일이 있는 경로에 Directory.Build.props 파일을 생성한 다음 아래와 같이 설정해 주면 된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;xml&quot;&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;Project&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;BaseIntermediateOutputPath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;경로&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;BaseIntermediateOutputPath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;Project&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;경로에는 C# 프로젝트에서 설정한 것과 동일한 중간 파일 경로를 입력하면 된다. $(SolutionDir) 같은 변수도 지원하기 때문에 그대로 사용하면 된다.&lt;/p&gt;
&lt;p&gt;이제는 잘 되겠지?! 하고는 했는데 여전히 되지 않았다. 온갖 오류 메시지를 하나씩 추적하면서 수정하는 온갖 삽질을 ChatGPT와 함께하고 알게 되었다. project.sln 파일이 AnyCPU에 대해서 정상적으로 설정돼 있지 않으면 nuget이 project.assets.json 파일을 생성을 못한다. 예를들어 포함된 test 프로젝트가 AnyCPU에 대해서 빌드 설정이 체크되어 있지 않으면 생성이 되지 않는 식이다. 또는 솔루션 파일에 포함된 구성 요소 프로젝트가 없어도 생성이 되지 않는다. 이런 모든 원리를 살펴보면 위 커맨드를 수행할 때 아래 커맨드가 먼저 수행되는 것으로 보여진다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;msbuild project.sln -t &quot;restore&quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;즉, 솔루션 전체를 복원하는 것이다. 나는 cslib만 빌드하고 싶을 뿐인데 말이다. 그래서 ChatGPT와 함께 열심히 찾아 보았지만 개별 프로젝트를 복원하는 방법은 없어 보였다. 그렇다면 어쩌지?! 솔루션을 멀쩡하게 만들어야 하나? 그러기엔 외부 참조가 많아서 빌드서버에서 clone해야 할게 너무 많아지는 문제가 있었다. ChatGPT는 다음과 같은 방법을 나에게 대안으로 알려주었다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;msbuild cslib.csproj -m -t &quot;restore,rebuilt&quot; -p:Configuration=Release -p:Arch=AnyCPU&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;오 역시 ChatGPT. 바로 이거였어, 하고는 테스트를 했는데 한가지 추가적인 문제가 있었다. $(SolutionDir)이었다. 이는 프로젝트 파일을 직접 참조하기 때문에 $(SolutionDir)이 정의되지 않은 상태인 것이다. 다시 ChatGPT를 독촉하자. 완벽한 커맨드를 알려주었다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;msbuild cslib.csproj -m -t &quot;restore,rebuilt&quot; -p:Configuration=Release -p:Arch=AnyCPU -p:SolutionDir=path/to/solution&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;얼마간 삽질했지만 정상적으로 빌드되도록 만들 수 있었다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[시스템] CloudFlare Pages 수동 배포 방법]]></title><description><![CDATA[CloudFlare Pages를 자동 배포가 먹통이라 수동으로 배포해야 할 때는 아래 명령어를 사용하면 된다. <account_id>는 cloudflare pages 화면의 아래 빨간 네모로 표시된 위치에 값이 있다.  <worker_name…]]></description><link>https://jiniya.net/2023/11/cloudflare-pages-manual-deploy/</link><guid isPermaLink="false">https://jiniya.net/2023/11/cloudflare-pages-manual-deploy/</guid><pubDate>Wed, 29 Nov 2023 12:00:00 GMT</pubDate><content:encoded>&lt;p&gt;CloudFlare Pages를 자동 배포가 먹통이라 수동으로 배포해야 할 때는 아래 명령어를 사용하면 된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-X&lt;/span&gt; POST &lt;span class=&quot;token string&quot;&gt;&quot;https://api.cloudflare.com/client/v4/accounts/&amp;lt;account_id&gt;/pages/projects/&amp;lt;worker_name&gt;/deployments&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;token parameter variable&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Authorization: Bearer &amp;lt;token&gt;&quot;&lt;/span&gt;  &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;token parameter variable&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Content-Type:application/json&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&amp;#x3C;account_id&gt;는 cloudflare pages 화면의 아래 빨간 네모로 표시된 위치에 값이 있다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 705px; margin-bottom: 16px;&apos; data-url=&apos;cf.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5f147edcc104fc56bb7b86ee639e0d7d/f8d10/cf.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 46.8421052631579%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABhklEQVR42m1SSXIUMRDUm7jwJLjwDiI48wYieAanuWIwbhPgjV4tqVvqdXpRd5LS2OAZuyIytJVKmakS27bhKXyM4whb1zDGhHnXdZBSYhgGzPOEqqzQtl0407pE1w9h7fPFUUEWW/24rlhP4Jw7Wj/GgcThvt8X1liUVYmKUFofJf+/BDhuL+7wqGcc/4mRJAnSNMGvrIdpp5ArLi8jfD37hiiKsNvtSNs+efnl8NK1UmiallJbaNPDNl1QJhQP4jhBnudEwYIVhp4JtkbDZDcNuNbAu8/A20/Axy9kSx99MV/4VJFom5rGKhhK1koiKxSkNrSgglS0YO5wlgKvPwCv3gNvWHRbFyiel1TjWOQRXpO41w1ukhK3aYW0KHEVl7i4azBM6z+zT2Ohh71U6KkujER3LzGyM0RhFlwVI35ne+SchxYhQ1u3wZNnMc+Yflygv73DzI9xaRawZjnc9Q3Enr00zQu92A4t8/D9Hi9+DPP30U/01mImI0cCGz1v2CHy+zn+AidtslOoGo44AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;cf&apos; title=&apos;&apos; src=&apos;/static/5f147edcc104fc56bb7b86ee639e0d7d/f8d10/cf.png&apos; srcset=&apos;/static/5f147edcc104fc56bb7b86ee639e0d7d/08678/cf.png 190w,
/static/5f147edcc104fc56bb7b86ee639e0d7d/2edd7/cf.png 380w,
/static/5f147edcc104fc56bb7b86ee639e0d7d/f8d10/cf.png 705w&apos; sizes=&apos;(max-width: 705px) 100vw, 705px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;#x3C;worker_name&gt;은 자신의 페이지 프로젝트 이름을 입력하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;token&gt;은 발급받은 api 토큰을 넣어주면 된다.&lt;/p&gt;
&lt;p&gt;호출에 성공하면 대시보드에서 빌드가 진행되는 것을 볼 수 있다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] jiniya.net 리마스터링]]></title><description><![CDATA[#0 2…]]></description><link>https://jiniya.net/2023/11/jiniya-net-remastering/</link><guid isPermaLink="false">https://jiniya.net/2023/11/jiniya-net-remastering/</guid><pubDate>Tue, 28 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/X-yIEMduRXk?si=wE2rXepkhoypd77z&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;20대 어느 날 중고등학생 때 썼던 일기장을 모두 버린 기억이 있다.
본가에 두고 온 일기장을 누나가 읽었다며 놀린 게 계기가 되었다.
그 얘길 듣고 그걸 전부 자취방으로 가지고 왔었다.
내가 다시 읽어봐도 워낙 오글거려서 그날로 다 버렸다.
그때는 몰랐다. 데이터가 얼마나 소중한지.
그 글들이 내가 유일하게 추억할 수 있는 그 시절 나의 생생한 모습이란 사실도 말이다.&lt;/p&gt;
&lt;p&gt;일기장을 버린지 근 20년이 되어간다.
가끔 그때 버린 일기장이 기억날 때가 있다.
오글거리긴 해도 가끔 그시절 내가 어떤 생각을 했고, 어떤 고민을 했는지가 궁금할때가 있는 것이다.
물론 나이가 들어서일수도 있다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;올해 이글루란 블로그 서비스가 문을 닫는다는 소식이 들렸다.
어렸을 때 그곳에 적잖게 글을 썼던지라 들어가 보았다.
2004-5년 학생 시절에 쓴 글들이 많이 있었다.
웃기기도 하고, 이렇게 살았구나 싶기도 했다.
같은 실수를 두번하지 않기 위해서 이번에는 데이터가 삭제되기 전에 모두 백업을 했다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;이 블로그를 시작할 때만해도 내가 이걸 8000일이 넘는 시간동안 운영하게 될 거라곤 생각하지 못했다.
다만 조금 아쉬운 점은 자작 게시판, phpBB, 태터툴즈, 워드프레스, 지킬을 거치면서 얼마간은 데이터가 유실되었다는 점이다.
예전엔 데이터가 소중한지도 몰랐었고, 나중에 그게 아쉬울지도 몰랐다.
어쨌든 그런 일들을 겪고 보니 이제라도 한번 전체를 다시 재정비를 해야겠다는 생각이 들었다.&lt;/p&gt;
&lt;p&gt;기존에 파편화되어 있던 글들을 한곳에 다 모으기로 했다.
대체로 모을 수 있는 모든 글들을 모았다.
그리고 그렇게 모은 글들은 다시 다듬었다.
소위 블로그 리마스터링이라고 부를만한 작업을 했다.&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;작업을 하기에 앞서서 gatsby 템플릿을 변경할 필요가 있었다.
기존 템플릿이 너무 단촐해서 글을 너무 많이 담기에는 다소 무리가 있어 보였다.
여기저기 구경하던 중 &lt;a href=&quot;https://hudi.blog&quot;&gt;hudi 님께서 만든 템플릿이&lt;/a&gt; 좋아 보였다.
디자인도 멋지고, 반응형에, 태그와 시리즈를 지원하는 멋진 템플릿이었다.&lt;/p&gt;
&lt;p&gt;템플릿을 교체하는 과정도 순탄하지만은 않았다.
gatsby에 g도 모르는 입장이라 오류가 발생하면 뭐가 문제인지도 몰랐으나 오류 메시지를 복붙하면 대체로 ChatGPT가 다 해결해 주었다.&lt;/p&gt;
&lt;p&gt;기존 글들을 정리하면서 느낀 가장 큰 재앙은 오래된 글에 있는 링크는 거의 모두 사라졌거나 동작하지 않는다는 사실이었다.
퍼가는 사람들이 왜그럴까 했는데 이해가 되는 지점이었다.
그래서 나는 대체로 기존 링크를 유지할 수 있으면 유지하기로 결정했다.
이 기능도 템플릿을 고쳐서 가능했는데 gatsby의 유연한 시스템과 ChatGPT의 어시스트로 가능했다.
어쨌든 기본적인 프레임워크는 다 준비된 것 같아서 이제 글을 옮기기로 했다.&lt;/p&gt;
&lt;h3&gt;#4&lt;/h3&gt;
&lt;p&gt;시작은 최근 데이터부터 시작했다.
단순 무식하게 카피앤페이스트로 지킬의 데이터를 다 옮겼다.
이것도 수작업으로 하니 생각보다 힘든 작업이었다.
그리고 남은 글들을 보았다. 워드프레스와 태터툴즈만 합쳐도 1000개가 넘는 글이 남아 있었다.
와 이거 노답인데 하는 생각도 순간, 나에게는 ChatGPT가 있었다.&lt;/p&gt;
&lt;p&gt;자동으로 긁어서 마크다운으로 변환해서 파일로 저장하는 스크립트를 작성하라고 시켰다.
ChatGPT는 나를 실망시키는 법이 없다.
녀석이 작성해준 코드는 기가 막히게 동작했고, 나는 제로 콜라 하나를 다 마시는 동안 모든 페이지가 마크다운으로 변환되는 기적을 맛보았다.&lt;/p&gt;
&lt;p&gt;그러고 나니 텍스트는 거의 다 저장되었는데 페이지에 포함된 이미지가 문제였다.
다시 ChatGPT에게 물었다. 녀석은 마크다운으로 변환하는 페이지에 포함된 이미지까지 모두 다운로드 받아서 저장해주는 스크립트를 안겨주었다.
올레~&lt;/p&gt;
&lt;h3&gt;#5&lt;/h3&gt;
&lt;p&gt;물론 23년 가까이 쓴 글들은 지금 돌아보면 우습고 부끄럽고 이불킥하고 싶은 글들이 많다.
하지만 그런 것들도 다 나의 일부라 생각하고, 추억이기에 보존하기로 했다.&lt;/p&gt;
&lt;p&gt;그렇게 모아진 글들만 1200개가 넘는다.
없애지 않고 지금까지 잘 보존해준 과거의 나에게 감사함을 표한다.
그덕에 나는 &lt;a href=&quot;https://devblogs.microsoft.com/oldnewthing/&quot;&gt;존경해 마지 않는 레이몬드 첸 아저씨&lt;/a&gt;보다 블로그를 오래한 몇 안되는 프로그래머 중에 한 명이 되었다.&lt;/p&gt;
&lt;h3&gt;#6&lt;/h3&gt;
&lt;p&gt;나는 더는 스타크래프트를 즐기지 않고, 와우를 미친 듯이 하지 않는다.
킹 오브 파이터즈를 하러 오락실을 찾지도 않고, 무한도전이나 러닝맨 같은 예능을 즐겨 보지도 않는다.
일요일 밤을 마감하는 웃찾사나 개그콘서트같은 개그 프로를 안 본지도 오래됐다.
과자를 자주 먹지도 않는다.&lt;/p&gt;
&lt;p&gt;긴 세월 만큼이나 나란 사람도 정말 많이 변했다.
하지만 그렇게 많은 세월이 지났어도 나는 여전히 여기에 글을 쓴다.
어쩌면 이게 내가 코딩을 제외하고 본질적으로 거의 유일하게 좋아하는 일인지도 모르겠다는 생각이 들었다.&lt;/p&gt;
&lt;p&gt;주춤했던 최근을 넘어서 앞으로는 그래도 종종 글을 남기겠다는 다짐을 해본다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[ai] AI 주도 개발]]></title><description><![CDATA[최근 Github Copilot 출시 소식을 접했다. 소개 페이지를 보면 월 10불, 년 100불에 Python, JavaScript, TypeScript, Ruby, Go, C#, or C…]]></description><link>https://jiniya.net/dev/ai-driven-development/</link><guid isPermaLink="false">https://jiniya.net/dev/ai-driven-development/</guid><pubDate>Tue, 28 Jun 2022 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;최근 Github Copilot 출시 소식을 접했다. 소개 페이지를 보면 월 10불, 년 100불에 Python, JavaScript, TypeScript, Ruby, Go, C#, or C++ 코딩을 도와주는 도구라고 나와있다. 알파고가 등장하기 전이었다면 쳐다보지도 않았겠지만 알파고의 위력을 알았기에 설치를 해보았다. 결과는 실로 놀라웠다. 처음 3분간 테스트 해 본 코드를 첨부하면 다음과 같다. ai+라고 주석이 달린 부분은 모두 인공지능이 작성해서 추가한 부분이다. 살펴보면 대체로 함수 원형만 작성하면 나머지는 모두 코파일럿이 작성했다는 것을 알 수 있다. 사실 여기까지만 보고도 많이 놀랐다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;plus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;IsPrime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;


&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetFactorial&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetFactorial&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetFactorialWithoutRecursion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		result &lt;span class=&quot;token operator&quot;&gt;*=&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetFibonacci&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetFibonacci&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetFibonacci&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetFibonacciWithoutRecursion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;IsPalindromeString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; len &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; len &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;len &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetMaxValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_t cnt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; max &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; cnt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; max&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			max &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; max&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SortData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_t cnt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; cnt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; j &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; j &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; cnt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; j&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
				&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; tmp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
				data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
				data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tmp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_STUDENT&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; score&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; STUDENT&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PSTUDENT&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;FindStudentScore&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PSTUDENT students&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; cnt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; cnt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;students&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; students&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;score&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;QuickSortData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_t cnt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cnt &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; pivot &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;cnt &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	size_t i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	size_t j &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cnt &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; j&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; pivot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; pivot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			j&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; j&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; tmp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tmp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			j&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;QuickSortData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; j &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;QuickSortData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cnt &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;테스트 하면서 웃긴 장면이 하나 있었다. 다음 함수다. 중괄호 매치가 끝나지 않은 지점에 인공지능 코딩이 끝난 것이다. 사실 인간 입장에서 여기에서 코드가 종결된 것인지, 아니면 코드를 더 작성해야 하는지 알기가 쉽지 않겠다는 생각이 들었다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;QuickSortDataWithoutRecursion&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_t cnt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;stack&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; stack&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	stack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	stack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cnt &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;stack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; right &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; stack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		stack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; left &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; stack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;top&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		stack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; pivot &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;left &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; right&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; left &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; j &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; right &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
				i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; pivot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;

		&lt;span class=&quot;token comment&quot;&gt;// 이 시점에 인간 프로그래머의 심정&lt;/span&gt;
		&lt;span class=&quot;token comment&quot;&gt;// 1) 다 짠걸까? 2) 더 있는걸까? 3) 맞는걸까?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;여기까지 샘플 코드를 살펴보면 저건 단순하고 많이 테스트되는 코드들이니까 인공지능이 잘 작성했다고 생각할 수 있다. 어쨌든 나는 여기에서 가능성을 보았다. 그리고 이후 몇일간 실질적으로 회사 코딩을 하는데 적용해서 함께(?!) 코딩을 해보았다. 결과는 실로 놀라웠다.&lt;/p&gt;
&lt;p&gt;내가 테스트한 개발 방식은 총 3가지였다. 안드로이드 C++ 개발, 윈도우 C++ 개발, 윈도우 커널모드 C 개발. 안드로이드와 윈도우 C++ 개발은 굉장히 편리하게 사용할 수 있는 수준이었다. 윈도우 커널모드 C 개발의 경우 주석을 굉장히 디테일하게 작성해야 사용할 수 있는 코드가 도출되었다. 결론부터 총평하자면 무조건 써라. 회사에서 사주지 않으면 개인 비용으로라도 쓰길 추천한다.&lt;/p&gt;
&lt;p&gt;써보면서 가장 편리했던 부분은 끊임없이 레퍼런스를 참고하면서 작업해야 하는 반복적인 코딩이었다. 예를들면 Java 호출 코드를 JNI로 컨버팅하는 류인데 이런 경우 안드로이드 문서와 JNI 스펙 문서를 찾아보면서 일일이 타입, 시그니처를 찾고 생성해서 테스트를 해야 한다. 그렇게 일일이 수작업으로 생성해도 세미콜론이나 달러 기호가 빠져서 정상 동작하지 않는 경우가 많다. 하지만 코파일럿을 사용할 경우 주석만 적당히 입력하면 마법처럼 완벽한 코드를 생성해 냈다. 이게 몇 개 쌓이자 나중에는 일일이 확인을 하지도 않았다. 그냥 얘가 생성한거는 똑바로 생성했겠거니 하는 생각이 들었다.&lt;/p&gt;
&lt;p&gt;두번째로 놀란 부분은 주석이 없어도 인공지능이 문맥을 어느 정도 파악한다는 점이다. 예를들면 내가 특정 조건을 실패로 리턴하면 다음부터는 그 함수 내에서는 그런 류의 판단은 자기가 알아서 성공/실패를 결정한다. 이건 진짜 웃긴데 내가 함수를 작성하다 구조가 마음에 안 들어서 위에서 한두개를 바꾸면 나머지는 다시 알아서 재추천을 해준다. 진짜 얘가 나와 상호작용을 하고 있다는 생각이 절로 든다. 나는 페어 프로그래밍은 시간 낭비라 생각해 많이 해보진 않았지만 그간 일반적인 신입 프로그래머와 코딩 작업이나 코드 리뷰를 해 본 경험에 비추어보자면 코파일럿이 보통의 신입 프로그래머보다는 훌륭하다는 생각이 들었다.&lt;/p&gt;
&lt;p&gt;세번째로 놀란 부분은 완벽하진 않지만 힌트를 제공하면 마법처럼 내 의도를 알아차린다는 점이었다. 예를들면 다음과 같은 코드였다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CombineValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; buf&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_t buf_size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;uint64_t&lt;/span&gt; msb&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;uint64_t&lt;/span&gt; lsb&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;uint64_t&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msb &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; lsb&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; buf_size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		buf&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;value &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0xFF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이건 아니지라는 생각에 AI가 추가한 코드를 지우고 memcpy(까지 치고 기다리면 다음처럼 올바른 코드를 생성해 낸다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CombineValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; buf&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_t buf_size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;uint64_t&lt;/span&gt; msb&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;uint64_t&lt;/span&gt; lsb&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buf&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;msb&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msb&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buf &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msb&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;lsb&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lsb&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;함수가 리턴 값이 있어야 할 거 같아서 다음과 같이 bool 형으로 바꾸고 if까지 입력하고 대기하면 다음과 같은 코드를 생성해 준다. 물론 완벽하진 않지만 내가 뭘 체크하려고 if를 입력했는지를 캐치했다는 점은 놀랍다. 함께 코딩해보면 이런 적이 제법 많다. 실질적으로 내가 의도한 바는 &lt;code class=&quot;language-text&quot;&gt;buf_size &amp;lt; 16&lt;/code&gt;이다. 그럼에도 주석 한 줄 없이 이 정도 코드를 추천했다는 것은 놀랍다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CombineValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;uint8_t&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; buf&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_t buf_size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;uint64_t&lt;/span&gt; msb&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;uint64_t&lt;/span&gt; lsb&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buf_size &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buf&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;msb&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msb&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buf &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msb&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;lsb&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lsb&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;회사 작업을 하면서 코파일럿이 추가한 코드는 여기에 올린 것처럼 ai+라는 주석을 달았다. 실질적으로 얼만큼 실용적인지를 보고 싶었다. 하지만 이제 더는 달지 않는다. 몇일 작업하면서 이미 코파일럿은 그 자체로 존재 가치를 충분히 증명했기 때문이다.&lt;/p&gt;
&lt;p&gt;나는 코파일럿이 제공하는 프로그래밍 언어를 다 다룰 줄 안다. 다만 주력으로는 파이썬, C++이고 나머지는 서브로 사용하고 있다. 그래서 해당 언어의 라이브러리 코드 등을 세세하게 다 기억하지 못해서 구글을 통해서 검색해가면서 개발하는 경우가 다반다사. 이런 경우에도 코파일럿은 굉장히 큰 도움이 되었다. 왜냐하면 그런 언어로 하는 작업은 실질적으로 아주 간단한 샘플 코드인 경우가 많아서 코파일럿 추천을 받기가 훨씬 쉽기 때문이었다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Test&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; String &lt;span class=&quot;token function&quot;&gt;GetFileText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;String path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		String text &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			FileInputStream fis &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;FileInputStream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			BufferedReader br &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BufferedReader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;InputStreamReader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fis&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			String line&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;line &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; br&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readLine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; null&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
				text &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; line &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			br&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IOException e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
			e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;printStackTrace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; text&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;RequestPermission&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;String permission&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		ActivityCompat&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;requestPermissions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; String&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;permission&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ai+&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;예전에 나는 이런 도구에 대해서 조금은 부정적인 의견이 있었다. 이런 도구들이 발전할수록 개발자가 점점 멍청해지지 않을까라는 생각이 있었던 것이다. 그러나 이제는 생각이 좀 바뀌었다. 인공지능이 진화할수록 결국 나를 100% 대체할 것은 자명한 사실이다. 하지만 100% 대체가 되기 전까지는 어쨌든 인공지능의 도움을 받는 것이 다른 사람들과 경쟁을 하는데 도움이 된다는 생각이다. 그리고 코파일럿을 써 본 입장에서 생산성 차이는 엄청나다. 최신형 사이보그 의족을 달고 우샤인 볼트와 대결할 수 있게 된 것이다. 아직도 코파일럿을 안 쓰는 개발자도 많을 것이다. 그런 점에서 사용하는 사람은 비교우위에 설 수 있다는 게 내 생각이다.&lt;/p&gt;
&lt;p&gt;그리고 조심스레 예측해 본다. 앞으로 코파일럿에 적응한 개발자가 늘어날수록 함수명이나 변수명, 주석 등을 코파일럿이 적절하게 추천할 수 있도록 작성하는 것이 능력이 될 것이란 점이다. 아직까지는 주는 사람이고, 보조가 인공지능이지만 인공지능이 주가 될 날도 머지 않았다는 생각이 든다. 인공지능이 추천한 코드를 사용하다, 인공지능에게 코드 리뷰를 받다가, 결국에는 인공지능이 모두 다 작성하게 될 세상. 그런 세상에서 아마도 우린 이런 얘기를 하겠지? 라떼는 사람이 직접 프로그램을 입력하는 시절도 있었다고 말이다.&lt;/p&gt;
&lt;p&gt;진짜 정말 놀라운 세상이다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;충분히 발달한 과학 기술은 마법과 구별할 수 없다.&lt;/p&gt;
&lt;p&gt;-- 아서 C. 클라크&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[[소고] 내가 오늘 교통사고를 당할 확률은?]]></title><description><![CDATA[출근길, 이렇게까지 막힐 길이 아닌데 터무니 없게 차들이 막혀 있다. 한참을 지나오니 3차선 길에 교통사고가 나서…]]></description><link>https://jiniya.net/life/traffic-accident-probability/</link><guid isPermaLink="false">https://jiniya.net/life/traffic-accident-probability/</guid><pubDate>Fri, 22 Apr 2022 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;출근길, 이렇게까지 막힐 길이 아닌데 터무니 없게 차들이 막혀 있다. 한참을 지나오니 3차선 길에 교통사고가 나서 2개 차로가 막혀 있었다. 그렇게 사고를 지나 한참을 달려 톨게이트를 지나는데 또 거북이가 된 차선. 멍밍? 톨게이트 위 표지판에 전방에 사고로 1, 2차선이 막혀 있다는 글귀가 스크롤 된다. 비도 오지 않고, 눈도 오지 않고, 단지 조금 흐린 날씨인데 왜케 사고가 많은 것일까?, 라는 생각도 잠시. 사고가 나지 않아서 다행이란 생각이 오버랩됐다. 그러자 마음이 한결 편해진다.&lt;/p&gt;
&lt;p&gt;그렇게 또다시 막힌 길을 지나 열심히 달려서 상습 정체 구간에 도착했다. 느림보가 된 차안에서 갑자기 궁금증이 밀려온다. 오늘 내가 교통사고를 당할 확률은 얼마일까, 라는 생각. 어댑티브 크루즈를 켜두고 &quot;교통사고 확률&quot;같은 키워드로 포풍 검색을 해본다. 대체로 우리나라 사람이 평생 교통사고를 1번이라도 당할 확률은 나오지만 오늘 내가 교통사고를 당할 확률이 얼마인지는 나오질 않았다. 그래서 한번 역산을 해보기로 했다.&lt;/p&gt;
&lt;p&gt;이어지는 모든 내용은 나의 부족한 수학 지식에 기반한 것이므로 오류 및 잘못된 내용이 포함되어 있을 수 있다는 점 명심해주길 바라면서 계산을 한 번 시작해보자. &lt;a href=&quot;https://n.news.naver.com/mnews/article/086/0001996511&quot;&gt;이 기사&lt;/a&gt;에 따르면 우리나라 국민이 일평생 1번이라도 교통사고를 당할 확률은 35.2%라고 한다. 우리나라 국민의 평균 수명은 &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_countries_by_life_expectancy#List_by_the_World_Health_Organization_(2015)&quot;&gt;이 자료&lt;/a&gt;에 따르면 83.3세라고 한다. 계산의 편의를 위해서 80년이라고 가정한다.&lt;/p&gt;
&lt;p&gt;일평생 한번이라도 교통사고를 당할 확률이 35.2%라는 말은 일평생 교통사고를 한번도 당하지 않을 확률은 64.8%라는 말이 된다. 일평생 교통사고를 한번도 당하지 않을 확률은 오늘 내가 교통사고 당하지 않을 확률을 사는 기간 만큼 곱한 것이 된다. 결국. 0.648의 80제곱근을 구한다면 한해동안 내가 교통사고를 당하지 않을 확률, 29200(80*365)제곱근을 구한다면 오늘 내가 교통사고를 당하지 않을 확률이 나온다. x의 n제곱근은 x^(1/n)으로 구할 수 있다고 한다. 그렇게 계산을 해보면 0.648^(1/29200) = 0.999985가 나온다. 마침내 내가 오늘 교통사고를 당하지 않을 확률에 도달했다. 99.9985%, 교통사고를 당할 확률은 그 반대이니 0.0015%가 될 것이다.&lt;/p&gt;
&lt;p&gt;0.0015%라, 생각보다 확률이 너무 낮은 느낌적인 느낌. 인구가 5천만이라고 가정하면 하루에 확률적으로 750명 가량이 교통사고를 경험할 수 있게 되고, 그런 사람들 중 최소 4명을 내가 오늘 아침에 목격한 셈이 된다.&lt;/p&gt;
&lt;p&gt;오늘 하루, 교통사고 없이 무사히 출근하게 되어 억세게 운이 좋다고 생각하려고 하였으나 그렇게 생각하기에는 무리가 있어 보이는 확률 같다. 확률을 본다면 퇴근길에도 난 교통사고를 겪지 않을 것 같다. 그렇게 오늘도 보통 사람이 보통의 확률로 하루를 살아간다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 2022 쿠팡, 과연 아마존이 될 상인가?]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/invest/coupang-20022/</link><guid isPermaLink="false">https://jiniya.net/invest/coupang-20022/</guid><pubDate>Thu, 21 Apr 2022 13:00:01 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://brunch.co.kr/@fbrudtjr1/44&quot;&gt;쿠팡은 왜 적자를 탈출할 수 없는걸까?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;이런 글을 보면 정말 애널리스트도 힘들겠구나 하는 생각이 든다. 반도의 흔한 블로거의 분석글 수준이 정말 넘사벽이다.&lt;/p&gt;
&lt;p&gt;쿠팡은 몇년전부터 개인적으로 몹시 미래가 궁금했던 기업 중 하나였다. 왜냐하면 저 사업 모델이 성공할까? 하는 생각도 있었고, 소비자로써는 너무나 지나치게 편리했기 때문이다. 상장전에는 실패할 확률이 높다고 생각했지만 보란듯이 나스닥에 성공적으로 상장해서 어마어마한 밸류에이션을 받는 걸 보고 나의 예측이 빗나갔음을 인정해야 했다.&lt;/p&gt;
&lt;p&gt;최근에 멤버십 가격을 올리고, 반품 정책을 변경하는등 서서히 비용 지출에 신경을 쓰는 모습으로 변신하고 있는 쿠팡. 과연 그들은 흑자 전환을 할 수 있을까? 안타깝게도 난 위 분석글과 같은 이유로 쉽지 않을거라 생각한다. 아래는 분석글 내용 요약.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;쿠팡은 2021년 매출 22조, 영업손실 1조8700억을 기록&lt;/li&gt;
&lt;li&gt;국내 소매시장 온라인 침투율 28.9%로 거의 포화상태, 플레이어 너무 많음, 흑자 거의 없음&lt;/li&gt;
&lt;li&gt;물류센터 자동화가 추후 규모의 경제를 달성하는데 중요함, 징동닷컴 85%, 슥 80%, 쿠팡 10% 수준&lt;/li&gt;
&lt;li&gt;멤버십은 흑자지만 거기서 나오는 비용은 조족지혈&lt;/li&gt;
&lt;li&gt;캐시카우 부재&lt;/li&gt;
&lt;li&gt;신규 사업은 모두 돈먹는 하마&lt;/li&gt;
&lt;li&gt;번외) 배민이 2019년부터 적자전환, 퀵커머스 진출로 유추 (충격)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;그리고 원글에는 없는 개발자라면 모두 아는 아마존과의 결정적 차이, 아마존은 AWS를 팔고, 쿠팡은 AWS를 쓴다는 거. 심지어 베조스 다음 사장이 AWS 수장이 되었다. 그리고 다른 하나는 직고용 중인 천문학적 수준의 택배기사들. 규모가 커질수록 직고용이 늘고, 그렇게 늘어난 인원은 쿠팡이 바라는 규모의 경제를 달성하는데 거대한 허들이 되지 않을까 싶다.&lt;/p&gt;
&lt;p&gt;이 모든 이야기에도 불구하고 로켓배송, 사랑한다.&lt;br&gt;
쿠팡의 적자만큼 소비자에겐 혜자라는 의미가 되기도 한다.&lt;/p&gt;
&lt;p&gt;대한민국 유니콘 신화가 계속 이어지기를...&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] Begin Again]]></title><description><![CDATA[2000년도 인터넷 수업 과제로 시작한 홈페이지가 이렇게 오랜 기간 이어질 줄은 몰랐다. 그러고보니 2…]]></description><link>https://jiniya.net/life/begin-again/</link><guid isPermaLink="false">https://jiniya.net/life/begin-again/</guid><pubDate>Wed, 20 Apr 2022 12:00:01 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/hWYM5QEt0Fg&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;p&gt;2000년도 인터넷 수업 과제로 시작한 홈페이지가 이렇게 오랜 기간 이어질 줄은 몰랐다. 그러고보니 20년간 줄기차게 이어진 나의 유용한 취미 중 하나가 공개된 장소에 글을 쓰는 건 아니었나 싶다. 뜸한 시절도 있었고, 열정적으로 올린 시절도 있었지만 어쨌든 중요한 건 아직까지 이어지고 있다는 사실일 것이다.&lt;/p&gt;
&lt;p&gt;그간 자작 게시판, phpBB, 태터툴즈, 워드프레스, 지킬을 거쳐서 이번에는 개츠비로 정했다. 요즘 유행하는 github 저장소, cloudflare 배포 방식을 사용해보려고 도메인도 새로 만들어봤다. 이제부터 얼만큼 남아 있을지 모를 나의 인생 후반전의 기록을 여기에 남겨볼까 한다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;가장 훌륭한 시는 아직 씌어지지 않았다.&lt;br&gt;
가장 아름다운 노래는 아직 불려지지 않았다.&lt;br&gt;
최고의 날들은 아직 살지 않은 날들.&lt;br&gt;
가장 넓은 바다는 아직 항해되지 않았고,&lt;br&gt;
가장 먼 여행은 아직 끝나지 않았다.&lt;br&gt;
불멸의 춤은 아직 추어지지 않았으며,&lt;br&gt;
가장 빛나는 별은 아직 발견되지 않은 별.&lt;br&gt;
무엇을 해야 할지 더 이상 알 수 없을 때&lt;br&gt;
그때 비로소 진정한 무엇인가를 할 수 있다.&lt;br&gt;
어느 길로 가야 할지 더 이상 알 수 없을 때&lt;br&gt;
그때가 비로소 진정한 여행의 시작이다.&lt;/p&gt;
&lt;p&gt;– 진정한 여행, 나짐 히크메트&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;지금이 비로소 내 인생의 진정한 여행을 시작할 때인 것 같은 느낌...&lt;br&gt;
아직 오지 않은 최고의 날들을 기다리며 비긴 어게인...&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 누가 성장 했을까?]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2022/04/who-has-grown-up/</link><guid isPermaLink="false">https://jiniya.net/ng/2022/04/who-has-grown-up/</guid><pubDate>Tue, 19 Apr 2022 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;회사를 시작하고 직원을 채용하고 그들과 함께 일을 하면서 가장 많이 들은 불만 사항중에 하나는 방목이다. 나는 꼰대라 그렇게 생각을 하지 않지만 직원들은 회사가 본인들을 충실하게 교육시켜서 연차에 알맞게 총총 성장을 시켜주길 바라는 것 같다. 물론 나도 그런 생각을 안해본 사람은 아니다. 창업을 했던 초창기에는 어렸고, 열정이 있었다. 밤을 새면서 A부터 Z까지 알려주려고 해본 적도 있었다. 응당 개발 속도는 달팽이보다 느려졌다. 그때마다 빨리 가려면 혼자 가고, 멀리 가려면 함께 가라는 말을 주문처럼 되내이면서 자기 위안을 삼았다.&lt;/p&gt;
&lt;p&gt;하지만 현실은 녹록치 않았다. 그 속도로 가다간 멀리는 고사하고 당장 한두달만돼도 굶어죽을 것 같았다. 속도도 느렸지만 품질도 문제였다. 충실하게 A부터 Z까지 교육을 받고 만든 친구는 성장했을지 모르겠지만 회사는 제자리였다. 아 이렇게 해서는 달은 고사하고 대기권 통과도 힘들겠구나 하는 생각이 절로 들었다. 결국 나는 방목을 택했다. 할 수 있는 것들만 시켰고, 못한다는 것은 할 수 있는 다른 사람들에게 부탁했다.&lt;/p&gt;
&lt;p&gt;그렇게 개발 속도가 올라갔고 몇해가 지났다. 사내 이슈 트래커는 해결되지 않은 문제들로 가득찼고 제법 오래 일한 직원들과 이야기를 했다. 돌아온 답은 방목. 교육을 받지 못해서 직원들이 성장을 못했다는 이야기였다. 그리고 주된 문제점은 쉬운 문제들은 연차가 쌓인 사람들이 다 빨리 해버리고 나니 어려운 문제만 남아서 아무도 해결을 못한다는 이야기들이 많았다. 그래서 쉬운 이슈들을 처리하면서 배울 수 있도록 해야 한다는 솔루션이 나왔다. 그래? 그럼 그렇게 해볼까? 회사가 그렇게 배고픈 시절은 아니었기에 해볼만한 시점이기도 했다.&lt;/p&gt;
&lt;p&gt;쉬운 일감들이 할 수 있을만한 사람에게 스스로 배정되었고, 그들은 차곡차곡 문제를 해결하고 코드를 제출했다. 나는 빨간펜 선생님처럼 리뷰를 하고 머지를 했다. 당연한 소리겠지만 과정은 아름다웠지만 속도는 거의 그린란드 상어가 성장하는 속도만큼 느려졌다. 그래도 이 시기만 거친다면 직원들이 충분히 성장할거란 기대를 해보았다. 그렇게 제법 오랜 시간을 우리는 아주 느려터졌지만 개발 교과서에 나오는 우아한 방식으로 업무를 진행해 보았다. 결과는 당황스러웠다. 내가 봤을 때는 방목일때나 빨간펜일때나 성장의 속도와 범위는 비슷한것처럼 보였다. 더 안타까운 사실은 그 아름다운 시기를 함께 경험한 직원들 중 지금까지 근무하는 사람이 별로 없다는 사실이다.&lt;/p&gt;
&lt;p&gt;그렇게 오랜 시간을 지켜보고 이 방법 저 방법 해보고 내린 결론은 이렇다. 누가 성장했을까? 1) 회사 업무와 관련된 도메인에 관심이 있는 사람 2) 자기 동기부여가 되는 사람 3) 주도적으로 업무 처리가 가능한 사람 4) 열린 마인드를 가진 사람 5) 긍정적인 사고를 하는 사람들이 성장했다.&lt;/p&gt;
&lt;p&gt;우리는 게임 보안 회사다. 입사 후에 가장 많은 성장과 기여를 한 친구들을 보면 대체로 입사 전부터 게임 보안에 관심이 있거나 그런 쪽의 작업을 한 친구들이 많았다. 사전에 관심이 많았다는 이야기는 스스로 학습할 가능성이 높다는 것을 담보하기도 하고, 입사 시점부터 경력직과 비슷한 효과를 가지기도 한다. 역대 입사한 직원들을 모두 나열해놓고 기여도가 높은 순서대로 정렬을 해본다면 거의 이 순서와 동일한 순서가 나온다. 그러니 애초에 도메인에 관심이 있다는 건 그 사람이 입사 후 성장할 가능성이 높이다는 가장 강려크한 지표 중에 하나라 할 수 있겠다.&lt;/p&gt;
&lt;p&gt;칭찬은 고래도 춤추게 한다지만 현실은 그리 녹록치 않다. 회사란 공간은 칭찬은 인색하고, 평가는 냉혹하다. 이런 환경에서 버티기 위해서는 자기 동기부여가 되는 사람들이 유리하다. 우쭈쭈해줘야 뭔가 에너지를 받을 수 있는 사람들은 오래 버티기가 힘들다. 또한 계속 우쭈쭈하기도 힘들다. 칭찬은 고래도 춤추게 한다는 생각으로 그런 걸 남발하면 종국에는 고등학교 써클의 축제 출품작 같은 결과물을 마주하게 될 가능성이 농후하다. 그러니 스스로 동기부여가 되는 사람들을 찾는 것이 여러모로 유리하다.&lt;/p&gt;
&lt;p&gt;주인 의식을 가지자는 말도 꼰대의 대표적인 언어가 된 요즘이다. 하지만 안타깝게도 성장하는 직원들은 대체로 주도적인 업무 처리를 하는 경우가 많았다. 우리 회사에 남겨진 대부분의 좋은 유산들은 회사에서 어떤 어떤 업무를 강제로 시켜서 남겨진 것은 거의 없다. 실무자들이 업무를 진행하면서 본인이 불편을 느끼거나, 다른 사람들이 업무 진행하는 것을 보면서 답답한 마음에 만든 것들이 남겨진 경우가 대부분이다. 주도적인 업무 처리를 하지 않는 사람들은 대체로 시킨대로 하거나, 현재 상태에서 개선을 하려는 의지가 없기 때문에 성장 기회를 얻을 가능성이 제한적이다.&lt;/p&gt;
&lt;p&gt;요즘 개발자 면접을 보면 이런 말을 꼭한다. 우리 회사는 이것도 하고, 저것도 하고, 심지어 지금은 말은 안했지만 나중에는 이만저만한 업무도 해야 할 수 있다. 구직자들이 극혐한다는 풀스택 이야기다. 나는 그들을 혹사시키려고 이런 구질구질한 이야기를 하는 것은 아니다. 작은 회사라는 것이 언제 어떤 업무를 하게될지 모르기 때문에 애초에 이야기를 하는 것이다. 입사 후 성장한 친구들도 살펴보면 대체로 열린 마인들을 가진 친구들이 많았다. 나는 테스터니까 테스트만 하겠다 라든지, 나는 C++ 개발자니까 C++만 하겠다는 친구들은 그렇지 않은 친구들보다 성장 범위가 제한되는 경우가 많았다. 또한 개인적인 경험에서도 다양한 개발을 해보는 것이 도움이 됐다. 왜냐하면 다른 분야나 시스템에서 좋은 것들을 배우게되면 원래 알던 분야에도 적용할 수 있기 때문이다. 그리고 이제는 제법 유명한 이야기지만 깊이 파기 위해서는 애초에 넓게 파기 시작해야 한다. 물론 레이저는 예외다.&lt;/p&gt;
&lt;p&gt;끝으로 긍정적 사고다. 긍정의 배신과 같은 책들도 있지만 어쨌든 긍정적 사고는 본인 내부에 가진 에너지를 보다 오래 보존시키는데 중요한 역할을 한다. 보안이라는 업무를 오래 하다보면 현타가 오는 시점이 있게 마련이다. 매번 대응 한다고 해도 해킹툴은 쏟아지고, 고객들의 불만은 미어터지고, 지원팀의 압박은 거세다. 나에게 감사한 사람은 아무도 없는 것 같은 순간이 찾아온다. 사실 그런 일들은 입사 시점부터 있어 왔겠지만 현타가 오는 시점은 본인에게 있던 긍정성이 고갈되는 순간인 경우가 많았다. 성장은 고통을 수반하고, 고통의 과정을 이겨내기 위해서는 결국 긍정 에너지가 어느 정도 필요 조건이 아닐까 싶다.&lt;/p&gt;
&lt;p&gt;이제 방목과 교육을 다시 생각해본다. 도메인에 대한 관심, 자기 동기부여, 주도적 업무처리, 열린 마인드, 긍정적 사고와 같은 것들이 교육될 수 있는 것일까? 나는 그렇지 않다고 생각한다. 왜냐하면 이것들은 개인의 취향, 성격, 태도, 기질과 굉장히 밀접한 관련이 있는 것들이기 때문이다. 따라서 불행하게도 이런 종류의 것들은 입사 전부터 결정된 것들이고, 입사 후에도 변할 가능성은 별로 없다. 달리 말하면 어이없게도 성장할 사람은 입사 시점에 이미 거의 다 결정되어 있다는 말이다. 방목을 하든, 교육을 하든, 애자일을 하든, 코드리뷰를 하든, TDD를 하든, 세미나를 하든 하지 않든 말이다. 그 모든 것들을 하든지 하지 않든지 진짜 성장하는 사람은 그런 것들과는 상관이 없을 확률이 높다. 물론 애초에 좋은 기질을 가진 사람들에게 적절한 환경이 주어진다면 부스터가 될 수는 있을 것이다. 하지만 그 또한 미치는 영향력은 이러한 기질적 특성보다는 작은것처럼 보였다.&lt;/p&gt;
&lt;p&gt;결국 인사가 만사고 채용이 중요하다는 관점에서 이 사실을 역으로 적용하면 이렇다. 도메인에 관심이 있어 보이는 똑똑한 사람을 뽑는게 최선이다. 나머지 것들은 알아낼 수 있다면 좋겠지만 면접 과정에서 알아내기란 몹시 어려운 부분에 속한다. 반면에 수습 기간에는 알아낼 확률은 높아지겠지만 3년도 아닌 3개월로도 실상 알기가 어렵다. 어쨌든 면접 및 수습 과정을 통틀어 최대한 이 5가지 항목을 잘 관찰하는 것이 중요하다고 할 수 있겠다.&lt;/p&gt;
&lt;p&gt;개인의 관점에서 이 사실에서 한가지 교훈을 얻자면 똑같은 개발을 하더라도 관심있는 도메인이 어디인지는 한번쯤 생각해 보는게 도움이 된다는 점일 것이다. 평생 게임이라곤 한번도 안해본 사람이 게임 회사에 취직하는 것도, 주식은 도박이라고 생각하는 사람이 HTS 개발하는 업체에 취직하는 것도 고역일 것이고, 거기서 본인이 성장하기는 정말 어려울테니 말이다. 딜러, 힐러가 뭔지도 모르고, 이동평균선이 뭔지도 모르는 사람과 입사 전부터 딜힐 사이클과 각종 계산 방식 및 그것들이 가진 문제점에 대해서, 볼린져 밴드가 뭔지 P/E가 뭔지, 또 각종 지표의 문제점과 한계에 대해서 이미 모두 다 꿰고 있는 사람의 차이란 당신이 생각하는 것보다 클 수 있다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;노력은 해야겠지만 애쓰지 마. 될 일은 되고 안될 일은 안된다.&lt;br&gt;
— 시지프스 EP.06&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;당신의 채용에, 당신의 입사에 성장 열매가 가득 하기를…​&lt;br&gt;
건투를 빈다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 제갈량은 과연?]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2022/04/zhuge-liang/</link><guid isPermaLink="false">https://jiniya.net/ng/2022/04/zhuge-liang/</guid><pubDate>Fri, 15 Apr 2022 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;삼국지는 정말 흥미로운 책이다. 온갖 사람들이 등장해서 펼치는 활극도 대단하지만 그게 또 일부는 실화라는 점은 더 말문이 막히게 만든다. 그런 삼국지 인물 중에서도 최애하는 한명을 꼽으라면 단연 제갈량이다. 유비와 함께 가장 많은 사람들이 사랑하는 캐릭터가 아닐까 싶다.&lt;/p&gt;
&lt;p&gt;와이프 미모 빼고는 모든 걸 다 가졌다는 제갈량을 보면서 항상 궁금한게 있었다. 그렇게 똑똑하고 세상 이치를 잘 아는 그가, 왜 하필 유비를 따라 갔을까? 삼고초려해서? 결국 천하통일에 실패 했다는 관점에서 생각해 보자면, 1) 모르고 따라 갔다면 그의 수읽기가 부족한 것이고, 2) 어짜피 실패할 걸 알고 따라 갔다면 왜 따라간 것일까? 하는 의문들 가지지 않을 수 없다.&lt;/p&gt;
&lt;p&gt;그리고 또 한 장면, 출사표…​ 그는 줄기차게 출사표를 내고 사마의에 도전하지만 결국 하늘과 시간은 무심하게도 그를 버렸다. 1) 그는 질 걸 알면서도 줄기차게 출사표를 던지고 도전한 것일까? 2) 아니면 진심으로 이길 생각으로 나섰지만 패배한 것일까?&lt;/p&gt;
&lt;p&gt;자신의 사후 세계 전략까지도 지시할만큼 대단했던 그는 자기 운명을 알면서도 겁없이 도전한 것일까? 아니면 그냥 생각보다 멍청했던 것일까? 제갈량을 보면 항상 그런 스타크래프트 게임이 생각난다. 템플러 드랍해서 일꾼 테러하고, 리버 드랍해서 재미보고, 다크템플러로 씐나게 테러하고, 신은 있는대로 다 내고 재미있게 즐겼지만 결국 물량에 밀려서 패배하는 게임…​ 전 인생의 관점에서 바라본다면 과정이 재밌었던 프로토스가 이긴 게임일까? 꾸역꾸역 막고 버텨서 역전한 테란이 이긴 게임일까? 우리는 어떤 게임을 하고 있는 것일까?&lt;/p&gt;
&lt;p&gt;따뜻한 동남풍이 불어온다…​&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 21세기 게임 보안 프로그래머의 변천사]]></title><description><![CDATA[세상이 MS와 MS가 아닌 것들로 양분되던 시기에 개발을 시작했던 나는 참 편했다. MS가 워낙 독점적이었기에 MS가 아닌 것들은 사실 거들떠 볼 필요도 없던 시절이었다. 단지 MS것 내에서 이거냐 저거냐에 따라 차이가 있을 뿐. 그렇게 2…]]></description><link>https://jiniya.net/ng/2022/04/21st-game-security-programmer/</link><guid isPermaLink="false">https://jiniya.net/ng/2022/04/21st-game-security-programmer/</guid><pubDate>Thu, 14 Apr 2022 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;세상이 MS와 MS가 아닌 것들로 양분되던 시기에 개발을 시작했던 나는 참 편했다. MS가 워낙 독점적이었기에 MS가 아닌 것들은 사실 거들떠 볼 필요도 없던 시절이었다. 단지 MS것 내에서 이거냐 저거냐에 따라 차이가 있을 뿐. 그렇게 20년의 세월이 지난 요즘은 MS가 너무 초라해졌고 개발자는 넘나 피곤해졌다. 재미로 정리해보는 시대별 변천사…​&lt;/p&gt;
&lt;h3&gt;2002&lt;/h3&gt;
&lt;p&gt;windows 95/98만 없으면 세상 편해질 것 같았던 시절, VxD는 인간이 코딩하라고 만든 것일까?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;IsWindows9x()&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;2008&lt;/h3&gt;
&lt;p&gt;windows 2000에는 뭐가 이렇게 부족한게 많은 건지. 2000만 제거할 수 있다면 제품의 일관성을 유지하기가 한결 편할 것 같았던 시절.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;IsWindows2k()
IsWindows9x()&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;2015&lt;/h3&gt;
&lt;p&gt;어느덧 XP는 구시대의 유물이 되었고, 지원 안되는 기능은 너무나 많고, 심지어 시스템 고유 기능들 조차도 지원 안되는 것들이 많았던 시절. 슬슬 컴파일러들도 XP를 손절각을 보던 시기.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;IsWindowsXP()
IsWindows2k()&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;2016&lt;/h3&gt;
&lt;p&gt;64비트 운영체제가 일반화 되는 시기. 하지만 아직 대부분의 프로그램은 32비트. wow64처리가 안드로메다로 가는 시절. MS가 만든 에뮬레이팅 레이어를 벗어나기 위한 처절한 몸부림. 왜 이런게 생겼을까? 그냥 32/64만 있었으면 세상 편하겠구만…​&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;IsWow64()
IsWindowsXP()
IsWindows2k()&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;2017&lt;/h3&gt;
&lt;p&gt;누군가 wow64에 존재하는 천국의 문을 발견하면서 32비트 프로그램에서 64비트 코드를 직접 구동하는 것이 가능해진 시기. 진짜 64비트 시스템인지 판별하는 코드들이 삽입되고, 32비트 프로그램이 메모리 상에서 64비트 코드를 직접 실행하면서 32/64 포인터 변환 헬게이트가 열림.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;IsNative64()

IsWow64()
IsWindowsXP()&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;2020&lt;/h3&gt;
&lt;p&gt;wow64는 양반이었다. arm이라뉘. chpe는 또 무엇. 심지어 이건 당연한 소리겠지만 천국의 문 따윈 없다. 대중화되지 않았지만 실리콘 맥으로 대중화의 물꼬가 트일거 같은 느낌적인 느낌. 인텔만 있을때가 꿀이었던 것인가??&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;IsWindowsOnArm()

IsNative64()
IsWow64()
IsWindowsXP()&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;2022&lt;/h3&gt;
&lt;p&gt;윈도우만 있던 시절은 세상 편했다. 온갖 윈도우 포트 레이어 wine, proton, 네이티브 리눅스, 맥, 안드로이드, iOS가 난무하는 세상이란. 2022년의 게임 보안 개발자는 월요일은 온갖 윈도우 인텔/암/32/64/wow64/xp, 화요일은 리눅스와 각종 포트 레이어 linux/proton/wine, 수요일은 안드로이드, 목요일은 iOS/macOS를 개발해야 하는 세상이 돼 버렸다. 여기에 더 무서운 건 윈도우는 인사이더 빌드로 수시로 내부 구조체와 함수 구조를 바꾸고, 안드로이드와 iOS는 빼먹지 않고 매년 대규모 업데이트를 단행한다는 것…​&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;IsWine()
IsProton()
IsMacOS()
IsLinux()
IsAndroid()
IsiOS()

IsWindowsOnArm()
IsNative64()
IsWow64()
IsWindowsXP()&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;금요일은? 놀 순 없지. 어서와 LLVM은 처음이지…​ Xcode가 이렇게 자주 업데이트 되는 줄 몰랐어? LLVM 애플 버전은 업스트림에 반영하지 않는 거도 몰랐어? 그럼 지금부터 LLVM 지옥문을 맛보도록 하자.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;IsTripleAndroid()
IsTripleiOS()
IsTripleMacOS()&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;주말은? 새나라의 게임 보안 프로그래머라면 콘솔 개발해야지…​&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;IsXbox()
IsPS()
IsNSW()&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;20년간 우리가 버릴 수 있었던 if문은 IsWindows9x와 IsWindows2k 단 두 개 밖에 없었다. 새로 추가된 if문들을 보면 눈물이…​&lt;/p&gt;
&lt;p&gt;그럼에도 긍정적으로 바라보자면 우리에겐 github, slack, aws가 생겼다는거…​&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[시스템] 커널 모드 드라이버 삭제에 부쳐]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2022/04/delete-kernel-mode-driver-file/</link><guid isPermaLink="false">https://jiniya.net/ng/2022/04/delete-kernel-mode-driver-file/</guid><pubDate>Wed, 13 Apr 2022 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;최근에 드라이버 코드를 개발하면서 새로 들어온 개발자와 다소 의견 차이가 있었다. 내가 드라이버 파일이 삭제된 경우에는 어떻게 할거냐고 물었는데 그 친구는 계속 로드된 드라이버 파일이 삭제되지는 않는다는 이야기를 했다. 아니? 뭐지? 일반적으로 커널 모드 드라이버 파일은 로딩을 완료한 후에는 자유롭게 삭제가 된다. 특수한 처리 방식이 있는 게 아니고 아래와 같은 코드로 간단하게 구현할 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;LoadDriver(path);
DeleteFile(path);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그래서 혹시 그 친구가 테스트를 안해본게 아닌가 해서 이만저만하게 해서 테스트를 해보라고 했더니 테스트 했는데 삭제가 안된다고 한다. 아니? 그럴수가? 그래서 나도 테스트 해봤는데 삭제가 되지 않았다. 이 무슨 시츄레이션이지…​&lt;/p&gt;
&lt;p&gt;해서 Windows 7에서 테스트를 해봤다. 역시나 삭제가 잘됐다. &lt;del&gt;그래서 혹시나 해서 Windows 10 TH1에서 테스트를 해봤다. 역시나 삭제가 잘 됐다.&lt;/del&gt; TH1 이후 어딘가부터 윈도우 구조가 바뀌면서 드라이버 파일이 삭제가 되지 않도록 변경된 것으로 보였다.&lt;/p&gt;
&lt;p&gt;그 친구는 개발을 배울 당시가 해당 윈도우 버전이라 파일이 삭제된다는 걸 본적이 한번도 없었고, 나는 Windows XP부터 개발을 했던 사람이라 삭제가 안된다는 걸 최근에 테스트한 적이 없었던 것이다. 그래서 혹시나 해서 드라이버 개발을 전문적으로 하는 사람한테 물어봤더니 역시나 몰랐다. 고인물들이란 ㅎㅎ^^&lt;/p&gt;
&lt;p&gt;그럼에도 이 모든 걸 뚫고 최신 버전 윈도우에도 파일이 없는 드라이버가 상주한 것들이 몇 개 있었다. 당췌 얘들은 뭐지 해서 검색해봤더니 레이몬드 첸 아저씨가 2016년에 이미 다 알려준 내용들.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://devblogs.microsoft.com/oldnewthing/20160913-00/?p=94305&quot;&gt;https://devblogs.microsoft.com/oldnewthing/20160913-00/?p=94305&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;고인물들의 지식은 업데이트된지 너무 오래 되었고, 새로 배우는 친구들은 역사를 알기가 어렵다.
그와중에 MS 개발자들은 너무 열일하신다는거…​&lt;/p&gt;
&lt;p&gt;덧) windows 10 th1 부터 변경된 것으로 보여집니다. feat KINUX&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] strcpy_s에서 예외가 잡히지 않는 이유]]></title><description><![CDATA[어제 직원이 strcpy_s를 사용하면 예외가 잡히지 않는다며 코드를 보내왔다. 아래 코드다. 어떻게 컴파일하든 catch가 출력되는 것을 볼 수 없다. strcpy_s대신 strcpy…]]></description><link>https://jiniya.net/ng/2022/04/no-exception/</link><guid isPermaLink="false">https://jiniya.net/ng/2022/04/no-exception/</guid><pubDate>Tue, 12 Apr 2022 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;어제 직원이 strcpy_s를 사용하면 예외가 잡히지 않는다며 코드를 보내왔다. 아래 코드다. 어떻게 컴파일하든 catch가 출력되는 것을 볼 수 없다. strcpy_s대신 strcpy를 하면 잘 된다는 이야기.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;Windows.h&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    __try
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;strcpy_s&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;aaaa&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;__except&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EXCEPTION_EXECUTE_HANDLER&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;catch\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그래서 알아보기로 했다. 왜 예외가 잡히지 않는지를…​ strcpy_s는 다음과 같이 구현되어 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;C&quot;&lt;/span&gt; errno_t __cdecl &lt;span class=&quot;token function&quot;&gt;strcpy_s&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;       &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; destination&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    size_t      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; size_in_elements&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; source
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;common_tcscpy_s&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;destination&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_in_elements&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; source&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;common_tcscpy_s로 들어가보면 다음과 같다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// _strcpy_s() and _wcscpy_s()&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typename&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Character&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;_Success_&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; errno_t __cdecl &lt;span class=&quot;token function&quot;&gt;common_tcscpy_s&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;_Out_writes_z_&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;size_in_elements&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; Character&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; destination&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    _In_                                 size_t &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; size_in_elements&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    _In_z_                     Character &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; source
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;_VALIDATE_STRING&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;destination&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_in_elements&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;_VALIDATE_POINTER_RESET_STRING&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;source&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; destination&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_in_elements&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    Character&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;       destination_it &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; destination&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    Character &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; source_it      &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; source&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    size_t available &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; size_in_elements&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;destination_it&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;source_it&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;available &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;available &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;_RESET_STRING&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;destination&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_in_elements&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;_RETURN_BUFFER_TOO_SMALL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;destination&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_in_elements&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;_FILL_STRING&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;destination&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_in_elements&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_in_elements &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; available &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    _RETURN_NO_ERROR&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;_VALIDATE_STRING 매크로에서 destination이 NULL인 경우 체크가 들어간다는 것을 알 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* validations */&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name function&quot;&gt;_VALIDATE_STRING_ERROR&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _Size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _Ret&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token function&quot;&gt;_VALIDATE_RETURN&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_Size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; EINVAL&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_Ret&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name function&quot;&gt;_VALIDATE_STRING&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_String&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _Size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token function&quot;&gt;_VALIDATE_STRING_ERROR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_String&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_Size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; EINVAL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

_VALIDATE_RETURN 매크로는 _INVALID_PARAMETER 호출로 이어진다&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name function&quot;&gt;_VALIDATE_RETURN&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; errorcode&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; retexpr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                             &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;                                                                          &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; _Expr_val &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;                                              &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token function&quot;&gt;_ASSERT_EXPR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_Expr_val&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_CRT_WIDE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;#expr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;                           &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_Expr_val&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                                                      &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;                                                                      &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
            &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_errno&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;errorcode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;                                           &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
            &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token function&quot;&gt;_INVALID_PARAMETER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_CRT_WIDE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;#expr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;                              &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
            &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;retexpr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;                                                  &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;                                                                      &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;
    &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;_INVALID_PARAMETER는 릴리즈 버전에서 _invalid_parameter_noinfo 호출로 이어진다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;_DEBUG&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name function&quot;&gt;_INVALID_PARAMETER&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_invalid_parameter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; __FUNCTIONW__&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; __FILEW__&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;__LINE__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name function&quot;&gt;_INVALID_PARAMETER&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_invalid_parameter_noinfo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;_invalid_parameter_noinfo는 최종적으로 _invalid_parameter_internal 호출로 이어진다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;C&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; __cdecl &lt;span class=&quot;token function&quot;&gt;_invalid_parameter_noinfo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;_invalid_parameter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;nullptr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;nullptr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;nullptr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;C&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; __cdecl &lt;span class=&quot;token function&quot;&gt;_invalid_parameter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;wchar_t&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; expression&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;wchar_t&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; function_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;wchar_t&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; file_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;   &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; line_number&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    uintptr_t      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; reserved
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    __crt_cached_ptd_host ptd&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_invalid_parameter_internal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expression&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; function_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; file_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; line_number&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reserved&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ptd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;_invalid_parameter_internal을 살펴보면 다음과 같다. _thread_local_iph 핸들러가 있는 경우 해당 핸들러를, 없는 경우 글로벌 핸들러를, 그마저도 없는 경우에는 _invoke_watson으로 이어진다. 일반적으로 핸들러 설정이 되어 있지 않기 때문에 _invoke_watson 호출로 진행된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;C&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; __cdecl &lt;span class=&quot;token function&quot;&gt;_invalid_parameter_internal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;wchar_t&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;     &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; expression&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;wchar_t&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;     &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; function_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;wchar_t&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;     &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; file_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;       &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; line_number&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    uintptr_t          &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; reserved&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    __crt_cached_ptd_host&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;   ptd
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    __acrt_ptd &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; raw_ptd &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ptd&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get_raw_ptd_noexit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;raw_ptd &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; raw_ptd&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;_thread_local_iph&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        raw_ptd&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_thread_local_iph&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expression&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; function_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; file_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; line_number&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reserved&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    _invalid_parameter_handler &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; global_handler &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__crt_fast_decode_pointer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__acrt_invalid_parameter_handler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ptd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;global_handler&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;global_handler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expression&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; function_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; file_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; line_number&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reserved&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;_invoke_watson&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expression&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; function_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; file_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; line_number&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reserved&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; null 인경우 이쪽으로 도달
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;_invoke_watson은 다음과 같이 구현되어 있다. 일반적으로 PF_FASTFAIL_AVAILABLE 플래그가 설정되어 있어서 __fastfail 호출로 이어진다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;C&quot;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__declspec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;noreturn&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; __cdecl &lt;span class=&quot;token function&quot;&gt;_invoke_watson&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;wchar_t&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; expression&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;wchar_t&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; function_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;wchar_t&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; file_name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;   &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; line_number&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
	uintptr_t      &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; reserved
	&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;UNREFERENCED_PARAMETER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;expression   &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;UNREFERENCED_PARAMETER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;function_name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;UNREFERENCED_PARAMETER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;file_name    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;UNREFERENCED_PARAMETER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;line_number  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;UNREFERENCED_PARAMETER&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reserved     &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;IsProcessorFeaturePresent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PF_FASTFAIL_AVAILABLE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;__fastfail&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;FAST_FAIL_INVALID_ARG&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;// Otherwise, raise a fast-fail exception and termintae the process:&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;__acrt_call_reportfault&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
		_CRT_DEBUGGER_INVALIDPARAMETER&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		STATUS_INVALID_CRUNTIME_PARAMETER&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
		EXCEPTION_NONCONTINUABLE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;TerminateProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetCurrentProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; STATUS_INVALID_CRUNTIME_PARAMETER&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;__fastfail은 아래 문서를 참고하면 int 0x29로 구현된 컴파일러 함수다.&lt;br&gt;
&lt;a href=&quot;https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail?view=msvc-170&quot;&gt;https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail?view=msvc-170&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;결국 strcpy_s는 최종적으로 int 0x29로 이어진다. fastfail이란 말에서 알 수 있듯이 해당 인터럽트는 예외에 잡히지 않는다. 결국 strcpy_s 내부적으로 널체크를 해서 특수한 처리를 했기 때문에 예외에 잡히지 않는다. strcpy_s((char*)0x123, 10, &quot;aaaa&quot;); 등과 같이 호출하면 정상적으로 예외 처리가 이루어진다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    __try
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;asm&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x29&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;__except&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EXCEPTION_EXECUTE_HANDLER&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;catch\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;strcpy_s 입장에서는 NULL이면 프로그램을 종료시켜버리는 게 안전한 구현일 수 있다. 하지만 경우에 따라서는 오바하는 함수가 될수도 있겠다. 내가 알아서 할건데 왜 고작 문자열 복사하는 기능만 하면 될 함수가 릴리즈 버전에서 널체크까지 해가며 멋대로 강종시키지? 프로그램을? 예외처리도 안되게?&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[리뷰] 미드나잇 라이브러리]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/2022/midnight-library/</link><guid isPermaLink="false">https://jiniya.net/2022/midnight-library/</guid><pubDate>Sat, 29 Jan 2022 13:00:01 GMT</pubDate><content:encoded>&lt;h3&gt;저자&lt;/h3&gt;
&lt;p&gt;매트 헤이그, 영국 소설가. 우울증과 불안 장애로 자살 시도를 하고 극복한 경험이 있음. 그래서 관련된 내용에 관한 저술이 많아 보인다. 미드나잇 라이브러리도 그런 연장선상의 책이다.&lt;/p&gt;
&lt;h3&gt;줄거리&lt;/h3&gt;
&lt;p&gt;주인공 노라는 되는 일이 없다. 재능은 많았지만 많은 것들을 포기했다. 게다가 우울증과 불안장애 증상까지 있다. 키우던 고양이가 죽고, 직장을 잃으며 삶의 나락으로 몰린 주인공은 자살 시도를 한다. 그리고 자살 시도 과정에서 삶과 죽음의 중간 단계에 있는 미드나잇 라이브러리에 간다.&lt;/p&gt;
&lt;p&gt;미드나잇 라이브러리에서는 노라가 사는 동안 후회했던 것들을 바꾼 다양한 삶을 경험해 보게 된다. 그 경험한 삶이 마음에 든다면 그곳에서 살아도 되고, 마음에 들지 않는다면 다시 라이브러리로 돌아올 수 있다. 노라는 올림픽 메달리스트가 되기도 하고, 성공한 록밴드 작곡가 겸 보컬이 되기도 하고, 빙하학자가 되기도 한다.&lt;/p&gt;
&lt;p&gt;이런 온갖 다양한 삶을 경험하면서 역설적이게도 노라는 삶의 이유를 깨닫는다 그리고 다시 원래의 삶으로 돌아오고 거기서 아직 쓰지 못한 자신의 인생 이야기를 계속 써내려 간다.&lt;/p&gt;
&lt;h3&gt;인상 깊은 구절&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;모든 게 달라진 이유는 이젠 그녀가 단지 다른 사람의 꿈을 이뤄주기 위해 존재하지 않기 때문이었다. 상상 속 완벽한 딸이나 동생, 애인, 아내, 엄마, 직원, 혹은 무언가가 되는 데서 유일한 성취감을 찾아야 한다고 생각하지 않기 때문이었다. 이제는 그저 한 인간으로서 자신의 목표만 생각하며 자신만 책임지면 그만이었다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;노라는 자신이 블랙홀이 아니라는 결론을 내렸다. 그녀는 화산이었다. 그리고 화산처럼 그녀는 자신에게서 달아날 수 없었다. 거기 남아서 그 황무지를 돌봐야 했다.&lt;br&gt;
역설적이게도 화산은 파괴의 상징인 동시에 생명의 상징이다. 용암이 흘러내리는 속도가 느려지고 열이 식으면, 용암은 응고되었다가 시간이 흐르면서 부서져 흙이 된다. 비옥하고 영양가가 풍부한 토양이 된다.&lt;br&gt;
자기 자신 안에 숲을 가꿀 수 있었다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;“이번 판은 선생님이 이기겠는데요.” 노라가 말했다.&lt;br&gt;
엘름 부인의 눈동자가 갑자기 생기를 띠며 반짝거렸다. “그게 체스의 미덕 아니니? 어떻게 끝날지 모른다는 거.”&lt;br&gt;
노라는 아직 체스판에 남아 있는 자신의 기물을 내려다보며 미소 짓고, 다음 수를 어떻게 둘지 생각했다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;노라는 다이아몬드에 대한 닐의 잘못된 지식을 바로잡아주지 않았다. 석탄과 다이아몬드는 둘 다 탄소이기는 해도 석탄은 불순물이 너무 많이 섞여서 아무리 압력을 가해도 다이아몬드가 될 수 없다. 광물학에 따르면 한 번 석탄은 영원한 석탄이다. 어쩌면 그게 현실적인 교훈일 것이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;그녀가 둔 모든 수는 실수였고, 모든 결정은 재앙이었으며, 매일 자신이 상상했던 모습에서 한 걸음씩 멀어졌다.&lt;br&gt;
수영 선수. 뮤지션. 철학가. 배우자. 여행가. 빙하학자. 행복하고 사랑받는 사람.&lt;br&gt;
그중 어느 것도 되지 못했다.&lt;br&gt;
심지어 ‘고양이 주인’이라는 역할조차 제대로 해내지 못했다. 혹은 ‘일주일에 한 시간짜리 피아노 레슨 선생님’도. 혹은 ‘대화가 가능한 인간’도.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;난 올림픽에 출전하지 못했어. 빙하학자가 되지 못했어. 댄의 아내가 되지 못했어. 엄마가 되지 못했어. 라비린스의 리드 보컬도 되지 못했어. 정말로 좋은 사람 혹은 행복한 사람이 되지 못했어. 볼테르도 제대로 보살피지 못했어.&lt;br&gt;
그리고 이제 마지막으로 제대로 죽지도 못했다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;“모든 삶에는 수백만 개의 결정이 수반된단다. 중요한 결정도 있고, 사소한 결정도 있지. 하지만 둘 중 하나를 선택할 때마다 결과는 달라져. 되돌릴 수 없는 변화가 생기고 이는 더 많은 변화로 이어지지. 이 책들은 네가 살았을 수도 있는 모든 삶으로 들어가는 입구야.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;“걱정 마라. 화장지는 인생과 같아. 늘 더 있는 법이야.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;댄에게는 장점이 훨씬 많았다. 아픈 노라의 엄마에게 극진히 대했고, 어떤 주제에 관해서든 편안히 이야기할 수 있었고, 미래에 대한 꿈으로 가득 찼으며, 매력적이고 함께 있으면 편안했다. 또한 예술을 열렬히 사랑했고, 길에서 노숙자를 보면 늘 걸음을 멈추고 얘기를 나눴다. 세상에 관심을 가졌다. 사람은 도시와 같아서 마음에 덜 드는 부분이 몇 개 있다고 해서 전체를 거부할 순 없다. 위험해 보이는 골목길이나 교외 등 마음에 안 드는 부분이 있을지라도 다른 장점이 그 도시를 가치 있게 만들어준다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;“왜냐하면 노라, 때로는 살아봐야만 배울 수 있으니까.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;읽은 후&lt;/h3&gt;
&lt;p&gt;읽기는 굉장히 편한 책이다. 서사 구조가 복잡하지 않고 단조롭고 교훈적이다. 그리고 한 100페이지쯤 읽으면 책 내용이 어떻게 전개될지는 대충 예측이 된다. 심지어 마지막에 현재 삶을 의미하는 책을 찾겠다는 것까지.&lt;/p&gt;
&lt;p&gt;다만 소설적인 재미를 떠나 소설이 제공하려는 교훈을 끌어내는 측면에서 바라보자면 너무 급진적인 측면이 있는 건 아닌가라는 생각이 든다. 많은 인생을 경험하고 후회를 되돌려본 인생이 자기 생각과 달랐다는 측면이 있었다는 것까지는 이해가 된다. 하지만 그런 다양한 인생 경험을 토대로 블랙홀로 생각했던 내 인생이 화산이었다고 바라보는 시각을 변경하는 과정은 개연성이 충분한가 라는 생각이 든다.&lt;/p&gt;
&lt;p&gt;살아봐야만 배울 수 있는 것들이 있다. 또 아직 끝나지 않았다면 인생은 끝날 때까지 어떤 게임이 될지는 알 수 없다. 어떤 게임이 되었든 그것도 멋진 한 판의 바둑이었을 것이다. 다만 현실적인 생각을 조금 해보자면 게임이 진행될수록 경우의 수는 급격히 줄어든다는 점이다. 바둑판에 돌이 많이 있을 수록 경우의 수는 점점더 제한된다. 체스판의 기물이 줄어들수록 경우의 수 또한 급격하게 줄어든다. 그래서 시작은 무한한 가능성을 가진 한판의 게임이 펼쳐질 가능성이 있겠지만 중반을 넘어서면 사실상 경기의 궤도는 어느 정도 정해진 경우가 대다수다. 따라서 끝날 때까지 끝난 건 아니고, 어떤 게임이 될지 알 수 없다는 말처럼 희망이 있을 수 있겠지만 현실적으로는 게임이 진행될 수록 삶이 진행될수록 선택할 수 있는 선택지와 그 선택으로 벌어질 수 있는 희망의 가능성은 줄어든다.&lt;/p&gt;
&lt;p&gt;저자와 달리 나는 시뮬레이션 우주론과 결정론적 세계관을 가지고 있고, 자유의지는 없다고 믿는 편이다. 그런 나에겐 테드 창의 조언이 조금 더 현실적이란 생각이 많이 들었다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;자유의지가 있는 것처럼 행동하라. 설령 사실이 아님을 알고 있어도, 스스로 내리는 선택에 의미가 있는 듯이 행동하는 것이 가장 중요하다. 무엇이 현실인지는 중요하지 않다. 정말로 중요한 것은 당신이 무엇을 믿느냐이며, 이 거짓말을 믿는 것이야말로 깨어 있는 혼수상태에 빠지는 것을 피할 수 있는 유일한 방법이다. 문명의 존속은 이제 자기기만에 달려 있다. 어쩌면 줄곧 그래 왔는지도 모른다.&lt;br&gt;
&lt;br&gt;
-- 숨(우리가 해야 할 일) | 테드 창&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이책과 비슷한 내용으로 훨씬 극적으로 삶의 의지를 불태우게 해주는 컨텐츠로 K드라마 “나의 아저씨”를 추천하고 싶다. 어쩌면 복잡한 내용을 떠나서 우리 모두가 듣고 싶은 이야기는 결국 이 한 마디가 아닐까. 괜.찮.아...&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[리뷰] 호모 데우스]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/2022/homo-deus/</link><guid isPermaLink="false">https://jiniya.net/2022/homo-deus/</guid><pubDate>Tue, 25 Jan 2022 13:00:01 GMT</pubDate><content:encoded>&lt;h3&gt;간단한 소개, 동기, 저자에 관하여&lt;/h3&gt;
&lt;p&gt;유발 하라리는 사피엔스라는 책으로 일약 스타덤에 오른 역사학자다. 사피엔스는 호모 사피엔스가 어떻게 다른 호모 종들을 제치고 이 세상을 지배하는 종이 되었는지에 대한 그의 충걱적인 가설 및 서사를 들려주는 책이다. 아마도 그의 가설과 서사가 굉장히 그럴듯하고 충격적이었기에 많은 사람들의 공감과 관심을 받지 않았을까 싶다.&lt;/p&gt;
&lt;p&gt;호모 데우스는 그런 그가 호모 사피엔스의 다음 단계, 즉 앞으로 펼쳐질 미래 세상에 대한 이야기를 하는 책이다. 흔히들 미래를 알기 위해서는 과거를 알아야 한다는 말을 한다. 과거를 충실히 연구했고 호모 종이 지배종이 될 수 있었던 충격적인 서사를 들려준 그가 바라보는 미래는 어떤지 궁금해서 이 책을 선택하게 되었다.&lt;/p&gt;
&lt;h3&gt;인상 깊은 내용&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;오늘날 정설에 따르면 유기체는 알고리즘이고, 알고리즘은 수학 공식으로 표현할 수 있다. 자판기가 차 한 잔을 만들기 위해 밟는 일련의 단계들 그리고 우리의 뇌가 사자의 접근에 촉각을 곤두세울 때 밟는 일련의 단계들을 우리는 숫자와 수학 기호를 사용해 적을 수 있다. 그렇다면, 그리고 의식적 경험들이 어떤 중요한 기능을 한다면, 그 경험들 역시 수학적으로 표현할 수 있어야 한다. 왜냐하면 경험은 알고리즘의 필수적 부분이기 때문이다. ‘두려움 알고리즘’을 적고 ‘두려움’을 일련의 정확한 계산식으로 쪼개면 이렇게 말할 수 있다. ‘계산 과정의 93단계, 바로 이곳이 두려움이라는 주관적 경험이 개입하는 곳이다!’ 하지만 수학이라는 거대한 영역에 주관적 경험을 포함하는 알고리즘이 존재할까? 우리가 알기로 그런 알고리즘은 없다. 수학과 컴퓨터 과학 분야의 방대한 지식을 총동원해봐도, 우리가 창조한 데이터 처리 장치 가운데 그 어떤 것도 작동을 위해 주관적 경험이 필요한 것은 없고, 그 어떤 것도 고통, 쾌락, 분노, 사랑을 느끼지 않는다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;유기체가 알고리즘이고 주관적 경험은 실질적으로 필요 없다는 그의 주장은 파격적으로 들린다. 하지만 많은 최신 연구에 따르면 자유의지가 없다는 진영이 승리하는 것은 맞는 것처럼 보여지고 있다. 우리는 어떤 선택을 의식하기 전에 뇌는 이미 결정을 끝냈으며, 의식은 마치 그 끝낸 결정에 대한 그럴듯한 보충 설명을 해주는 것에 지나지 않는다고 한다. 또한 현재까지는 의식의 존재 자체가 미스테리이긴 하지만 인공지능 기술이 발전하면서 일정 수준의 복잡도를 넘어서는 순간 인공지능에서도 의식이 발현될 것으로 예측하고 있다. 어쨌든 유기체는 알고리즘이라는 정설을 받아들이는 순간 나는 무엇인가라는 생각이 저절로 따라오게 된다. MMORPG 게임 존재하는 NPC와 내가 다를 게 무엇일까?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;그러면 구글은 이렇게 대답할 것이다. &quot;나는 네가 태어난 날부터 너를 알고 있었어. 네 이메일을 모두 읽었고, 네 통화를 모두 기록했고, 네가 좋아하는 영화들, 네 유전자 정보, 네 심장 기록도 모두 갖고 있어. 네가 데이트한 정확한 날짜도 보관하고 있으니, 존이나 폴과 만날 때마다 네 심장박동, 혈압, 혈당수치를 초 단위로 기록한 그래프를 원한다면 보여줄 수 있어. 필요하다면 네가 그들과 가진 모든 성관계의 정확한 순위도 제공할 수 있어. 그리고 당연히 나는 너를 아는 것만큼 그들도 잘 알아. 이 모든 정보, 내 뛰어난 알고리즘, 수많은 관계에 대한 수십 년에 걸친 통계자료를 토대로, 나는 너에게 존을 선택하라고 권해. 장기적으로 그와 함께할 때 더 만족스러울 확률이 87퍼센트야.&quot;&lt;br&gt;
&lt;br&gt;
&quot;나는 너를 잘 아는데, 너는 이 답변이 마음에 들지 않을 거야. 존보다 폴이 훨씬 더 잘생겼지. 너는 외모를 중시하니까, 내가 &apos;폴&apos;이라고 말해주기를 내심 바랐을 거야. 물론 외모는 중요하지. 하지만 네가 생각하는 것만큼은 아니야. 수만 년 전 아프리카 사바나에서 진화한 네 생화학적 알고리즘은 배우자감을 전반적으로 평가할 때 외모에 두는 비중이 35퍼센트야. 하지만 최신 연구와 통계를 바탕으로 하는 내 알고리즘은 외모가 사랑하는 관계에 장기적으로 미치는 영향은 14퍼센트에 불과하다고 말해. 그러니 폴의 외모를 고려한다 해도 네가 존과 함께하는 게 더 낫다고 생각해.&quot;&lt;br&gt;
&lt;br&gt;
이런 충실한 상담 서비스를 받는 대가로 우리가 포기해야 하는 것은 인간은 분할할 수 없는 존재이며 각 개인은 무엇이 선이고 무엇이 아름다움이고 무엇이 인생의 의미인지 결정할 자유의지를 갖고 있다는 개념뿐이다. 인간은 더 이상 이야기하는 자아가 꾸며내는 이야기들의 지시를 따르는 자율적 실체들이 아니라, 거대한 전 지구적 네트워크의 필수불가결한 일부가 될 것이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;미래 세계에 대한 그의 묘사 중 일부지만 내용이 다소 충격적인 것과 동시에 몇년 내에 저런 세상이 올지도 모른다는 생각에 굉장히 인상 깊었다. 구글 나우라는 기술은 지금도 켜두기만 하면 내가 자료를 입력하지 않아도 내 회사가 어디있고, 집이 어디있으며, 내가 수요일 저녁 시간에 어떤 공간에 있을 확률이 높고, 내가 좋아하는 음악이 무엇인지 등을 알려준다. 유발 하라리가 전개한 것과 같은 기술은 어쩌면 우리가 개인 정보 동의를 하는 순간부터 계속 진행되고 있는지도 모른다.&lt;/p&gt;
&lt;p&gt;과연 저런 세상이 펼쳐졌을때 우리는 인공지능의 선택에 저항할 수 있을까? 내 생각은 쉽지 않다는 생각이다. 왜냐하면 지금도 사람들은 초행길을 갈 때에 아무 생각없이 네비게이션이 우회전을 하라면 믿고 우회전을 하기 때문이다. 심지어 초행길이 아닌 길도 우회전을 하라고 하면 이 길이 더 빨라서 그런가? 하고는 생각없이 우회전을 한다. 주차를 할 때에도 본인의 느낌보다는 센서의 삑삑 소리에 더 의존하고 있다. 이런 세상은 가속화 될 것이고 우리는 점점 더 자유의지가 없는 것 같은 존재가 될지도 모른다. 그 시대가 된다면 과연 나란 무엇인지? 우리의 자유의지가 존재하긴 하는 것인지? 인공지능이 모든 선택을 대체한다면 삶의 의미는 무엇인지가 궁금해지는 대목이다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;코타나가 신탁에서 대리인으로 진화하면 주인들 대신 자기들끼리 직접 이야기하기 시작할 것이다. 처음에는 내 코타나가 당신의 코타나에게 연락해 약속 장소와 시간을 잡는 것과 같은 단순한 일로 시작할 것이다. 하지만 어느 순간 정신을 차리고 보면, 내가 입사 지원한 회사의 인사팀장이 나에게 이력서를 보낼 필요 없이 자신의 코타나가 내 코타나를 면접 볼 수 있도록 해달라고 말한다. 또는 나에게 관심 있는 이성의 코타나가 내 코타나에게 접근해 서로 정보를 교환하며 두 사람이 좋은 짝인지 결정한다. 물론 이 모든 일은 그들의 주인들이 전혀 모르는 상태에서 이루어질 것이다.&lt;br&gt;
&lt;br&gt;
코타나가 권한을 얻으면 주인의 이익을 위해 상대의 코타나를 교묘히 조종하기 시작할 것이고, 그 결과 직업시장 또는 결혼시장에서의 성공이 점점 더 코타나의 자질에 따라 판가름날 것이다. 그래서 최신 버전의 코타나를 소유한 부자들은 구버전을 소유한 가난한 사람들보다 결정적 우위를 점할 것이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;장자의 호접지몽 이야기가 생각나는 대목이다. 나비 꿈을 꾸고 깨어보니 지금이 현실인지, 나비가 꾸는 꿈인지 구분이 되지 않는다는 이야기. 코타나가 대리인이 되는 순간 코타나가 나인지, 내가 코타나인지 구분할 수 있을까? 모든 선택과 결정을 코타나가 한다면 과연 그가 나의 인공지능 비서일까? 내가 그의 아바타일까?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;자유주의가 직면한 세 번째 위협은, 일부 사람들은 업그레이드되어 필수불가결한 동시에 해독 불가능한 존재로 남아 소규모 특권집단을 이룰 거라는 점이다. 이런 초인간들은 전대미문의 능력과 전례 없는 창의성을 지닐 것이고, 그런 힘을 이용해 세계적으로 중요한 대다수의 결정들을 계속 내릴 수 있을 것이다. 그들은 시스템의 유지보수를 담당할 것이고, 시스템은 그런 사람들을 이해하고 관리할 수 없을 것이다. 그러나 대부분의 사람들은 업그레이드되지 않을 것이고, 그 결과 컴퓨터 알고리즘과 새로운 초인간 양쪽의 지배를 받는 열등한 계급이 될 것이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;인간은 항상 계층을 나눠왔다. 누가 힘이 센지와 같은 유전자에 의해서 나누다가, 누구의 아들 딸인지 같은 출신 성분에 의해서 나누다가, 누가 시험을 통과했는지와 같이 능력에 의해서 나누다가, 누가 자본을 더 가졌는지와 같이 돈에 의해서 나누는 등. 문명이 시작된 이후 인간이 실질적으로 평등했던 순간은 없었다는 생각이다. 그의 예측대로라면 그렇다면 앞으로는 시스템을 이해하고 설계할 수 있는 계층과 그렇지 않은 계층으로 나뉘게될까?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;첫째, 의학은 중대한 개념적 혁명을 겪고 있는 중이다. 20세기에 의학의 목표는 병에 걸린 사람을 치료하는 것이었다. 하지만 21세기에 의학의 목표는 건강한 사람의 성능을 높이는 쪽(업그레이드)으로 가고 있다. 병든 사람을 치료하는 것은 평등주의적 목표였다. 왜냐하면 모두가 누릴 수 있고 누려야 하는 육체적ㆍ정신적 건강의 표준이 존재한다는 전제에서 출발했기 때문이다. 만약 어떤 사람이 그 표준 밑으로 떨어지면, 문제를 고쳐서 그 사람이 ‘다른 모든 사람들과 같아지게’ 만드는 것이 의사의 본분이었다. 반면 건강한 사람을 업그레이드하는 것은 엘리트주의적 목표이다. 모두에게 적용되는 보편적 표준이라는 개념을 거부하고, 일부 개인들에게 우위를 제공하려는 일이기 때문이다. 사람들은 뛰어난 기억력, 평균 이상의 지능, 최고의 성적 능력을 원한다. 만일 어떤 형태의 업그레이드가 저렴하고 흔해져서 누구나 접근할 수 있는 것이 된다면, 그것이 새로운 기준점이 되어 그것을 능가하는 차세대 치료법이 개발될 것이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;유전자 가위 기술은 상당히 발전해 있다. 인공지능을 통한 업그레이드가 되지 않더라도 우리가 유전자 코드를 해독하면 할수록 더 뛰어난 유전자 코드를 스스로 만들어 내는 길을 선택할지도 모른다.&lt;/p&gt;
&lt;h3&gt;읽은 후...&lt;/h3&gt;
&lt;p&gt;흔히들 미래를 인공지능, 사이보그의 세상이 될 것이라 얘기한다. 그리고 마치 그 세상은 모든 인류가 공통으로 그 혜택을 누리는 판타지 같은 세상일 것이라 얘기한다. 하지만 유발 하라리가 예측한 세상은 그렇지 않았다.&lt;/p&gt;
&lt;p&gt;전체적으로 그는 1) 유기체로써의 인간의 진화는 지금이 끝이다. 2) 그 이후 단계는 인공지능과, 사이보그 기술을 이용해 일부 인간들이 초인간으로 업그레이드 될 것이다. 3) 그 초인간들의 업그레이드가 완료되면 기존의 인간들은 더이상 쓸모 없는 잉여 인간이 될 것이다. 4) 그 초인간들 조차도 상당수가 인공지능의 도움으로 스스로 결정할 것이 없는 세상이 될 것이다. 5) 유기체로써의 모든 부분이 제거되고 나면 우주로 나갈 수 있는 진정한 초인간의 시대가 열린다고 말한다.&lt;/p&gt;
&lt;p&gt;디스토피아적 미래지만 상당히 그럴듯한 전개라고 생각한다. 엘론 머스크는 벌써 뉴럴 링크를 통해서 뇌에 인공지능 칩을 심는 실험을 하고 있다. 아마 그 실험이 성공적으로 끝난다면 우리는 머지 않아서 영어 기능을 제공하는 칩을 몇 백 달러에 사게 될지도 모른다. 그리고 각종 기능들이 칩으로 제공될 것이고 그것은 점점 더 그 칩을 가진 사람들과 못 가진 사람들의 격차를 벌리게 될 것이다. 이렇게 초인간과 불필요한 인간으로 나뉘는 세상이 오게 된다면 우리는 어떻게 대처해야 할까? 아직 그런 세상이 오지 않았고 내가 사는 기간 동안에는 안전할 것 같으니 괜찮은 것일까? 아니면 어떻게든 아등바등 그 초인간의 무리에 끼기 위해서 달려야 하는 것일까?&lt;/p&gt;
&lt;p&gt;미래에 대한 선명한 지도같은 책이었지만 역설적이게도 이 책은 나에게 엄청난 질문 덩어리만 안겨준 책이었다. 그리고 그 중간에는 사람, 인간이 있었다. 과연 그 수많은 잉여 인간의 존재 가치는 무엇이 될까?&lt;/p&gt;
&lt;h3&gt;당신의 생각은?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;유기체로써의 진화가 지금이 끝일지와 이유. 유전자 가위 vs 사이보그&lt;/li&gt;
&lt;li&gt;초인간으로 진화되어 인간이 두 부류로 나뉘게될지와 이유.&lt;/li&gt;
&lt;li&gt;저자의 생각대로 인간이 자체적으로 업그레이드해서 초인간이 된다고 했을 때 잉여 인간은 생존할까? 또 존재 가치는?&lt;/li&gt;
&lt;li&gt;텍스트에 나온 존과 폴 중 인공지능의 선택대로 존을 선택할까? 아니면 마음이 끌리는 잘생긴 폴을 선택할까?&lt;/li&gt;
&lt;li&gt;인공지능이 복잡한 의사 결정의 상당수를 대체한다고 했을때 인간의 존재가치는? 그리고 지금 현재 상태에서 자유의지가 있다고 믿는지? 아닌지? 그 이유는?&lt;/li&gt;
&lt;li&gt;대체로 이런 이야기 끝에 불멸의 존재가 되기 위해 전뇌화, 또는 마인드 업로딩으로 불리는 뇌를 네트워크에 업로드 하는 이야기가 나온다. 만약 본인이 그런 업로드를 통해 영생을 누릴 수 있다면 업로드 할지 말지와 그 이유.&lt;/li&gt;
&lt;li&gt;미래 방향 예측의 큰 갈래가 인간이 우주로 확장할 것이다와 메타버스 세계로 확장할 것이다로 나뉜다. 둘중 어떤 세상으로 확장할 가능성이 크다고 생각하는지와 그 이유.&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[[cpp] 버퍼로써 vector가 적합하지 않은 이유]]></title><description><![CDATA[C언어에서 동적 버퍼를 사용하던 코드를 C++로 포팅할 때 흔히 vector를 사용한다. 가장 편리하기 때문이다. 하지만 반복적으로 호출되는 코드일 경우 의외로 해당 코드 때문에 부하가 발생할 수 있다. 왜 그런지 살펴보고 더 적합한 C…]]></description><link>https://jiniya.net/2022/the-reasons-why-a-vector-is-unsuitable-for-use-as-a-buffer/</link><guid isPermaLink="false">https://jiniya.net/2022/the-reasons-why-a-vector-is-unsuitable-for-use-as-a-buffer/</guid><pubDate>Tue, 25 Jan 2022 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;C언어에서 동적 버퍼를 사용하던 코드를 C++로 포팅할 때 흔히 vector를 사용한다. 가장 편리하기 때문이다. 하지만 반복적으로 호출되는 코드일 경우 의외로 해당 코드 때문에 부하가 발생할 수 있다. 왜 그런지 살펴보고 더 적합한 C++ 객체가 없는지도 알아보자.&lt;/p&gt;
&lt;h2&gt;고정 버퍼&lt;/h2&gt;
&lt;p&gt;dir에 name을 붙여서 파일을 생성하는 흔한 C언어 코드다. 흔히들 이렇게 작성하기도 한다. 하지만 MAX_PATH가 왠지 걸린다. MAX_PATH면 충분할까? 제한도 없어진다는데? 더 긴 경로가 오면 어떻게 될까, 하는 불안감이 든다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateTempFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; dir&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;MAX_PATH&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;StringCbCopyA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dir&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;StringCbCatA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;CreateFileA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;동적 버퍼&lt;/h2&gt;
&lt;p&gt;길이를 런타임에 계산해서 필요한 만큼 공간을 확보하도록 만들 수 있다. 아래 코드는 dir과 name에 어떤 길이의 문자열이 오더라도 잘 동작한다. 메모리만 있다면 말이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateTempFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; dir&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	size_t size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	
	size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dir&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	path &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;malloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	
	&lt;span class=&quot;token function&quot;&gt;StringCbCopyA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dir&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;StringCbCatA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	
	&lt;span class=&quot;token function&quot;&gt;CreateFileA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	
	&lt;span class=&quot;token function&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;vector&lt;/h2&gt;
&lt;p&gt;동적 버퍼를 요하는 코드를 C++로 바꿀 때 흔히 사용하는 객체가 벡터다. 간단하고 깔끔하고 사이즈 관리되고, 나무랄 때가 없는 것이다. 대체하기도 너무 심플하다. resize와 &amp;#x26;vector[0]만 사용하면 만사 OK다.&lt;/p&gt;
&lt;p&gt;C의 저급함과 C++의 고급함 사이의 가장 적절한 수준을 보여주는 것 같기도 하다. 하지만 한가지 문제가 있다. 이 코드가 그렇게 빠르지는 않다는 점이다. 왜냐하면 벡터는 내부적으로 공간을 확장할 때 모두 초기화를 시키기 때문이다. 사실상 우리는 초기화가 필요 없음에도 resize를 하는 순간 모든 공간이 초기화된다. 낭비다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateTempFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; dir&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;vector&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	
	path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dir&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	
	&lt;span class=&quot;token function&quot;&gt;StringCbCopyA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dir&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;StringCbCatA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	
	&lt;span class=&quot;token function&quot;&gt;CreateFileA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;shared_ptr&lt;/h2&gt;
&lt;p&gt;벡터의 초기화를 피할 수 있는 한가지 대안은 shared_ptr이다. 다만 배열 해제를 위한 메모리 해제 코드를 별도로 작성해야 하는 불편함이 있다. 물론 사이즈도 별도로 트래킹을 해야 한다. 하지만 더이상 벡터가 가지고 있는 개별 아이템 초기화에 대한 부담은 없다. 하지만 또 포인터 소유권과 관련된 레퍼런스 카운트 체크에 대한 부담이 늘어난다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateTempFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; dir&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	size_t size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	
	size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dir&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;shared_ptr&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; p&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; p&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	
	&lt;span class=&quot;token function&quot;&gt;StringCbCopyA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dir&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;StringCbCatA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	
	&lt;span class=&quot;token function&quot;&gt;CreateFileA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;unique_ptr&lt;/h2&gt;
&lt;p&gt;또 다른 대안으로 unique_ptr을 사용할 수 있다. unique_ptr&amp;#x3C;[]&gt;은 특수화가 되어 있어 사용하기도 무척 편리하며 vector와 같이 초기화 코드가 없기 때문에 빠르다. 게다가 레퍼런스 카운트 체크와 관련한 부하도 없기 때문에 더 빠르다. 지역 버퍼 용도로 쓰기에 가장 문안한 형태로 볼 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateTempFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;dir&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	size_t size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dir&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;unique_ptr&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; path &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;unique_ptr&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;StringCbCopyA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dir&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;StringCbCatA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	
	&lt;span class=&quot;token function&quot;&gt;CreateFileA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[정보] 재테크 관련 유튜브]]></title><description><![CDATA[바야흐로 재테크 시대. 특히나 202…]]></description><link>https://jiniya.net/2022/investing-youtube/</link><guid isPermaLink="false">https://jiniya.net/2022/investing-youtube/</guid><pubDate>Mon, 24 Jan 2022 13:00:01 GMT</pubDate><content:encoded>&lt;p&gt;바야흐로 재테크 시대. 특히나 2020은 투자한 사람과 그렇지 않은 사람 사이의 자산 갭이 많이 발생한 한 해가 아니었나 싶다. 뭐라도 투자한 사람들은 수익률 올리기에 바쁘고, 들어서지 못한 사람들은 놓친 기회가 아쉬워 난리다. 하지만 기회는 언제든 다시 온다. 다가올 기회를 놓치기 싫다면 운전하면서 또는 심심할 때 보면 크게 도움될만한 재테크 채널들. 순서는 랜덤.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/channel/UCsJ6RuBiTVWRX156FVbeaGg&quot;&gt;슈카월드&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/channel/UCKTMvIu9a4VGSrpWy-8bUrQ&quot;&gt;내일은 투자왕 - 김단테&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/c/%EC%82%BC%ED%94%84%EB%A1%9Ctv/featured&quot;&gt;삼프로TV_경제의신과함께&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/channel/UCSJELOytOHjywS1ynjNsLDA&quot;&gt;dp - Investor Unknown D.P.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/channel/UCn_38aaCktkBLPv3EtfmiUA&quot;&gt;박종훈의 경제한방&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 코딩의 시대, 배움의 방식]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2021/07/coding-era/</link><guid isPermaLink="false">https://jiniya.net/ng/2021/07/coding-era/</guid><pubDate>Wed, 21 Jul 2021 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;올초 넥슨이 전직원 연봉을 일괄 인상하면서 인재 전쟁의 서막을 알렸다. 이후 각종 거의 모든 소위 잘나간다는 게임 업체들이 연봉 인상 러시에 동참하면서 코딩의 시대가 절정을 향해 가고 있음을 느끼게 해줬다. 그런 분위기를 반영하듯 페북에는 게임회사 직원을 대상으로 과외 선생님을 모신다는 광고가 연신 팝업된다.&lt;/p&gt;
&lt;p&gt;일자리가 없어서 난리인 시대에 아이러니하게도 주변에서는 개발자를 못 구해서 난리다. 김국현님의 자바 두명 타세요를 보면서 암울한 미래를 예견했던 우리 세대에게 지금의 현실은 다소 생경하기도 하다. 어쨌든 이런 모든 혼란스러움을 뒤로 하고 현재를 정의한다면 프로그래머 전성 시대다. 직무를 불문하고 삼성전자의 입사 시험 과목으로 파이썬이 들어갔다니 두말하면 입아픈 것 같기도 하다.&lt;/p&gt;
&lt;p&gt;그런만큼 요즘 사람들은 꿀 떨어지는 이 분야에 관심이 많다. 자연스레 그에 관한 비전공자들의 여러가지 질문을 받는다. 클래스101 이거 들으면 코딩할 수 있어? 유튜브 이거 보면 나도 프로그래머로 취직할 수 있을까? 거의 대부분 어디서 무엇으로 어떻게 공부하면 프로그래머가 된다거나 코딩을 할 수 있느냐는 질문이다. 그래서 주변을 둘러보며 이미 프로그래머가 된 다른 이들은 어떻게 배웠는지를 한 번 살펴봤다.&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;A는 게임 테스트 아르바이트로 입사했다. 테스트 아르바이트라는 것이 대체로 그러하듯 컴퓨터로 게임을 할 줄 알면 입사 요건이 충족된다. 내가 알기로 A는 이쪽 전공이 아니고 교육을 받은 적도 없다. A가 코딩을 공부한 건 유튜브와 블로그였다. 테스트를 하면서 코딩 유튜브를 틀어놓고 보면서 공부를 했고, 그런 장면이 내부 툴 개발자 B의 눈에 띄었다. B는 A와 같이 개발을 해보고 싶다는 얘기를 했고, 내가 잃을 거라곤 깃헙 슬롯 비용 밖에는 없을것 같아서 그러라고 했다. 그렇게 A는 깃헙 권한을 획득했다.&lt;/p&gt;
&lt;p&gt;최근에 A의 작업과 관련한 얘기들이 나와서 그가 커밋한 코드를 몇개 보았다. 유튜브로 공부한 거라고 생각하기에는 제법 필요한 코드를 필요한 장소에 올렸다. 물론 전공자가 아니라서 전공자도 어려워하는 스레딩 같은 것들과 관련해 잘못 이해하는 부분도 있는듯 보였지만 우리끼리 사용하는 내부 툴이라 크게 중요하진 않아 보였다. 어쨌든 A가 퇴근 후에도 얼마나 많은 시간을 공부에 할애했는지는 모르겠지만 아르바이트로 근무하면서 유튜브와 블로그로 코딩을 공부해서 실무에 써먹을 수준이 되었다는 건 제법 인상적이었다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;C는 A가 개발을 할 수 있도록 만들어준 B의 후임이다. B는 병특이 끝나고 게임을 개발하고 싶다고 퇴사를 했다. 그래서 그의 후임을 뽑게 됐다. 병특이 가능해 제법 여러 친구를 면접 봤다. 걔중에는 소위 스카이 대학에 재학중인 친구도 두명 정도 있었다. 하지만 최종 합격한 친구는 다소 이 분야와는 인연이 없을 것 같은 이력의 C다.&lt;/p&gt;
&lt;p&gt;C는 고등학교를 졸업하고 다양한 일을 했다. 그의 이력 중 가장 인상 깊었던 건 롯데리아 매니저였다. 어쨌든 그렇게 이일저일 하다가 그는 최근에 개발 관련 일자리가 많다는 걸 알고 국비 지원 자바 교육 과정을 5개월 이수했다. 그리고 지원한게 우리 회사였다. 아이러니하게도 그가 배운건 자바였지만 그가 지원한 포지션은 C#과 파이썬을 사용하는 자리였다. 파이썬은 면접 보기 전에 조금 공부했다고 했다. 그럼에도 그는 그 면접을 진행한 모든 사람을 통틀어 면접 문제를 다 푼 2명에 포함됐고 롯데리아 경력을 높게 평가받아 채용됐다.&lt;/p&gt;
&lt;p&gt;C는 국비 지원 과정을 하기 전에 컴퓨터 관련 교육을 받은 적도 혼자 공부한 적도 없다고 했다. 물론 교육 과정 동안은 정말 치열하게 공부했다고 한다. 예전엔 사실 정부에서 웹프로그래머 일만명 키운다고 국비 교육 과정 만들고 할때에는 회의적인 생각이 많았지만 C를 보면서 생각이 좀 바뀌었다. 교육의 영향력과 밀도는 모두에게 다를 수 있고 기회가 제공될 수 있다는 측면에서 긍정적인 효과가 있다고 생각하게 됐다.&lt;/p&gt;
&lt;p&gt;자바를 5개월 동안 공부했던 그는 선생님에게 하나를 잘 하면 다른 거도 금방 배운다는 얘기를 들었다고 했다. 틀린 말이 아니다. 어쨌든 좋은 선생님에게 배워서 그런지 그는 오늘도 C#으로 내부 툴을 고치고 업그레이드 한다. C는 어리다. 그래서 스펀지처럼 많은 것들을 흡수한다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;E는 한국이 아닌 다른 아시아 국가 출신이다. 그는 고등학교를 중퇴했다. 대신 그 기간동안 독학으로 프로그래밍, 리버싱 등에 관한 공부를 했다고 한다. 그가 회사로 보낸 건 간단한 이력서와 깃헙, 블로그 링크였다. 그의 깃헙 링크는 그가 얼마나 훌륭한 코드를 쓸 수 있는지를 보여 주었고, 블로그는 그가 체계적인 글을 쓰는 능력이 있다는 걸 증명할만큼 충분했다. 그렇게 그의 기술 면접은 바이패스 됐다. 3년 정도 독학으로 공부했다는 그에게 특별한 공부 방법이 있었냐고 물어보자 그저 관심이 있어서 빨리 배울 수 있었다고 했다.&lt;/p&gt;
&lt;p&gt;학부 시절 친한 후배에게서 정말 강려크한 인상을 받은 적이 있었다. 그 후배의 레드블랙 트리를 카피하던 순간이었다. 카피하다 말고 너무 잘 작성된 소스 코드 앞에서 눈물을 훔쳤다. 오프로 아는 다른 이의 코드를 보고 울었던 적은 그때가 처음이었고, 그 다음으로도 없었다. 그런 그가 공동 창업한 회사는 올해 카카오 모빌리티에 인수됐다. 오늘 E가 제출한 풀리퀘스트 코드를 보면서 그때가 떠올랐다. E는 20살이고, 고등학교 대신 3년을 독학한게 전부고, 그의 교재는 인터넷이다. 경력의 허무함과 신입의 가능성을 동시에 보여주는 그는 다소 신비한 존재다.&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;F는 몇해전 회사에 근무했던 직원이다. 그는 특성화 고등학교를 졸업했고, 학창 시절부터 게임 해킹에 관심이 있어서 이것 저것 해보다 졸업과 동시에 입사를 했다. 그가 입사할 때 우리 회사의 손코딩 문제는 지금보다 어려웠음에도 그는 잘 풀었다. 선생님과 함께 회사를 왔었던 기억이 난다. 처음에는 서툴렀지만 그나이 사람들이 그렇듯 그는 금방 배웠고 에이스 자리를 꿰찾다. 우리는 그를 여포라 불렀다.&lt;/p&gt;
&lt;p&gt;F는 특성화 고등학교를 졸업했지만 정규 교육 과정을 통해서 관련 지식을 배운 건 아니었다. 그도 거의 모든 걸 독학으로 배웠는데 특이하게도 그 경로에는 네이버 카페가 있었다. 비슷한 또래의 네이버 카페에서 난다 긴다하는 애들과 경쟁하다 보니 더 빨리 배우게 된 게 아닐까라는 추측을 해본다. 네이버 카페는 조금 재미난 특징이 있는데 모르는 애들끼리 모여서 말도 안되는 소리를 하는거 같은데 그 와중에 집단 지성이 동작해서 뭔가 발전이 일어난다는 점이다. 보통의 다른 커뮤니티나 사이트는 가르치는 사람이 있고 배우는 사람이 있는데 네이버 카페는 모르는 애들끼리 모여서 자기가 알아낸걸 각자 자신만의 방법으로 한마디씩 하다가 짠하고 종국에는 답이 나온다. 보고 있으면 황당하기도 하도 신기하기도 하고 그렇다.&lt;/p&gt;
&lt;p&gt;그렇게 배운 F는 지금은 국내에서 이름만대면 아는 유명한 IT 회사에 근무한다.&lt;/p&gt;
&lt;h3&gt;#4&lt;/h3&gt;
&lt;p&gt;G는 이 이야기에 등장하는 유일한 컴퓨터 공학 전공자다. 그는 대학을 졸업하고 입사했다. 병역특례를 하지 않았다. 너무 평범한 일반적인 케이스가 아닌가? 그렇다. 다만 그가 입사에 있어 특이했던 점은 게임 보안 솔루션을 만들어서 제출을 했다는 것이다. 그는 이력서에 깃헙 링크를 함께 보냈고 거기엔 그가 만든 동작이 가능한 게임 보안 솔루션이 있었다. 뽑지 않을 이유가 없다. 동작하는 게임 보안 솔루션을 직접 생각해서 다 만들었다니…​&lt;/p&gt;
&lt;p&gt;면접 때 그에게 이걸 어떻게 만들었나 물었던 기억이 있다. 그는 자주 했던 게임에서 비슷한 걸 봤고 재밌어 보여서 직접 만들었다고 했다. 동아리나 그런 곳에서 함께 만든 거냐고 물었더니 혼자 만들었다고 했다. 오프에서 이쪽 분야에 관심이 있는 사람들을 만나기 힘들어 혼자서 공부했다는 얘기를 덧붙였다. 그는 지방에서 나고 그곳에서 대학을 졸업했다. 그가 만든 작품은 오버워치에 적용된 이후로 제법 업계에서 핫한 기법이었고 나는 몇가지 질문을 더했다. 그리고 이어진 그의 답변. 그 속에는 그가 얼마나 많은 시간을 날밤새며 사고실험과 삽질을 했는지가 오롯이 담겨 있었다.&lt;/p&gt;
&lt;h3&gt;#5&lt;/h3&gt;
&lt;p&gt;유튜브, 블로그, 책, 국비 지원 교육 과정, 커뮤니티 사이트, 웹사이트, github, 네이버 카페, 대학교, 사고실험, 삽질 등 다양한 경로로 배움의 과정을 거친 이들을 봤다. 경로는 다양했지만 그들은 하나같이 그일을 하기에 차고도 넘칠 정도로 충분한 지식을 기지고 있었다. 물론 그런 실력을 가지기 위해서 그들이 얼마나 많은 시간과 노력을 투입했는지는 알 길이 없다. 하지만 어쨌든 한가지는 분명하다 관심과 취향이 맞고 노력이 더해진다면 어떤 경로를 택하든 당신이 원하면 당신은 직업 프로그래머가 될 수 있을 거라는 점이다.&lt;/p&gt;
&lt;p&gt;바야흐로 코딩의 시대, 당신이 배우는 단계에 있다면 응당 의문이 많을 수 밖에 없다. 이 방법이 맞을까? 남들도 이렇게 하는걸까? 이렇게해서 취직할 수 있을까? 어떤 길이든 지속할 수 있다면 틀린 길은 아니라고 감히 말할 수 있을 것 같다. 당신의 배움에 건투를 빈다.&lt;/p&gt;
&lt;p&gt;우리 때에는 김국현님의 자바 두명 타세요라는 괴담이 난무했다. 요즘은 업그레이드 된 인공지능 괴담이 난무하는 것 같다. 인공지능이 개발자를 모두 대체한다는 얘기 말이다. 하지만 김국현님의 괴담이 그랬듯 너무 겁낼 필요는 없을 것 같다. 인공지능이 언젠간 개발자를 모두 대체하겠지만 그때는 다른 직업도 상당수는 대체되었을테니 사회적으로 뭔가 다른 솔루션이 나왔을 가능성이 높다. 그리고 그 시간은 생각보다 오래 걸릴 수 있고, 전혀 엉뚱한 방향으로 전개될지도 모른다. 당신의 미래에도 지금 세대 개발자들이 누린 행운이 조금이나마 함께하길 바란다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[리뷰] 의천도룡기 2019]]></title><description><![CDATA[넷플릭스를 방황하다 우연찮게 틀게 된 "의천도룡기 201…]]></description><link>https://jiniya.net/2021/the-heaven-sword-and-dragon-saber-2019/</link><guid isPermaLink="false">https://jiniya.net/2021/the-heaven-sword-and-dragon-saber-2019/</guid><pubDate>Fri, 29 Jan 2021 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;넷플릭스를 방황하다 우연찮게 틀게 된 &quot;의천도룡기 2019&quot;가 내 인생 첫 중드가 되었다. 이상하게 중드는 그간 잘 보지 않았던 기억이 있다. 물론 어렸을 적 이연걸의 광팬이었고, 홍콩 무협 영화를 좋아했었던 것을 보면 딱히 중드를 안 볼 이유도 없는데 그저 이상하게 중드면 시작조차 하지 않았던 기억이 많았다. 그럼에도 의천도룡기를 정주행 할 수 있었던 가장 큰 힘은 아무래도 여캐들의 훈훈한 비주얼 탓이 아닌가 싶다. 그간 한중일중 미모는 한국이 원탑이라 생각했었는데 의천도룡기를 보고 생각이 다소 바뀌게 되었다. 여튼 각설하고,...&lt;/p&gt;
&lt;p&gt;김용의 소설 원작을 읽지 않았지만 의천도룡기 또한 그의 다른 소설과 비슷하게 몹시 재미있다. 시대를 초월해서 바뀌지 않는 인간상, 그리고 고뇌할 수 밖에 없는 인생사를 그리고 있어서 그런 것 같다. 이루어질 수 없는 사랑, 가질 수 없는 것들에 대한 욕망, 그리고 이루고 싶은 것에 대한 집요하고 끊질기며 처절하게 이어지는 집착, 그런 모든 면에서 이 드라마는 많은 것들을 담고 있다고 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./chomin.png&apos; data-alt=&apos;내가 조민이다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/1bcdd4ebfe67f56ffe2b9bfd100a9531/78d47/chomin.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 56.315789473684205%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAAAsTAAALEwEAmpwYAAADJUlEQVR42h2TXUybBRSGPygtHbRohjCQmm1cTOYWkykmOJeYOOPMvPFiGqOLiTNxW2QmskU3jNE4olsNDHSGzGHFTId0ZbgNRl07V1ugCmVtVwqU/pF+/LSQdR1stJbSx287yZv37sl7zpsjVJatpWbrBgRBIC8vD5nkx977gAezFF/i9kSQbCoFK6Ct+4QNygIqVGpU8nyK16gozi+gfG0x40N+ZryzCNVb1/P681uQCzkUKtdQmifj1OfHSSeShD1+7kfnSc1GsVy4TFdrO9pDtaxXFVIgk6FS5LOusAh1bi497Re5G15EqNSUsGfXNuQKGVWlFRzcUYP26Jf4Bh0MXenhdiiEOHITp/Ev5sZiWM5f4J2dLz2EqBUKHi96jBKFms/2HyHuTyDsemEzL1ZvQiFX8HJZOQeee5YTR+q5K0axduolYBDSabyDLux/mOlsaUXXoKW64gkekSspUa/j0fwidm9/hdCIiPD0kxp21lRRJN3ljfJSvtn9KsMmM8vxBOGbbshmWZye489zBjobv+PwW3tpP3GKk7UfUlVcxpvbnmHHpko2ajYyNhBAyM3JQSEVsUWjoWHPa7R/dICIx0ciMk8mmX6YztFlwHvDju3iNWnlbq7/1k1n8/ecqf8U3f532f7UZpQKJbqmNoRDbx/kq7oGfmo5j9Xkwmlx0y8VEA1ESC4kyMzG+Megl0B6en5oo6+1DfMvenp1HeibmqnbV4uuYwDdz0a+ONyA4AtnCM7AZARuTaRwee4RnrxD5n5KUhKWV3HdsNHR2IT560ZOv78PQ/NprradQ/vxUX79vR+TTcQ1cQ+TaQTBaA5yqW+CriujGC6N0msKYXfEEafThEJJ7EMxBu0if1v8WIy3uK43cvb4SX6sP8aZb89y1RzANiAyNplkKrqKMDC0wL/uRYalZE5vklF/Buf4fzg8y4x4Uww6l7A6EniksnvscdzBJH29w+i0LfR292OzBpmOrDI1k0FcyCB4Axk8EsQ9mcblS0u+gifwAJqSfAW/iKQM41NZrM5FrjkWSEiPY7EGCPruMCdtMj+fRYxJ0FiW/wEZfmoICCWI7QAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;내가 조민이다.&apos; title=&apos;&apos; src=&apos;/static/1bcdd4ebfe67f56ffe2b9bfd100a9531/efd7b/chomin.png&apos; srcset=&apos;/static/1bcdd4ebfe67f56ffe2b9bfd100a9531/08678/chomin.png 190w,
/static/1bcdd4ebfe67f56ffe2b9bfd100a9531/2edd7/chomin.png 380w,
/static/1bcdd4ebfe67f56ffe2b9bfd100a9531/efd7b/chomin.png 760w,
/static/1bcdd4ebfe67f56ffe2b9bfd100a9531/78d47/chomin.png 800w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;내가 조민이다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;그 모든 스토리 중에서도 단연 돋보였던 캐릭터는 다름아닌 조민이었다. 물론 그녀가 여주이면서 가장 예뻐서 그랬다는 점도 부인은 못하겠지만 그것 외에도 그 캐릭터가 보여주는 태도는 많은 것들을 느끼게 해주었다. 이루어질 수 없는 사랑, 그것을 위해서는 엄청난 희생이 따를 것이라는 것을 알면서도 그녀는 처절하고 끊질기고 집요하게 그 사랑을 얻기 위해 모든 것을 걸었다. 그녀 출신 성분 자체가 그것을 통해 얻을 것 보다는 잃을 것이 더 많다는 점은 그 과정을 더욱 납득하기 힘들게 만들었지만 반대로 또 더 애절해 보이게 만드는 효과가 있었다.&lt;/p&gt;
&lt;p&gt;드라마 3대 빌런을 꼽자면 나는 아미파의 멸절사태, 대사저, 지약을 꼽겠다. 작가가 남자라 그런지 악역을 여자 무림파에 몰아 넣은 감이 없잖아 있는 것 같다. 자신의 주장을 죽음을 앞에 두고도 굽히지 않으며 의미 없게 죽어서 여러사람 피곤하게 만드는 고집불통 빌런 멸절사태, 그리고 본인의 알량의 권력을 믿고 위로는 굽신거리며 아래 사람들에게는 끊임없이 막대하는 대사저, 그리고 우유부단 빌런의 끝판대장 지약.&lt;/p&gt;
&lt;p&gt;이 드라마는 시작부터 끝까지 인간의 처절한 고뇌를 담고 있다. 이루어지면 안 되는 정파와 사파의 사랑, 자신의 복수를 위해 한 평생을 바치며 온갖 악행을 저지르는 한 남자, 그들 사이에서 출생부터 복잡하게 꼬여버린 주인공, 삶과 죽음의 경계에서의 처절한 사투, 대업과 사랑 사이의 갈등 같은 우리가 살면서 겪을 수 있는 시대를 초월한 온갖 고뇌와 인간 군상들을 닮고 있기에 이 드라마는 재밌었고 유익했다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[ai] 너와 나의 인공지능이 멍청한 이유]]></title><description><![CDATA[모든 사람이 그렇듯 내가 머신러닝에 관심을 갖게 된 시점은 알파고가 이세돌을 무참히 격파하던 그 즈음이었다. 대국이 시작되기 전 나는 당연히 이세돌의 전승을 점쳤고,…]]></description><link>https://jiniya.net/ng/2020/07/deep-learning-101/</link><guid isPermaLink="false">https://jiniya.net/ng/2020/07/deep-learning-101/</guid><pubDate>Wed, 15 Jul 2020 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;모든 사람이 그렇듯 내가 머신러닝에 관심을 갖게 된 시점은 알파고가 이세돌을 무참히 격파하던 그 즈음이었다. 대국이 시작되기 전 나는 당연히 이세돌의 전승을 점쳤고, 1국이 끝나고 세상이 바뀌었다는 사실을 깨달았다. 그리고는 봇물처럼 머신러닝 자료와 강연들이 이어졌다. 그덕에 구글의 제프딘을 실제로 보기도 하는 호사를 누리기도 했다 (텐서플로 홍보차 국내에 옴)&lt;/p&gt;
&lt;p&gt;그때 제프딘이 발표한 내용 중에 이미지 인식(이게 고양이인지, 강아지인지, 나팔꽃인지, 장미인지, 등등을 판단) 분야에서는 기계가 인간을 뛰어 넘은지가 제법 됐다는 이야기를 했다. 그리고 얼마 지나지 않아 각종 렌즈앱들이 나오기 시작했고, 그 렌즈앱이 우리 엄마보다 더 정확하게 각종 식물의 이름을 나열하는 것을 보면서 2차 충격을 받았다. 그렇게 머신러닝의 르네상스는 시작되었고, 요즘 IT쪽 사람들을 만나서 뭐 하는지 물어보면 분야를 안 가리고 머신러닝 한다는 대답이 돌아오는 세상이 되었다.&lt;/p&gt;
&lt;p&gt;어쨌든 그맘때 이미지 인식을 그렇게 기계가 잘 한다면 바이너리 인식도 잘하지 않을까라는 생각이 들었다. 컴퓨터한테야 이미지든 바이너리든 결국은 숫자일 뿐이니 말이다. 그런 선상에서 그당시 유행하던 머신 러닝 라이브러리로 해킹툴 바이너리를 분류해서 몇 개 학습시켜 보고 결과를 체크해 보았다. 샘플에서는 너무 완벽하게 동작했지만 각종 정상 바이너리를 집어 넣자 오진이 무지하게 많이 났다.&lt;/p&gt;
&lt;p&gt;그당시 MS에서도 바이너리 분류와 관련한 컨테스트를 진행하고 있었다. 심지어 결과물도 공개가 되어 있었다. 테스트 안해볼 이유는 없기에 거기 1등한 사람들의 방법을 가져와서 우리도 테스트를 해보았다. MS 대회의 1위 답게 그냥 우리가 막 이미지 인식 시킨 것 보다는 훌륭했다. 그래서 본격적으로 돌려보자고 했는데, 회사 장비로는 한계가 있고 AWS에서 돌리면 수백만원 정도의 비용이 지출될 것 같다는 얘기를 했다. 될지 안될지도 모르는 일에 그 정도를 투자한다는게 쉽지 않은 일이라 거기까지 하고 말았던 기억이 난다.&lt;/p&gt;
&lt;p&gt;그 1등의 방식도 재미있었는데 각종 팩터를 넣어서 학습시키는데 그 중에 하나가 바이너리 앞부분 200바이트 해시를 사용한다거나(200이란 숫자는 정확한 건 아님) 하는 것이 있다. 그래서 왜 300도 아니고, 400도 아니고 200이지라는 의문을 가지고 그들이 쓴 논문을 봤는데, 그 논문 왈, 200바이트가 왜 잘되는지는 우리도 모르겠지만 여러 테스트 결과 그게 좋아서 그렇게 했다는 다소 충격적인 답변. 아, 이런게 머신러닝 이구나 라는 느낌만 가지고 기억속 한편으로 사라졌다.&lt;/p&gt;
&lt;p&gt;그렇게 잊고 있었던 머신러닝 관련해서 최근 지인 한 명이 그때 그 생각이 틀린 건 아닌 거 같다면서 MS에서 발표한 링크 를 보내줬다. 소오름. 내 생각이 바로 저거였는데 저게 된다니 ㄷ ㄷ ㄷ 그리고 우리가 머신러닝알못이라 그렇지 구현을 제대로 했으면 그때부터 잘됐을까라는 생각도 들었다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.microsoft.com/security/blog/wp-content/uploads/2020/05/stamina-steps-blog.png&quot; alt=&quot;Analyzing malware represented as image&quot;&gt;&lt;/p&gt;
&lt;p&gt;그렇게 다시금 인공지능에 대한 연구 의지가 불타오름과 동시에 교보문고에서 인공지능 책들을 마구 질렀다. 친구가 심지어 2권은 선물까지 해줬으나 서평은 요원한 단계. 어쨌든 그 책들을 읽고 이미지 분류에 그렇게 좋다는 CNN으로 이미지를 좀 분류해보려고 돌렸으나 결과는 썩 좋지 않았다. 인공지능 쪽에 다소 조예가 있는 주변인들에게 물어보면 대다수가 그게 교과서에 나오는 건 잘 되는데 실질적으로 현실 세계 데이터로 뭐를 해보려면 잘 안 된다는 이야기를 했다. 그 이야기와 함께 다시금 광속으로 연구 의지는 마이너스 무한대로 발산하게 되었다.&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;그런 기억이 희미해질만했던 6월 말 회사에서 병역특례로 근무하던 DevOps 친구가 그만두는 일이 있었다. 여러모로 똑똑한 친구였는데 헤어지는 자리에서도 다소 충격적인 이야기를 들려주었다. 머신러닝을 하기 위해서 무.려. 4400만원짜리 컴퓨터를 질렀다는 이야기.&lt;/p&gt;
&lt;p&gt;그 이야기의 여러 요소에서 다중 충격을 받았는데, 1) 머신러닝을 하기 위해서 개인 돈으로 컴퓨터를 사는 투자를 한다는 데 놀랐고, 2) 그것도 무려 4400만원짜리를 샀다는 데 두 번 놀랐고, 3) 그 엄청난 비용의 상당수가 최근 유행하는 T 코인(테슬라)에서 충당됐다는 사실에 놀랐다. 어쨌든 그 머신은 제온씨퓨에 타이탄을 무려 4개나 달았다고 했다.&lt;/p&gt;
&lt;p&gt;머신러닝을 하려면 그 정도 장비가 필요한 거냐고 물어봤더니 자기도 잘은 모르는데 제대로 해보려고 좋은 장비를 샀다는 이야기를 했다. 그와 더불어 요즘 AI 대회가 많아서 그런 곳에서 상금을 받으면 투자금 회수가 가능하다는 이야기도 덧붙였다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;그 친구가 퇴사한 이후에 회사에 인공지능 하는 친구들이 현장실습을 왔다. 그당시 하다가 포기한 이미지 분류 작업을 진행하기 위해서 왔는데 그들은 학교에 있는 1080TI가 몇 개 있는 장비를 사용할 수 있는 상태였다.&lt;/p&gt;
&lt;p&gt;출근한 날 같이 저녁을 먹을 시간이 있어서 이런 저런 얘기를 하다가 애니를 좋아한다는 이야기를 듣게 되었고, 추천작을 물어봤더니 고스트 바둑왕을 꼽았다. 나는 만화책으로 봤는데 끝이 너무 허했다는 이야기를 전했다. 작가가 히트 좀 하자 끝낸 용비불패같은 느낌. 그 친구가 애니는 그래도 괜찮다는 이야기를 했고 마침 스트리밍 서비스에 올라와 있길래 사이와 히카루의 대국을 애니로 몇 편 보게 되었다. 모든 만화가 그렇지만 보면 뿜뿜하게 된다. 바둑 기사 존멋~&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;히카루와 사이의 바둑에 빠져서 애니를 보다보니 자연스레 바둑을 배우고 싶다는 생각이 들었고, 예전에 프로 기사를 준비했던 동생이 알파고 이후에 제로 시리즈 인공지능 바둑이 많이 나왔다는 이야기를 들었던 기억이 많이 났다. 그래서 집에 설치해보고 돌렸는데 자기들끼리 두게 해도 제법 모양이 나오게 두었다. 나는 바둑을 둘 줄 몰라 실력을 알 수 없어서 온라인 바둑에 들어가서 몇 판 둬봤는데 지는 법이 없었다. 그리고 유튜브를 찾아보니 프로 기사들도 3점 놓고 둬야 이기고, 2점은 힘들다는 이야기들이 올라와 있었다.&lt;/p&gt;
&lt;p&gt;간략하게 인공지능 바둑에 대해서 이야기하자면 알파고가 시초고, 알파고 제로가 나오고 그들이 연구 방식을 논문으로 공개해서 유사한 종류의 인공지능이 많이 나오게 됐다. 제로의 특징은 인간의 기보를 사용하지 않고 자기 스스로 게임을 반복(self play)하면서 기량을 향상시켜 나가는 기법을 쓴다. 따라서 바둑의 룰만 넣어주고 돌리면 스스로 점점 더 강해진다는 알고나면 다소 단순해 보이는(?!) 컨셉이다.&lt;/p&gt;
&lt;p&gt;그 이후에 등장한 것 중에는 릴라제로의 경우 개인이 오픈소스로 만들어 대중의 참여로 분산 학습시켜 나가는 구조로 진행되고 있다, 페이스북에서도 엘프고라는 프로젝트로 야심차게 진행했으나 현재는 퇴물, 그리고 가장 최근에 나온 게 카타고다. 카타고의 특징은 기존 알파고가 바둑이란 게임의 특징을 별로 활용하지 않았다면 카타고는 바둑에 특화된 특징을 많이 사용해서 학습 속도가 빠르고 승률 외의 다른 종류의 예측들을 더 가지고 있다고 한다. 개인 컴퓨터에서 각종 인공지능들끼리의 대국을 펼쳐 보았는데 카타고가 제일 강했다. 심지어 생각하는 시간을 차이를 두어도 카타고가 이기는 경우가 많았다.&lt;/p&gt;
&lt;p&gt;대체로 프로 기사들 사이에서는 알파고 제로 &gt; 텐센트 절예 &gt; 카타고 &gt; 릴라 제로 정도로 판단되고 있는 것 같았다. 이런 걸 보면 궁금증이 생기게 마련이다. 비슷한 셀프 플레이란 방식으로 학습을 시켰음에도 그들 사이에서 큰 기량 차이가 생기는 이유는 뭘까? 심지어 페이스북도 나름 똑똑할텐데 왜 엘프고는 순위에도 끼지 못할까라는 생각을 하면서 릴라제로 소개 페이지를 보다가 신기한 사실을 알게 되었다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Recomputing the AlphaGo Zero weights will take about 1700 years on commodity hardware.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;알파고 제로의 가중치 데이터를 재계산하는데에는 상용 하드웨어로 1700년이 걸린다는 이야기. 요는 이렇다. 제로 방식은 셀프 플레이를 토대로 가충치 파일을 만들어 추후 탐색을 할 때 더 적절하고 빠르게 하는 형태로 사용을 한다. 즉, 대다수 제로 방식 봇의 알맹이는 이 가중치 파일이란 것이다. 릴라제로 개발자는 1080ti 그래픽 카드 한 장으로 개발을 하는데 본인이 생각하는 추정치로는 그 그래픽 카드 하나로 알파고만큼의 수준을 계산하기 위해서는 1700년이 걸린다고 말한 것이다. 그걸 극복하기 위해서 릴라제로는 개인의 컴퓨팅 자원을 지원 받아 클라우드 형태로 계산해서 학습하는 구조로 진화를 하고 있다. 그냥 숫자만 보고 역시 구글이라는 생각을 하면서 카타고 자료도 살펴보게 되었다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;KataGo’s latest run used about 28 GPUs, rather than thousands (like AlphaZero and ELF), first reached superhuman levels on that hardware in perhaps just three to six days, and reached strength similar to ELF in about 14 days. With minor adjustments and some more GPUs, starting around 40 days it roughly began to match surpass Leela Zero in some tests with different configurations, time controls, and hardware. The run continued for a total of about five months of training time, reaching several hundred Elo stronger than Leela Zero and likely other open-source bots. The run has ended for now, but we hope to be able to continue it or begin another run in the future!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;여기는 조금 구체적인데 28개의 GPU로 학습을 시켰고, 인간을 뛰어넘는데 3-6일이 걸렸고, 14일에 엘프고 수준에 도달했다. 여기에 조금의 조정을 하고 GPU를 몇개 더 추가해서 40일 정도 되니까 릴라 제로의 수준에 도달했고, 총 5개월 정도가 지나서는 릴라제로에 비해서 Elo 점수가 수백점 차이가 났고 학습을 중단시켰다는 이야기. 내용이 재밌어서 그들의 논문도 찾아서 읽어보았다. 도입부가 무척 흥미로웠는데 다음과 같이 정리돼 있었다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In 2017, DeepMind’s AlphaGoZero demonstrated that it was possible to achieve superhuman performance in Go without reliance on human strategic knowledge or preexisting data [18]. Subsequently, DeepMind’s AlphaZero achieved comparable results in Chess and Shogi. However, the amount of computation required was large, with DeepMind’s main reported run for Go using 5000 TPUs for several days, totaling about 41 TPU-years [17]. Similarly ELF OpenGo, a replication by Facebook, used 2000 V100 GPUs for about 13-14 days, or about 74 GPU-years, to reach top levels of performance [19].&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;알파고 제로의 경우 5000 TPU로 몇일 계산을 했다고 나와 있다. 총 41년 TPU 시간이 사용되었다. 엘프고의 경우 2000개의 V100 GPU를 사용해서 13-14일 계산을 했고, 총 74년 GPU 시간이 사용되었다.&lt;/p&gt;
&lt;p&gt;결국 당연한 소리겠지만 동등한 설정이라면 결국 연산 시간에 따라서 인공지능의 강함이 결정된다고 할 수 있겠다. 그런데 그 연산 시간이라는 것이 생각보다 천문학적이라는데 놀랐다. 릴라제로 개발자는 1080TI GPU 한장으로 개발을 하고 있고, 카타고는 V100 28장에서 몇 장을 더썼고, 엘프고는 V100 2000장, 알파고제로는 TPU 5000개를 사용했다.&lt;/p&gt;
&lt;p&gt;FP32벤치 마크 자료를 살펴보면 1TPU를 1.0으로 계산 시에, V100이 0.9정도, 1080TI가 0.4 정도 되는 것으로 추정된다. 이 데이터를 토대로 연산에 사용된 비용을 계산해보면 다소 충격적이다.&lt;/p&gt;
&lt;p&gt;카타고의 경우 줄여서 V100 28개 5개월로 계산할 경우 (28 x 5 x 30) / 365 = 11.5년에 해당하는 GPU 시간을 사용했다고 볼 수 있다. aws에서 v100을 8개 탑재한 p3.16xlarge의 경우 시간당 사용 비용이 24.48불이다. 단순 계산할 경우 5개월간 총 308,448불이 사용되었다고 볼 수 있다. 1200원 환율로 계산할 경우 3억 7천만원에 해당하는 금액이다.&lt;/p&gt;
&lt;p&gt;엘프고의 경우 동일한 장비로 74년 GPU 시간을 썼다고 나와 있기 때문에 계산해보면 1,983,614불을 썼고, 한화로 23억 8천만원 정도를 썼다고 볼 수 있다.&lt;/p&gt;
&lt;p&gt;구글 TPU의 경우 선점형 v2 8코어가 시간당 1.35불이다. 이걸 토대로 41년 TPU시간을 계산해보면 60,608불, 7300만원 가량 사용한걸로 보여진다. 선점형이 아닌 주문형으로 할 경우 시간당 가격이 4.45로 올라가기 때문에 계산해보면 199,782불, 한화로 2억 4000만원 가량이 된다. 1대 0.9로 GPU 환산 계산시 45.51년 GPU 시간이 나오고 aws 비용으로 환산해 보면 1,219,922불, 한화로 14억 6400만원 가량이다.&lt;/p&gt;
&lt;p&gt;아마 이건 최적화된 경로로 계산을 하는 걸 밝힌 것이기 때문에 실질적으로 테스트에 사용되거나 폐기되거나 한 걸 감안한다면 훨씬 더 천문학적인 비용이 지출된다는 걸 알 수 있다. 그리고 왜 학습을 멈추는지도 이해할 수 있다.&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;우리가 바둑 인공지능을 만든다고 한다면 적어도 사람과는 대등하거나 잘 두는 수준이 되어야 쓸 만 하다고 인정을 해 줄 것이다. 이를 카타고 데이터를 토대로 최적화 시켜서 3일 걸린다고 가정을 하더라도 최적화된 계산 비용만 49,351불 한화로 6000만원 가까이를 써야 가능하다. 물론 이 또한 실패는 전혀 없는 모든 게 아마도 완벽한 상태에서의 계산 시간만을 가정했을 때 그렇다는 이야기일 것이다.&lt;/p&gt;
&lt;p&gt;재미삼아 또는 가능성만 보고 하기에는 쉽지 않은 분야라는 답이 나온다. 그리고 너와 나의 인공지능이 왜 그렇게 바보같은지도 어느 정도 이해가 된다. 구글이 왜 TPU를 만들었는지도 답이 나온다. 카타고가 더 강하게 만들지 않는 이유도 알 수 있고, 언제 새로 돌리기 시작할지도 예측해 볼 수 있다. 알파고 제로 가중치 파일을 공개하지 않는 이유도 추측해 볼 수 있고, 절예의 최신 가중치 파일을 왜 중국 프로 기사에게만 제공하는지도 납득이 된다. 심지어는 똑똑한 사람들이 돈을 많이 넣어도 결과가 좋지 않을 수 있다는 사실도 참고할 수 있다. 끝으로 몇년전 우리가 몇 백만원에 망설였던 게 얼마나 조족지혈인지도 알게 되었다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[정보] 웰비아닷컴은 채용 중~]]></title><description><![CDATA[이 채용 공고에 관심이 있고 해당 자격 요건을 갖추었다고 판단되시는 분은 codewiz 앳 wellbia 닷 com으로 이력서와 자기소개서를 메일 주시면 됩니다. 자격 요건 C/C…]]></description><link>https://jiniya.net/ng/2020/05/recruit/</link><guid isPermaLink="false">https://jiniya.net/ng/2020/05/recruit/</guid><pubDate>Tue, 12 May 2020 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;이 채용 공고에 관심이 있고 해당 자격 요건을 갖추었다고 판단되시는 분은 codewiz 앳 wellbia 닷 com으로 이력서와 자기소개서를 메일 주시면 됩니다.&lt;/p&gt;
&lt;h3&gt;자격 요건&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;C/C++ 시스템 프로그래머&lt;br&gt;
윈도우, 리눅스 둘 중 하나는 잘 알아야 합니다.
CreateThread와 fork 둘 중 하나는 제대로 호출할 줄 아는 분이면 좋겠습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;리버스 엔지니어&lt;br&gt;
윈도우 시스템에 대한 이해가 있는 분석가를 모집 중입니다.
가상 메모리 구조, 실행 파일 구조, x86/64 어셈블리어에 대한 이해가 있는 분을 채용 중입니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;장점&lt;/h3&gt;
&lt;p&gt;(주)웰비아닷컴은 세계적으로 얼마 안되는 상용 게임 보안 제품을 만드는 회사입니다. a) 대체로 이쪽의 커리어를 쌓기 위해서는 한국, 독일, 핀란드 중에 한곳에 연고가 있는 것이 유리합니다. 한국에 계시다구요? 네 그러시면 저희와 함께 일하는 것이 좋을 것 같습니다. b) 저희는 전세계적으로 가장 인기있는 게임을 제작하는 게임 벤더들과 작업하고 있습니다. 그렇기에 최신의 최고급 해킹 테크닉과 방어 메커니즘을 가장 빠르게 배울 수 있습니다. 또한 그만큼 성장할 기회도 많다는 걸 의미하기도 합니다. c) 저희는 열린 회사입니다. 여러분이 접근할 수 없는 소스 코드는 없습니다. 모든 걸 볼 수 있고, 모든 걸 바꿀 수 있습니다. d) 야근이 없습니다. 99.478% 이상의 확률로 칼퇴근을 보장합니다. e) 직원을 어린이 취급하지 않습니다. 모두 똑같은 성인으로 존중합니다. 언제 쉴지 언제 일할지는 충분히 본인이 결정할 수 있다고 판단하고 그 의사를 존중합니다. 다른 것들도 마찬가지입니다.&lt;/p&gt;
&lt;h3&gt;단점&lt;/h3&gt;
&lt;p&gt;30명 미만의 작은 기업입니다. 연봉이 높지 않습니다. 박봉이라고 생각하지는 않지만 배달의민족 채용 공고처럼 그걸 강점으로 내세울 수 있는 수준은 아닙니다. 폭발적으로 성장하는 기업은 아닙니다. 물론 그렇다고 정체된 회사는 아니지만 쿠팡 채용 공고처럼 압도적으로 높은 성장률을 강점으로 내세울 수준은 아닙니다.&lt;/p&gt;
&lt;h3&gt;사족&lt;/h3&gt;
&lt;p&gt;덧1) 긍정적인 분만(!!) 채용합니다. 부정적인 성격이시면 저희와는 잘 맞지 않을 수 있습니다. 기본적으로 세상이 더 나은 방향으로 발전하고 있다고 확고하게 믿는 분들과 함께 일하는 것을 선호합니다.&lt;/p&gt;
&lt;p&gt;덧2) 관련 경력이 15년 이상인 올드스쿨 멤버들도 채용하고 있습니다. 이쪽 분야의 아주 오래된 고유 경력을 가지고 계시고 본의 아니게 경력을 이어나가기가 힘들어진 엔지니어 분이라면 언제든지 연락 주시면 좋겠습니다. 저희는 해당 경력을 완전하게 존중합니다. RESPECT!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] 2019-06-26]]></title><description><![CDATA[지난 4년을 회고한다. 어쩌다 여기까지 오게 되었나? 무엇이 문제였나? 앞으로 어떻게 살아야 하는가? 내가 나를 몰랐다. 미래]]></description><link>https://jiniya.net/2019/06/2019-06-26/</link><guid isPermaLink="false">https://jiniya.net/2019/06/2019-06-26/</guid><pubDate>Wed, 26 Jun 2019 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;지난 4년을 회고한다.&lt;/p&gt;
&lt;p&gt;어쩌다 여기까지 오게 되었나?&lt;br&gt;
무엇이 문제였나?&lt;br&gt;
앞으로 어떻게 살아야 하는가?&lt;/p&gt;
&lt;p&gt;내가 나를 몰랐다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;미래&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 책임진다는 말...]]></title><description><![CDATA[오래전 일이다. 먹고 살기 힘들어 인건비 따먹기 SI 사업을 하던 때였다. 당연한 얘기지만 SI…]]></description><link>https://jiniya.net/ng/2018/11/take-responsibility/</link><guid isPermaLink="false">https://jiniya.net/ng/2018/11/take-responsibility/</guid><pubDate>Thu, 08 Nov 2018 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;오래전 일이다. 먹고 살기 힘들어 인건비 따먹기 SI 사업을 하던 때였다. 당연한 얘기지만 SI 사업에는 적은 리소스를 투입하고 최고의 효과를 얻어야 하던 시절이기도 했다. 그래야 시간이 생기고 그래야 우리 솔루션도 돌 볼 수 있기 때문이다. 그 당시 과제의 한 모듈을 담당했던 개발자가 자꾸 직접 구현해서 될 일이 아닌 것을 직접 구현하려고 했다. 문자열 인코딩을 처리해야 하는 모듈이었다. 문자열 인코딩만 본다면 개발자가 직접 구현해도 될 것 같지만 온갖 코드페이지를 다 처리해야 했기에 또 그렇게 간단하진 않은 모듈이었다. 그래서 왠만하면 오픈소스를 쓰라고 검토해서 알려주었다. 다소 C++ 중2병 환자가 만든 소스 코드 같아 보였지만 코드 내부를 봤을 때 온갖 코드페이지를 잘 처리할 수 있을 만큼 충분히 복잡하게 만들어져 있었다. 안타깝게도 문제의 개발자는 온몸으로 거부했다. 스스로 직접 구현할 수 있고, 그 소스는 너무 복잡하다고 했다. 그러고 덧붙였다. 잘못되면 책임지겠다.&lt;/p&gt;
&lt;p&gt;뭐 뻔한 결말이지만 그 친구가 만든 코드가 잘 되지도 책임을 지지도 못했다. 직접 만든 코드는 우리가 실시한 간단한 테스트는 통과 했지만 의뢰한 업체의 온갖 테스트에는 속속 문제가 발생했다. 러시아어에서 비롯된 문제는 온갖 if문을 달아가며 언어 하나가 나올 때마다 땜빵을 해봤지만 잘 되지 않았다. 결국 처음부터 그 오픈소스 코드를 가져다 쓰는 코드로 바꾸고서야 문제가 해결됐다. 하지 않아도 될 고생을 한 것도 화가 났지만, 우리에게 천금같았던 시간을 낭비했다는 데 더 많은 울화가 치밀었다.&lt;/p&gt;
&lt;p&gt;책임진다는 말을 우리는 너무 쉽게 하는 경향이 있다. 아마도 그 직원은 두 가지 의미에서 책임진다는 말을 했을 가능성이 높다. 1) 책임지고 그만두겠다. 2) 잘못되면 내가 그 돈을 메꾸겠다. 대체로 1번의 의도로 말하는 경향이 많지만 그건 그 어떤 것에 대한 책임도 되지 않는다. 회사 입장에서 책임이란 말은 그저 문제가 없는 상태로 일이 잘 처리되는 것 외에는 어떠한 방법도 없기 때문이다. 그런 맥락에서 2번도 해법은 아니다. 금전적 손실은 메꿀 수 있겠지만 일을 맡긴 업체와의 관계는 보상이 불가능하니 말이다. 사실 돈을 메꾼다는 것도 불가능한 상황이긴 했다. 그 친구가 숨도 안 쉬고 5년을 일해도 메꿀 수 없는 규모였다.&lt;/p&gt;
&lt;p&gt;시간이 많이 흘렀다. 이 어리고 서툴렀던 시절의 추억담이 종종 떠오른다. 그 친구 입장에 내가 서 있다는 생각이 들어서다. &quot;방향이 틀리면 속력은 아무런 의미가 없다&quot;라는 간디의 말도 다시금 생각나는 요즘이다. 아주 사소한 나의 잘못된 생각 하나에 시간과 속력이 더해져 우리는 완전 엉뚱한 장소에 도착해 버렸다. 이제는 내가 잘못 생각한 일들을 책임지고 바로 잡아야 하는 시간인 것 같다는 느낌. 사실 앞서도 말했지만 책임진다는 건 그 어떤 형태로도 불가능하다. 그 말을 꺼낸 순간 우리는 책임질 수 없는 상황에 도달한 경우가 더 많이 때문이다. 그럼에도 최선을 다해야 한다. 그게 그나마 나의 잘못을 조기에 알려준 현명한 사람들에 대한 예의일테니까…​ 머리가 나쁘면 손발이 고생이고, 똥인지 된장인지 먹어봐야 안다.&lt;/p&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/bo_efYhYU2A?si=BljkyVBznwiFGqbr&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;</content:encoded></item><item><title><![CDATA[[소고] 재현 가능한 빌드, 재현 가능한 시드]]></title><description><![CDATA[#0 최근에 덤프 파일 심볼이 맞지 않는 문제가 있었다. wow64 프로세스 덤프를 뜬 건데 .reload를 해봐도 심지어 다운로드 받은 심볼을 지우고 다시 받아도, windbg를 업그레이드 해봐도 소용 없었다. 항간에 windows 10 rs…]]></description><link>https://jiniya.net/ng/2018/07/reproducible-builds/</link><guid isPermaLink="false">https://jiniya.net/ng/2018/07/reproducible-builds/</guid><pubDate>Mon, 23 Jul 2018 12:00:01 GMT</pubDate><content:encoded>&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;최근에 덤프 파일 심볼이 맞지 않는 문제가 있었다. wow64 프로세스 덤프를 뜬 건데 .reload를 해봐도 심지어 다운로드 받은 심볼을 지우고 다시 받아도, windbg를 업그레이드 해봐도 소용 없었다. 항간에 windows 10 rs4에서 심볼이 잘 안 맞춰진다는 이야기도 있어서 그런건가 싶어서 포풍 검색을 해봤지만 뾰족한 수가 없었다. 증상은 심플했는데 wow64 프로세스임에도 ntdll이 하나만 있었고, 로드된 dll 목록의 타임스탬프가 invalid라고 나왔다. 그리고 ntdll의 함수를 디스어셈블 하면 이상한 코드들이 나왔다. 여튼 그런 증상…​ 그렇게 퇴근 시간은 다가오고 오늘의 일을 내일로 미루고 퇴근을 했다…​&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;다음날. 덤프를 다시 열어서 방망이 깎는 노인이 그랬듯 출력되는 메시지를 한줄 한줄 꼼꼼히 쳐다 보았다. 그랬더니 이상한 점이 보였다. 덤프를 열면 통상적으로 운영체제 버전이 표기되는데 64비트 운영체제가 아니라 32비트 운영체제로 나오는 것이었다. 순간, 많은 정황을 고려해 보았을 때 덤프를 64비트 PC에서 32비트 덤프 생성 도구로 덤프를 뜬 것이 아닐까라는 생각이 들었다. 덤프를 생성한 직원에게 물어보자 그렇게 생성했다고 하길래 64비트로 다시 생성해 달라고 했다. 새롭게 만들어진 덤프은 기다렸다는 듯이 잘 동작했다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;뭐 이 즈음에는 대체로 내가 원한 모든 문제는 다 해결이 되었지만 그럼에도 불구하고 찜찜한 점이 하나 있었는데, 그건 여전히 dll들의 타임스탬프가 invalid라고 나오는 문제였다. 다른 모든 것은 기대한대로 동작했지만 타임스탬프 값은 여전히 오리무중…​ 다시 포풍 검색을 했다. 나에게 항상 해답을 주시는 레이몬드 첸 횽님께서 벌써 올해 1월에 관련 질문에 대한 답을 올려 놓으셨다. 이렇게 바지런 하시니 몸둘 바를…​&lt;/p&gt;
&lt;p&gt;해당 글을 통해 알게 된 썰은 이렇다. 윈도우 10부터 재현 가능한 빌드(reproducible builds)로 방향을 정했고, 그 정책의 일환으로 타임스탬프를 타임스탬프가 아닌 해시 값으로 변경했다는 것이다. 재현 가능한 빌드라는 건 한 마디로 정리하면 동일 소스 코드로 컴파일을 하면 동일 바이너리가 생성된다는 것을 보장한다는 개념이다. 즉, 니가 소스 코드를 한 줄도 안 고쳤다면 넌 어디에서건 다시 컴파일해도 동일한 바이너리를 가지게 된다는 의미다. 이렇게 하는 이유는 당연히 버그에 보다 빠르게 대응하기 위함이겠거니…​ 내지는 높으신 분의 개취…​&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;여기까지 오자 몇 해 전 우리에게 혁신적인 개념을 소개했던 직원의 아이디어에 대한 이름을 이제야 붙이 수 있게 되었다. 그 이름은 다름아닌 재현 가능한 시드(reproducible seed) 정도가 되겠다. 적어도 4-5년은 거슬러 올라가야 하는 이야기다. 우리는 당시 아주 난해한 버그를 마주하고 있었다. 100번 정도에 한 번씩 게임이 시작 시점에 크래시가 나는 문제였다. 지금에 비하면 아주 단촐했던 테스트 인력을 가지고 있던 당시로써는 문제를 발견해 낸 것만 해도 대단한 것이었다. 하지만 그 문제를 해결하는 것은 발견하는 것 이상의 노력이 필요했다. 재현을 하려면 100번을 실행해야 했기 때문이다. 어쨌든 그 당시 테스트 인력의 도움으로 어렵사리 덤프를 확보했다. 하지만 아무도 문제를 찾지 못했다. 딱 미제(미해결 과제)가 되기 좋은 사안이었는데 어디선가 혜성같이 등장한 구원 투수가 마법같이 문제의 원인을 알아냈다. 랜덤이 문제였다. 랜덤 결과가 특정 값이 될 경우 메모리가 오버래핑되는 문제가 있었던 것이다. 그 확률이 1/100정도 됐던 모양이다.&lt;/p&gt;
&lt;p&gt;그때 그 덤프에서 문제를 찾은 직원은 우리가 업무 특성상 랜덤을 많이 사용한다면 재현 가능한 시드 시스템을 도입해야 한다는 것을 주창했다. 그 메커니즘은 재현 가능한 빌드와 동일한데 시작 시에 랜덤 시드를 지정하면 프로그램 전체가 그 시드에 동기화되어서 동작하는 것을 보장하는 것을 의미한다. 이렇게 말하면 어려운데 그냥 쉽게 코드로 말하면 전역 의사 난수 시스템을 사용하고 시작 시에 시드를 고정할 수 있는 방법을 제공해야 하는 것을 말한다.&lt;/p&gt;
&lt;p&gt;이렇게 할 경우 어쩌다 한 번 크래시 났을 때, 시드를 알고 있다면 그 다음에는 굳이 100번 실행할 필요가 없다. 해당 시드를 넣고 실행하면 동일한 실행 결과를 보장하기 때문이다. 랜덤이 문제라면 똑같이 문제가 발생할 것이다. 즉, 버그를 찾기가 엄청 쉬워지는 장점이 있다. 여기에 플러스 퍼징 테스트를 하기가 아주 쉬워진다. 그 시드 값만 순차적으로 증가시켜 가면서 쭉 실행을 시키면 문제가 있는지 없는지 손쉽게 찾을 수 있으니 말이다.&lt;/p&gt;
&lt;p&gt;찾아낸 것도 대단하지만 그런 문제를 두 번 다시 겪지 않기 위해서 재현 가능한 시드라는 것을 주창했다는 것 또한 더 대단한 일이 아닐 수 없다 하겠다. 하지만 현실은 언제나 바쁘기에 그의 의견은 아직도 구현되진 못했다. 조선 최고의 천재라 일컬어지는 율곡 이이 선생의 십만양병설이 떠오르는 시점이 아닐 수 없다.&lt;/p&gt;
&lt;p&gt;윈도우 10도 재현 가능한 빌드를 사용하는 마당에 오래 전 그 직원이 주창했던 아이디어를 반성하는 의미에서 구현해야 겠다는 생각이 든다. 구슬이 서 말이라도 꿰어야 보배고, 아이디어가 아무리 많아도 구현이 없으면 공허한 메아리일 뿐이니 말이다.&lt;/p&gt;
&lt;h3&gt;#4&lt;/h3&gt;
&lt;p&gt;다시 다음날. 반성하는 의미에서 우리가 사용하는 랜덤의 호출 경로를 추적하는 작업을 해 보았다. 그러다보니 이 문제가 생각보다 쉽지 않다는 것을 알게 되었고, 똑같은 짓을 몇 년 전에도 했다는 사실을 알게 되었다. 메멘토 같은 상황…​&lt;/p&gt;
&lt;p&gt;전말은 이렇다. 일반적으로 사용하는 rand 함수는 시드를 가지고 있고 멀티스레드 환경에 최적화하기 위해서 해당 시드를 스레드 로컬 스토리지에 저장한다. 이 말은 이걸 전역으로 한 번 초기화 한다고 해서 해당 값에 바인딩된 rand를 호출하는 모든 상황에 적용되는 것은 아니라는 것을 의미한다. 즉, 제대로 돌아가게 만들기 위해서는 모든 스레드의 시작 시점에 해당 시드로 초기화를 하는 루틴을 삽입해야 한다는 것을 의미한다. 응당 그게 쉽지 않으니 달리 생각할 수 있는 방법은 의사 랜덤 생성 함수를 새롭게 만드는 방법을 생각해 볼 수 있다. 이렇게 구현할 경우 스레드 안정성을 보장하기 위해서는 락을 쓰거나 락리스한 방법으로 좁혀진다. 그런데 랜덤 값 하나 만들겠다고 락을 쓰는 것은 뭐 빈대잡겠다고 초가삼간 태우는 격이니 결국은 락리스한 랜덤으로 방법은 더 좁혀진다. 그럼 그런 것을 내가 직접 만들 수는 없으니 구글에 검색을 하게 된다. 그렇게 나온 결과물을 쳐다 보고 있으면 그런 결론에 도달한다. 아~ 다른 일부터 해야겠구나…​&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] 송도 지열군 스튜디오 돌상 사진 촬영기]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2018/05/one-year/</link><guid isPermaLink="false">https://jiniya.net/ng/2018/05/one-year/</guid><pubDate>Mon, 14 May 2018 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;송도(인천)는 살기에 정말 거의 단점이 없는 동네인데 그 중에도 특히 최고의 강점 중에 하나가 거의 모든 인프라가 굉장히 잘 갖춰져 있다는 점이다. 홈플러스, 오네스타, 현대 프리미엄 아울렛, 트리플 스트리트로 이어지는 몰들의 향연에 한 번 빠지면 도대체 여긴 어딘가 싶다. 특히나 평일에는 사람도 많이 없어서 정말 좋다. 돈많은 아줌마가 살기에는 정말이지 최고의 동네라 할 수 있다.&lt;/p&gt;
&lt;p&gt;스튜디오도 그렇다. 네이버 검색 결과 송도 내에 스튜디오가 몇 개 있는 것으로 보였다. 그 중에서 다른 블로그를 보다 보니 지열군 스튜디오 사진이 괜찮고, 집과도 가까워서 장모님 칠순 가족 사진을 지열군에서 찍기로 했다. 가족 사진 찍으니 서비스 컷을 두 컷 주신다고 하셔서 한 컷을 애들 돌상 촬영을 해봤다. 첫째 애도 돌잔치는 집에서 하고 사진은 분당에 있는 스튜디오에서 전통 돌상 사진으로 찍었었다. 왠지 돌은 전통이 더 어울리는 듯한 느낌이다.&lt;/p&gt;
&lt;p&gt;첫째 아이 사진을 강남, 이태원, 마포, 분당 등지에서 찍어 봤는데 대부분의 스튜디오가 굉장히 열악하기 그지 없었다. 네비를 찍고 가도 찾기 어려운 건 기본이고, 주차 공간은 거의 제로에 가까워서 근처에 불법 주차를 해야 하는 경우가 대부분이었다. 그렇지 않은 경우는 발렛을 제공해 주기는 했는데 이 경우에는 발렛비를 별도로 내야 했다. 건물도 일반 가정집을 개조한 경우가 많아서 사진 촬영을 하다 보면 아래 위층을 왔다 갔다 해야 하는 경우가 많아서 아직 잘 걷지 못하는 애들을 데리고 사진을 찍기란 여간 어려운 일이 아니었다. 찍다가 부모도, 아이도 파김치가 되는 건 일상적인 풍경…​&lt;/p&gt;
&lt;p&gt;하.지.만. 지열군 스튜디오는 이런 모든 불편함이 없었다. 일단 아파트형 공장 같은 건물의 한 호실에 모든 스튜디오가 갖춰져 있어서 계단 사용할 일이 없다. 애들 안고 이동을 하지 않아도 된다는 의미다. 인테리어도 요즘 새로 한 것 같아서 상당히 깔끔하다. 특히 창가쪽 벽면 전체에 인테리어 형태의 쇼파가 쫙 붙어있는데 정말 좋았다. 앉아서 쉬기도 좋고, 애들 뭔가 뒷정리 해줄때도 상당히 유용했다. 아파트형 공장 같은 건물이기 때문에 주차 문제는 애시당초 없다. 게다가 무려 300만원에 달하는 디트로네를 타 볼 수 있다. 물론 사장님께서 허락해 주셔야 하는데 애들이 칭얼 거리면 사장님께서 흔쾌이 탈 수 있도록 배려해 주셨다. 우리도 두바퀴를 탔는데 첫째가 참 좋아했다. 집에 있는 30만원짜리 싸구려 아우디 전동차와는 뭔가 격이 다른 느낌 ㅋㅋㅋ~ 이런 모든 장점을 가진 스튜디오가 무려 우리 집에서 5분 거리. 이러니 송도를 사랑하지 않을 수 없다.&lt;/p&gt;
&lt;p&gt;아직 정신 못차리는 애들이 둘이나 있기에 사진 촬영은 정말 쉽지 않았음에도 인내심을 가지고 촬영을 잘 해 주셨다. 특히 돌상 찍을 때는 애들 컨디션이 나락 상태였음에도 최선을 다해서 찍어 주셔서 고마울 따름이었다. 전통 돌상 촬영은 사실 별반 특별할 것이 없다. 돌상 아이템이 얼마나 잘 갖춰져 있느냐와 때깔 좋은 한복이 얼마나 갖춰져 있느냐의 승부인데, 사장님 말씀으로는 새로 시작하는 세트라 특별히 신경써서 고급 한복을 많이 가져다 놓을 예정이라고 했다. 그리고 요즘 시작하는 세트니 당연히 색감이나 이런 것들이 오래된 스튜디오에 있는 한복보다 곱다. 실제로 서비스 컷으로 찍은 한복 때깔이 첫애 때 분당서 돈 주고 촬영한 한복보다 훨씬 더 고급져 보였다.&lt;/p&gt;
&lt;p&gt;전통 돌상 촬영의 다른 한 부분은 세트 장이 얼마나 다양하게 꾸며져 있느냐가 있는데 지열군 스튜디오는 아직까지는 일반 돌상이 전부다. 전통 가옥으로 된 스튜디오 장은 없다. 하지만 아.마.도. 돌상 촬영을 하게 되는 경우에는 일반 스튜디오에서 다른 사진을 함께 찍을 수 있을 것으로 추정된다. 그리고 중요한 가격 정보는 와이프가 모두 얘기해서 알 길이 없다. 아마 친절하신 사장님 마인드를 봐서는 가격도 많이 착할 것으로 예상된다. 어쨌든 송도나 송도 근처 인천에 계신 분들이라면 애들 사진 찍기에 강추할만한 스튜디오다. 서울에서 오기에도 괜찮다. 위에서 언급한 홈플러스, 오네스타, 현대 프리미엄 아울렛, 트리플 스트리트 바로 옆이기 때문에 사진 찍고 몰에 가서 쇼핑도 하고, 맛난 것도 먹고, 애들 데리고 놀기도 좋다. 애들 사진은 가급적 인터넷에 안 올리는 것이 좋다고 생각하지만 사진이 넘나 잘나와서 몇 장 올려본다. 어서어서 무럭 무럭 자라라. 얘들아…​&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./b1.jpg&apos; data-alt=&apos;Figure 1. 둘째, 사장님 포스, 잘 찍고 있지? ㅋ&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/e840e63db2712fa0f60b6bb44ca798f8/56d4e/b1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 77.89473684210526%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAQABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIFBP/EABUBAQEAAAAAAAAAAAAAAAAAAAEA/9oADAMBAAIQAxAAAAHe01hpkkL/xAAZEAEAAgMAAAAAAAAAAAAAAAABAAIREiH/2gAIAQEAAQUC2JtwmeZa2Sw//8QAFhEBAQEAAAAAAAAAAAAAAAAAABES/9oACAEDAQE/AYy//8QAFhEBAQEAAAAAAAAAAAAAAAAAABES/9oACAECAQE/Aa0//8QAGBAAAwEBAAAAAAAAAAAAAAAAAAEREEH/2gAIAQEABj8C2dGqSn//xAAcEAACAgIDAAAAAAAAAAAAAAABEQAhMUFRYYH/2gAIAQEAAT8h4jUQs2IT2vY1TsCW8QFh7odQ2y7U/9oADAMBAAIAAwAAABB0P//EABYRAQEBAAAAAAAAAAAAAAAAAAABEf/aAAgBAwEBPxCOn//EABURAQEAAAAAAAAAAAAAAAAAABAx/9oACAECAQE/EIH/xAAcEAEAAgMBAQEAAAAAAAAAAAABABEhMUFRYXH/2gAIAQEAAT8QoM1Dd7+zqAcYIVCvTpBUhDgCYb4DbyJct35pannqpF4UZoUv9n//2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 1. 둘째, 사장님 포스, 잘 찍고 있지? ㅋ&apos; title=&apos;&apos; src=&apos;/static/e840e63db2712fa0f60b6bb44ca798f8/56d4e/b1.jpg&apos; srcset=&apos;/static/e840e63db2712fa0f60b6bb44ca798f8/8ccab/b1.jpg 190w,
/static/e840e63db2712fa0f60b6bb44ca798f8/ea4c8/b1.jpg 380w,
/static/e840e63db2712fa0f60b6bb44ca798f8/56d4e/b1.jpg 640w&apos; sizes=&apos;(max-width: 640px) 100vw, 640px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 1. 둘째, 사장님 포스, 잘 찍고 있지? ㅋ&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./b2.jpg&apos; data-alt=&apos;Figure 2. 첫째랑, 둘째랑 함께, 어서어서 무럭 무럭 자라길…​&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/3a1dab3b664379ac4fc74862e1389c08/56d4e/b2.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 66.84210526315789%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMEAf/EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAF7JNmqBQn/xAAaEAACAwEBAAAAAAAAAAAAAAAAAQIDERIT/9oACAEBAAEFAo2JnaO0yNeSzX5o/8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQMBAT8BiP/EABURAQEAAAAAAAAAAAAAAAAAAAAR/9oACAECAQE/Aar/xAAZEAEAAgMAAAAAAAAAAAAAAAABABARITH/2gAIAQEABj8Ca1Az2Ff/xAAbEAACAgMBAAAAAAAAAAAAAAAAAREhMWGxcf/aAAgBAQABPyGkTsVynArLSjmsPo7Im4bXh//aAAwDAQACAAMAAAAQx8//xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAwEBPxAl/8QAFREBAQAAAAAAAAAAAAAAAAAAAAH/2gAIAQIBAT8QZL//xAAbEAEBAAIDAQAAAAAAAAAAAAABEQAhQWGBsf/aAAgBAQABPxBZblqej5m4FdvMoXHPeQjscRNChuV2TzGUZaCgZ//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 2. 첫째랑, 둘째랑 함께, 어서어서 무럭 무럭 자라길…​&apos; title=&apos;&apos; src=&apos;/static/3a1dab3b664379ac4fc74862e1389c08/56d4e/b2.jpg&apos; srcset=&apos;/static/3a1dab3b664379ac4fc74862e1389c08/8ccab/b2.jpg 190w,
/static/3a1dab3b664379ac4fc74862e1389c08/ea4c8/b2.jpg 380w,
/static/3a1dab3b664379ac4fc74862e1389c08/56d4e/b2.jpg 640w&apos; sizes=&apos;(max-width: 640px) 100vw, 640px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 2. 첫째랑, 둘째랑 함께, 어서어서 무럭 무럭 자라길…​&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./b3.jpg&apos; data-alt=&apos;Figure 3. 첫째 짬컷, 이러니 딸바보 안 될래야 안 될 방법이 없다…​&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 427px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/1cea6b6296ca22fa0f20de4599064524/a2c7b/b3.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 150%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAeABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQFAQP/xAAWAQEBAQAAAAAAAAAAAAAAAAAAAQL/2gAMAwEAAhADEAAAAbfKW1JSIYO41rUgoEf/xAAbEAADAQEAAwAAAAAAAAAAAAABAgMRABASE//aAAgBAQABBQL2GbiclKcLMCzULRmR1IBj8mXg2+CRv//EABURAQEAAAAAAAAAAAAAAAAAABAR/9oACAEDAQE/ASn/xAAWEQEBAQAAAAAAAAAAAAAAAAAAERD/2gAIAQIBAT8BXI//xAAdEAACAQQDAAAAAAAAAAAAAAAAARECECExEjKB/9oACAEBAAY/AjVuoqWsD4vBNRhwRE+30f/EABsQAAMAAwEBAAAAAAAAAAAAAAABESExQVEQ/9oACAEBAAE/IWzB8KTuttlXpCpixDZTlnYrjIpo6tUsgdRGmgrgq8+Y/9oADAMBAAIAAwAAABD/AM3P/8QAGhEAAgIDAAAAAAAAAAAAAAAAABEBMUFRYf/aAAgBAwEBPxBTY50JkfT/xAAWEQEBAQAAAAAAAAAAAAAAAAARAAH/2gAIAQIBAT8QchGBC//EAB4QAQADAQADAAMAAAAAAAAAAAEAESExQWFxUYHR/9oACAEBAAE/EHFLdjfEsQtgPNhzpnuWgEq3OlfyAxlLL37Em24es/cvDsgBp4X3K1HWtdfzF1w8CCfIZ1kXG1DUq1P/2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 3. 첫째 짬컷, 이러니 딸바보 안 될래야 안 될 방법이 없다…​&apos; title=&apos;&apos; src=&apos;/static/1cea6b6296ca22fa0f20de4599064524/a2c7b/b3.jpg&apos; srcset=&apos;/static/1cea6b6296ca22fa0f20de4599064524/8ccab/b3.jpg 190w,
/static/1cea6b6296ca22fa0f20de4599064524/ea4c8/b3.jpg 380w,
/static/1cea6b6296ca22fa0f20de4599064524/a2c7b/b3.jpg 427w&apos; sizes=&apos;(max-width: 427px) 100vw, 427px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 3. 첫째 짬컷, 이러니 딸바보 안 될래야 안 될 방법이 없다…​&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;아, 지열군 스튜디오를 처음 방문한다면 주차장 찾는데 조금 난항을 겪을 수 있다. 네비가 알려주는 곳에 주차장 입구가 없기 때문이다. 정확한 주차장은 아래 위치에 있다. 워낙 건물이 길어서 모르면 다소 헤맬 수 있다. 아래 그림의 빨간 부분이 주차장 입구다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./map.png&apos; data-alt=&apos;Figure 4. 빨간데가 주차장 입구다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/fbb288434c14bebec9991e27338255fe/0f09e/map.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 83.6842105263158%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAAA7DAAAOwwHHb6hkAAADsElEQVR42k2UCW/bRhCF+d+L/oQ2RRq4QOvUTRO7cdPYiWXlsAvbjS1LlqyLFO/7piieEqXX4QItQmCw0i717ZuZN+IO7n/Ay8EztOv+3fcU3+F4tI+3k9/QnfwBOzjHet1DXWlQ3SF0X8QyiRAGLtJlgCyNWRRZwoJ72W9BT/F7/xl+7T3B87snOHzYw+vRAU4e3iAvT7FZL1AUOyiCClt3YOoWLMOGF3iIkwxFvUOz3WFLwWXle1yJz3HQ+5FFq/bPx328unsNN+4Au/fICh6eG0LTVHieB8dxYRom7XkwDANBQEqznCID5/sPaOrPsJNjnI5/wosBQXtHmFvvAHyC7B+BdwdwrBCT6RSiJGKVrhCGIaIoYpA4jkndFid/HYPjpQVEZUp1+UJqupiZpxipLewDkvwMndnPUIIpkriAqulQVRWqosKyLEiSxNZ2r2kaAkfgRIXHQhZYKPoAbniBHYF32w8woxMcP+4xoB+EUCwVpkf1cy0kScLUtSrTNKXf7NA+DCgxKI/BdIws/0i3nWOzOce26VK6hxDdB2R1CWtpw0ldRHmMuEiwrFJ8/bTQ/4H34zmC6G/aPkMUX0MzhkiW12jWJ8hznkpSwKP0NnlO9shYiv+p+vrhVL1VxkMxbxlsmV4ytQtZhCAJMOxbFKWMut6iqiry5IY1oNk07HsbG9qryvZsDa43FjDiB1Szc/LaJ0gqdZKpntFnHrw4g+s5dFZRrZa0rgjYoCxL2I4H13aRUT01XaM6++De3UzopY9EPyfAkFTxBJwzaBuCPCVQgnVVIF/Z9G6f1Haxqa+xShSI5ghd/hU+L45wIR6RD6NLlqphDSgCyJoMURUILoCXqLuhR7VqkEQGQt9Gmc9Q0+Vn/R5WeQdxdoYr6QVOpr/gzXCPgHEXtnsN3fKQrnJESQrdtLBQBFiOzsapyENS59PMmkxdls7woKZYZiNqWofq2SFrvcXhP0/B6c4FJqKFql4jiJdYEtT1Q0pXIuussa4LgpSkLKTCX6IqHlFvKhjjW8z6t+QEhf44boBtBysaY46Xb+F4MWRFBi+QKtshdSLyIiNYTspcgsVkE5e6OYdtiBjOR4i+/Qb53Q2ox3SeIM8EOr8CZ1gGmwJRlmm0NExmU0o7ojRq8pvPXi7yKdnjhi4gpdTlwDexLnPKgGxTrmgvpqaVEK17cIK8IK85NCEVbC8gtS5NyIZubFNMCabTekFwjSKg9DJmYFGYYNi/YVk0dQ3NH2NufsG/lXzdbiXa+tEAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 4. 빨간데가 주차장 입구다.&apos; title=&apos;&apos; src=&apos;/static/fbb288434c14bebec9991e27338255fe/0f09e/map.png&apos; srcset=&apos;/static/fbb288434c14bebec9991e27338255fe/08678/map.png 190w,
/static/fbb288434c14bebec9991e27338255fe/2edd7/map.png 380w,
/static/fbb288434c14bebec9991e27338255fe/0f09e/map.png 640w&apos; sizes=&apos;(max-width: 640px) 100vw, 640px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 4. 빨간데가 주차장 입구다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 완벽한 회사...]]></title><description><![CDATA[설 연휴에 SBS…]]></description><link>https://jiniya.net/ng/2018/02/perfect-company/</link><guid isPermaLink="false">https://jiniya.net/ng/2018/02/perfect-company/</guid><pubDate>Mon, 19 Feb 2018 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;설 연휴에 SBS 스페셜 다큐를 한 편 봤다. &quot;검색 말고 사색, 고독연습&quot;이라는 제목의 다큐였다. 제목 그대로 현대인들은 너무나 고독한 시간이 없고, 스스로 생각을 안 하고 산다는 그런 내용이다. 그리고 고독한 시간 속에서 진정한 내면의 문제를 해결할 수 있다는 아주 교훈적인 내용의 다큐. 뻔한 이야기긴 한데 내가 감탄한 부분은 다른데 있었다. 그건 다름 아닌 해당 내용과 같이 소개된 회사였다. 아래 멘트로 소개되는 회사. 특히 소프트웨어 회사라 어떤 회사인지 더 궁금하기도 했다.&lt;/p&gt;
&lt;p&gt;건설 설계 소프트웨어 분야 세계 1위, 무스펙, 무징벌, 무상대평가, 무정년, 이른바 4무 경영, 5성급 호텔 쉐프가 매일 아침, 점심, 저녁 제공, 1인당 연간 식비만 1천만원 이상 지출, 회사에서 운영하는 20일의 자아성찰 프로그램 (제주도에서 20일간 묵으며 자아 성찰을 하는 프로그램, 유급)&lt;/p&gt;
&lt;p&gt;몇몇 인상 깊었던 대표의 멘트, &quot;제 인생으로 온 사람들이잖아요. 모두 행복했으면 좋겠습니다.&quot;, &quot;개나리는 개나리대로, 진달래는 진달래대로 각자 자신의 꽃을 아름답게 피울 수 있도록 만들어 주는 회사가 됐으면 좋겠습니다.&quot; (대충 기억나는 대로 적은 거라 다를 수도 있음)&lt;/p&gt;
&lt;p&gt;당연한 얘기지만 다큐에서는 회사명이 직접 거론되지는 않았다. 오늘 궁금해서 검색해보니 금방 나온다. 판교에 있는 마이다스아이티라는 회사. &lt;a href=&quot;https://insight.wanted.co.kr/company/059fac2b8cb41ad377349994df59f6e967f285b0&quot;&gt;궁금해서 한 번 찾아봤다.&lt;/a&gt; 세상에 완벽한 회사는 존재하지 않는다. 양쪽의 입장 사이에는 너무나 극명한 차이가 있기 때문인 것 같다. 서로 약간씩 물러나 상대의 입장을 이해하기란 여간 쉬운 일이 아닌 것 같다.&lt;/p&gt;
&lt;p&gt;몇 해 전 구글 코리아에서 제법 오래 근무하다 그만 둔 형이 한 이야기가 떠올랐다. 입사할 때 그 회사는 정말 좋은 회사였는데, 그만둘 때에는 그런 장점들이 많이 퇴색해진 것 같다고. 그리고 이어서 떠오르는 최근에 이슈가 된 &lt;a href=&quot;https://www.yna.co.kr/view/AKR20180207059700091&quot;&gt;페이스북에서 CEO 개인에 관한 여론을 조사하는 직원을 고용했다던 기사&lt;/a&gt;가 생각나기도 했다. 아이언맨으로 칭송되는 엘론 머스크의 테슬라와 스페이스엑스도 말도 안 되게 높은 업무 강도로 유명하다는 이야기도 자주 들린다. 아마존 대표 베조스의 막말은 언급하면 입 아픈 정도.&lt;/p&gt;
&lt;p&gt;회사는 회사고, 나는 나다. 직원들에게는 그저 다니는 회사가 블랙 회사가 아니면 만족하고 다닐 법 하다는 이야기를, 대표님들에게는 그저 일 적게 시키고 돈 많이 주면 그게 좋은 회사라는 이야기를 해주고 싶다.&lt;/p&gt;
&lt;p&gt;엄마가 늘 하시던 말씀이 생각나는 시점. 물 좋고, 정자 좋은 곳은 세상에 없단다…​&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 트레이드 오프]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2018/01/trade-off/</link><guid isPermaLink="false">https://jiniya.net/ng/2018/01/trade-off/</guid><pubDate>Fri, 26 Jan 2018 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;전산학에서 배운 개념 중에서 일상에 가장 쓸모 있는 개념이 있다면 바로 트레이드 오프다. 트레이드 오프는 간단히 말하면 두가지를 동시에 추구하기란 쉽지 않다는 개념이다. 속도를 빠르게 하려면 공간을 더 써야 하고, 공간을 줄이려면 속도를 희생해야 한다는 것과 같이 두 가지 목표를 동시에 추구하기가 쉽지 않은 문제에 쓰인다. 즉, 하나를 선택하면 다른 하나는 일정 부분 포기해야 함을 의미한다. 물론 고상한 전산학까지 가지 않아도 초중등 교과서에도 이 내용이 나온다. 두마리 토끼를 잡지 못한다는 이야기다. 트레이드 오프는 그것보다는 조금 더 확장된 개념이긴 하다. 두마리 토끼를 잡을 수 없다고 한다면 한 마리만 잡을 수 있다는 이야기처럼 들리지만 트레이드 오프는 반반을 추구할 수도 있기 때문이다. 더 내려가서 초등학교 때에도 이 개념을 배우긴 한다. 사탕 항아리에 아이가 사탕을 꺼내려고 손을 넣고 있다. 사탕을 집고 있어서 손이 나오지 않는다. 아이가 사탕을 적당히 포기해야 손을 뺄 수 있다는 이야기가 그것이다. 그렇게 인생 전반에 걸쳐서 우리는 트레이드 오프란 개념을 배운다. 그만큼 중요한 개념이기 때문일 수도 있고, 그만큼 사람들이 쉽게 잊어버리는 내용이기 때문일지도 모르겠다.&lt;/p&gt;
&lt;p&gt;인생은 B(Birth)와 D(Death)사이의 C(Choice)라고 얘기한 철학자의 말처럼 인생은 선택의 연속이고, 그 선택이란 것이 결국은 트레이드 오프를 조율하는 과정이다. 연봉을 많이 주는 회사에 입사하면 돈은 더 벌 수 있겠지만 개인 시간은 더 많이 희생할 수 밖에 없다. 작은 회사에 다니면 보다 많은 사사로운 자유로움은 누릴 수 있겠지만 어디 가서 이야기할 때 그 회사를 아는 사람이 없을 수 있다. 아이를 놓으면 아이가 커 가는 것을 지켜 보는 기쁨은 누릴 수 있겠지만 자신의 인생 중 중요한 시간 대부분을 아이를 위해서 희생해야 한다. 유명해지면 많은 사람들이 알아보기 때문에 좋겠지만 그 사람의 사생활은 없어진다. 인생 전반에서 우리를 향해 달려오는 많은 일들이 사실은 트레이드 오프적인 성격의 것들이고 우리는 그 사이에서 어떤 것을 얼만큼 추구할지 결정해야 한다.&lt;/p&gt;
&lt;p&gt;사람들이 가장 많이 잊어버리는 내용 중 하나는 바로 항아리에서 손을 못 빼고 있는 아이처럼 그런 종류의 많은 문제들이 트레이드 오프적인 성격의 것이라는 것을 인지하지 못한다는 사실이다. 아이를 놓고 기르면서도 그 전과 같은 평범한 일상을 누릴 수 있다고 생각한다거나, 연봉을 많이 주는 회사에 들어가도 일은 조금 해도 된다고 생각한다거나, 유명한 연예인이 되어도 그 전과 같은 사소한 일상을 누릴 수 있을 것이라고 생각한다. 현실은 그렇지 않은데 말이다.&lt;/p&gt;
&lt;p&gt;예전에 친구의 죽음으로 충격을 받은 모 프로그래머가 만든 게임이 생각난다. 그 게임은 간단하다. 시작은 직사각형 모양의 왼쪽 상단에서 한다. 한번에 우리는 네 방향 중 한 칸만큼 움직일 수 있다. 우리가 게임 내에서 움직일 수 있는 최대 횟수는 정해져 있다. 그 프로그래머가 말하고 싶었던 것이 바로 트레이드 오프다. 우리가 오른쪽으로 많이 움직인다면 상대적으로 위나 아래, 왼쪽으로는 적게 움직일 수 밖에 없다. 우리는 그 제한된 횟수 내에서 우리가 선택한만큼 경험하게 되고 죽음을 맞이하게 된다는 것이다.&lt;/p&gt;
&lt;p&gt;세상 모든 것을 다 가질 순 없다. 하나를 더 많이 가지기 위해서는 다른 하나는 그만큼 포기해야 한다. 보통 사람들이 무엇을 더 가질지는 잘 선택하지만 무엇을 포기할지는 망설이는 경우가 많다. 하지만 중요한 것은 무엇을 더 가질지 보다는 무엇을 포기해도 되는지를 먼저 정하는 것이다. 그래야 비로소 어떤 방향으로 가야 하는지가 명확해지기 때문이다. 당신은 오늘 무엇을 트레이드 오프 하고 있는가? 또 무엇을 얻고, 무엇을 포기했는가?&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[정보] 서피스 프로 LTE]]></title><description><![CDATA[그러하다. 하드웨어 명가 MS가 드디어 완벽한 껍데기를 만들었다. 팬리스, i5, LTE가 달린 서피스. 내가 원하는 바로 그것. 지름신 강림…​ ㅋㅋㅋ 지금 사용하는게 서피스 프로4 M…]]></description><link>https://jiniya.net/ng/2017/11/surface-pro-lte/</link><guid isPermaLink="false">https://jiniya.net/ng/2017/11/surface-pro-lte/</guid><pubDate>Wed, 08 Nov 2017 12:00:01 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/X8Z91UjM9PM?si=N-f5xN1FTcjvuxUw&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;p&gt;그러하다. 하드웨어 명가 MS가 드디어 완벽한 껍데기를 만들었다.&lt;/p&gt;
&lt;p&gt;팬리스, i5, LTE가 달린 서피스. 내가 원하는 바로 그것. 지름신 강림…​ ㅋㅋㅋ&lt;/p&gt;
&lt;p&gt;지금 사용하는게 서피스 프로4 M3 버전인데, 지금껏 써 온 그 어떤 노트북보다 만족한다…​.&lt;/p&gt;
&lt;p&gt;쓰면서 딱 불편한게 M3의 약한 파워, 태더링의 불편함…​ 그런데 이 모든 문제점을 해결한 버전이 나온 것이다…​&lt;/p&gt;
&lt;p&gt;12월 출시라는데 한국도 제발 출시해주길…​&lt;/p&gt;
&lt;p&gt;이런 거 들고 발리가서 서핑하면서 코딩하면 한 2천배쯤 생산성이 향상될 거 같은 느낌적인 느낌…​&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 윈도우 x64 호출 규약 리뷰]]></title><description><![CDATA[윈도우 x64 호출 규약은 굉장히 심플하다. 파라미터가 첫번째부터 rcx, rdx, r8d, r9d…]]></description><link>https://jiniya.net/ng/2017/11/x64-calling-convention/</link><guid isPermaLink="false">https://jiniya.net/ng/2017/11/x64-calling-convention/</guid><pubDate>Tue, 07 Nov 2017 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;윈도우 x64 호출 규약은 굉장히 심플하다. 파라미터가 첫번째부터 rcx, rdx, r8d, r9d를 통해서 전달되고 그 다음 추가 파라미터는 스택을 통해 전달된다. 스택 정리는 호출한 쪽에서 수행한다. 그런데 여기서 한 가지 주의해야 할 것이 홈 공간이다. 홈 공간이란 파라미터가 레지스터를 통해서 전송되더라도 그걸 저장하기 위한 스택 공간을 호출하는 쪽에서 제공해야 한다는 것을 의미한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Func1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; param1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위 코드를 보자. 위의 파라미터 전송 설명대로라면 Func1(3)은 아래와 같이 호출하면 될 거 같다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;mov rcx, 3
call Func1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;하지만 그렇지 않다. 홈 공간이 필요하기 때문이다. 그래서 아래와 같이 값을 저장하지는 않더라도 공간은 확보해 주어야 한다. sub rsp, 8을 통해서 Func1이 param1 저장을 위해서 사용할 공간을 확보한 후에 호출해야 한다. 이게 홈 공간이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;sub rsp, 8
mov rcx, 3
call Func1
add rsp, 8&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;조금 복잡하게 파라미터가 5개인 함수를 살펴보자.&lt;/p&gt;
&lt;p&gt;void Func2(int p1, int p2, int p3, int p4, int p5);
Func2(1, 2, 3, 4, 5)를 호출한다고 생각해보자. 그러면 아래와 같이 호출하면 된다. push 5를 통해서 스택에 마지막 값을 기록한다. 이후 앞에 4개의 값을 기록할 공간을 확보한 후, rcx, rdx, r8d, r9d에 변수를 지정하고 Func2를 호출하면 된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;push 5
sub rsp, 32
mov rcx, 1
mov rdx, 2
mov r8d, 3
mov r9d, 4
call Func2
add rsp, 40&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;실제로 컴파일러는 매 함수 호출마다 이렇게 스택을 조작하지는 않는다. 여유 있는 스택 공간을 함수 도입부에 확보해놓고 지속적으로 사용한다. 어쨌든 우리가 기억해야 할 사항은 이것이다. 앞에 4개는 레지스터로 뒤에꺼는 스택으로, 그리고 파라미터 개수만큼 스택 공간은 항상 확보해 주어야 한다는 점이다. 호출 규약에 관한 더 자세한 내용은 호출의 예술을 참고하자.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[py] 주차를 알고 싶을 땐 isocalendar]]></title><description><![CDATA[일주일씩 묶어서 통계를 내고 싶을 때가 있다. 그런데 이게 날짜를 기준으로 하기도 애매하고 위크데이를 기준으로 해도 영 뭔가 계산하기가 쉽지 않다. 이럴 때 isocalendar를 사용하면 편리하다. 해당 날짜가…]]></description><link>https://jiniya.net/ng/2017/11/isocalendar/</link><guid isPermaLink="false">https://jiniya.net/ng/2017/11/isocalendar/</guid><pubDate>Sun, 05 Nov 2017 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;일주일씩 묶어서 통계를 내고 싶을 때가 있다. 그런데 이게 날짜를 기준으로 하기도 애매하고 위크데이를 기준으로 해도 영 뭔가 계산하기가 쉽지 않다. 이럴 때 isocalendar를 사용하면 편리하다. 해당 날짜가 1년의 몇 번째 주차인지 반환해 준다. 사용법은 아래와 같이 심플하다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;Python &lt;span class=&quot;token number&quot;&gt;3.5&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;.2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;v3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5.2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;4def2a2901a5&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Jun &lt;span class=&quot;token number&quot;&gt;25&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2016&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;55&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;MSC v&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1900&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;64&lt;/span&gt; bit &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;AMD64&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; on win32
Type &lt;span class=&quot;token string&quot;&gt;&quot;help&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;copyright&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;credits&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;license&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; more information&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; datetime
&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; datetime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;datetime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;now&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isocalendar&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2017&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;45&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; datetime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;datetime&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2017&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isocalendar&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2017&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;44&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;isocalendar의 반환 값은 튜플인데 차례대로 ISO 연도, ISO 주차, ISO 요일 번호다. 오늘이 벌써 올해 45주차라뉘…​ 일년이 52주라 그랬던거 같은데 이렇게 또 일년이 흘러가려고 하나보다. 여튼 이렇게 일주일 단위로 묶은 통계를 낼 때에는 isocalendar가 참 편리하다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 정규 표현식]]></title><description><![CDATA[C++11부터 정규 표현식이 표준 라이브러리에 포함됐다. 문자열 다루기 힘든 C…]]></description><link>https://jiniya.net/ng/2017/11/regex/</link><guid isPermaLink="false">https://jiniya.net/ng/2017/11/regex/</guid><pubDate>Wed, 01 Nov 2017 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;C++11부터 정규 표현식이 표준 라이브러리에 포함됐다. 문자열 다루기 힘든 C++에서 이런게 되다니 정말 기가 찰 노릇이다. 구슬이 서말이라도 꿰어야 보배이듯이 표준 라이브러리에 있어도 사용법을 모른다면 의미가 없다. 간략하게 사례별로 어떻게 사용하는지 살펴보도록 하자. 일단 코드를 먼저 보고,…​&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;string&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;regex&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string s &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;123&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;regex &lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;[0-9]+&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;regex_match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; number&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;number\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;not number\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;정규 표현식을 이용해서 문자열이 숫자인지 아닌지를 판단하는 프로그램을 만들어 본 것이다. s의 값을 변경해가면서 출력 값을 체크해보면 대략 어떻게 쓰는 것인지 알 수 있다. std::regex_match 함수를 사용하면 특정 문자열이 정규 표현식에 부합하는지 아닌지를 체크할 수 있다는 사실을 알면 되겠다. 한 가지 주의해야 할 점은 std::regex_match 함수의 경우 재귀 호출을 사용한다는 점이다. 따라서 정규 표현식에 따라서 문자열이 길면 스택 오버플로로 크래시가 발생할 수 있다. Visual Studio 2015에서는 이러한 문제점을 없애기 위해서 재귀 호출의 최대 깊이를 상수로 지정할 수 있도록 되어 있다. regex를 포함하기 전 _REGEX_MAX_STACK_COUNT를 특정 값으로 선언해 주면 된다. 기본적으로 64비트는 600, 32비트는 1000으로 설정돼 있다. 그 크기를 늘려주면 더 긴 문자열도 오류 없이 매치할 수 있다. 물론 너무 높게 설정하면 스택 오버플로로 크래시가 발생할 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;string&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;regex&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string s &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;123 456 789&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;regex &lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;[0-9]+&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;sregex_iterator &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; number&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;sregex_iterator end&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;it &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; end&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;smatch m &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;it&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%s\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; m&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;c_str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;it&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위 예제는 특정 문자열에서 정규 표현식에 부합하는 요소만 추출해서 출력하는 예를 보여주고 있다. std::sregex_iterator를 사용해서 부합하는 요소만 열거할 수 있고, std::smatch 객체를 이용하면 부합한 내용이 무엇인지 출력할 수 있다. 위 프로그램의 출력 결과는 123, 456, 789가 된다. std::smatch의 str 함수의 첫번째 파라미터로 넘어간 숫자가 애매한데 그건 매치한 대상 중에 어떤 것을 출력할지를 결정한다. 위 예에서는 매치 대상이 별도로 구분되어 있지 않기 때문에 0번 밖에는 없다. 아래 예제를 살펴보자.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;string&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;regex&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string s &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;123 456 789&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;regex &lt;span class=&quot;token function&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;([0-9])([0-9])([0-9])&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;sregex_iterator &lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; number&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;sregex_iterator end&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;it &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; end&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;smatch m &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;it&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%s\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; m&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;c_str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;it&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위 프로그램의 출력 결과는 1, 4, 7이 된다. 정규 표현식이 ([0-9])([0-9])([0-9]) 이와 같이 구성되어 있기 때문에 123이 이 표현식에 매치되면 std::smatch의 str 함수의 0번은 123을, 1번은 1을 2번은 2를, 3번은 3을 나타낸다. 그렇다면 정규 표현식 전체를 괄호로 한 번 더 묶으면 어떻게 될까? &quot;(([0-9])([0-9])([0-9]))&quot; 이렇게 말이다. 이러면 0은 123을 1도 123을 2는 1을, 3은 2를, 4는 3을 반환한다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 봇 트레이딩 체험기...]]></title><description><![CDATA[어쩌다 올초에 비트코인에 투자를 했다. 처음에 재미삼아 1비트를 사봤는데 계속 떨어져서 물타기를 하다가 금액이 커져서 그냥 냅두게 됐었다. 그게 4,…]]></description><link>https://jiniya.net/ng/2017/10/bot-trading/</link><guid isPermaLink="false">https://jiniya.net/ng/2017/10/bot-trading/</guid><pubDate>Wed, 25 Oct 2017 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;어쩌다 올초에 비트코인에 투자를 했다. 처음에 재미삼아 1비트를 사봤는데 계속 떨어져서 물타기를 하다가 금액이 커져서 그냥 냅두게 됐었다. 그게 4, 5월 엄청 폭등하는 바람에 수익을 좀 봤다. 이런 사실을 아는 출판사 다니는 친구 녀석이 자기 회사에서 주식 자동매매 책이 잘 팔린다고 암호화폐 자동매매 책을 써 볼 생각이 없냐는 제안을 했다. 그렇게 어쩌다보니 봇 거래를 해보게 됐다.&lt;/p&gt;
&lt;p&gt;사실 전업 프로그래머 입장에서 투자 전략이야 천차만별이지만 시스템 트레이딩 코드를 만드는 건 너무 쉽다. 게다가 포인터를 다뤄야 하는 C/C++도 아니고 파이썬이면 충분하기 때문에 뻥 좀 보태서 한 시간이면 봇을 만들 수 있다. 요는 코딩이 어려운 건 아니고 전략이 어렵다는 의미다. 어쨌든 30분 정도 REST API를 훓어보고 봇으로 거래를 해보게 됐다. 당연한 얘기지만 된다. 거기에 내가 생각한 한 가지 아이디어를 넣어서 거래를 해보게 했더니 수익이 발생하는게 아닌가? 긴 추석 연휴 기간 동안 봇을 조금 다듬었다. 그렇게 25일이 됐고 봇이 나에게 월급을 줘야 하는 시점에 봇의 성적표는 다음과 같다. 각각 날짜, 비트코인봇 수익, 비트코인봇 거래회수, 이더리움봇 수익, 이더리움봇 거래회수, 토탈 수익, 토탈 거래회수, 누적 수익이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./bot_result.png&apos; data-alt=&apos;BOT 트레이딩 수익&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 544px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/d47d4dbbcda61dc3eaaeb850086a3a3f/cfd82/bot_result.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 87.36842105263158%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAC8klEQVR42k1U2VLiUBBtISqyKioimxu7oBAMkc3BcqYs/2BqZvRJovOgzv+/9JyTTpU+3Arc9D19lr6RX48/dfX8W4PgSV9ennQV/NHX18fw/9/XJ31/f9Z/H4F+YL29BdgLdLUKNFh9Pl8C+82nJLOO5nKi2azoxoZoJiPh/9w2fmPPcUQ3N20ltkRja6JrXDH7LWIrFrN9GXop7XRien4e11QyroNhXBv1uPp+XAv7cRQ6Wiw6Wig4Wjty0MBRd+TgjKPX145Wqw4aO7qY45l2VAZeQtttAaDozo7odCZ6eornRAAoenQi2mqK9i9Q0wXLhOjVFfZaAkDRw0PRItYE9SkokPEsoV2AXVxCNuQ2cLhRF51N0SAvOsJh1xX1cbiPuizsmC9Em6i7vRUtl0SrNdH7ewAmAehNAIjOlwPRbfjmjQVyAAimu7sGdIlmrbYxTILFzY2EqsZjU9FoiD48iG6RISWTPlnu46Xvi56B4QRA+3sA6pgdvR5AWsZwOjXAwRByD0TrdWNLO2TkG2CvD4ACfJmYP5RMhs22Me7jfb9nKsi607baStlqlgDMpADojg2QksoVK6I/HrwrHBgLWkJQgjC4+dxqyJSAfE+GaQIOx5ZyHT5UAOgD8OzMUi4hPfcqAsOhbsckhx62zMNa1YJczCOGw4hhE6sAybOoO72kBQyJ/rkjSzmdsRFhEJOIIeupLEzZnyfCAzS+hvhnC+t+uzQLmDbH5hqHXaS9jVG6u7P6b0tTxQn5/sMmQFyEQkntjs0TmdWjOeTAcojp0XBkknklZ1HK9LBUMvaLhV1dXL1EGAgXu3FoW5FkArJ7v/c5OrzfngeZDfOyWrF9BpVMfkmZoZTKZnTIEFIPijbU9GvkGTBDIRvWEKRatTGjr8mvN4XGnp7YPLGYh3hPeYdpB2V1oSKPYV8uo1kF4PEx9nu2l2LK+UIi/HTxs8U5KpftU7a3Z58sFvEdu3Ofe5wG7uURUDpts8nm6+ui/wHTGcdou5+3rgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;BOT 트레이딩 수익&apos; title=&apos;&apos; src=&apos;/static/d47d4dbbcda61dc3eaaeb850086a3a3f/cfd82/bot_result.png&apos; srcset=&apos;/static/d47d4dbbcda61dc3eaaeb850086a3a3f/08678/bot_result.png 190w,
/static/d47d4dbbcda61dc3eaaeb850086a3a3f/2edd7/bot_result.png 380w,
/static/d47d4dbbcda61dc3eaaeb850086a3a3f/cfd82/bot_result.png 544w&apos; sizes=&apos;(max-width: 544px) 100vw, 544px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;BOT 트레이딩 수익&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h3&gt;bot result&lt;/h3&gt;
&lt;p&gt;생각보다 많을 수도 있고, 적을 수도 있는데 나는 이 봇의 이름을 최저임금봇이라 명명했다. 시급 만원 정도를 추종하도록 설계됐다. 물론 시장 상황이 좋으면 더 벌기도 하고, 나쁘면 덜 벌기도 하는데 대략 그 정도 수준에서 24시간 돌면서 거래를 한다. 재미난 건 상수 값 몇 개 바꾸면 저 단위가 10배가 될 수도 있다는 점이다. 물론 내가 쪽빡찰 확률은 100배가 되겠지만 말이다. 여기까지만 쓰면 단순 자랑질 이상도 이하도 아닐 것이다. 그래서 트레이딩 봇을 만들면서 알게된 점 몇 가지를 정리해 본다. 분명 이런 시스템을 만드려는 금융 쪽 종사자가 아닌 프로그래머가 있다면 도움이 되리라 확신한다.&lt;/p&gt;
&lt;h3&gt;삼위일체&lt;/h3&gt;
&lt;p&gt;처음에 봇을 만들고 가동시키자 봇이 엉뚱한 실수를 계속 했다. 분명 50원에 샀으면 100원에 팔라고 코딩을 해놨는데 계속 40원에 팔면서 수익을 내고 있다고 착각하고 있는 것이었다. 나같은 프로페셔널한 프로그래머가 if문 따위를 잘못 코딩할리도 없는데 말이다. 부랴부랴 Ctrl + C를 눌러서 봇을 껐지만 제법 손실이 난 후였다. 이 버그 아닌 버그를 찾는데 가장 많은 시간이 들었는데 원인은 다름아닌 트랜잭션에 있었다.&lt;/p&gt;
&lt;p&gt;내가 상상한 퐌타지한 세계는 그랬다. 거래소에서 나에게 제공하는 모든 데이터는 수직 동기화가 되어 있을 줄 알았다. 즉 그 사이게 시간 차가 존재할 줄 몰랐다는 의미다. 하지만 현실 세계는 그렇지 않았다. KRW 잔고가 먼저 반영되기도 하고, BTC 잔고가 그 다음에 움직이기도 하고, 거래 트랜잭션 데이터는 몇 십초가 있다가 확정되기도 했다. 즉 이 사이에는 어느 정도 시간적인 불일치가 있었다. 이걸 한쪽 데이터만 보고 판단해서 거래를 하면 나처럼 낭패를 볼 수 밖에 없다. 검산을 해야 한다. KRW 잔고와 BTC 잔고와 거래 내역이 모두 일치하는 삼위일체의 상태에 있을 때에 수익을 계산하고 베팅을 해야 한다.&lt;/p&gt;
&lt;h3&gt;부동소수점?&lt;/h3&gt;
&lt;p&gt;이 오류가 정확하게 부동소수점 때문인지 아니면 내 계산 방식 때문인지는 모르겠지만 위 삼위일체 검산 로직을 추가해도 정확하게 데이터가 일치하지 않았다. 나는 그냥 편하게 부동소수점 때문이라고 판단했는데 1사토시 근처에서 오류가 있는 경우가 많았다. 그래서 그냥 0.00000001 정도의 차이는 동일하다고 간주했다.&lt;/p&gt;
&lt;h3&gt;하락장을 고려해야 한다&lt;/h3&gt;
&lt;p&gt;상승만 한다면 바보 같은 봇들도 모두 수익을 낼 수 있다. 그리고 어렵게 봇을 만들 필요도 없다. 사두고 장기 보유하면 되기 때문이다. 하지만 시장은 항상 그렇듯이 오르기도 하고 내리기도 한다. 암호화폐 시장은 그 변동성이 더 크다. 그래서 봇 거래가 수익을 내기 좋은 환경이기도 하다. 어쨌든 하락장을 고려해야 한다.&lt;/p&gt;
&lt;p&gt;처음 만든 봇은 그저 오른다는 가정하에 만들었고 시장 상황이 계속 올라서 참 쉬웠다. 그러다 하락장이 왔는데 봇은 어쩔줄을 몰라 했다. 출구전략이 필요했다. 그런데 이론적으로 주구장창 하락한다면 일반 거래로 수익을 얻을 방법은 없다. 여기서 일반 거래란 공매도 같은 장치가 없음을 의미한다. 따라서 출구 전략은 단순할 수 밖에 없다. 더 사서 물타기를 할지 아니면 손절을 할지를 판단하는게 전부다. 여러가지 전략이 있을 수 있는데 나도 5가지 정도의 전략을 테스트 해보았다. 갈수록 산수에서 수학으로 가는 내용들이 도입됐고 코드도 복잡해졌다. 그런데 아니러니 하게도 수익률은 두번째 방법이 가장 좋았다. 그래서 그냥 그걸로 적용해 두었다.&lt;/p&gt;
&lt;h3&gt;인간은 개입하지 말지어다&lt;/h3&gt;
&lt;p&gt;위에서 말한 하락장에서 봇의 손실이 제법 커졌다. 사람은 당연히 불안해질 수 밖에 없다. 봇은 사지도 팔지도 못하고 있었다. 그러다 코인 가격이 반등되어 적당한 가격이 왔다. 봇은 아직 팔 때가 아니라서 거래를 하고 있지 않았다. 사람인 나는 조급해질 수 밖에 없었다. 봇이 사들인 코인의 대부분을 이 시점에 손절해 버렸다. 봇은 회복할 수 없는 타격을 입었다. 봇은 내가 저지른 만행을 복구할 수가 없는 지경이 됐다. 결국 나는 봇의 수익률 추종치를 리밸런싱할 수 밖에 없었다. 이게 비트코인 봇인데 원래 비트코인 봇이 이더리움 봇 보다는 수익률이 월등했는데 이 당시의 내 개입으로 인해서 구려졌다.&lt;/p&gt;
&lt;p&gt;봇이 어쩔 줄 몰라 하면 봇을 고쳐서 대응하면 된다. 절대 수동 트레이드로 개입할 필요가 없다. 왜냐하면 내가 느끼는 감성적인 수치와 봇이 정확하게 계산한 수치 사이에는 항상 간극이 존재할 수 밖에 없기 때문이다. 감정적인 대응의 결과는 손실 밖에 없다.&lt;/p&gt;
&lt;h3&gt;거래 수수료 트레이프오프&lt;/h3&gt;
&lt;p&gt;봇 트레이딩의 가장 큰 리스크는 다름 아닌 거래 수수료다. 봇이라서 엄청나게 많은 회수의 거래를 하는데 그때마다 수수료가 발생하기 때문이다. 상당수는 거래 볼륨으로 커버가 가능한데 대부분의 거래소가 거래 볼륨이 커질 수록 수수료가 낮아지도록 책정되어 있기 때문이다. 거래소에 따라서 일정 수준을 넘어서면 수수료 없이 거래하는 것도 가능하다. 그런데 문제는 그 수수료가 한 가지가 아니라 두 가지란 점에 있다. 모든 거래소 시스템이 비슷한 방식의 수수료를 책정하고 있는데 일명 메이커, 테이커 비용이다.&lt;/p&gt;
&lt;p&gt;시장에 유동성을 공급하는 거래에는 메이커, 유동성을 없애는 거래에는 테이커 비용을 물린다. 이게 거의 수수료가 없는 쪽은 메이커 비용이고, 테이커 비용은 수수료가 높다. 테이커 비용에 물리게 되면 사실상 단타 매매로 수익을 내기가 굉장히 어려워진다. 문제는 이 테이커 비용을 최대한 덜 내게 하는 방법인데 이게 쉽지가 않다. 그런 API가 존재하면 좋겠지만 거래소 수익 때문인지 그런 API를 제공하지 않는다. 내가 주문을 낼 때에는 멀쩡한 메이커 주문이었는데 그게 거래소 트랜잭션 시스템에서 직렬화 되면서 테이커 비용을 물게 되는 경우가 왕왕있다.&lt;/p&gt;
&lt;p&gt;당연한 얘기겠지만 되도록 이 테이커 비용을 피하면서 거래를 성사시키는 것이 중요하다. 그런데 문제가 그렇게 간단하지는 않은 것이 거래를 성립시키려면 테이커 비용을 무는 쪽으로 다가 가야 하기 때문이다. 즉, 이 사이에는 트레이드 오프가 있다. 거래를 잘 성립하게 만들다보면 테이커 비용을 무는 경우가 많고, 그렇다고 완전 회피하려면 유동성만 공급할 뿐 거래가 성사되지 않기 때문이다. 즉, 최대한 원활하게 거래를 성립시키면서 테이커 비용은 최대한 피하는 그런 방법을 만드는 것이 중요하다.&lt;/p&gt;
&lt;h3&gt;두려움을 넘어서&lt;/h3&gt;
&lt;p&gt;이 모든 봇 거래의 가장 큰 어려움은 두려움이다. 이 단순한 봇도 내 전재산의 무시 못할 수준의 금액을 가지고 도박을 한다. 내가 자는 동안에 위에서 말한 삼위일체 문제 같은게 발생한다면 거지되는 것이다. 그 두려움이 처음 3일 정도는 있었던 것 같다. 이제는 어느 정도 봇을 믿게 됐다. 특히 내가 한 수동 거래가 병신짓으로 판명난 이후에는 봇을 더 신뢰하게 됐다. 어쨌든 자신이 만든 버그가 현실 세계에서 어떻게 발현될 수 있는지 확인해 보고 싶은 프로그래머라면 도전해 볼 만한 영역인 것 같다. 물론 수익은 덤이다. 재미삼아 시작했는데 결과가 나쁘지 않아 누적 수익이 0이 될 때까지는 봇 실험을 계속해 볼 생각이다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 코딩은 어려워]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2017/10/coding-is-difficult/</link><guid isPermaLink="false">https://jiniya.net/ng/2017/10/coding-is-difficult/</guid><pubDate>Sun, 22 Oct 2017 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;판교, 커피숍. 앉아서 간만에 회사 일이랑은 관련 없는 코딩을 좀 하고 웹서핑을 하고 있다. 옆에 여자 아이도 한 명 앉아서 뭔가를 만들고 있다. 그렇게 한참 지났을 무렵, 그 여자의 남자 친구가 왔다. 어딘가 면접을 보고 온 것 같다. 바로 옆자리 — 전원 있는 자리가 한정적이다 — 들으려고 듣는건 아닌데 말 소리가 커서 귀에 쏙쏙 꼽힌다. 흥분한 남자의 첫 마디. &quot;넌 링크드 리스트, 요이땅 하면 바로 짤 수 있어?&quot; 못짜지라는 말을 기대하고는 묻는 질문처럼 들린다. 여자가 링크드 리스트는 기본 아니냐는 말을 하자, 남자는 재차 말한다. &quot;기본인데, 요이땅 하면 바로 만들 수 있냐고?&quot; …​ 그렇게 한참을 입사 시험 문제에 대한 이야기들이 오간다. 판교 어딘가에 있는 회사의 코딩 시험을 방금 보고 나온 것 같다. 첫번째 문제가 링크드 리스트를 만들어서 그걸로 스택을 구현하라는 문제였던 것 같다. 다음 문제는 피보나치 수열, 팩토리얼 …​ 대화 내용으로 추정컨데 남자 보다는 여자가 프로그래밍을 잘하는 것으로 보인다.&lt;/p&gt;
&lt;p&gt;면접도 많이 보고 프로그래머 채용도 더러 해봐서 그런지 대화 내용이 납득이 가기도 하고 일견 또 이해가 되지 않기도 한다. 과연 프로그래머로 일을 하는데 얼마만큼의 지식이 필요한걸까? 프로그래머라는 직업을 가지는 데 필요한 최소 수준의 지식이라는 게 있을까? 라는 생각을 해봤다. 링크드 리스트를 못 만들어도 요즘은 문제가 없다. 잘 만들어진 링크드 리스트는 정말 많다. 스택을 못 만들면 또 어떤가? 푸시, 팝 하면 기똥차게 동작하는 코드들이 널려 있다. 피보나치 수열, 팩토리얼이 뭔지 몰라도 상관 없지 않을까? 재귀호출을 모르면 또 어떤가? 사실 실전에서 그리 사용 빈도가 높지도 않은데 말이다. 그런데 또 반대로 생각해 보면 그렇다. 링크드 리스트도 요이땅 하면 못 만드는 친구가 더 복잡한 건 어떻게 만들 수 있을까? 푸시는 어떻게든 구현했는데, 팝을 구현 못했다는데 팝을 어떻게 만들어야 하는지도 모르는 친구가 현업에서 작성할 코드가 있을까? 재귀호출은 또 어떤가? 그 정도의 복잡함을 시뮬레이션 할 수 없다면 과연 더 복잡한 추상적인 구조는 어떻게 머리속에서 떠올릴 수 있을까?&lt;/p&gt;
&lt;p&gt;하지만 세상 일이 그리 단순하진 않을 것이다. 예전의 나라면 단호하게 말했겠지만 지금의 나는 그러지는 못하겠다. 세상이 얼마나 넓은지 예전보다는 조금 더 알게 되었기 때문이다. 유명한 오픈소스 개발자가 트리를 못 뒤집어서 구글에서 떨어졌다는 일화가 한 때 유행했었다. 그때도 비슷한 생각을 했다. 과연 프로그래머로 일을 하는데 필요한 기본적인 지식이라는 게 무엇일까? 나도 구글이든 페북이든 큰 회사들의 코딩 시험에 나오는 문제들을 못 푼다. 예전에 회사에서 그런 시험에 대비하는 책을 사서 본 적이 있었는데 생각보다 문제가 어려웠다. 우리 회사의 시험 문제도 그럴지도 모른다. 문자열 복사 함수를 구현하는 일이 누군가에겐 쉬워도 누군가에겐 &apos;=&apos; 하나로 되는 일이기도 하고 또 누군가에겐 &apos;strcpy’로 되는 일이기도 하니 실제로 포인터를 조작하면서 구현하는게 어려울 수도 있다. 그래도 한 가지 바램이 있다면 그런 생각이 있다. 적어도 요이땅 하면 링크드 리스트를 구현할 수 있는 프로그래머랑 같이 일하고 싶다는 바램…​ 트리를 뒤집는 문제는 좀 더 생각해보고…​&lt;/p&gt;
&lt;p&gt;이랬든 저랬든 코딩은 어렵다. 입사 시험에 나오는 코딩도 이렇게 어려운데 현실 세계의 복잡한 문제들을 해결하는 코드들을 작성하는 일은 또 얼마나 어렵겠는가? 알파고 제로가 하루빨리 코딩을 마스터 하는 날이 오기를 희망해 본다. 너무 어려워서 사람이 하기에 적합한 일이 아닌 것 같다. 코딩이 말이다. 물론 이건 나 혼자만의 생각은 아닌 것 같다. 세계에서 손꼽히는 석학인 Knuth 노교수도 자신이 해 본 어떤 일보다 프로그래밍이 어렵다는 이야기를 했었다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In fact, my main conclusion after spending ten years of my life working on the TEX project is that software is hard. It’s harder than anything else I’ve ever had to do.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;TEX 프로젝트에서 10 년을 보낸 후 내가 내린 주요 결론은 소프트웨어가 어렵다는 것입니다. 내가 이제까지 했던 그 어떤 일보다 더 어려워요.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[py] 파이썬으로 김프 계산하기]]></title><description><![CDATA[requests 패키지가 있으면 편리하다. 아래 명령어로 requests 패키지 설치가 가능하다. 거래소가 많기 때문에 일단 기준 거래소를 정해야 가격 비교가 쉽다. 거래소가 비교를 위한 REST API…]]></description><link>https://jiniya.net/2017/07/calculate-kimchi-premium/</link><guid isPermaLink="false">https://jiniya.net/2017/07/calculate-kimchi-premium/</guid><pubDate>Wed, 05 Jul 2017 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;requests 패키지가 있으면 편리하다. 아래 명령어로 requests 패키지 설치가 가능하다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;pip install requests&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;거래소가 많기 때문에 일단 기준 거래소를 정해야 가격 비교가 쉽다. 거래소가 비교를 위한 REST API를 제공하지 않으면 힘들다. 만약 제공하지 않으면 그냥 과감하게 그런 거래소는 빼도록 하자. 개념이 있는 대부분의 거래소는 REST API를 제공한다. 우리는 거래량이 많은 Bittrex와 Coinone의 가격을 토대로 김치 프리미엄을 계산해 보자.&lt;/p&gt;
&lt;p&gt;Bittrex거래소의 API는 여기 설명 페이지를 참고하면 어떤 REST API를 제공하는지 알 수 있다. Coinone은 여기 설명 페이지를 참고하면 된다. REST API라는게 별 거 없다. 그냥 get이나 post 방식으로 명령을 주면 주로 json 형태로 응답을 주는게 전부다.&lt;/p&gt;
&lt;p&gt;우리가 가격 비교를 위해서 사용할 Bittrex API를 알아보면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://bittrex.com/api/v1.1/public/getticker?market=USDT-BTC&quot;&gt;https://bittrex.com/api/v1.1/public/getticker?market=USDT-BTC&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;위 쿼리를 날리면 비트트렉스에서 가격 정보를 JSON 형태로 날려준다. 응답에서 우리가 참고할 부분은 success필드가 true인가 하는 것과 result의 Last 값이다.&lt;/p&gt;
&lt;p&gt;Coinone API는 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://api.coinone.co.kr/ticker/?currency=BTC&quot;&gt;https://api.coinone.co.kr/ticker/?currency=BTC&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;위 쿼리 응답의 result가 success인지 체크하고 last 값을 사용하면 된다.&lt;/p&gt;
&lt;p&gt;이제 프리미엄을 계산할 달러 환율만 있으면 된다. 달러 환율은 아래 사이트를 통해서 구할 수 있다. 똑같이 REST API 형태의 쿼리로 결과를 얻을 수 있다. 결과의 USD_KRW 필드의 val 값을 참조하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://free.currencyconverterapi.com/api/v5/convert?q=USD_KRW&amp;#x26;compact=y&quot;&gt;https://free.currencyconverterapi.com/api/v5/convert?q=USD_KRW&amp;#x26;compact=y&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;이제 준비물이 모두 모였다. 파이썬 코드를 작성해보자.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; requests
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; json

resp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; requests&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;https://free.currencyconverterapi.com/api/v5/convert?q=USD_KRW&amp;amp;compact=y&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text
usd_krw &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;json&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loads&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;USD_KRW&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;val&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

resp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; requests&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;https://bittrex.com/api/v1.1/public/getticker?market=USDT-BTC&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text
btc_usd &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;json&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loads&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;result&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Last&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

resp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; requests&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;https://api.coinone.co.kr/ticker/?currency=BTC&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text
btc_krw &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;json&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loads&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;last&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

fprice &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; btc_usd &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; usd_krw
&lt;span class=&quot;token keyword&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Bittrex: %d Coinone: %d KP: %.2f%%&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fprice&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; btc_krw&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; btc_krw &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; fprice &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;각각 Bittrex 가격, Coinone 가격, 김치 프리미엄이 표기된다. +면 한국이 비싼거고, -면 한국이 싼 거라고 생각하면 된다. +면 Bittrex에서 사서 Coinone에서 팔고, -면 Coinone에서 사서 BIttrex에 파는 전략을 구사하면 완벽하다. 물론 거래 수수료와 전송 속도에 따른 불확실성을 헷징할 방법은 각자 찾는 걸로…​&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[정보] C++ 프로그래머 채용합니다.]]></title><description><![CDATA[C++ 프로그래머 채용합니다. 학력, 경력, 출신, 나이, 종교, 성별, 정치성향, 외모, 성격 따지지 않습니다. C++ 코드를 읽을 수 있는지, 또 C…]]></description><link>https://jiniya.net/ng/2017/03/recruit-cpp-programmer/</link><guid isPermaLink="false">https://jiniya.net/ng/2017/03/recruit-cpp-programmer/</guid><pubDate>Wed, 29 Mar 2017 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./deadlock.png&apos; data-alt=&apos;Figure 1. 이 정도 유머는 이해할 수 있는 C++ 프로그래머를 찾고 있습니다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 520px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5a4a4a33ed79c4eec846c494b70d09df/407f2/deadlock.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 66.84210526315789%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABsklEQVR42qVSXY+TQBTl//8FH9XEBxNfNGvii3aptrCt7paPMkwZGD5moNgCLUm7KYyHuppVm2jiCSEzk3vO3DPnaofDgfg0CILl0suyzLJsIaVtO58mk4CxvCiWnmc7jsxzpVTf9+oRtKbZ6eOP5s1sNps7rjubz8F0l5DyhBB13QgheZxsNpsL5LL8+v7DaDKdTgxjNLqmlHqEVFXVtm3TNPX567pOXYJ2PB718fjq6q1+rS8WFjqwLAtapnlze3tn2fbUMCB0mYyb9QFjVN8tFlPDnH/+AucsjNTfoKGlw/39qXswg+3pdOrP+H7ym89fyUqNXr989eJZmOJhMp6KMMkymXd/ACqPFwMZl9I3z989fSLKqijWRVnKokB+6h8wtC2lJMQPw4jzeL1eD9lE3PMI9SmST9M0SZI0SdkqCMMwTTMpoF88kBEG5xwhoQbZojSK+IquGGPQTWLYyPCXYAkRxxBKivxMVv8BDe7RQ7tvkVlV1cAwG3W9PQNrzNZ2u9k1O5zu9yhs+x/QEAwGEzZc1/V9QqkPYD5XhIaM4dAwTMux45gTglfwWch+RvgNpbDRuLTCv5QAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 1. 이 정도 유머는 이해할 수 있는 C++ 프로그래머를 찾고 있습니다.&apos; title=&apos;&apos; src=&apos;/static/5a4a4a33ed79c4eec846c494b70d09df/407f2/deadlock.png&apos; srcset=&apos;/static/5a4a4a33ed79c4eec846c494b70d09df/08678/deadlock.png 190w,
/static/5a4a4a33ed79c4eec846c494b70d09df/2edd7/deadlock.png 380w,
/static/5a4a4a33ed79c4eec846c494b70d09df/407f2/deadlock.png 520w&apos; sizes=&apos;(max-width: 520px) 100vw, 520px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 1. 이 정도 유머는 이해할 수 있는 C++ 프로그래머를 찾고 있습니다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;C++ 프로그래머 채용합니다. 학력, 경력, 출신, 나이, 종교, 성별, 정치성향, 외모, 성격 따지지 않습니다. C++ 코드를 읽을 수 있는지, 또 C++ 코드를 쓸 수 있는지만 봅니다. 파이썬을 할 줄 알면 더 좋구요. 몰라고 크게 상관은 하지 않습니다. 데드락 유머들 이해할 수 있다면 충분하다는 생각입니다. 윈도우/리눅스/BSD/macOS 중 하나 이상 시스템 프로그래밍 경험이 있다면 금상첨화지요.&lt;/p&gt;
&lt;p&gt;하는 일은 심플합니다. 저희가 11년째 해오고 있는 게임 해킹툴 박멸 작업에 참여하는 일입니다.&lt;/p&gt;
&lt;p&gt;병역특례 전직, 보충역 신규 편입 가능합니다.&lt;/p&gt;
&lt;p&gt;참고할만한 과거 채용 공고들…​
&lt;a href=&quot;http://www.jiniya.net/wp/archives/12367&quot;&gt;http://www.jiniya.net/wp/archives/12367&lt;/a&gt;
&lt;a href=&quot;http://www.jiniya.net/wp/archives/7276&quot;&gt;http://www.jiniya.net/wp/archives/7276&lt;/a&gt;
&lt;a href=&quot;http://jiniya.net/tt/694&quot;&gt;http://jiniya.net/tt/694&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;하는 일은 동일합니다.&lt;/p&gt;
&lt;p&gt;환경은 많이 변했습니다. 좋은 쪽으로…​&lt;/p&gt;
&lt;p&gt;관심 있는 분들은 codewiz 앳 wellbia.com으로 이력서, 자기소개서 보내 주세요.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 실험 주도 프로그래밍]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2017/02/expr-driven-programming/</link><guid isPermaLink="false">https://jiniya.net/ng/2017/02/expr-driven-programming/</guid><pubDate>Sun, 19 Feb 2017 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;신입 프로그래머들이 자주 사용하는 기법 중에 하나로 실험 주도 개발이 있다. 정식 용어는 아니고 그들이 프로그래밍 하는 과정이 일종에 물리 법칙에 관한 실험을 하는 것과 유사해서 나는 그렇게 부른다. 잘 사용한다면 빠르게 결과물을 도출할 수 있는 방법이지만 잘못 사용된다면 아주 위험할 수 있는 방법이기에 간단하게 그 방식에 관한 생각을 정리해 본다.&lt;/p&gt;
&lt;h3&gt;실험 주도 프로그래밍&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BadFunc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;PLATFORM_A&lt;/span&gt;&lt;/span&gt;
    some code
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
    some other code
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위와 같은 코드에서 PLATFORM_A 환경에서만 크래시가 발생한다. 어떻게 해야 할까? 이때 우리가 대처할 수 있는 방법은 크게 두 가지 방법이 있다. 1) 덤프 파일을 분석해서 정확하게 왜 크래시가 발생했는지를 알아낸다. 2) 위 코드가 정확하게 어떤 동작을 하는 코드인지 이해하고 무엇이 잘못되었는지 생각해서 잘못된 원인을 찾아낸다. 그런데 여기에 이 두가지 방법이 아닌 전혀 새로운 방식의 접근 방법이 있다. 바로 실험 주도 프로그래밍이다.&lt;/p&gt;
&lt;p&gt;실험 주도 프로그래밍은 물리적 현상을 추론해 내는데 사용하는 가설, 검증 방식의 실험과 유사하게 코드를 고쳐 나가는 것을 말한다. 전체적인 시나리오는 이렇다. 1) 가설을 세운다. 2) 실험을 한다. 3) 결과를 관찰한다. 아주 심플하다. 그러면 간단한 가설을 세워보자. PLATFORM_A에서만 크래시가 나니 some code의 문제일 수 있다. some code를 주석처리 한 다음 컴파일을 해본다. 이제 결과를 관찰한다. 잘 동작한다면 가설이 맞은 것이니 주석을 풀고 그 코드 내부에 대한 추가적인 세부 가설을 세우고 실험을 진행한다. 가설이 맞지 않다면 주석을 풀고 return 1 부분에 관한 가설을 세우고 다시 테스트를 한다.&lt;/p&gt;
&lt;p&gt;이 방식은 관찰된 현상에 따라서 가설만 잘 세운다면 본질적인 구조를 모르고도 굉장히 빠르게 문제를 수정할 수 있다는 장점이 있다. 그래서 대체로 다른 이들이 작성한 코드를 유지보수해야 하는 신입 프로그래머들이 많이 사용하는 것 같다.&lt;/p&gt;
&lt;h3&gt;가설, 검증 구조가 가지는 함정&lt;/h3&gt;
&lt;p&gt;앞선 실험 주도 프로그래밍의 가설, 검증 방식의 함정은 잘 동작하는 결과를 가졌을 때 발견된다. 예를들어 보자. 앞선 코드에서 가설, 검증 과정을 통해서 return 뒤의 1을 0으로 바꾸니 크래시가 발생하지 않고 잘 동작했다고 생각해보자. 그러면 이제 거기서 1을 0으로 바꾸고 끝을 내도 되는 것일까? 만약 끝을 내도 된다고 생각한다면 다음 우스개에 나오는 과학자와 비슷한 오류를 범하는 꼴이 된다.&lt;/p&gt;
&lt;p&gt;옛날에 한 과학자가 있었다. 파리에 관한 연구를 하던 과학자는 한날 박수를 치니 파리가 날아가는 것을 보고는 파리에게도 분명 귀가 있을 거라는 생각을 한다. 그리고 그 귀가 어디에 달려 있을까를 알아내기로 했다. 과학자는 가설을 세운다. 처음에는 파리의 귀가 다리에 붙어 있을 거라고 생각했다. 그래서 다리를 뜯었다. 그리고는 옆에서 박수 소리를 들려줬다. 그러니 파리가 날아서 도망을 갔다. 다리에 귀가 있다면 박수 소리를 못 들어 도망 가지 못했을테니 과학자는 다리는 아니라고 생각한다. 다음은 날개에 귀가 있다는 가설을 세운다. 그리고는 날개를 뜯고 실험을 했다. 그러자 이번에는 박수를 쳐도 파리가 도망 가지 않고 가만히 있었다. 과학자는 당당하게 실험 결과를 토대로 파리의 귀는 날개에 달려 있다는 논문을 쓴다.&lt;/p&gt;
&lt;p&gt;사실 위의 우스개는 과학이 가지는 본질적인 문제점을 풍자한 것이다. 요즘 발표되는 많은 논문들이 사실은 위와 다름이 없다. 어느 날은 비타민 과다 복용이 좋다고 했다가 어느 날은 과다 복용은 위험하다고 한다. 어느 날은 운동이 건강에 좋다고 했다가, 어느 날은 운동하다 죽는 사람이 더 많다고 한다. 과학이 이러니 프로그래밍도 이렇게 하면 되는 것일까? 하지만 거기엔 엄청난 차이가 있다. 가장 큰 차이는 과학이 탐구하는 대상인 자연, 인간, 우주 같은 것들은 본질적으로 우리가 만든 것이 아니다. 그러니 우리는 그 원리를 알 수 없기 때문에 귀납적 추론을 할 수 밖에 없다. 반대로 프로그래밍은 아주 사소한 약속 하나부터 모두 우리가 정한 것이다. 그러니 이 세계는 본질적으로는 귀납적으로 추리할 필요가 없다. 모두 우리가 만든 약속을 쌓아 올려서 만든 것이니 당연히 그 모든 것을 연역적인 방식으로 설명할 수 있어야 하는 것이다.&lt;/p&gt;
&lt;p&gt;앞선 return으로 돌아가 보자. 1을 0으로 바꾼 결과 정상 동작하는 것을 관찰했다면 그 다음은 무엇을 해야 할까? 왜 1이면 동작하지 않고, 0이면 동작하는지에 대한 설명을 할 수 있어야 한다. 만약 그걸 설명하지 못한다면 원인을 찾은 것도 아니고 코드를 이해한 것도 아니다. 이 단계에서 완전한 설명이 가능하고 그것을 다른 프로그래머에게 이야기를 했을 때에 똑같이 동의를 한다면 그것은 어느 정도 올바른 해결책을 찾은 것으로 간주해도 될 것이다.&lt;/p&gt;
&lt;h3&gt;완전한 이해&lt;/h3&gt;
&lt;p&gt;신입 프로그래머들이 실험 주도 프로그래밍의 함정에 빠지는 것은 그들이 이해해야 하는 어떤 대상에 대해서 완전한 이해를 하지 않기 때문인 것 같다. 완전한 이해의 대상은 기존에 작성된 코드일 수도 있고, 특정 프로그래밍 언어일 수도 있고, 특정 라이브러리나 프레임워크일 수도 있고, 특정 운영체제일 수도 있다. 심지어는 특정 표준에 대한 스펙일 수도 있다. 그런 대상에 대한 이해가 부족하기 때문에 어느 지점에서 문제가 발생한다는 것을 관찰했을 때에도 느낌표가 없고 계속 물음표만 존재하는 것이다.&lt;/p&gt;
&lt;p&gt;그렇다면 많은 신입 프로그래머들이 실력 향상을 원한다고 이야기를 하면서도 정작 중요한 문제 해결에 필요한 완전한 이해를 하지 않는 것일까? 아마도 그 과정이 시간이 오래 걸리고 고통스럽기 때문일 것이다. 따분하고 지루한 공부가 필요하다는 의미다. 하지만 안타깝게도 현실 세계에서 내가 관찰한 대부분의 경우는 공부가 부족한 경우가 많았다. 일단 대체로 절대적으로 공부하는 시간이 부족하다. 앞선 이해의 대상 중 어떤 것이든 간단하게라도 살펴보기 위해서는 상당히 많은 시간이 필요하다. 하지만 많은 신입 프로그래머들은 그런 연속된 시간을 투자하는 것을 시간 낭비라고 생각한다. 심지어는 퇴근 후에 컴퓨터를 본다는 것은 뭔가 손해보는 일이라고 생각하기까지 한다. 다음으론 검색의 지나친 발달로 인한 폐해를 들 수 있다. 대체로 거의 모든 문제에 대해서 구글 검색을 하면 결과가 나오기 때문이다. 그러니 복잡하고 원론적인 이해 보다는 단편적인 현상에 대한 답만 알고 넘어가려는 경향이 강하다. 그렇게 빈약하게 이해를 하더라도 문제가 해결되니 말이다.&lt;/p&gt;
&lt;p&gt;검색으로 얻는 파편적인 지식으로는 한계가 있다. 잘 쓰여진 좋은 책을 통해서 한 점이 아닌 전체적인 선 모양이 어떤지를 알 수 있는 공부를 해야 한다. 또 일주일에 한두시간 공부하는 것으로도 한계가 있다. 아마 환갑 잔치 때가 되서야 목표에 도달할 수 있을 것이다. 훨씬 더 많은 시간을 투자해야 한다. 물론 취미로 프로그래밍을 하거나 직업의 영속성이 크게 중요하지 않은 사람들에겐 이런 조언이 별로 중요하지 않을 수 있다. 하지만 반대로 해자를 구축하고 장기적으로 살아 남아야 하는 사람이라면 그래야 하지 않을까라는 생각을 해본다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;여기서는 제자리에 머물기 위해서라면 아주 빨리 달려야 해.&lt;br&gt;
만약 다른 곳에 가려면 지금보다 두 배는 빨리 뛰어야 하지.&lt;/p&gt;
&lt;p&gt;-— 거울 나라의 앨리스&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[[정보] 샌프란시스코 음식점들...]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2017/02/sf-food/</link><guid isPermaLink="false">https://jiniya.net/ng/2017/02/sf-food/</guid><pubDate>Fri, 17 Feb 2017 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;기억을 위해 샌프란시스코에서 가 본 음식점을 정리해 본다. 또 누군가에겐 도움이 되지 않을까 싶은 마음에…​&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://goo.gl/maps/HYmxWvQU9qy&quot;&gt;산라쿠&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;일식집. 초밥, 사시미, 롤, 우동, 튀김 등을 판다. 일식이 대체로 그렇지만 기본은 하는 집. 쏘쏘하다. 생각보다 손님이 많다. 식사 시간에 간다면 예약하고 가는 게 정신 건강에 좋을듯.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://goo.gl/maps/6M1BmMhGrmm&quot;&gt;수퍼 두퍼&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;이쪽 동네에 있는 햄버거 체인. 패티 두개 들어간 수퍼 버거를 먹었는데 약간 느끼했다. 토핑을 추가할 수 있는데 모두 추가한다는게 잘못돼서 그냥 일반 버거로 먹었다. 기름기가 많다. 피클을 나눠주는데 나눠주는 이유가 있는듯. 갠적으론 쉑쉑이 더 맛있었다. 첨 나오면 조그맣게 생겨서 양이 별로 안 되는 것 같은데 이동네 음식들이 다 그렇지만 먹고 나면 그런 생각이 싹 사라진다. 네이버 검색에 의하면 미니 버거에 이것 저것 추가해서 먹어보는 사람이 많은 것 같다.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://goo.gl/maps/3aDuf4pcgio&quot;&gt;닉스 라이트하우스&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;피어에 위치한 해산물 집. 랍스터와 만찬 세트(?!)를 먹어봤다. 아줌마가 장사를 잘한다. 랍스터는 진짜 큰 걸 먹었는데 그닥 취향은 아니었다. 만찬 세트도 그저 그런 정도. 와 맛있어서 찾아가야겠다 할 정도는 아님. 맥주는 맛있다.&lt;/p&gt;
&lt;p&gt;39번 피어 쪽에서 구경도 하고 가게를 찾아가는게 조금 더 현명한듯한 느낌적인 느낌.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://goo.gl/maps/518d46dtvKU2&quot;&gt;크랩 하우스 앳 피어 39&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;크랩집. 나쁘지 않았다. 배고플 때 한 번 가봐서 정확한 느낌은 아닐 수 있다.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://goo.gl/maps/sp2SR3VSST52&quot;&gt;존스 그릴&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;진짜 가지 말아야 할 집. 저주할 지어다. 스테이크 집인데 스테이크가 별로다. 비싸다. medium rare와 medium well을 시켰는데 medium well은 거의 태운 상태 medium rare는 색깔은 그런대로 맞춰 구어진 것 같은데 육즙이 제로였다. 스테이크가 아니라 고무 씹는 느낌. 역사가 오래된 느낌이어서 가봤는데 역사만 오래된 집이었다. 먹고 나서 yelp에 가봤더니 투어리스트 트랩이라는 평이 인상적이었다. 심지어 추리소설에 나온 적이 있는 집이라고 했다. 정말 돈 값 못하는 집…​ 참고로 함께 간 일행 모두 보통 뭔들 먹고 나서 맛없다는 이야기를 안 하는데 모두가 최악이라 평했다.&lt;/p&gt;
&lt;p&gt;너무 빡쳐서 나오면서 다른 사람들이 시킨 것도 살펴봤는데 죄다 육즙이 없기는 마찬가지. 손님은 정말 많아서 마치 진짜 맛집같은 느낌인데…​ 투어리스트 트랩이라는 평이 딱 맞다. 애피타이저까진 나쁘지 않았는데…​&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://goo.gl/maps/LzpUJdWmU9U2&quot;&gt;미스 사이공&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;미스 사이공, 베트남 쌀국수 집. 샌프란시스코에 왔을 때 첨 가 본 쌀국수 집. 이후에 다른 쌀국수 집도 몇 군데 가봤는데 이곳이 그나마 나은듯한 느낌. 블루보틀 근처라 나오면서 블루보틀에서 라떼 한 잔 하기 좋은 위치.&lt;/p&gt;
&lt;p&gt;고수를 싫어한다면 주문전에 노 실란트로 외워갈 것. 대체로 그렇지만 디폴트로 탑재해서 나온다.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://goo.gl/maps/WfLGRg1xc7q&quot;&gt;꼬꼬방&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;한국식 포차. 온갖 메뉴를 다 판다. 치맥을 주로 했는데 갈비가 먹을만 했다. 라면도 괜츈하다. 늦게까지(새벽 2시?!) 하는게 장점이다. 힐튼 쪽에 호텔이면 가깝다는 것도 큰 장점. 그래서 그런지 늦은 시간에 손님이 많다.&lt;/p&gt;
&lt;p&gt;이번에 길을 잘못 들어서 꼬꼬방 간다는게 aria라고 다른 곳을 갔는데 거기는 테이블이 별로 없고 주로 포장해서 가는 집인듯 했다. yelp 보고 찾아가면 대략 낭패.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://goo.gl/maps/7Py2ZmKvpjB2&quot;&gt;이자카야 닌자&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;이자카야. 그냥저냥 먹을만하다. 시킨 거 먹기만 해서 그닥 무슨 메뉴가 있었는지 잘 기억이 안남.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://goo.gl/maps/UeZ1ZFYg3V42&quot;&gt;고려정&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;한식 고기집. 삼겹살과 갈비를 먹어봤는데 쏘쏘하다. 10시에 문을 닫는다는게 술을 많이 마시는 사람 입장에서는 다소 부담스러울 수도 있다.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://goo.gl/maps/LdnHGoBMMts&quot;&gt;산왕반점&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;중국집. 한번쯤 가서 먹기에 괜찮다. 짬뽕 국물도 괜찮고 다른 요리 메뉴도 대체로 다 괜찮은듯.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://goo.gl/maps/qFuebhzcxdF2&quot;&gt;블루보틀 커피&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;샌프란시스코의 명물이라고 했는데 그 출발점이 다소 불분명하다. 여튼 샌프란시스코에 파는데가 있다. 처음 가보면 간판에 이름도 없고 파란병만 그려 있는 것이 다소 황당하다. 라떼가 맛있다. 탁월한 부드러움, 적당한 온도, 고소함이 특징. 사실 다른 라떼랑 섞어 놓고 고르라면 고를 자신은 의문…​&lt;/p&gt;
&lt;p&gt;블루보틀 앞에 푸드 트럭이 있는데 의외로 현지인들에게 인기있는 듯 하다. 보울드 아사이라고, 기회되면 한 번 먹어 보고 싶었다. 현지인들이 많이 먹는 것으로 봐서는 먹을만한 것 같은 느낌적인 느낌. 한국으로 치면 일종의 컵밥 같은?! 단점이라면 근처에 홈리스가 많아서 잊을만하면 한번씩 온다는 점.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://goo.gl/maps/6UpGeyMB6ym&quot;&gt;태드네 스테이크&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;스테이크만 달랑 나온다. 싸고 양이 많은 게 장점인듯. 그냥저냥 먹을만 하다. 존스 그릴 보다는 백만배쯤 맛있다.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://goo.gl/maps/RkyzDZs5L9q&quot;&gt;테일러 커피숍&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;아침을 판다. 엄청 좁다. 아침에 가면 사람이 좀 있다. 재수 없으면 엄청 오래 기다려야 함. 그냥 미국식 아침 메뉴를 판다. 베이컨, 에그, 뭐 그런. 먹을만 하다.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://goo.gl/maps/hbMxTA7yfNv&quot;&gt;진미순두부&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;순두부집. 샌프란시스코에는 BCD 북창동 순두부는 없는 듯 하다. 왤까? 해물순두부만 먹어봤는데 그럭저럭 먹을만하다. 아침 식사 가능하다.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://goo.gl/maps/vpegiePHGLR2&quot;&gt;더 스피나커&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;다운타운에 있는 집은 아니다. 금문교 건너 소살리토라는 동네에 위치한 집. 바다에 완전 접해 있어서 전망이 예술이다. 간다면 꼭 창가 자리로 예약할 것. 스테이크를 먹었었는데 맛있었다. 소살리토도 구경하기 좋은 동네. 다운타운이랑은 분위기가 천지차이다. 일단 홈리스와 지린내가 없다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] RSA 2017 DAY #2]]></title><description><![CDATA[1일차는 노스관 2일차는 사우스관을 봤다. 사우스 쪽은 우리랑 비슷한 일을 하는 업체는 없는 것으로 보였다. 1, 2일 모두 쭉 돌아보면서 많이 본 키워드를 뽑아 보면 breach, endpoint, malware, NGAV(Next…]]></description><link>https://jiniya.net/ng/2017/02/rsa-2017-day-2/</link><guid isPermaLink="false">https://jiniya.net/ng/2017/02/rsa-2017-day-2/</guid><pubDate>Fri, 17 Feb 2017 10:00:01 GMT</pubDate><content:encoded>&lt;p&gt;1일차는 노스관 2일차는 사우스관을 봤다. 사우스 쪽은 우리랑 비슷한 일을 하는 업체는 없는 것으로 보였다. 1, 2일 모두 쭉 돌아보면서 많이 본 키워드를 뽑아 보면 breach, endpoint, malware, NGAV(Next Generation Anti-Virus), mobile, virtual 정도 인 듯. 대략 그런 일을 하는 업체들이 많은 것 같다. 백신 업체도 더이상 백신 이야기를 많이 하지 않는 느낌적인 느낌. 메이저 백신 업체들의 타겟팅은 이제 일반 PC 보다는 IoT 쪽이 많은 것 같아 보였고, 심지어는 국가 기간망을 대상으로 영업 활동을 전개하는 곳도 있어 보였다.&lt;/p&gt;
&lt;p&gt;이런 쇼 오면 꼭 하나 살펴보는 게 빨때 꼽는 업체들을 찾아본다. 보안 쪽은 로그 서비스와 라이브러리 정도가 전부인 것 같다. 보안 업체 특성 상 또 외부 솔루션을 잘 사용하지 않기 때문인 것 같아서 그런 것 같기도 하다. 직원 보호 솔루션이라 쓰고 감시(?!)하는 솔루션도 더러 있었는데 약간 무섭기도 했다.&lt;/p&gt;
&lt;p&gt;대체로 대다수 업체가 센서를 통해서 온갖 정보를 수집하고 인공 지능이나 머신 러닝 같은 기술을 사용해서 마이닝을 하여 뭔가 찾아낸 다음 그걸 알흠답게 고객에게 뷰잉해주겠다는 방향으로 달려가는 것 같은 느낌…​&lt;/p&gt;
&lt;p&gt;또하나 인상적인 것은 미국 국가 기관 부스가 많이 있었다. 대체로 홍보나 기술 전시 보다는 채용에 목적을 둔 것으로 추정되는데 신기한 점이긴 했다. 한국 업체 중에서는 파수가 그나마 부스를 멋들어지게 만들었다. 부스만 보고는 한국 업체 아닌줄…​ ㅋㅋㅋ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] RSA 2017 DAY #1]]></title><description><![CDATA[세계 최대 보안 컨퍼런스인 RSA…]]></description><link>https://jiniya.net/ng/2017/02/rsa-2017-day-1/</link><guid isPermaLink="false">https://jiniya.net/ng/2017/02/rsa-2017-day-1/</guid><pubDate>Thu, 16 Feb 2017 10:00:01 GMT</pubDate><content:encoded>&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./rsa_badge.jpg&apos; data-alt=&apos;Figure 1. RSA 2017 엑스포 배지&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 315px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/77384aa6a195909aee19d28ec57af609/ba98e/rsa_badge.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 133.1578947368421%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAMEBQH/xAAWAQEBAQAAAAAAAAAAAAAAAAABAwL/2gAMAwEAAhADEAAAARelw3KaImeiqeU0ihr/AP/EAB0QAAICAgMBAAAAAAAAAAAAAAACAQMREgQTMSH/2gAIAQEAAQUCwexpYaLELk+k8ga5jtOtDxrLGiz/xAAZEQADAAMAAAAAAAAAAAAAAAAAARECEkH/2gAIAQMBAT8BKa5vonD/xAAWEQEBAQAAAAAAAAAAAAAAAAAQESH/2gAIAQIBAT8Bwp//xAAbEAACAwEBAQAAAAAAAAAAAAAAAQIhMREQMv/aAAgBAQAGPwLnRRPkwvzDUi5MdGIkk6P/xAAdEAACAgIDAQAAAAAAAAAAAAABEQAhUXExQWGx/9oACAEBAAE/Iblk9MSxlTcl4LjxxXb5L5gA0R3OnpRs/cFzm5SAAPER4A0FP//aAAwDAQACAAMAAAAQa9D9/8QAGhEAAgIDAAAAAAAAAAAAAAAAAAEQETFRwf/aAAgBAwEBPxC1qKyAxK4f/8QAGREAAwEBAQAAAAAAAAAAAAAAAAERIUFR/9oACAECAQE/EFHCrwo16f/EABwQAQEBAQEAAwEAAAAAAAAAAAERACExUWGBof/aAAgBAQABPxBBmKNwwAGSdaeZu9fZe4WF6Hr/AHXUD4kB+adAVwgeL6CZA8TsVXE+ReRyfmYKGnq6JmAgdwTiA5w3/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 1. RSA 2017 엑스포 배지&apos; title=&apos;&apos; src=&apos;/static/77384aa6a195909aee19d28ec57af609/ba98e/rsa_badge.jpg&apos; srcset=&apos;/static/77384aa6a195909aee19d28ec57af609/8ccab/rsa_badge.jpg 190w,
/static/77384aa6a195909aee19d28ec57af609/ba98e/rsa_badge.jpg 315w&apos; sizes=&apos;(max-width: 315px) 100vw, 315px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 1. RSA 2017 엑스포 배지&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;세계 최대 보안 컨퍼런스인 RSA에 처음으로 참관했다. 뭐 배우러 온것은 아니고 세상이 어찌 돌아가는지 구경하는게 목적이라 엑스포만 참관했다. 그간 다녀본 게임 관련 쇼나 컨퍼런스랑은 다소 다른 분위기였다. 보안이라 그런지 대체로 거의 모든 사람이 정장을 입고 있다는데 적응이 되지 않았고, 보안이라 비주얼이 약해서 보는 재미가 별로 없었다. 대부분의 부스가 그럼에도 액티브하게 보이려고 노력을 했지만 한계가 있어 보였다. 말이 많이 필요했고, 부스도 대체로 수많은 텍스트로 꾸며진 경우가 많았다.&lt;/p&gt;
&lt;p&gt;어쨌든 참관하면서 관심 있게 본 유사 분야 업체를 간단히 정리해 본다. 별로 없을 줄 알았는데 생각보다 없지는 않았다. 알리바바가 특히 의외였다. 마윈 회장이 자율 주행 자동차도 만든다고 얘기하는 걸 티비에서 본 적이 있었는데 정말 안 하는게 없는 것 같다.&lt;/p&gt;
&lt;p&gt;GuardSquare
안드로이드에서 많이 사용되는 난독화 도구인 ProGuard, DexGuard의 제작사. DexGuard 플러그인으로 DexGuard NDK와 Secure Keyboard, Device Fingerprinting이 있다는 것을 새롭게 알게 됐다. 그리고 iOS 버전으로 새롭게 출시한 iXGuard가 있다는 것도. 부스에서 iXGuard를 그닥 홍보하고 있지는 않았다. 왤까?&lt;/p&gt;
&lt;p&gt;AlibabaCloud Mobile Security
알리바바에서 클라우드를 하는 업체인 알리바바클라우드에서 모바일 보안 서비스도 제공하고 있는 것으로 보여진다. Alibaba JAQ Security Solution으로 불리는 것으로 애플리케이션 하드닝으로 표현하는 기술이 기존에 난독화 솔루션이 대체로 제공하는 기능으로 보여진다. 브로셔를 보면 SO, DEX 난독화 기능을 SO shelling, DEX shelling으로 표현한게 인상적. 껍데기를 씌우는거라 그렇게 표현한 것으로 추측된다. 인상적인 부분은 Java execution simulation 자바단의 코드를 덤프하는 것을 막기 위해서 별도의 환경에서 코드를 돌리는 기술을 말하는 것으로 보여졌다.&lt;/p&gt;
&lt;p&gt;알리바바가 이런 것도 한다는게 다소 신기했다. 대기업들이 돈되는 건 다하는 세상인 것 같아 조금은 씁슬한 면도 없잖아 있었다. 불과 몇년만에 알리바바를 스타트업에서 대기업으로 표현하는 게 좀 웃기긴 하지만. 어쨌든 이제는 대기업이니…​&lt;/p&gt;
&lt;p&gt;ARXAN
기술적인 진화 보다는 시장을 분류해서 마케팅하는 방법이 인상적이었다. 게임을 위한 제품(for Gaming), 모바일 결제 및 뱅킹을 위한 제품 (for Mobile Payment &amp;#x26; Banking), 헬스케어 장비를 위한 제품 (for Healthcare IoT), 자동차 장비를 위한 제품(for Automotive IoT)으로 나눠서 제품을 만들었다. 물론 근간이 되는 기술은 크게 다르지 않은 것으로 보여진다. 사실 자동차까지는 많이들 얘기하지만 의료 장비는 다소 의외였다. 보안이 필요 없는 분야가 있겠냐만은, 의료장비 레퍼런스가 있는지가 조금 궁금하긴 했다.&lt;/p&gt;
&lt;p&gt;AllthatSoft
쉴딩 형태의 제품으로 보여지는 모바일 코드 보호 제품인 App Servo를 홍보하고 있었다. 제품의 기술적인 특이점은 흔히 스톨른 바이트(Stolen Bytes)라고 불리는 기법을 적용한 제품이라는 것. 원본 코드를 분리하고 특정 코드를 외부에 보관한 다음 필요한 시점에 동적 결합 또는 원격 실행을 하는 구조인 것으로 보여진다. 해당 회사는 그 기능을 Self-Randomization으로 소개하고 세부 주요 구현 기술로 CODE-SPLITTING, SELF-MODIFYING이라고 설명했다. 어쨌든 스톨른 바이트에 기반한 앱 보호 제품은 첨 본 것 같다.&lt;/p&gt;
&lt;p&gt;적용 분야로 모바일 결제, 모바일 뱅킹, 자동차 공유, 모바일 게임을 들고 있다. 자동차 공유 서비스를 타게팅한 것도 다소 의외였다.&lt;/p&gt;
&lt;p&gt;intertrust
whiteCryption의 Code Protection 기능이 하드닝, 난독화 기능을 제공하는 것으로 보여진다. 대체로 브로셔에서 설명하는 개념은 ARXAN이랑 비슷한 것으로 보여졌다. 단지 ARXAN은 가드라고 부르고 intertrust는 체커라고 부르는 게 차이점인듯.&lt;/p&gt;
&lt;p&gt;덧) 구경하는데 왜 이렇게 줄이 길지 하는 곳이 있었다. 뭐 나눠 주나보다 했는데 케빈 미트닉 옹께서 &quot;The Art of Invisibility&quot;라는 본인의 저서에 사인을 해주고 사진을 같이 찍어주는 행사를 하고 있었다. 첨에는 케빈 미트닉이 아닌 줄 알았다. 줄이 길고 피곤해서 사인북을 받지는 않았는데, 나중에 나와서 검색해보니 매년 오시는 것 같다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] 광고, 예술이 되다.]]></title><description><![CDATA[어쩌다 유튜브 보는데 나온 광고. 차에 관심 1도 없는데 살짝 심쿵했다. 간지 멘트하며, 그 멘트들의 절묘한 전개, "The balance isn’t found. It’s created…]]></description><link>https://jiniya.net/ng/2017/02/super-bowl-ads/</link><guid isPermaLink="false">https://jiniya.net/ng/2017/02/super-bowl-ads/</guid><pubDate>Fri, 10 Feb 2017 12:00:01 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/piU6jh56NPE?si=rlkT5QfwPzwJHzpg&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;p&gt;어쩌다 유튜브 보는데 나온 광고. 차에 관심 1도 없는데 살짝 심쿵했다. 간지 멘트하며, 그 멘트들의 절묘한 전개, &quot;The balance isn’t found. It’s created&quot;에서는 이래서 이빨에 넘어가는 구나 했다. 저 느린듯 템포 있게 조화로운 배경 음악 하며. 저 차 사면 진짜 막 용에 올라타는 그런 느낌일거 같고…​ 급기야 무슨 브랜드인지를 몰라서 심지어 정지시켜 놓고 검색해보게 만드는 위엄. 이래서 광고가 돈이 되는구나 싶다. 하지만 결정적으로 차 디자인은 내 스타일은 아니긔…​ ㅋㅋㅋ&lt;/p&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/HIpoTW1JDFQ?si=YxqzUM0Qum65d4qK&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;p&gt;정반대 느낌의 기아차 슈퍼볼 광고, 재미는 있다. 아니 재미만 있다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 당신의 연말 정산 이야기]]></title><description><![CDATA[연말 정산 시즌이다. 이맘때면 한숨과 고성이 오간다. 13월의 급여를 받는 사람도 있고, 한달치 급여가 사라진 사람들도 있다. 연말 정산의 아픔이 잊혀질만한…]]></description><link>https://jiniya.net/ng/2017/02/tax/</link><guid isPermaLink="false">https://jiniya.net/ng/2017/02/tax/</guid><pubDate>Mon, 06 Feb 2017 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;연말 정산 시즌이다. 이맘때면 한숨과 고성이 오간다. 13월의 급여를 받는 사람도 있고, 한달치 급여가 사라진 사람들도 있다. 연말 정산의 아픔이 잊혀질만한 4월이 되면 건보료 폭탄이 또 한 번 때린다. 대체로 급여가 오른 만큼 건보료도 정산해서 토해낸다. 그때는 다들 한숨만 깊어진다. 나이가 들고 연봉이 오르고 하다보면 결국 알게 되는 건 세금 밖에 없다.&lt;/p&gt;
&lt;p&gt;토해내는 입장에서는 도대체 돌려 받는 사람들은 왜 돌려받는지가 무척 궁금해진다. 그리고 무지에 의해서 마치 엄청난 비밀이 숨어 있는 것처럼 음모론들을 제기해 보지만 거기에 음모 따위는 없다. 그저 여러분이 국가가 장려하는 활동을 많이 하면 혜택을 많이 주고, 국가가 싫어하는 활동을 많이 하면 세금이 많아지고 하는 것이다. 각설하고 이 말도 많고 탈도 많은 연말 정산이 어떤 구조로 이루어지는지 살펴보도록 하자.&lt;/p&gt;
&lt;p&gt;연말 정산은 말 그대로 일년 동안 내야할 세금을 최종적으로 확정짓는 과정이다. 대한민국은 급여소득자에게 세금을 미리 원천 징수하고 나중에 다시 정산 과정을 통해서 원천 징수한 금액이 많으면 돌려주고, 적으면 더 받아내는 시스템을 사용한다. 흔히 직장인 급여를 유리 지갑이라고 하는 이유가 여기 있다. 애초에 받을 때 국가에 신고가 들어가고 세금은 공제하고 남은 차액만 받기 때문이다. 당신의 급여 명세서 항목 중에서 소득세와 지방세라는 것이 국가가 이렇게 미리 뜯어가는 비용이다.&lt;/p&gt;
&lt;p&gt;그러면 그냥 원천 징수만 하고 끝내면 될텐데 왜 연말 정산이라는 것을 할까? 원천 징수는 표준 모형에 의한 것이기 때문에 원천 징수를 얼마 할지는 급여가 정해지면 일괄적으로 책정된다. 하지만 국가가 그리 나쁜 놈들은 아니다. 아니면 더 나쁜 놈일수도 있다. 어쨌든 그런 이유로 국가는 사람들이 그 급여를 몽땅 다 써버리길 원하지 않는다. 그들의 미래를 위해서 쓰기를 바라기도 하고 자신들의 세금 계산을 위해서 현금이 아닌 카드를 사용하기를 원하기도 한다. 또 부양 가족이 있어서 돈이 많이 필요한 사람들에게는 세금을 감면해 주기도 한다. 결국 국가는 최종적으로 개개인들에게 그들의 돈을 어떻게 사용해야 할지에 대한 인센티브를 세금을 통해서 제공한다고 보면 된다.&lt;/p&gt;
&lt;p&gt;그럼 먼저 소득세를 어떻게 계산하는지에 대해서 간단히 살펴보자. 대한민국의 소득세는 누진적 구조로 이루어져 있다. 즉 많이 벌면 세금을 더 많이 내도록 된 구조다. 살펴보면 1200만원 이하는 6%의 세금을, 그 다음 4600만원 이하는 15%의 세금을 그 다음 8800만원 이하는 24%의 세금을, 그 다음 1억 5000만원 이하는 35%의 세금을, 그 다음 5억 이하는 38%의 세금을, 5억을 초과하면 40%의 세금을 낸다. 자, 통크게 내 연봉이 10억이라고 가정해보자. 그럼 얼마를 세금으로 내야 할까? 1200만원까지는 72만원 4600만원까지 510만원, 8800만원까지 1008만원, 15000까지 2170만원, 5억까지 13300만원, 끝으로 10억까지 20000만원을 세금으로 낸다. 다 더하면 72 + 510 + 1008 + 2170 + 13300 + 20000 = 37060만원을 세금으로 낸다. 여기에 10% 지방세가 붙는다. 3706만원을 지방세로 납부하니 최종적으로는 10억을 벌면 국가에 4억 하고도 766만원을 세금으로 내야 한다. (계산하고 공제하는 더 간편한 방법이 있다. 단지 어떻게 세금이 누진되어 가는지를 보여주기 위해서 불편한 방법을 썼다.)&lt;/p&gt;
&lt;p&gt;다음으로는 이제 이렇게 산정된 소득세에 대해서 어떤 방식으로 인센티브를 제공하는 살펴보자. 인센티브를 제공하는 방식은 크게 두 가지 방식이 있다. 하나는 소득 공제이고 다른 하나는 세액 공제다. 소득 공제는 전체 소득에서 정해진 만큼 빼고 세금을 계산하는 방식이고, 세액 공제는 최종 확정된 세금에서 정해진 만큼 빼는 구조다. 이 둘의 차이는 쉽게 말하면 이렇다. 소득 공제는 세금 계산 전에 빼기 때문에 혜택이 차등적이고, 세액 공제는 균등하다. 다시 말하면 소득 공제는 배율을 확정짓기 전에 빼기 때문에 고소득자일수록 유리하다. 최고 세율인 40%인 사람들의 경우 100만원 소득 공제가 되면 40만원을 돌려 받는 것과 동일한 효과를 가진다. 반면 소득세율이 15%인 사람은 15만원을 돌려받는데 그친다. 똑같이 100만원 쓴 것에 대한 혜택을 받는데 고소득자가 더 유리한 제도인 것이다. 반면 세액 공제는 최종 금액에서 차감하기 때문에 동일한 활동을 했을 때 고소득자와 저소득자가 받는 차이는 크게 없다.&lt;/p&gt;
&lt;p&gt;여기서 조삼모사가 나온다. 예를 들면 연금저축을 들 수 있다. 이게 원래 400만원까지 소득 공제 항목에 있었다. 그러면 40% 세금을 낸다면 연 160만원을 돌려받을 수 있고, 20% 세금을 내는 사람은 80만원을 돌려 받는 구조였다. 그런데 정부에서 이를 세액 공제로 변경했다. 그리고는 400만원을 납입하면 연 100만원을 세액 공제 해준다고 한 것이다. 40% 세금을 내던 사람은 이제는 60만원을 덜 돌려 받게 되었고, 20% 세금을 내던 사람은 20만원을 더 돌려받게 된다. 즉, 대체로 세액 공제로 바뀌면 없는 사람에게 더 유리해 지는 것이다. 그럼에도 정부가 그때 개욕을 먹었던 것은 저 세액 공제율을 잘못 선정하는 바람에 고소득자든 저소득자든 다 손해보는 구조를 만들어서 그런 것이었다. 물론 그것조차도 계획된 것일 수 있지만…​ (참고로 여기에 제시된 수치들은 가상적인 수치다)&lt;/p&gt;
&lt;p&gt;자 이게 연말 정산의 모든 비밀이다. 국가가 세금을 미리 계산해서 가져갔고, 연말 정산을 할 때에는 이제 국가가 장려하는 활동에 얼마를 썼느냐에 따라서 세금을 다시 조정할 것이다. 국가가 좋아하는 일을 했다면 세금을 많이 돌려받을 것이고, 국가가 싫어하는 일을 했다면 그닥 못 돌려 받을 것이다.&lt;/p&gt;
&lt;p&gt;2017년 대한민국은 어떤 활동에 인센티브를 제공하는지 살펴보자. 소득 공제 항목을 살펴보면 이렇다. 부양 가족. 최고로 갑이다. 벌이가 없는 부모님, 자식 등을 부양가족으로 올리면 일정 수준 소득 공제를 해준다. 더불어 그 부양 가족이 사용한 모든 비용도 내가 사용한 비용으로 인정해준다. 일정 조건에 합당한 무주택자가 집 산다고 빌린 돈. 님들이 집을 사도록 국가가 유도하는 것이다. 어쨌든 이를 갚은 것들은 국가가 비용으로 인정해주고 일정 수준 세금을 감면해 준다. 신용카드 사용액, 이는 최초에는 현금이 아닌 신용카드 사용을 장려하기 위해 생긴 제도였다. 지금은 많이 퇴색되어 수명이 오늘 내일 하는 소득공제 항목 중에 하나다. 여기에 관해 생긴 가장 큰 오해 중에 하나가 연말 정산에서 많이 쓰면 많이 돌려받는 다는 것이다. 그런데 신용 카드 사용에 관해서는 아주 복잡한 공식이 존재하지만 결론만 말하면 쓰는 금액 대비 공제해 주는 양이 아주 적기 때문에 이를 위해서 지출을 늘리는 것은 정말 바보 같은 행위다. 기부금. 이는 사실 소득공제로 보긴 힘들다. 기부한 금액보다는 적게 소득 공제를 해주기 때문이다. 주택마련 저축 납입금. 집 산다고 통장을 만들어 납입하면 정해진 한도 내에서 소득 공제를 해준다. 그리고 일반인들에게는 잘 알려지지 않았지만 지금 최고의 소득 공제 항목으로는 벤처 기업 투자가 있다. 조건에 해당하는 벤처기업에 투자할 경우 파격적인 소득 공제 혜택을 준다.&lt;/p&gt;
&lt;p&gt;세액 공제 항목을 살펴보면 이렇다. 보장성 보험을 가입하면 연간 100만원 한도 내에서 일정 수준 세액 공제를 해준다. 일년에 여유되면 100만원 정도는 보장성 보험에 돈을 투자하라는 예기다. 연금저축 연간 400만원 한도 내에서 일정 수준 세액 공제를 해준다. 이는 말이 많은 항목인데 더 맡이 많아지게 되었다. 왜냐하면 정부의 안대로 지금 당장 납입하면 세액 공제를 받을 수 있지만 나중에 연금을 받을 때 다시 세금을 납부하기 때문에 실제로는 정말 조삼모사같은 상품이기 때문이다. 이는 실상은 과세 이연이지 혜택이라고 보기는 힘들다. 그래도 어쨌든 국가는 여러분의 미래를 위해서 연금을 들기를 희망하고 있다. 퇴직 연금 또한 연에 300만원 한도로 세액 공제를 해준다. 의료비, 교육비도 일정 수준 공제를 해준다. 또 정치 기부금의 경우 10만원까지는 전액 세액 공제가 된다. 좋아하는 국회의원이 있다면 10만원 기부하면 10만원을 돌려받게 된다. 참으로 신박한데 법을 누가 정하는지 알게되면 왜 이런 신박한 제도가 생겼는지 절로 이해가 된다. 월세에 대한 세액 공제도 해준다. 일정 수준의 조건이 맞아야 하지만 월세로 납부한 금액의 일부를 세액 공제로 돌려준다.&lt;/p&gt;
&lt;p&gt;자 종합해보면 그렇다. 정부는 여러분이 결혼을 해서(+부양가족) 빚을 내서(+대출) 집을 산(+부동산) 다음에도 여유가 있다면 기부를 하기를 희망한다. 자신의 소득의 일정 수준 이상은 신용카드로 사용하기를 희망하고, 신용카드 보다는 체크카드 사용을 더 장려하고 있다. 보장성 보험을 연간 100만원 정도 내기를 바라고, 개개인의 미래를 위해서 연금 저축을 400만원, 퇴직 연금을 300만원 정도 매년 투자하기를 바란다. 국회 의원에게는 매년 10만원 정도 무조건 기부를 했으면 하고, 여러분이 그나마 월세에서 고통 받는 것을 조금은 덜어주고 싶어한다. 그리고 여러분이 이 모든 활동을 넘어서 돈이 너무 많은 자산가라면 벤처 기업에 투자하기를 희망한다.&lt;/p&gt;
&lt;p&gt;조금 더 현실적인 조언을 해보자. 여러분이 일반적인 급여 수준의 미혼 남성이라면 어떤 활동을 하는 것이 좋을까? 일단 영혼까지 끌어모아 부양가족 수를 늘린다. 청약 저축을 만들고 매달 10만원씩 납부한다. 보장성 보험이 없다면 만들고 매달 9만원 정도 납부하고, 연금 저축을 개설하고 매달 34만원씩 납부하고, 퇴직 연금이 된다면 매달 25만원씩 납부하고, 12월에 한 번 그 해 제일 맘에 드는 국회의원에게 10만원 기부를 하면 대체로 정부가 원하는 대로 행동했다고 볼 수 있겠다. 물론 월세를 살고 있다면 월세 비용도 공제 받으면 금상첨화.&lt;/p&gt;
&lt;p&gt;끝으로 최근 들어 생긴 조삼모사 끝판 대장 중에 하나를 소개하고 마칠까한다. 바로 원천 징수율을 결정하는 것이다. 80%, 100%, 120% 중에 선택할 수 있다. 적게 내고 적게 돌려 받을 지, 사전에 많이 떼고 많이 돌려받을지 결정하는 것이다. 대체로 자금 관리에 자신이 있는 사람이라면 80%가 유리하다. 왜냐하면 시간 가치가 있기 때문이다. 이자도 없이 정부가 일년간 묵혔다가 주는 돈을 받는 것 보다는 먼저 많이 받고 그 돈을 투자해서 불리는 것이 유리하기 때문이다. 모두가 이상적인 사람으로만 구성되었다면 사실상 100%와 120%는 의미 없는 선택지다. 하지만, 여러분이 비자금이 필요한 유부남이라던가, 자금 관리에는 젬병인 사람이라면 120%를 선택하는 것도 나쁘진 않다. 어쨌든 미리 많이 뗐기 때문에 돌려 받을 돈이 많을 수 밖에 없다. 강제 비자금 통장, 강제 적금 통장으로 국세청을 이용하는 셈이된다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 서울 유동인구 어디가 많을까?]]></title><description><![CDATA[200…]]></description><link>https://jiniya.net/ng/2017/02/seoul-floating-population/</link><guid isPermaLink="false">https://jiniya.net/ng/2017/02/seoul-floating-population/</guid><pubDate>Mon, 06 Feb 2017 10:00:01 GMT</pubDate><content:encoded>&lt;p&gt;2003년에 처음 구로공단에 내렸을 때가 생각난다. 병역특례 전직 업체를 찾아서 온 서울, 그 전 면접은 최악이었다. 스마트폰도 없던 시대. 주소 하나 가지고 건물을 찾아가야 하는 상황, 뭔가 이상해서 길을 물어보면 아무도 길을 몰랐다. 그렇게 서울은 20대의 나에겐 차가운 도시였다.&lt;/p&gt;
&lt;p&gt;병역특례를 마치고는 영원히 인연이 없을것 같았던 구로디지털단지에 10년이 훌쩍 넘는 내 청춘의 시간을 갈아 넣었다. 그나마 조금의 위안이 있다면 2003년과 지금은 상전벽해라는 말이 어울릴 정도로 많이 변했다는 것 하나. 온통 공사중이던 빌딩들은 이제 더 이상 지을 공간이 부족할 정도로 빼곡이 들어섰고, 그 사이 호텔이 두개나 지어졌고, 최근 들어 국내에서 돈을 제일 잘 번다는 게임사도 본사를 두고 있다. 가끔 지인들과 근처에서 술을 마시면 이런 얘기들을 하곤 한다. 여기가 요즘 서울에서 유동인구로는 순위권에 드는 동네라고 말이다. 뭐 사실 근거 있는 얘기는 아니었다. 그냥 먹자 골목에 사람이 많다는 것, 그리고 우리가 들어간 식당에 대기가 너무 길다는 것 같은 추상적인 현상을 토대로 하는 말들어었다.&lt;/p&gt;
&lt;p&gt;문득 갑작스럽게 그 말이 진짜인지 궁금했다. 구글 검색을 해보았지만 예전 데이터 뿐이었다. 이럴 때는 프로그래머라는 직업이 다소 편리하다. 디지털 데이터는 도처에 널려있고, 프로그래머는 그것들을 아주 손쉽게 입맛에 맞게 가공할 수 있기 때문이다. 다양한 방법이 있겠지만 나는 그 지역 대중 교통을 사용하는 사람의 인원으로 유동인구를 측정해 보기로 했다. 서울 시에서 제공하는 공공 원시 데이터를 가공해서 수치를 뽑아 보았다.&lt;/p&gt;
&lt;p&gt;먼저 지하철이다. 2016년 12월 승하차 데이터를 대상으로 집계한 순위다. 데이터 내용은 순번, 만단위 승하차인원, 지하철역이다. 2호선 강남역이 1등으로 12월 한달간 562만명이 그 역에서 승하차를 했다. 2등은 잠실역으로 480만명, 3등은 홍대로 473만명이 이용을 했다. 회사가 있는 구로디지털단지역은 5등으로 357만명이 승하차를 했다. 다음 역들을 보아도 대체로 우리가 알고 있는 유명한 역들이 상위권에 랭크돼 있는 것을 확인할 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;001 562 2호선_강남
002 480 2호선_잠실(송파구청)
003 473 2호선_홍대입구
004 399 2호선_신림
005 357 2호선_구로디지털단지
006 350 2호선_신도림
007 347 2호선_삼성(무역센터)
008 326 3호선_고속터미널
009 315 1호선_서울역
010 301 2호선_을지로입구
011 297 경부선_영등포
012 288 2호선_선릉
013 287 2호선_서울대입구(관악구청)
014 285 2호선_신촌
015 274 1호선_종각
016 271 2호선_역삼
017 270 2호선_강변(동서울터미널)
018 270 4호선_혜화
019 267 2호선_건대입구
020 263 2호선_사당
021 253 4호선_명동
022 252 4호선_수유(강북구청)
023 251 5호선_광화문(세종문화회관)
024 241 경부선_수원
025 240 3호선_양재(서초구청)
026 233 3호선_연신내
027 227 경인선_부천
028 227 7호선_가산디지털단지
029 223 경인선_부평
030 221 2호선_교대(법원.검찰청)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;다음은 버스를 기준으로 살펴보았다. 같은 기간 2016년 12월 데이터로 순번, 정류장ID, 만단위 승하차 인원, 역이름이다. 정류장ID는 네이버 지도를 이용하면 해당 역의 위치가 어디인지 검색된다. 버스는 미아사거리와 수유역이 1, 2등을 차지했다. 강남역은 3등에 54만명, 11위에 46만명이, 구로디지털단지는 4등에 53만명, 6등에 51만명이 랭크됐다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;001 09012 064 미아사거리역
002 09004 061 수유역.강북구청
003 22012 054 지하철2호선강남역
004 17014 053 구로디지털단지역환승센터
005 22020 051 고속터미널
006 21001 051 구로디지털단지역
007 09011 049 미아사거리역
008 22019 048 고속터미널
009 06015 047 청량리역환승센타
010 24146 046 잠실역.롯데월드
011 22011 046 지하철2호선강남역
012 09013 045 수유(강북구청)역
013 08008 045 돈암사거리.성신여대입구
014 19112 044 경방타임스퀘어.신세계백화점
015 14015 043 홍대입구역
016 21148 040 신림사거리
017 08010 039 삼선교.한성대학교
018 24138 037 잠실역.롯데월드
019 06019 037 청량리역환승센터
020 21350 037 신림사거리.신림역
021 14016 036 홍대입구역
022 11283 035 석계역1번출구A
023 17001 035 신도림역
024 21916 034 신림역4번출구
025 17002 034 신도림역
026 21117 034 신림사거리.신림역
027 08007 033 돈암사거리.성신여대입구
028 02140 032 롯데백화점
029 24132 032 잠실역8번출구
030 13028 032 홍제역&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;상기 데이터로 볼 때 우리가 얘기했던 구로디지털단지가 강남, 홍대 수준의 유동인구를 가지고 있다는 말은 실제 사실인 것으로 보인다. 압구정과 신촌이 죽었다는 것도 어느 정도 사실인 것으로 보인다. 번외로 신기했던 점은 전혀 몰랐던 수유역이 사람이 많다는 점과 신림역은 알았지만 생각외로 많다는 점 정도인 것 같다. 시간 나면 장기 데이터를 토대로 추계를 뽑아보면 더 재밌을거 같기도 하다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] CES 2017 DAY #3]]></title><description><![CDATA[미국시간 2017.01.06 14:00 pm - 20:00 pm 전날의 여파로 모두가 늦잠을 잤다. 그나마 S만 일찍 일어났다. S가 네 번 Y와 J를 깨웠지만 그들은 너무 깊이 잠든 상태였다. TKS가 먼저 CES를 구경하로 떠났다. S…]]></description><link>https://jiniya.net/ng/2017/01/ces-2017-day-3/</link><guid isPermaLink="false">https://jiniya.net/ng/2017/01/ces-2017-day-3/</guid><pubDate>Wed, 04 Jan 2017 12:30:01 GMT</pubDate><content:encoded>&lt;h3&gt;미국시간 2017.01.06 14:00 pm - 20:00 pm&lt;/h3&gt;
&lt;p&gt;전날의 여파로 모두가 늦잠을 잤다. 그나마 S만 일찍 일어났다. S가 네 번 Y와 J를 깨웠지만 그들은 너무 깊이 잠든 상태였다. TKS가 먼저 CES를 구경하로 떠났다. S는 먼저 간다고 일어나면 연락 달라는 라인 메시지를 남기고 떠났다. Y와 J가 그것을 본 것은 오후가 되어서였다.&lt;/p&gt;
&lt;p&gt;오후에 일어난 Y와 J는 어짜피 늦었다는 생각에 급하게 굴지는 않았다. 씻고 준비한 다음 1층에서 아점으로 라면을 먹기로 했다. 컵라면이 없어 끓인 라면 두개를 했다. 계란도 있어 두 개를 넣었다. 햇반도 두 개 데우고, 김과 참지를 꺼냈다. Y는 차려진 한 상을 보면서 여기가 베가스인지 판교인지 알기가 힘들다는 생각을 했다. 라면을 먹고 J가 우버를 불렀다. 도착한다고 해서 밖에서 기다렸는데 기사가 취소를 해버렸다. 다시 부른 사이 가스 아저씨가 와서 그 집 가스 미터기를 보여줄 수 있냐는 말을 건낸다. 대략 무슨 말인지는 알겠지만 그에게 우리 상황을 설명하기는 쉽지 않았다. 버벅대는 영어로 힘들게 이것 저것 이야기한다. 결국 그는 포기하고 돌아간다. 조금 있다 우버가 도착했고, 그걸 타고 컨벤션 센터로 이동했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./ces_2017_d03_01.jpg&apos; data-alt=&apos;Figure 1. 어제 아껴 놓았던 사우스 관&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 315px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/1b8914df3b859cc8aac76a6c65837b61/ba98e/ces_2017_d03_01.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 133.1578947368421%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQFAgP/xAAWAQEBAQAAAAAAAAAAAAAAAAADAAL/2gAMAwEAAhADEAAAAW1u81TbNmjej0Yxq2Jlf//EABsQAQEAAgMBAAAAAAAAAAAAAAIBAxAAESIh/9oACAEBAAEFAoPOsqTMSl7N5kMgXlXIe3fj1//EABcRAQEBAQAAAAAAAAAAAAAAAAEAERD/2gAIAQMBAT8BwsZOf//EABgRAQEAAwAAAAAAAAAAAAAAAAEAEBES/9oACAECAQE/ARbqHWP/xAAaEAACAgMAAAAAAAAAAAAAAAABEAIxADJB/9oACAEBAAY/AiTTlyICsPXC/wD/xAAdEAEAAwABBQAAAAAAAAAAAAABABExIRBBUXGR/9oACAEBAAE/IbeGBNlQArAIYHIGs+0VHmIJuqY7kX3E2nc9P//aAAwDAQACAAMAAAAQEPiO/8QAFhEBAQEAAAAAAAAAAAAAAAAAEQEQ/9oACAEDAQE/EKRklz//xAAWEQEBAQAAAAAAAAAAAAAAAAAAESH/2gAIAQIBAT8QrqEjX//EAB4QAQACAgMAAwAAAAAAAAAAAAEAESExQWGBELHR/9oACAEBAAE/EN8jTtqUDefjS9iLa3hfyDkNqulrzcwQvH3Co2imPOwEOdxA9iC5ujiZCZbcsMk//9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 1. 어제 아껴 놓았던 사우스 관&apos; title=&apos;&apos; src=&apos;/static/1b8914df3b859cc8aac76a6c65837b61/ba98e/ces_2017_d03_01.jpg&apos; srcset=&apos;/static/1b8914df3b859cc8aac76a6c65837b61/8ccab/ces_2017_d03_01.jpg 190w,
/static/1b8914df3b859cc8aac76a6c65837b61/ba98e/ces_2017_d03_01.jpg 315w&apos; sizes=&apos;(max-width: 315px) 100vw, 315px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 1. 어제 아껴 놓았던 사우스 관&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;이미 너무 늦었기 때문에 사우스 관을 다 보기는 힘들어 보였다. 그래서 애초에 다 보는 것은 포기하고 볼 수 있는 만큼만 보겠다는 생각으로 돌아 다녔다. DJI 부스가 컸다. 드론계의 애플이라 불리는 중국 회사. 하지만 부스가 크게 감흥은 없었다. 그저 접어지는 들고다니기 편한 드론이 있다는 정도? 그렇게 부스를 보다가 M을 만났다. M을 만나 조금 더 구경을 하고는 밖으로 나왔다. M은 DJI 보다 달걀 모얌으로 생긴 드론 팜플렛을 보여주며 이게 더 인상 깊었다는 이야기를 했다. 그러면서 오늘 아침 이야기를 했는데 정말 황당했다. 그가 타고오는 모노레일의 같은 칸을 T와 K와 S가 탔다는 것이었다. 그러면서 만나도 어떻게 그렇게 만나냐며 너스레를 떤다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./ces_2017_d03_02.jpg&apos; data-alt=&apos;Figure 2. DJI의 접히는 드론. 접어서 들고다니기가 편하다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/6cfc1ed7504399edea540a53ff212b29/7fbea/ces_2017_d03_02.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAUDBAb/xAAUAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAFfLVfjngB//8QAGxAAAgMAAwAAAAAAAAAAAAAAAgMAAREEEhP/2gAIAQEAAQUCRVEbOOQzMiz6G4q8s2f/xAAVEQEBAAAAAAAAAAAAAAAAAAAAIf/aAAgBAwEBPwFX/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGxAAAgIDAQAAAAAAAAAAAAAAAAERMRIhQVH/2gAIAQEABj8CxfT0sWhubJP/xAAaEAACAwEBAAAAAAAAAAAAAAABEQAhMVFh/9oACAEBAAE/IREiGZ2G8yEiS1wxyQ2JiIBRhecOf//aAAwDAQACAAMAAAAQqC//xAAWEQEBAQAAAAAAAAAAAAAAAAAAAUH/2gAIAQMBAT8QSYf/xAAVEQEBAAAAAAAAAAAAAAAAAAABAP/aAAgBAgEBPxCUv//EABwQAAMBAAIDAAAAAAAAAAAAAAERIQAxQWFxkf/aAAgBAQABPxDuyJIRVcUbZIF+frEixJEAWEsDPheHUKSA98cXV0MMW//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 2. DJI의 접히는 드론. 접어서 들고다니기가 편하다.&apos; title=&apos;&apos; src=&apos;/static/6cfc1ed7504399edea540a53ff212b29/7fbea/ces_2017_d03_02.jpg&apos; srcset=&apos;/static/6cfc1ed7504399edea540a53ff212b29/8ccab/ces_2017_d03_02.jpg 190w,
/static/6cfc1ed7504399edea540a53ff212b29/ea4c8/ces_2017_d03_02.jpg 380w,
/static/6cfc1ed7504399edea540a53ff212b29/7fbea/ces_2017_d03_02.jpg 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 2. DJI의 접히는 드론. 접어서 들고다니기가 편하다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;J와 M과 Y가 기다리고 있는 장소는 어제 그곳이다. 버스정류장 벤치. J가 라인으로 위치를 보낸다. 조금 있다 S가 도착했다. K와 T를 물으니 중간에 헤어져서 모르겠다고 한다. 조금 있다 메시지가 하나 더 왔다. KT는 샤오미 부스에 있는데 조금 더 보다가 이동하겠다는 내용이다. JYMS는 모노레일을 타고 이동한다. 어제와 다르게 너무나 사람이 많고 줄은 개미가 기어가는 속도로 줄어들었다. 마칠 시간에 사람이 몰려서 그런 것 같다. 힘들게 들어가서 그들이 내린 곳은 센터에서 한 정거장 옆에 있는 LINQ 역이었다. Y는 이상한 생각이 든다. LINQ 호텔인데 자꾸 프로그래밍 할 때 만난 LINQ가 떠올랐기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./ces_2017_d03_03.jpg&apos; data-alt=&apos;Figure 3. LINQ 역과 카지노 입구 사이에 있던 NOOK, 나름 단열처리된 컵이다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 315px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/edbd8d0a1dee51b51c544f692e2c8250/ba98e/ces_2017_d03_03.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 133.1578947368421%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAMFAQT/xAAXAQEBAQEAAAAAAAAAAAAAAAAAAQID/9oADAMBAAIQAxAAAAFDevm56CgKvJG2ViIH/8QAHBAAAgIDAQEAAAAAAAAAAAAAAQIAAxESIRMx/9oACAEBAAEFAkSoONDFXSFBrRWQeQWIwyBPRZV9r7ZjM//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8BH//EABURAQEAAAAAAAAAAAAAAAAAABAR/9oACAECAQE/ASH/xAAgEAABAgYDAQAAAAAAAAAAAAABACECEBExQVESE1Jx/9oACAEBAAY/Aic+dKnW31Uhsiz7R5OspiJXEowdS//EABwQAQADAAMBAQAAAAAAAAAAAAEAESExUYFBkf/aAAgBAQABPyFI2865C0slQ01exuArHBR1L6fiWBHsPoD2VcyJQrLITaAkiNM//9oADAMBAAIAAwAAABDXzz//xAAYEQACAwAAAAAAAAAAAAAAAAAAERAhMf/aAAgBAwEBPxDKGOP/xAAWEQEBAQAAAAAAAAAAAAAAAAARABD/2gAIAQIBAT8QYwX/xAAdEAEBAAMAAgMAAAAAAAAAAAABEQAxQSFhcYGR/9oACAEBAAE/EEHiTQB57/c7MatEu+uVRsj5KXl7gooIARxg0Dy04CSXrECd0mNd9JiyU/NxyxVjDMiR4gpiMa63n//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 3. LINQ 역과 카지노 입구 사이에 있던 NOOK, 나름 단열처리된 컵이다.&apos; title=&apos;&apos; src=&apos;/static/edbd8d0a1dee51b51c544f692e2c8250/ba98e/ces_2017_d03_03.jpg&apos; srcset=&apos;/static/edbd8d0a1dee51b51c544f692e2c8250/8ccab/ces_2017_d03_03.jpg 190w,
/static/edbd8d0a1dee51b51c544f692e2c8250/ba98e/ces_2017_d03_03.jpg 315w&apos; sizes=&apos;(max-width: 315px) 100vw, 315px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 3. LINQ 역과 카지노 입구 사이에 있던 NOOK, 나름 단열처리된 컵이다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;LINQ 역에 내려서 호텔로 이동하는 연결 지점에 있는 NOOK 커피숍에 잠시 앉는다. 아메리카노를 시킨다. 그즈음 KT도 나왔다는 메시지를 보냈다. 하지만 JYMS가 있는 곳은 로밍 인터넷이 터지지 않는 지점이다. J가 멀리 돌아가서 인터넷 되는 곳에서 NOOK 커피숍 위치를 알려주고 돌아온다. 커피 잔에 두르는 골판지를 가지러 갔던 M이 돌아오면서 커피잔이 특수 처리돼서 필요 없다는 이야기를 들었다며 이래서 미국 촌놈이라는 이야기를 듣는다며 수줍어 한다. 그제서야 J, Y, S도 커피잔을 다시 만져본다. 잔이 이중으로 되어 있다. 그리고 그 사이에 공기가 들어가 있다. 어떤게 효과적인지는 모르겠지만 Y는 골판지 만큼 그 이중 공기 단열이 효과적인 것은 아니라는 생각을 한다.&lt;/p&gt;
&lt;p&gt;잠시후 KT가 도착했다. 똑같이 커피를 시킨다. 둘러앉아 남은 일정에 대해서 이야기를 한다. J와 M이 베가스에 왔으니 카지노를 한 번 하고 가자고 한다. Y도 그러자고 한다. 하지만 KTS는 신통찮은 분위기다. 마지못해 동의해서 차가 있는 플라밍고 근처에서 카지노를 하기로 한다. 그렇게 플라밍고에 도착할 무렵 K는 T와 S에게 대관람차를 타자는 제안을 한다. 그리고 JYM에게는 카지노를 하고 만나자고 제안한다. JYM도 동의한다. J, Y, M은 플라밍고 카지노로 들어갔다. J가 카지노로 들어가며 우리만 노름꾼이 된 것 같다는 불평을 한다. 잠시 방황하다 빈 자리가 있는 룰렛 테이블에 앉았다. 각자 100불씩 칩을 바꾸고 플레이를 한다. 모두가 처음이기에 베팅 실수가 조금 발생한다. 특히 Y가 딜러의 잔소리를 많이 듣는다. 3번 정도 실수 후에 룰을 완전히 알 수 있었다. 룰렛의 인과 아웃이 있는데 인은 개별 숫자가 있는 곳에 베팅을 아웃은 숫자 덩어리에 (홀짝 같은) 베팅을 하는 것이었다. 인, 아웃은 각각 최소 베팅 금액이 10불이었다. 인에서는 10불을 나눠서 여러개의 숫자에 걸 수 있고, 아웃은 무조건 한 칸에 10불 이상을 걸어야 했다. 이게 룰의 전부였다. 물론 걸쳐서 놓는 것들도 있었는데 그런 고급 베팅을 사용하지는 않았다. 다 초보였기 때문이다.&lt;/p&gt;
&lt;p&gt;크게 JYM의 전략은 세가지로 나뉘었다. J는 매턴 10불울 두개씩 쪼개어 다섯 군데의 개별 숫자에 걸었다. 이렇게 하다 하나가 걸리면 35배를 받게 된다. 즉 5군데 중에 한 곳이 맞으면 72불을 받게 된다. 10불얼 베팅했으니 이득이 62불이 된다. 베팅에 실패하면 10불을 잃는다. 가능성은 룰렛 숫자가 38개라 5/38이다. Y는 어제 본 사람과 유사한 전략을 택했다. 아웃의 세 덩어리로 나뉜 지점의 두 곳에 10불씩 베팅을 하는 것이다. 이렇게 해서 한 곳이 걸리면 3배인 30분을 준다. 베팅하지 않은 곳이 걸리면 20불을 잃는다. 당첨 확률은 24/38이다. M은 무작위 전략을 썼다. 홀짝에도 걸었다가, 검빨에도 걸었다가 개별 숫자에도 걸었다.&lt;/p&gt;
&lt;p&gt;생각보다 그 과정은 단순했다. Y는 처음에는 20불씩 거는 것에 약간 긴장했으나 몇 턴이 지나서는 더이상 돈을 의식하지 않았다. 그저 장난감 칩을 가지고 논다는 생각이었다. 의외로 J가 잘 맞춘다. M은 어떻게 맞추냐며 부러워한다. 그의 칩이 가장 빠른 속도로 사라졌기 때문이다. Y의 베팅은 큰 이득도 없지만 큰 손해도 없는 그런 전략이었다. Y는 대체로 차곡차곡 경기를 했고 이득이 생겼을 때 개별 숫자에 베팅해 칩을 불렸다. 그렇게 한시간 넘게 게임을 했고 Y는 150불 가량을 땄고, J와 M은 잃었다. 결국 카지노는 Y가 딴 돈보다 더 따서 손해는 아니었다. 다 아는 사실이지만 결국은 모두 카지노가 딴다. 룰렛의 경우 0과 00 때문에 대체로 많은 베팅이 카지노에게 유리하게 세팅돼 있다.&lt;/p&gt;
&lt;h3&gt;미국 시간 2017.01.06 20:00 pm - 2017.01.07 03:00 am&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./ces_2017_d03_07.jpg&apos; data-alt=&apos;Figure 4. 저녁을 먹은 야드 하우스 입구&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/42797c7ee3ea300b7f59875054fb6bf7/7fbea/ces_2017_d03_07.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAECBAX/xAAVAQEBAAAAAAAAAAAAAAAAAAACA//aAAwDAQACEAMQAAABt5DU3MQj/8QAGRABAAMBAQAAAAAAAAAAAAAAAQACAxES/9oACAEBAAEFAtOS1Fnjg62Usxus/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFREBAQAAAAAAAAAAAAAAAAAAACH/2gAIAQIBAT8BR//EABoQAAICAwAAAAAAAAAAAAAAAAABEBEhMUH/2gAIAQEABj8Ca7GS42f/xAAaEAEAAwEBAQAAAAAAAAAAAAABABEhMUFR/9oACAEBAAE/Iaz5u1GLDh5BhSP86VFGsS6n/9oADAMBAAIAAwAAABB/P//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAwEBPxBNIG//xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQIBAT8QHG2f/8QAHBABAQACAgMAAAAAAAAAAAAAAREAITFhccHw/9oACAEBAAE/EObU2Qk94SCgl+d4Q70p4zUw0zUwDZ1JdYUXUTnP/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 4. 저녁을 먹은 야드 하우스 입구&apos; title=&apos;&apos; src=&apos;/static/42797c7ee3ea300b7f59875054fb6bf7/7fbea/ces_2017_d03_07.jpg&apos; srcset=&apos;/static/42797c7ee3ea300b7f59875054fb6bf7/8ccab/ces_2017_d03_07.jpg 190w,
/static/42797c7ee3ea300b7f59875054fb6bf7/ea4c8/ces_2017_d03_07.jpg 380w,
/static/42797c7ee3ea300b7f59875054fb6bf7/7fbea/ces_2017_d03_07.jpg 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 4. 저녁을 먹은 야드 하우스 입구&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;K가 라인을 보내왔다. 배고프다고 밥 먹자는 이야기였다. JYM 모두 약간 아쉬워 하는 분위기였지만 늦지 않게 나왔다. 나와서 KTS가 있는 곳으로 왔더니 식당 앞에서 대기하고 있었다. JYM은 괜히 일찍 나왔다는 생각을 한다. 몇 판 더 할껄. Y는 그래서 도박이 무섭다고 느낀다. 사람은 의외로 쉽게 중독된다. 저녁은 야드 하우스라는 체인점에서 먹었다. 에일 맥주가 다양하게 있는 집이었다. KT가 주문을 했는데 많이 와 본 사람들 답게 일반적으로 좋아하는 메뉴로 식탁을 가득 채웠다. 배고픈 일행은 허겁지겁 먹기 시작한다. 그렇게 30분 가량 먹고 나니 이제는 모두 배가 불러 더이상 못먹는 상태가 되었다. 하지만 남은 음식은 아직도 많다. 화제 거리가 떨어질 무렵 티비 켜진 농구경기에 모두 집중했다. 멤피스와 다른 곳이 하고 있는 경기였는데 10점차가 넘게 나는 경기를 멤피스가 역전했다. 몇초 남지 않은 사이에 승부가 바뀌는 경기라 보고 있으면 짜릿한 맛이 있었다. K가 오늘은 타이밍이 좋은 것 같다는 이야기를 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./ces_2017_d03_04.jpg&apos; data-alt=&apos;Figure 5. 야드 하우스의 시그니처 하프 야드 맥주, 길이가 하프 야드다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 315px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/19832a91caff4ca35dbdefcd88b9cdd9/ba98e/ces_2017_d03_04.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 133.1578947368421%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAEDAgT/xAAXAQADAQAAAAAAAAAAAAAAAAAAAQID/9oADAMBAAIQAxAAAAGSi0IkMtuVMdtHIVH/xAAdEAACAgEFAAAAAAAAAAAAAAABAgADIQQQERIi/9oACAEBAAEFAksjMhAVSKMzr4PMqGFZlU6WyDYXWAf/xAAYEQACAwAAAAAAAAAAAAAAAAAAAQIQIf/aAAgBAwEBPwGlEw//xAAZEQABBQAAAAAAAAAAAAAAAAAAAQIQESH/2gAIAQIBAT8BuFcaf//EABwQAQACAQUAAAAAAAAAAAAAAAEAESECECAxUf/aAAgBAQAGPwKPcM1HbMaaYnvCjWz/xAAdEAEAAgMBAAMAAAAAAAAAAAABABEhMUFREGGR/9oACAEBAAE/IeP7F4s+6ilXDswJzyG2tMtfZBsLksxAaUxDdjf38XUoQBP/2gAMAwEAAgADAAAAEN8Ew//EABgRAQADAQAAAAAAAAAAAAAAAAEAESEQ/9oACAEDAQE/EAamQK3j/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAERUf/aAAgBAgEBPxBisZSbP//EAB0QAQEAAgIDAQAAAAAAAAAAAAERADEhQVFhcYH/2gAIAQEAAT8QFNU8C8esgQuxw/O8TKHkFu95JCqaVMBha6s6s59ZbhOJLJhLhAqfeO8RTYoWHrxmqEGhzUzZ8wtwqC6z/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 5. 야드 하우스의 시그니처 하프 야드 맥주, 길이가 하프 야드다.&apos; title=&apos;&apos; src=&apos;/static/19832a91caff4ca35dbdefcd88b9cdd9/ba98e/ces_2017_d03_04.jpg&apos; srcset=&apos;/static/19832a91caff4ca35dbdefcd88b9cdd9/8ccab/ces_2017_d03_04.jpg 190w,
/static/19832a91caff4ca35dbdefcd88b9cdd9/ba98e/ces_2017_d03_04.jpg 315w&apos; sizes=&apos;(max-width: 315px) 100vw, 315px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 5. 야드 하우스의 시그니처 하프 야드 맥주, 길이가 하프 야드다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;밥먹고 나오니 모두 배가 불렀다. 뭘하지라고 잠시 고민하던 시점에 J와 M이 룰렛을 하자는 이야기를 한다. K는 처음에는 내키지 않는 분위기 였으나 이내 따라 나선다. 구경을 하다 테이블이 없어서 카지노를 나가려던 즈음 빈 테이블이 하나 생겼다. 그게 시작이었다. JMK가 앉아서 플레이를 하고, YTS는 구경하다 방해될까봐 여기저기를 돌아다녔다. 앉을 때가 없어 카지노 안에 있는 이상한 펍 같은 곳을 들어갔다. 음악이 나오고 춤추는 사람도 더러 있었다. 자리는 많이 비어 있었다. Y는 음악이 너무 시끄러웠다. 그리고 T와 S가 자신이 없는게 더 편할거라는 생각을 했다. Y는 괜히 방해꾼이 된듯한 느낌이다. 그저 기다리고 있어야 하는 그들이 안스럽기도 했다. 그래서 JMK가 플레이하는 곳에 가서 TS가 놀다 오겠다는 이야기를 전한다. K는 그러라고 한다. Y는 라인으로 T에게 그렇게 전한다. 그리고 Y도 그 룰렛 판에 앉는다. 이미 JMK 모두 상당량을 잃은 상태였다. Y는 100불을 교환하고 아까와 같은 전략으로 플레이를 한다. 하지만 이번엔 광속으로 모두 잃는다. 다시 100불을 교환한다. 조금씩 따기 시작했다. 그즈음 100불 칩은 옆으로 분리해서 두고 딴 칩으로만 플레이를 한다.&lt;/p&gt;
&lt;p&gt;한참 시간이 지났다. T와 S가 왔다. 기다리다 지친 분위기다. K와 J가 T와 S에게 같이 하라며 100불씩을 준다. 각자 그걸 칩으로 바꿔서 참가한다. Y는 아직도 기계적으로 베팅하며 잃었다 땄다를 반복한다. 그즈음 M은 약간 잃었고, J는 제법 잃었고, K는 더 잃었다가 다시 따는 중이었다. T와 S가 칩을 바꿔 베팅을 시작한다. T가 처음 몇 판을 크게 딴다. Y는 옆에서 땄을 때 잃어나는게 용자라는 말을 전한다. 그는 아직도 본전을 힘겹게 되찾고 있는 중이었다. S는 광속으로 칩을 잃었다. J, M, S는 추가로 칩을 더 바꾸었다. 그렇게 하기를 한참. T가 칩을 캐시로 바꾼다. 별로 남지 않아서 Y가 아까 바꾸면 용자였다고 이야기를 하자 손에 비싼 칩을 보이며 그래도 조금 땄다는 이야기를 한다. 그즈음 K는 제법 크게 따고 있었다. S는 칩을 거의 다 잃어갈 무렵 Y를 따라 베팅하기 시작했다. M은 여전히 무작위로 베팅했다. 칩이 덜 줄어들기 위해서 그는 베팅을 잘 하지 않고 구경하는 판이 많았다. 조금 있다 J도 칩을 모두 잃고 일어났다. S가 그 뒤를 이었다. K, Y, M이 남았다. Y는 거의 본전을 찾아가고 있었다. Y가 본전이 되었을 때 K가 기다리는 사람도 지치니 5판만 하고 가자고 했다. Y는 사실 그때 멈추고 싶었지만 그러기도 쉽지 않았다. 그즘 M은 Y를 따라 베팅해야 겠다는 이야기를 한다. 그렇게 마지막 5판이 시작된다. M은 Y를 따라 베팅하다 달아 세번을 잃는다. 그는 크게 베팅했기에 손실이 훨씬 컸다. 그러다 Y가 딴 네번째 판에 같이 땄고 그는 크게 걸어서 크게 딴다는 이야기를 했다. 하지만 그건 옳은 이야기는 아니었다. 그가 3판에 잃은 칩은 120불이었고, 그가 4번째 판에 딴 칩은 60불이었기 때문이다. 그는 결국 60불을 잃은 것이었다. 마지막 5판 Y는 손실을 줄이기 위해 개별 칩에 10불만 베팅했다.&lt;/p&gt;
&lt;p&gt;칩을 정산해서 나왔다. 그때가 벌써 새벽 3시였다. K는 250불을 땄고, Y는 150불을 땄다가 50불을 잃어서 100불을 땄고, T는 50불을 땄다. 하지만 나머지 세 사람이 카지노에서 잃은 돈은 그보다는 훨씬 많았다. 결국은 당연하게도 하우스가 이기는 게임이다. 즐기러 간 자리였지만 즐기는 비용은 그리 싸진 않았다. 아무렇게나 플레이한다면 정말 10분만에 100불을 잃은 것은 아무것도 아니었다. 하지만 K는 반대로 자신감이 붙었다. 한 번 해서 이겼기 때문이다. 돈을 걸고 한다는 것이 묘한 흡입력이 있었다.&lt;/p&gt;
&lt;p&gt;집에 도착해서 T와 S는 광속으로 셧다운 되었고, K와 J가 담배피는 사이 Y는 옷을 갈아 입었다. 출출하던 그는 K와 J에게 라면을 먹겠냐고 물었고 K는 콜을, J는 다이를 했다. 공교롭게도 남은 라면은 너구리 컵라면 하나에 끓이는 참깨라면과 신라면이 하나씩 있었다. K는 참깨와 신라면을 섞어서 끓이자고 했다. 섞어서 끓이고 남은 계란까지 모두 넣었다. 햇반 두개에, 김 하나, 참치 하나까지 그 새벽에 Y와 K는 그걸 나눠먹고는 잠들었다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] CES 2017 DAY #2]]></title><description><![CDATA[미국 시간 2017.01.05 08:00 am - 2017.01.05 21:00 pm 잠에서 가장 먼저 깬 것은 S였다. 전날 다른 일행들이…]]></description><link>https://jiniya.net/ng/2017/01/ces-2017-day-2/</link><guid isPermaLink="false">https://jiniya.net/ng/2017/01/ces-2017-day-2/</guid><pubDate>Wed, 04 Jan 2017 12:20:01 GMT</pubDate><content:encoded>&lt;h3&gt;미국 시간 2017.01.05 08:00 am - 2017.01.05 21:00 pm&lt;/h3&gt;
&lt;p&gt;잠에서 가장 먼저 깬 것은 S였다. 전날 다른 일행들이 8시 즈음 일어나서 준비를 하자는 얘기를 곧이 곧대로 믿었기 때문이다. 심지어 더욱 놀라운 사실은 그녀는 다른 사람들이 일어나지도 않았는데 아침으로 라면을 준비했다는 점이다. 안타깝게도 그녀를 제외한 다른 사람들은 모두 꿈나라를 헤매고 있었기에 그 라면은 변기가 모두 먹어치웠다. 그녀는 단톡방에 푹 주무시라는 이야기를 올리고는 본인도 다시 잠을 청했다.&lt;/p&gt;
&lt;p&gt;Y가 잠에서 깬 시간은 9시였다. 화장실을 갔다와서 S의 메시지를 본 Y는 다시 잠에 들었다. 일행이 실제로 일어난 시간은 10시가 지났을 무렵이었다. 아침을 먹을지를 잠시 고민하다 K가 배고픈 사람이 없으면 그냥 커피나 먹자는 이야기를 했다. 자연스럽게 근처 스타벅스로 이동했다. K가 앱으로 주문을 받았다. Y가 먼저 아메리카노를 불렀고, J도 그걸 먹겠다고 했고, T도 동참했다. S는 라떼를 선택했다. K는 라떼가 어느 메뉴에 있냐며 운전 중이던 T에게 물었고 T는 몇 가지 추측성 답을 했다. 어렵게 메뉴를 찾은 K는 라떼를 시키고 본인의 아메리카노도 추가했다. 하지만 안타깝게도 주문은 큰 의미가 없었다. 왜냐하면 우리가 간 스타벅스는 드라이브 스루가 있었기 때문이다. 결국 앱 주문은 무시하고 드라이브 스루로 주문했다. 최종적으로 T가 주문한 메뉴는 아메리카노 셋, 라떼 둘이었다. T의 속마음을 조금 알 수 있는 대목이다.&lt;/p&gt;
&lt;p&gt;T가 원래 베가스는 주차가 무료였는데 최근 변경되어서 MGM 계열은 주차료를 받는다는 이야기를 한다. 그래서 MGM계열이 아닌 플라밍고 주차장에 차를 세우고 모노레일을 타자고 K에게 묻는다. K는 그러라고 한다. 주차장에 차를 세우고 모노레일을 타러 가는 사이 잠시 길을 헤맸다. T가 호텔 가드에게 물어서 정확한 방향을 알아낸다. 모노레일에 도착해 일행 모두 2일치 모노레일 프리패스를 끊었다. 베가스 모노레일 정거장은 몇 개 없었다. 그들은 2정거장 다음에 있는 컨벤션 센터역으로 향했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./ces_2017_d02_01.jpg&apos; data-alt=&apos;Figure 1. CES 2017 입구, 사람 진짜 많음&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/7cc5450c976adb1315472605faa7387c/7fbea/ces_2017_d02_01.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQFA//EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAFRlPeKRLK//8QAGhABAQACAwAAAAAAAAAAAAAAAQIAAxEhIv/aAAgBAQABBQLXTNVa5O8g46oDDzn/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAdEAABAgcAAAAAAAAAAAAAAAAAARECEBIzUXKh/9oACAEBAAY/AsF3pSsoNhnc/8QAGxAAAgMBAQEAAAAAAAAAAAAAAAERITFBUXH/2gAIAQEAAT8hoDNwy1ZHhHLac18GUMo56KkfQz//2gAMAwEAAgADAAAAEHgP/8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQMBAT8QiP/EABcRAQADAAAAAAAAAAAAAAAAAAABESH/2gAIAQIBAT8QjFv/xAAcEAEAAgMAAwAAAAAAAAAAAAABABEhMUFRYZH/2gAIAQEAAT8QKusKqWEPRltIZfCHgXpQQOEGrTRR8skGi2ArRGKBdSe2f//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 1. CES 2017 입구, 사람 진짜 많음&apos; title=&apos;&apos; src=&apos;/static/7cc5450c976adb1315472605faa7387c/7fbea/ces_2017_d02_01.jpg&apos; srcset=&apos;/static/7cc5450c976adb1315472605faa7387c/8ccab/ces_2017_d02_01.jpg 190w,
/static/7cc5450c976adb1315472605faa7387c/ea4c8/ces_2017_d02_01.jpg 380w,
/static/7cc5450c976adb1315472605faa7387c/7fbea/ces_2017_d02_01.jpg 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 1. CES 2017 입구, 사람 진짜 많음&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;센터에 내려서 CES 입구에서 담배를 피우며 서 있었다. J가 CES에 참관한다는 이야기를 듣고 미국에 있던 M도 합류하겠다고 했기 때문이다. 둘은 CES 입구에서 보기로 했다. M이 도착하지 않아 J의 일행은 적지 않은 시간을 입구에서 보냈다. 한참 후에 M이 도착했고 일행은 모두 M과 인사했다. J를 제외한 모든 사람이 M을 처음 보는 자리였다. Y는 J에게서 M 이야기를 여러번 들었지만 실제로 만나는 것은 이번이 처음이었다.&lt;/p&gt;
&lt;p&gt;CES 입구에서는 표와 짐을 검사하고 있었다. 총기 소지가 자유로는 미국은 대부분의 전시회 입구에서 가방 검사를 한다. 폭탄이나 총같은 것들이 있는지 체크하는 것 같다. 하지만 대체로 형식적인 검사다. 가방 검사를 하던 사이 Y는 잠시 일행과 떨어졌다. 다른 일행은 모두 먼저 검사하고 입구에 들어간 상태였고 Y는 늦게 들어갔다. 약간 헤대마 일행이 모여있는 곳이 합류했다. 그쪽 입구에 가장 먼저 위치한 것은 LG 부스였다. LG 부스인만큼 사람이 정말 많았다. 자연스럽게 일행은 둘로 쪼개졌다. K와 T는 K의 관심사가 있는 곳으로 같이 이동했고, J, M, Y, S는 붙어서 LG관 구경을 시작했다.&lt;/p&gt;
&lt;p&gt;사람이 너무 많아서 제대로 볼 수 없었다. 사람들이 TV 앞에서 연신 사진을 찍고 있었다. 베스트 오브 베스트에 선정된 그 초박형 TV였다. 어찌나 얇은지 아크릴판에 붙여 놓았는데 진짜 거짓말 좀 많이 보태서 껌딱지 두께 수준이었다. S가 대단한 것을 발견한 것처럼 소리친다. 와 이거 진짜 얇아요. 정말 소리칠만큼 얇았다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./ces_2017_d02_02.jpg&apos; data-alt=&apos;Figure 2. 우리가 낚인 보쉬 솜사탕 로봇. 솜사탕 만들어서 사람들에게 준다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 315px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/6ad30669f7c81b8793cf3d9715161708/ba98e/ces_2017_d02_02.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 133.1578947368421%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQFAgP/xAAWAQEBAQAAAAAAAAAAAAAAAAABAAL/2gAMAwEAAhADEAAAARbWBYOQVJChPriUTL//xAAdEAEBAAEEAwAAAAAAAAAAAAACAQMABBESITEy/9oACAEBAAEFArknF6qxzHONLFYiSoiceNZO0LQ1uPg+pPH/xAAWEQADAAAAAAAAAAAAAAAAAAAAEBH/2gAIAQMBAT8BI//EABYRAQEBAAAAAAAAAAAAAAAAABEAEP/aAAgBAgEBPwFnf//EAB8QAAIBAgcAAAAAAAAAAAAAAAERAAIQEiExQVFhkf/aAAgBAQAGPwJLO2F26mp8hO/MVJLiFLlUFv/EAB4QAAIDAAEFAAAAAAAAAAAAAAABESExcVFhgaHB/9oACAEBAAE/IXX4zJVWlnkTo67Ck1RD7StE8e0BJ1Rch9yNlYhBVdT0/oqVO6KhR//aAAwDAQACAAMAAAAQcAW+/8QAFxEBAAMAAAAAAAAAAAAAAAAAABEhYf/aAAgBAwEBPxBBin//xAAZEQADAAMAAAAAAAAAAAAAAAAAAREhMWH/2gAIAQIBAT8Q0HyYjbHaf//EABwQAQADAQEAAwAAAAAAAAAAAAEAESExYUFxkf/aAAgBAQABPxB4aGxFqKAbwp39uADBd7u9uKcS3YGq1URKwhT4e79x+ciFNKOVsVLqRr3kLsIipKNjcAPVkz7GBMBt9NxbUn//2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 2. 우리가 낚인 보쉬 솜사탕 로봇. 솜사탕 만들어서 사람들에게 준다.&apos; title=&apos;&apos; src=&apos;/static/6ad30669f7c81b8793cf3d9715161708/ba98e/ces_2017_d02_02.jpg&apos; srcset=&apos;/static/6ad30669f7c81b8793cf3d9715161708/8ccab/ces_2017_d02_02.jpg 190w,
/static/6ad30669f7c81b8793cf3d9715161708/ba98e/ces_2017_d02_02.jpg 315w&apos; sizes=&apos;(max-width: 315px) 100vw, 315px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 2. 우리가 낚인 보쉬 솜사탕 로봇. 솜사탕 만들어서 사람들에게 준다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;그렇게 JYMS 일행은 노스관가 센터관을 쭉 훓어 보기 시작했다. 삼성 부스도 구경을 했다. J는 작년에 왔었기에 올해도 LG가 이긴 거 같다는 이야기를 했다. 일행이 가장 많은 시간을 보낸 곳은 어처구니 없게도 보쉬의 로봇이 있는 코너였다. 가정용 로봇은 아니고 산업용 로봇이었다. 보쉬의 전략에 낚인 것일 수도 있었다. 처음 그들이 본 로봇은 솜사탕을 만들어 주고 있었다. 솜사탕이 나온다는게 신기해서 쳐다보다 로봇이 만든다는 것에 더 놀라웠다. 그러고 이동을 하려고 했으나 마지막 즈음에 주문을 받아서 커피를 타주는 로봇에 재차 낚였다. 거기서 가장 많은 시간을 보냈다. S는 직접 주문을 하기도 했다. 주문하는 곳에 이름을 적고 완료 버튼을 누르면 로봇이 컵을 가져와 서 프린터 앞에서 주문자가 쓴 이름을 프린트하고 커피 머신의 커피가 내려오는 곳에 놓았다. 그리고는 머신으로 커피가 내려오도록 한 다음 다 내려오면 그 컵을 옆에 있는 완료 지점에 위치 시켰다. 그러면 사람이 그 컵을 다시 구경꾼이 있는 테이블위이 올려주면 주문한 사람이 찾아가는 그런 구조였다. 그 산업용 로봇의 핵심 기능 중에 하나로 보쉬는 인간과의 자연스러운 협업이 가능하다는 것을 강조 했기에 사람을 억지로 끼워 넣은 것처럼 보였다. 실상 그 로봇은 사람 없이도 주문자가 있는 테이블에 컵을 가져다 놓을 수 있었기 때문이다. 대체로 그러하듯 JYMS 일행은 모두 일자리가 없어지는 우울한 미래를 상상했다. 우리는 무엇을 해야 할까? 우리의 아이들은 어떤 세상에 살게 될까, 라는 생각을 하면서 나머지 것들을 구경했다.&lt;/p&gt;
&lt;p&gt;그렇게 JYMS 일행은 노스와 센터에 있는 부스를 모두 구경했다. 밖에서 담배를 피우며 버스 정류장에 잠시 앉았다. KT 일행이 어디에 있는지 몰랐기 때문이다. 라인을 보낸다. KT는 벌써 사우스 관이라고 했다. J는 그것도 오늘 보면 내일은 할 것이 없기에 내일 사우스 관을 보자고 했다. YMS도 그러자고 한다. JYMS 일행이 정류장에 앉아서 각자 핸드폰을 하면서 기다리길 한참. KT 일행이 도착했다. 이후 모두 모노레일을 타러 이동했다. M이 표가 없었기에 M이 표 끊기를 기다려 모노레일을 탔다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./ces_2017_d02_03.jpg&apos; data-alt=&apos;Figure 3. 쉑쉑 버거 입구. 뉴욕꺼라고 뉴욕뉴욕에 있다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a09863dd6dc1e104c662d333ea34c599/7fbea/ces_2017_d02_03.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAQD/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQD/2gAMAwEAAhADEAAAAY98SXoBf//EABkQAAIDAQAAAAAAAAAAAAAAAAACAQMSEf/aAAgBAQABBQLWpW1lItUyhyDkH//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABsQAAIBBQAAAAAAAAAAAAAAAAABMQIDESEi/9oACAEBAAY/AjVaWTq82yCCD//EAB4QAAICAAcAAAAAAAAAAAAAAAABESExUWFxoeHx/9oACAEBAAE/IXjKixA4zR0IrcioyuZ6hm//2gAMAwEAAgADAAAAELT/AP/EABYRAQEBAAAAAAAAAAAAAAAAAAARgf/aAAgBAwEBPxCsf//EABcRAQADAAAAAAAAAAAAAAAAAAARIVH/2gAIAQIBAT8Qhev/xAAcEAEAAwACAwAAAAAAAAAAAAABABEhMXFBYfH/2gAIAQEAAT8QSg2XAH7AzfF3BU8nRPQVAG0OqStwOe0U8DrJ/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 3. 쉑쉑 버거 입구. 뉴욕꺼라고 뉴욕뉴욕에 있다.&apos; title=&apos;&apos; src=&apos;/static/a09863dd6dc1e104c662d333ea34c599/7fbea/ces_2017_d02_03.jpg&apos; srcset=&apos;/static/a09863dd6dc1e104c662d333ea34c599/8ccab/ces_2017_d02_03.jpg 190w,
/static/a09863dd6dc1e104c662d333ea34c599/ea4c8/ces_2017_d02_03.jpg 380w,
/static/a09863dd6dc1e104c662d333ea34c599/7fbea/ces_2017_d02_03.jpg 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 3. 쉑쉑 버거 입구. 뉴욕꺼라고 뉴욕뉴욕에 있다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;베가스가 처음이 Y와 S를 위해서 메인 스트리트 구경을 하기로 했다. 아침을 먹지 않아 출출한 일행은 점심으로 쉑쉑 버거를 먹기로 했다. MGM 역에서 내려 뉴욕뉴욕으로 걸어갔다. 가는 중간 중간 베가스에 관한 것들이 나오면 K가 설명을 해줬다. MGM의 카지노를 지날 때 J가 사람이 별로 없다는 이야기를 한다. M은 그것도 분위기가 있는 것 같다고 오래된 곳보다는 새로운 곳으로 많이 가서 그런 것 같다는 답변을 한다. 그렇게 이런 저런 이야기를 하며 쉑쉑버거 앞까지 걸어갔다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./ces_2017_d02_04.jpg&apos; data-alt=&apos;Figure 4. 우리가 주문한 버거. 쫀득한게 맛있었다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/2ee26db519e03863dca9eb767a0fbaf1/7fbea/ces_2017_d02_04.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAECBP/EABUBAQEAAAAAAAAAAAAAAAAAAAID/9oADAMBAAIQAxAAAAGlnmTRAz//xAAZEAADAQEBAAAAAAAAAAAAAAAAARIREzH/2gAIAQEAAQUC5ohFyI16/f/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABYRAAMAAAAAAAAAAAAAAAAAAAEQMf/aAAgBAgEBPwERf//EABsQAAIBBQAAAAAAAAAAAAAAAAAQEQEhMUFR/9oACAEBAAY/AqdL7IWZX//EABoQAQACAwEAAAAAAAAAAAAAAAEAESExQVH/2gAIAQEAAT8hVEOtW4jdSp6ghS8Rbe+xHSOjFaZ//9oADAMBAAIAAwAAABDDP//EABcRAAMBAAAAAAAAAAAAAAAAAAEQMWH/2gAIAQMBAT8QNxf/xAAYEQACAwAAAAAAAAAAAAAAAAAAEQEhMf/aAAgBAgEBPxB9TYz/xAAbEAEAAwEBAQEAAAAAAAAAAAABABEhMUFRYf/aAAgBAQABPxBxJVcsgcjEwzRevv6vJapGCslajoqyqTXJlDXPo+MfIpcn/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 4. 우리가 주문한 버거. 쫀득한게 맛있었다.&apos; title=&apos;&apos; src=&apos;/static/2ee26db519e03863dca9eb767a0fbaf1/7fbea/ces_2017_d02_04.jpg&apos; srcset=&apos;/static/2ee26db519e03863dca9eb767a0fbaf1/8ccab/ces_2017_d02_04.jpg 190w,
/static/2ee26db519e03863dca9eb767a0fbaf1/ea4c8/ces_2017_d02_04.jpg 380w,
/static/2ee26db519e03863dca9eb767a0fbaf1/7fbea/ces_2017_d02_04.jpg 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 4. 우리가 주문한 버거. 쫀득한게 맛있었다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;T가 주문을 받았다. 잘 몰라서 모두 K가 추천해 주는 메뉴로 통일해서 먹는다. M이 음료로 스트로베리 쉐이크를 시킨다. 그걸 들은 다른 사람도 콜라가 아닌 쉐이크를 시키자 T가 걱정하며 말린다. 엄청 달아서 별로 입에 안 맞을 수 있으니 하나씩 시켜 맛만 보라는 이야기였다. 그렇게 하기로 했다. 이후 메뉴가 나왔을 때 Y는 감탄했다. T가 정말 대단하다는 생각이 들었기 때문이다. 스트로베리는 지나치게 달았다. 한모금 이상 마시기가 어려웠다. T와 같은 잔을 먹는 K도 마찬가지였다. K는 미국 애들은 여기 감자튀김을 찍어 먹는다고 그렇게 먹자고 했다. 그렇게 먹어도 달았다. 결국 Y와 K는 쉐이크를 거의 다 버렸다.&lt;/p&gt;
&lt;p&gt;쉑쉑버거를 먹으면서 어쩌다가 M이 세금 이야기를 꺼냈고 대체로 K와 Y는 관심이 많은 주제였기에 집중해서 이야기가 이어졌다. K는 한국 회사에 근무하지만 미국에서 일하는 관계로 세금을 두 군데에 모두 내고 있다고 한다. 조세 협정이 맺어져서 미국에는 한국에 낸 세금을 제하고 나머지 세금만 낸다고 한다. M이 꺼낸 이야기는 양도 소득세에 대한 근로 소득세 이중 과세에 관한 이야기다. K는 그건 이치에 합당하지 않다는 말을 한다. 왜냐하면 이중 과세가 되기 때문이란다. M은 배당도 똑같이 이중 과세라며 국세청에서 관리하는 리스트에 올라가면 일단 세금을 물리고 그걸 나중에 개인에게 소명하라고 이야기 한다는 말을 한다. 실제로 자기 친구가 그렇게 당했다는 이야기를 붙인다. K 또한 다른 이유로 국세청에 가서 소명한 적은 있지만 지금까지 양도세와 근소세의 이중 과세를 당해서 간 적은 없다고 주장한다. 중간 중간에 최대 주주 및 비상장 법인에 대한 양도세 강화 등이 나왔고 Y는 네이버에 그런 것들을 찾아본다. K가 결과가 어떻게 되었냐고 Y에게 묻는다. Y는 K 말도 일부 맞고 M 말도 일부 맞는 것 같다는 답을 한다. 이중 과세 부분은 K의 말이 맞았고, 최대 주주 및 양도세 강화와 관련된 주장은 M의 말이 맞았다. S와 T는 딴나라 이야기를 듣는 듯한 표정이다.&lt;/p&gt;
&lt;p&gt;K는 세금을 지나치게 걷는 것은 나쁘다는 주장을 피력한다. 그러면 누가 사업을 하겠냐는 이야기다. 상당수 비상장 법인에 대한 투자 및 인수 합병에 세금이 많은 걸림돌이 된다는 이야기를 붙인다. 요는 세금이 투자 및 인수 비용을 상향 시키는 역할을 하기 때문에 일정 크기가 넘어가면 투자자와 피투자자 인수자와 피인수자 상호 간에 딜을 방해하는 허들 작용을 한다는 것이었다. Y는 그런 경험은 없었지만 K의 말도 일리 있다는 생각을 한다. 그러면서 또 한편으로는 모두가 각자의 입장에 맞는 주장을 한다는 생각을 해본다. 서는 데가 달라지면 풍경도 달라진다는 말처럼 말이다.&lt;/p&gt;
&lt;p&gt;쉑쉑버거는 맛있었다. 치즈는 쫀득쫀득했고, 패티는 부드러웠다. 굉장히 단촐한 햄버거인데 맛있었다. Y에게 약간 느끼하긴 했지만 버거가 크기 않아 부담스럽지는 않았다. 쉑쉑 버거를 처음 먹어보는 J와 S도 대체로 맛에 만족했다.&lt;/p&gt;
&lt;p&gt;M이 아리아 호텔에 아마존 부스가 있다는 이야기를 해서 일행은 그쪽 부스를 구경하러 아리아 호텔로 출발했다. 쉑쉑 버거에 들어갈때는 환했지만 나올 때는 약간씩 해가 지고 있었다. 보안 검사를 마치고 아마존 부스를 찾아 갔다. 하지만 거기엔 일행이 기대한 것은 없었다. B2B 관이었기 때문이다. 전시는 거의 없었고 B2B 룸만 잔뜩 있었다. 실망한 일행은 호텔을 나왔다. 드디어 밤이 됐다. 당연한 이야기지만 베가스는 이제 시작이었다. 낮보다 밤이 훨씬 화려했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./ces_2017_d02_05.jpg&apos; data-alt=&apos;Figure 5. 벨라지오 호텔. 이 거대한 분수에서 분수쇼가 펼쳐지려 했으나 바람 관계상 ㅠㅜ~&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/d761614e8381f936109feba96c39d0f3/7fbea/ces_2017_d02_05.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAEDBf/EABUBAQEAAAAAAAAAAAAAAAAAAAEA/9oADAMBAAIQAxAAAAHJtNCxBf/EABoQAQEAAgMAAAAAAAAAAAAAAAECAAMREyL/2gAIAQEAAQUCifbEoaXO2uXYuFuf/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oACAECAQE/AW1//8QAGBABAQADAAAAAAAAAAAAAAAAMQABECH/2gAIAQEABj8COROJ3//EABsQAAIDAAMAAAAAAAAAAAAAAAABESFBMWFx/9oACAEBAAE/IdcuxVIeDCtQrEjaZC5Z/9oADAMBAAIAAwAAABAQ/wD/xAAWEQADAAAAAAAAAAAAAAAAAAAAARH/2gAIAQMBAT8QUIj/xAAWEQEBAQAAAAAAAAAAAAAAAAARARD/2gAIAQIBAT8Qq4//xAAaEAEAAwEBAQAAAAAAAAAAAAABABEhUaGx/9oACAEBAAE/EAw+tVx5MpMvX9llT42zVQJFZ7cAT0n/2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 5. 벨라지오 호텔. 이 거대한 분수에서 분수쇼가 펼쳐지려 했으나 바람 관계상 ㅠㅜ~&apos; title=&apos;&apos; src=&apos;/static/d761614e8381f936109feba96c39d0f3/7fbea/ces_2017_d02_05.jpg&apos; srcset=&apos;/static/d761614e8381f936109feba96c39d0f3/8ccab/ces_2017_d02_05.jpg 190w,
/static/d761614e8381f936109feba96c39d0f3/ea4c8/ces_2017_d02_05.jpg 380w,
/static/d761614e8381f936109feba96c39d0f3/7fbea/ces_2017_d02_05.jpg 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 5. 벨라지오 호텔. 이 거대한 분수에서 분수쇼가 펼쳐지려 했으나 바람 관계상 ㅠㅜ~&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;일행은 벨라지오 호텔에서 하는 분수쇼를 보러 출발했다. 가는 길에 있는 메인스트리트에 대한 설명을 K가 해주었다. Y는 이제야 베가스에 온 것 같은 느낌이 들었다. 영화나 드라마에 등장하는 그 베가스가 이제야 나타났기 때문이다. 일행이 벨라지오 앞에 도착한 것은 분수쇼를 하기 15분쯤 전이이었다. 정각이 되면 분수쇼가 시작될 예정이었다. 바람이 많이 불고 날씨는 쌀쌀했지만 멋진 분수가 나타나길 일행은 기다렸다. 그사이 다스베이더가 나타났고 S는 그와 사진을 찍었다. 그리곤 1달러를 그에게 건냈다. 사진은 광속으로 찍었지만 가방에서 돈을 찾지 못해 다스베이더가 한참을 기다렸다. 급기야 헬맷을 벗기까지, Y가 대신 주러 다가갈 즈음 S는 가방에서 돈을 찾아서 그에게 주었다.&lt;/p&gt;
&lt;p&gt;정각이 다 되갈 즈음 레이디스 앤 젠틀맨이라며 방송이 나왔다. J는 자연스레 이제 시작하는 것 같다는 이야기를 했고, Y도 그런 것 같다고 했다. 사실 방송 내용은 너무 작았고 잘 들리진 않았다. 하지만 정각이 지나도 분수는 없었다. 일행은 포풍 검색을 했고, S가 바람 불면 안 하는 것 같다는 얘기를 했다. 5분 정도 더 기다려도 분수가 나오지 않아 일행은 포기하고 베가스 메인 스트리트를 걷기 시작했다. 우리의 구글 역할을 한 T가 화장실을 가고 없었다. 나중에 T가 전화를 해서 확인을 했는데 바람이 불어 취소된 것이 맞다고 했다.&lt;/p&gt;
&lt;p&gt;베가스의 호텔은 모두 각각의 특징이 있다. 파리를 테마로 한 호텔, 뉴욕을 테마로 한 호텔, 베니스를 테마로 한 호텔 같은 식이다. 괜찮은 생각 같았다. 한참을 길을 걸으며 내려갈 때 J가 허름한 숙소 한 곳을 가르키며 저기 2001년에 놀러왔었다는 이야기를 했다. 그때와 지금 많은 것들이 달라졌지만 그 숙소는 여전히 그 자리에 그대로 있었다. J는 아련한 생각에 잠시 빠진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./ces_2017_d02_06.jpg&apos; data-alt=&apos;Figure 6. 베네치안 호텔. 밖은 밤이지만 여긴 하늘이 별도 구현되어 있다. 곤돌라까지, 서프라이즈.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 315px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/26d046bb627fcdfb70dda4e0856bafbe/ba98e/ces_2017_d02_06.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 133.1578947368421%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAUBAwQC/8QAFwEAAwEAAAAAAAAAAAAAAAAAAQIDAP/aAAwDAQACEAMQAAABpZLJlRqLx0XWU9EbTEYf/8QAGxAAAgIDAQAAAAAAAAAAAAAAAQIAAxASExH/2gAIAQEAAQUCRzKrjYSrGKyzdROxEHkUjboMDH//xAAXEQEBAQEAAAAAAAAAAAAAAAAAARES/9oACAEDAQE/AbJXDWv/xAAXEQEBAQEAAAAAAAAAAAAAAAAAARES/9oACAECAQE/AZbHbGP/xAAeEAABAwQDAAAAAAAAAAAAAAAAARAxERIgIXGB4f/aAAgBAQAGPwKS1UZa9bNTyetBGH//xAAdEAACAgIDAQAAAAAAAAAAAAAAAREhMUEQYZGh/9oACAEBAAE/IZqfoeFp0xtNkHo0UTG6fQcJXjYZE6VlpAUNrxgyT//aAAwDAQACAAMAAAAQrP8AD//EABkRAAMAAwAAAAAAAAAAAAAAAAABESFRcf/aAAgBAwEBPxBRk7G8hez/xAAZEQACAwEAAAAAAAAAAAAAAAAAAREhUTH/2gAIAQIBAT8QcUieCTpDD//EABsQAQADAQEBAQAAAAAAAAAAAAEAESExYUFx/9oACAEBAAE/ECsFVgxlHIGg24tX5hiYKLAW9ncE5QX4uaRydLgfc8Ncjb6AbjtB9IBUxRBHFn//2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 6. 베네치안 호텔. 밖은 밤이지만 여긴 하늘이 별도 구현되어 있다. 곤돌라까지, 서프라이즈.&apos; title=&apos;&apos; src=&apos;/static/26d046bb627fcdfb70dda4e0856bafbe/ba98e/ces_2017_d02_06.jpg&apos; srcset=&apos;/static/26d046bb627fcdfb70dda4e0856bafbe/8ccab/ces_2017_d02_06.jpg 190w,
/static/26d046bb627fcdfb70dda4e0856bafbe/ba98e/ces_2017_d02_06.jpg 315w&apos; sizes=&apos;(max-width: 315px) 100vw, 315px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 6. 베네치안 호텔. 밖은 밤이지만 여긴 하늘이 별도 구현되어 있다. 곤돌라까지, 서프라이즈.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;그렇게 구경을 하면서 하염없이 걷는다. T는 한국 사람들이 베가스를 처음 오면 명동이랑 비슷하다는 말을 했다는 이야기를 한다. Y는 속으로 명동이라기엔 사람이 너무 없는데 라는 생각을 했다. 하지만 코너를 돌자 그 생각은 없어졌다. 사람들이 물밀듯이 쏟아졌기 때문이다. 일행이 미자막으로 도착한 곳은 베네치안 호텔이었다. 앞서도 말한 것과 같이 그곳은 베니스를 옮겨둔 곳이었다. Y는 처음 들어갈 때 깜짝 놀랐다. 왜냐하면 깜깜한 밤길을 걷다가 실내로 들어갔는데 갑자기 대낮이 되었기 때문이다. 대낮이 환하다는 의미가 아니라 그냥 아침이 된듯한 느낌이었다. 나중에 안 사실이지만 천정에다 하늘 그림을 자연스럽게 그린 다음 불을 켜 두어서 그런 착시를 일으키는 것이었다. Y는 정말 신박하다는 생각을 한다. 물길이 있고 곤돌라가 있다. 진짜 베니스라는 생각이 절로 든다.&lt;/p&gt;
&lt;p&gt;너무 걸어서 모두가 피곤했다. 모두 앉을 곳을 찾았지만 마땅치 않았다. 그러다 T가 푸드코트 같은 곳을 발견했고 음료수를 시켜 모두가 앉았다. 바로 옆이 카지노였다. 이후 일정에 대한 이런 저런 이야기를 한다. 어디를 갈거냐 이곳 저곳 전화를 해서 예약이 되는지를 묻는다. 당첨된 곳은 일식집이었다. 21시에 예약이 된다고 했다. 아직 두시간 가량 남은 시간이다. 피곤했지만 또 심심하기도 했다. J는 카지노에서 시간을 떼우다 가자는 이야기를 한다. 일행은 그러기로 한다. 하지만 K는 탐탁지 않아 하는 분위기다. 결국 K와 S는 밖으로 나가 바람을 쏘이기로 하고 T는 플라밍고에서 차를 찾아서 이쪽 호텔 입구로 가져오기로 한다. JYM만 남아서 카지노를 구경한다. 이곳저곳 구경을 하는데 대부분 싸지 않다. 블랙잭은 대체로 25불씩이다. 섣불리 하기엔 비싼 금액. 1불짜리 슬롯머신을 J가 잠깐 했지만 진짜 금방 끝이 난다. JYM은 룰렛 옆에서 다른 사람들이 하는 것을 구경한다. 사실 JYM 모두 대체로 처음이라 카지노를 아는 사람이 없다. 그래도 룰렛은 워낙 간단해서 옆에서 보자 대체로 룰이 이해가 된다. 구경하는 테이블은 혼자서 플레이 하고 있었는데 Y가 보기에 그 전략은 수학적으로 상당히 합당한 전략 같아 보였다. 플레이어는 따기도 하고 잃기도 했지만 혼자서 오랜 시간 플레이를 하고 있었다.&lt;/p&gt;
&lt;p&gt;카지노를 구경하니 시간은 금방 간다. 결국 JYM은 그날 카지노를 하지는 못하고 구경만 하다 밖으로 나간다. S가 했냐고 묻는다. Y는 케이스 스터디를 하고 왔다고 너스레를 떤다. K는 호텔 입구에서 큰 기업 회장으로 보이는 사람이 지나가는 것을 두 번 봤다며 한국의 의전 문제를 이야기 한다. 저런 문화는 좋지 않다고 비판한다. 그러면서 그나마 IT 업계는 그런 것은 덜한 것 같다는 이야기를 덧붙인다. Y는 IT 업계도 실상 조금만 커지면 똑같지 않냐는 반론을 이야기 해본다. M은 오늘 근처에 현대 정의선 부회장이 왔다는 이야기를 들었다는 말을 한다.&lt;/p&gt;
&lt;h3&gt;미국 시간 2017.01.05 21:00 pm - 2017.01.06 05:00 am&lt;/h3&gt;
&lt;p&gt;T가 플라밍고에서 차를 가지고 일행이 기다리는 호텔 입구로 오고 있었다. 거의 비슷한 시간에 도착해서 JYM은 많이 기다리지 않고 곧바로 차를 탈 수 있었다. 도착한 곳은 이자카야 분위기의 일식집. 어제 먹었던 A18 보다는 훨씬 좋다. 서빙을 하는 아가씨가 한국말을 참 잘한다. 그런데 옆 테이블에 가서는 또 유창한 일본어로 주문을 받는다. 일행은 서빙 하는 친구가 3개국어를 한다며 여러가지 추측을 쏟아낸다. 결국 물어서 알게 된 사실은 한국 사람이고 근처 간호 학교에 다니고 있다고 한다. 안주도 괜찮았고 술도 나쁘지 않다. 술자리가 길어지기에 금상첨화인 상황.&lt;/p&gt;
&lt;p&gt;분위기가 무르익을즈음 M이 핵폭탄 화두를 던진다. 한국의 회사 운영 시스템이 좋지 않다는 것이다. 어쩌다보니 또 어제처럼 M은 공격하고 K는 수비하는 입장이 된다. M의 주된 논지는 한국 회사는 너무 대표 독단으로 운영되는 경우가 많다며 대표를 견제할 시스템이 없는 것이 문제라는 것이다. 특히나 중소 회사의 경우 대표가 최대주주인 경우가 많기 때문에 문제가 더 심각하다고 한다. 하지만 미국 회사의 경우에는 이사회라는 시스템을 통해서 운영되기 때문에 그런 문제가 없다고 한다. K는 다양한 방법으로 자신을 수비한다. 자신은 공정하다, 그렇게 운영하지 않는다는 이야기를 수차례. M이 그냥 돌직구를 날린다. 그래서 그 회사의 대표는 누가 견제할 수 있어요? K의 말문이 막힌다. Y가 대신 대답한다. 없죠.&lt;/p&gt;
&lt;p&gt;K는 자신의 회사 사람들은 대표 의견에 반대하는 것이 있으면 직설적으로 말한다는 이야기를 여러차례 근거로 들었다. 그말에 Y가 M을 거든다. 그래도 결국 진짜 중요한 결정은 다 대표님 생각대로 되는 것 아니냐는 대답이다. K도 어쩔 수 없다는 이야기를 한다. M은 그게 문제라며 공격을 이어 간다. 이번엔 반대로 Y가 K를 도와준다. 미국 또한 이사회가 오염되면 똑같다는 이야기였다. 결국은 정치 문제로 귀결된다는 말이다. 이사회가 존재하지만 이상하게 운영되는 미국 회사들의 예는 수도 없이 많다며 콕 찝어 보자면 회사가 적자가 나도 대규모 인센티브를 받는 CEO들을 지적한다. M도 완벽한 시스템은 없다고 시인한다. 하지만 견제 세력이 있는 것과 없는 것은 천지 차이라는 말을 덧붙인다. Y는 소규모의 경우는 합의에 낭비하는 시간 보다는 빠른 결정을 통한 효율 추구가 더 좋을 수도 있다는 이야기로 맞불었다. 실제로 그도 창업 초기에 그런 경험을 했었기 때문이다.&lt;/p&gt;
&lt;p&gt;이 이야기는 길게 길게 무럭 무럭 이어졌다. 안주도 좋았고 술도 좋았기 때문이다. T와 S는 많이 힘들어 하는 분위기다. 재밌는 주제도 아니고 그들이 거들 말도 별로 없었기 때문이리라. 2시까지 하는 가게가 거의 마칠 즈음에 그들은 나왔다. T는 다시 운전대를 잡는다. M이 묵고 있는 호텔에 그를 데려다주고 나머지 일행은 에어비앤비로 예약한 집으로 향한다. 집에 도착하니 거의 3시가 다 된 시각. 정말 늦었고 술도 취했다. 하지만 K는 아직 끝이 아니었다. S를 두고 JYKT는 한잔 더 하기 위해 베가스로 우버를 타고 나왔다. K는 진짜 베가스의 밤은 지금부터라며 호기롭게 말했다. 모두가 피곤했지만 K를 말릴수는 없는 노릇이었다. 결국 그들은 베가스의 가장 화려한 곳으로 출동해서 베가스의 밤을 즐겼다. 다시 집에 도착했을 때 시간은 5시였다. Y는 속이 쓰려 컵라면에 햇반을 하나 먹고 잠들었다. 나머지 일행은 광속으로 셧다운 됐다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] CES 2017 DAY #1]]></title><description><![CDATA[미국 시간 2017.01.04 09:30 am - 2017.01.04 12:00 pm LA 공항에 도착했다. 베가스행 비행기를 갈아타는데 셋에게 허락된 시간은 한시간 남짓이다. 그마저도 J…]]></description><link>https://jiniya.net/ng/2017/01/ces-2017-day-1/</link><guid isPermaLink="false">https://jiniya.net/ng/2017/01/ces-2017-day-1/</guid><pubDate>Wed, 04 Jan 2017 12:10:01 GMT</pubDate><content:encoded>&lt;h3&gt;미국 시간 2017.01.04 09:30 am - 2017.01.04 12:00 pm&lt;/h3&gt;
&lt;p&gt;LA 공항에 도착했다. 베가스행 비행기를 갈아타는데 셋에게 허락된 시간은 한시간 남짓이다. 그마저도 J가 랜덤 체크에 걸리는 바람에 티케팅까지 해야하는 상황. 비행기에서 거의 다섯 손가락에 꼽힐만큼 빨리 내려서는 &quot;Express Connection&quot; 이라고 적힌 종이를 받아들고는 달리기 시작했다. 그나마 급행이라 그런지 입국 심사는 간단하게 넘어갔다. S가 조금 오래 걸렸지만 그래도 일반적인 미국 입국 심사보다는 간소했다. 짐들도 일등석 태그가 붙어 있어서 먼저 나왔다. 대한항공 티켓팅 직원이 환승 시간이 짧다고 발휘한 센스였다. 다시 달리기 시작. 세관 신고도 급행으로 하고 갸방을 다시 베가스행으로 보내고 델타 항공이 있는 게이트로 달리기 시작했다. J와 Y가 앞서고 S는 힘들게 쫓아온다. 델타가 있는 게이트는 5번 달려도 달려도 나오질 않는다. 4번이 무지 길다. Y는 잠시 이거 원래 뛰는게 아니라 교통 수단을 이용하는 것이 아닌가라는 생각을 해봤다. 그즘에 5번 게이트가 나왔다. 셋 모두 잽싸게 올라가서 티켓팅을 했다. 출력하고 다시 검색대 앞. 미국이라 그런지 보안 검사가 까다롭다. Y는 신발을 신고 있다가 지적질을 받았다. 짐을 검색대 안으로 넣지 않는다는 지적을 또 한 번 받는다. Y는 속으로 까탈스럽다는 생각을 한다.&lt;/p&gt;
&lt;p&gt;그렇게 검색대를 통과해 이제는 조금 여유롭게 걸어서 게이트 앞에 섰다. 그리고는 긴 줄 끝에 비행기에 올랐다. 셋 모두 안도했다. J는 50분에 이게 가능하네라며 허탈 웃음을 짓는다. 그리곤 이내 J, S, Y 모두 깊은 꿈나라로 빠져든다. 한시간 조금 넘는 비행 시간 동안 셋 모두 기절했다.&lt;/p&gt;
&lt;h3&gt;미국 시간 2017.01.04 13:00 pm - 2017.01.05 03:30 am&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./ces_2017_d01_01.jpg&apos; data-alt=&apos;Figure 1. 베가스 공항의 첫 장면, 벌써 카지노 머신들이 즐비하다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/1aeb95e279e8c8255d712db273203851/7fbea/ces_2017_d01_01.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 56.315789473684205%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAEEAgX/xAAVAQEBAAAAAAAAAAAAAAAAAAABAP/aAAwDAQACEAMQAAABT5+YtJBP/8QAGhABAAIDAQAAAAAAAAAAAAAAAQADAgQhEf/aAAgBAQABBQI2iN2KNh6S3jj0/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQIBAT8BJ//EABkQAAIDAQAAAAAAAAAAAAAAAAExABARcf/aAAgBAQAGPwJZGaPa0uf/xAAaEAEAAgMBAAAAAAAAAAAAAAABABEhMWFR/9oACAEBAAE/IXbu1dR8qPYZgGOQgyNCYnvFlZ//2gAMAwEAAgADAAAAEPff/8QAFhEAAwAAAAAAAAAAAAAAAAAAARAx/9oACAEDAQE/EDF//8QAFREBAQAAAAAAAAAAAAAAAAAAEDH/2gAIAQIBAT8Qo//EAB4QAQEAAgICAwAAAAAAAAAAAAERACExQVFhcYGx/9oACAEBAAE/ENCQu2i+8FKrK1wwPuZMGganc335yBB8i4Q0SFnff7jebqjlc//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 1. 베가스 공항의 첫 장면, 벌써 카지노 머신들이 즐비하다.&apos; title=&apos;&apos; src=&apos;/static/1aeb95e279e8c8255d712db273203851/7fbea/ces_2017_d01_01.jpg&apos; srcset=&apos;/static/1aeb95e279e8c8255d712db273203851/8ccab/ces_2017_d01_01.jpg 190w,
/static/1aeb95e279e8c8255d712db273203851/ea4c8/ces_2017_d01_01.jpg 380w,
/static/1aeb95e279e8c8255d712db273203851/7fbea/ces_2017_d01_01.jpg 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 1. 베가스 공항의 첫 장면, 벌써 카지노 머신들이 즐비하다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;비행기 소리에 Y가 깬다. 그래도 한숨 붙여서 다행이라고 생각한다. 그즈음 비행기가 베가스 공항에 도착했다. Y가 공항에 내린 첫 느낌은 여기가 베가스구나, 라는 생각이었다. 공항에는 벌써 슬롯 머신들이 즐비했다. 웰컴 투 라스베가스라는 푯말을 지나 가방을 찾으러 간다. 가방이 나오는 곳에 도착했을 때 가방은 모두 나와 있는 상태. 가방을 찾자 J가 예매한 CES 티켓을 공항에서 찾아가면 된다며 사람들이 기다리고 있는 줄을 가리킨다. 셋 모두 거기 줄을 섰다. 줄은 길었고, 티켓 발매 직원은 한 명이었다. 시간이 제법 걸렸다. J는 작년은 이렇지 않았다며 올해 사람이 많이 온 것 같다는 얘기를 건낸다. Y와 S는 아직도 어리둥절한 상태라서 그러려니 하고 있다. 한참을 기다려서는 셋 모두 티켓을 받고 공항을 빠져 나왔다. 담배 피는 곳에서 J는 담배를 태우고 Y와 S는 기다린다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./ces_2017_d01_02.jpg&apos; data-alt=&apos;Figure 2. CES 2017 티켓&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 236px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/e714483792eb93adc299890c4d92acb6/c701c/ces_2017_d01_02.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 177.89473684210526%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAkABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAMFBAb/xAAXAQEBAQEAAAAAAAAAAAAAAAACAQMA/9oADAMBAAIQAxAAAAFSquiSAWgPDQ5hzNwkiCWhisYGvf/EABsQAAIDAQEBAAAAAAAAAAAAAAECAAMSEyEi/9oACAEBAAEFAgGM4vqUEciwMxKX+El12GKlSlhEbTlRp7hlD6f/xAAZEQACAwEAAAAAAAAAAAAAAAAAARAREjH/2gAIAQMBAT8B6YQyxx//xAAbEQACAQUAAAAAAAAAAAAAAAAAEAECERIxMv/aAAgBAgEBPwHRnJdU9r//xAAfEAACAQQCAwAAAAAAAAAAAAAAAREQITEyA0EiUpH/2gAIAQEABj8CULY8+NnaE2WZqIwRPVMv6SxyW9qf/8QAHRABAAMAAgMBAAAAAAAAAAAAAQARITFBUXGB0f/aAAgBAQABPyFY26r5E0qOmUYIhiBCOJBsH3Ha13mVmMoP6lSPJBg1bOCu8EcwOdzc1qBRi7RWdep//9oADAMBAAIAAwAAABAM6gGML//EABkRAQADAQEAAAAAAAAAAAAAAAEAESEgYf/aAAgBAwEBPxA1TPQhTa4f/8QAGxEBAAICAwAAAAAAAAAAAAAAAQARIWEQMdH/2gAIAQIBAT8QcLJoYQWnUWRrzj//xAAgEAEBAAICAgIDAAAAAAAAAAABEQAhMUFRkXGBobHw/9oACAEBAAE/EDT6iv8AD7wmLvJ604zFuJC+s3TJ0V7cARx3U31zgpKKqG3J3Wbvzj4rZ2mfS4h4Ufk537qXj5xASFlBfesjm8AooeMC1lbdt84DEFmu5mkEjI0P3n//2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 2. CES 2017 티켓&apos; title=&apos;&apos; src=&apos;/static/e714483792eb93adc299890c4d92acb6/c701c/ces_2017_d01_02.jpg&apos; srcset=&apos;/static/e714483792eb93adc299890c4d92acb6/8ccab/ces_2017_d01_02.jpg 190w,
/static/e714483792eb93adc299890c4d92acb6/c701c/ces_2017_d01_02.jpg 236w&apos; sizes=&apos;(max-width: 236px) 100vw, 236px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 2. CES 2017 티켓&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;J가 라인으로 합류하기로 한 다른 일행의 위치를 점검한다. K와 T가 LA에서 베가스로 셋을 마중나오기로 했는데 아직 도착하지 않았기 때문이다. 담배를 달아서 몇 개비를 피웠을 때 K와 T가 도착했다. 그들도 CES 티케팅을 위해 기다려야 했다. 20분 넘게 걸렸다. 밖에서 담배를 피우며 점심으로 무엇을 먹을지를 이야기를 한다. K가 곰탕이 좋다며 이조곰탕으로 가자고 했다. 모두 그러자고 한다. CES 티켓을 끊고 K와 T가 타고온 차를 이용해서 곰탕 집으로 향했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./ces_2017_d01_03.jpg&apos; data-alt=&apos;Figure 3. 베가스 곰탕 맛집, 이조곰탕&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/433cf085f78865579c01b8551f2ee5ce/7fbea/ces_2017_d01_03.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAwAE/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAL/2gAMAwEAAhADEAAAAWzpnDjor//EABoQAQEAAgMAAAAAAAAAAAAAAAIBABEDEiH/2gAIAQEAAQUCU1ifneZdo8khKol//8QAFxEAAwEAAAAAAAAAAAAAAAAAAQIQEf/aAAgBAwEBPwFRk//EABYRAQEBAAAAAAAAAAAAAAAAAAIQEf/aAAgBAgEBPwFLZ//EABwQAAICAgMAAAAAAAAAAAAAAAABAiEQETFRcf/aAAgBAQAGPwJ9lqsOWxvzkuJ//8QAHBABAAMAAgMAAAAAAAAAAAAAAQARITFBUWFx/9oACAEBAAE/ISGinXmW0q9I3YM4YbUAgqa+opKJ/9oADAMBAAIAAwAAABBn/wD/xAAWEQEBAQAAAAAAAAAAAAAAAAAAARH/2gAIAQMBAT8QnLX/xAAXEQADAQAAAAAAAAAAAAAAAAAAARFh/9oACAECAQE/EGPCYf/EABwQAQEAAgMBAQAAAAAAAAAAAAERACExQVFhcf/aAAgBAQABPxBykAi+s2ULrYf3Dwg90Zy+Bi23zzKOicg9tGWYoJHUQz//2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 3. 베가스 곰탕 맛집, 이조곰탕&apos; title=&apos;&apos; src=&apos;/static/433cf085f78865579c01b8551f2ee5ce/7fbea/ces_2017_d01_03.jpg&apos; srcset=&apos;/static/433cf085f78865579c01b8551f2ee5ce/8ccab/ces_2017_d01_03.jpg 190w,
/static/433cf085f78865579c01b8551f2ee5ce/ea4c8/ces_2017_d01_03.jpg 380w,
/static/433cf085f78865579c01b8551f2ee5ce/7fbea/ces_2017_d01_03.jpg 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 3. 베가스 곰탕 맛집, 이조곰탕&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;ces 2017 d01 04
Figure 4. 이조곰탕에서의 거한 점심
이조곰탕, 베가스에서 나름 잘하는 집이다. 벌써 주차장은 가득 차고 웨이팅 종이는 모두 써서 더 적을 공간이 없었다. Y가 함께한 일행 보다 먼저 온 일행이 있다. 얘기하는 폼새가 삼성전자 직원 같았다. 그걸 모르고 늦게 온 K가 담배를 태우며 작년 CES와 올해 CES를 예상하며 올해도 LG가 이길 것 같다는 이야기를 한다. 이내 대기하는 사람들이 삼성 직원이라는 것을 알고는 조용해졌다. K의 팀이 늦게 왔지만 삼성 일행은 인원이 훨씬 많아 K팀 일행이 먼저 들어간다. 도가니 셋, 살코기 하나, 섞어 하나를 시킨다. 불고기 안주에 소맥으로 낮술이 시작된다. 그렇게 거하게 먹고는 에어비밴비로 예약한 집으로 이동했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./ces_2017_d01_05.jpg&apos; data-alt=&apos;Figure 5. 에어비앤비로 예약한 집. 헤니의 그 집이랑 흡사하다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/10db225ab0dc8da35920cb4786e3cff6/7fbea/ces_2017_d01_05.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMEAv/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/aAAwDAQACEAMQAAABJYnBbEFn/8QAHBAAAQMFAAAAAAAAAAAAAAAAAQACAxESIjFB/9oACAEBAAEFAgI73SOBNV04ra//xAAWEQEBAQAAAAAAAAAAAAAAAAAAASH/2gAIAQMBAT8Bla//xAAWEQEBAQAAAAAAAAAAAAAAAAAAASH/2gAIAQIBAT8BsY//xAAbEAABBAMAAAAAAAAAAAAAAAABAAIQYREhMf/aAAgBAQAGPwLDXFVYXWxsR//EABoQAQEBAAMBAAAAAAAAAAAAAAERACExYVH/2gAIAQEAAT8hSQB80qE+sNNVc8Urzu0h7dKUIO//2gAMAwEAAgADAAAAEATv/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAERIf/aAAgBAwEBPxCKg94z/8QAFxEBAQEBAAAAAAAAAAAAAAAAAREAIf/aAAgBAgEBPxALcM9N/8QAGxABAQACAwEAAAAAAAAAAAAAAREAMSFBUdH/2gAIAQEAAT8QQV0RTONa9xKsoACswuwArPjiSW1XvLEU8RtgBxFA6IZ//9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 5. 에어비앤비로 예약한 집. 헤니의 그 집이랑 흡사하다.&apos; title=&apos;&apos; src=&apos;/static/10db225ab0dc8da35920cb4786e3cff6/7fbea/ces_2017_d01_05.jpg&apos; srcset=&apos;/static/10db225ab0dc8da35920cb4786e3cff6/8ccab/ces_2017_d01_05.jpg 190w,
/static/10db225ab0dc8da35920cb4786e3cff6/ea4c8/ces_2017_d01_05.jpg 380w,
/static/10db225ab0dc8da35920cb4786e3cff6/7fbea/ces_2017_d01_05.jpg 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 5. 에어비앤비로 예약한 집. 헤니의 그 집이랑 흡사하다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;집에 짐을 풀고 잠시 집 구경을 했다. 다니엘 헤니가 사는 그런 일반적인 미국 집이다. 이층 집으로 방이 5개, 화장실 3개, 뒷마당에 수영장이 있는 그런 집. 대충 집의 상태가 파악될즈음 T와 S는 생필품을 사러 마트에 갔다. 출장 막내의 삶은 그렇게 피곤하다. Y는 그사이 배정받은 방에서 쓰러졌다. 한시간쯤 잤을까? 북적거리는 소리에 Y가 잠을 깨고는 내려간다. K가 새로산 블루투스 오디오를 자랑한다. 삼성이 인수한 하만카돈의 제품이라며 저렇게 조그마한 스피커에서 이렇게 웅장한 소리가 난다고 너스레를 떤다. Y가 생각해도 소리가 빵빵하긴 했다. 잠시 음악을 들으며 마트에서 사온 짐 정리를 대충 마칠때쯤 우버X를 불러서 저녁을 먹으로 출동했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./ces_2017_d01_06.jpg&apos; data-alt=&apos;Figure 6. 첫 저녁 A18, 절대 피하길…​&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/793b97932d00cbd24badbe24e9b6f032/7fbea/ces_2017_d01_06.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAIEAQP/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQP/2gAMAwEAAhADEAAAAZVXMn3JhT//xAAaEAEAAgMBAAAAAAAAAAAAAAABAAIDERIh/9oACAEBAAEFAo6hby7w3uI5p//EABURAQEAAAAAAAAAAAAAAAAAAAAR/9oACAEDAQE/Aar/xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAgEBPwGI/8QAGhAAAgIDAAAAAAAAAAAAAAAAACEBAhARYf/aAAgBAQAGPwLUDwjoqn//xAAbEAACAwADAAAAAAAAAAAAAAABEQAhMUFhcf/aAAgBAQABPyG8shJftCGFGoTR7Awi05EDQUhd7P/aAAwDAQACAAMAAAAQ6O//xAAWEQEBAQAAAAAAAAAAAAAAAAABEBH/2gAIAQMBAT8QdEf/xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAgEBPxAJH//EABwQAQEAAgMBAQAAAAAAAAAAAAERADEhQWFRgf/aAAgBAQABPxAgogYYIiFlEd9ZzAk0Wr++4To65N31l9UjYH2e8bw8kCJXLtz/2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 6. 첫 저녁 A18, 절대 피하길…​&apos; title=&apos;&apos; src=&apos;/static/793b97932d00cbd24badbe24e9b6f032/7fbea/ces_2017_d01_06.jpg&apos; srcset=&apos;/static/793b97932d00cbd24badbe24e9b6f032/8ccab/ces_2017_d01_06.jpg 190w,
/static/793b97932d00cbd24badbe24e9b6f032/ea4c8/ces_2017_d01_06.jpg 380w,
/static/793b97932d00cbd24badbe24e9b6f032/7fbea/ces_2017_d01_06.jpg 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 6. 첫 저녁 A18, 절대 피하길…​&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;T가 찾은 집은 A18이라는 치킨 집이었다. A18을 보는 순간 T를 제외한 모든 사람은 웃기다는 생각을 했다. T는 18이 에이틴으로 보이는 영어가 더 편한 교포였기 때문에 솔직히 무슨 말들을 하는지 잘 이해할 수 없었다. 잠시 바람을 쏘이고 가게로 올라갔다. 치맥으로 시작한다. 시키는 메뉴마다 양은 어마어마 했다. 하지만 맛은 그닥이었다. 한국식 영계 치킨에 익숙한 이들에게 다자란 노계로 만든 듯한 치킨은 살이 퍽퍽하고 맛이 별로였다. T도 그런 표정이다. 그나마 그 사이 섞여있는 감자 튀김이 제일 괜찮은 것 같다는 이야기를 한다. 안타깝게도 맥주 또한 별로였다. 김빠진 맥주는 정말이지 그들을 좌절시키기에 충분했다. 이것저것 바꿔가며 시켜봤지만 모든 맥주가 맛이 형편 없었다. 화제는 S의 연애사였다. 유부남 셋이서 S의 연애사에 관한 이야기를 한마디씩 거드니 이야기가 끝이없이 이어진다. Y는 속으로 남녀의 차이는 정말이지 시대와 나이와 성별과 인종을 막론하고 통하는 주제라는 생각을 했다. 한참 이야기를 하고 있을 무렵 J가 라인으로 연락하던 B가 합류했다. 혼자가 아이었다. G가 함께왔다.&lt;/p&gt;
&lt;p&gt;G는 나름 업계에서 유명한 사람이기에 Y는 신기하다는 생각을 했다. 비유를 들자면 술집에서 맥주를 마시고 있는데 연예인이 온 것과 비슷한 상황. Y는 G에 관한 웃지 못할 에피소드를 하나 들어서 알고 있었고, 과거 술자리 안주로 그 이야기를 많이 했었다. 그래서 그런지 G가 어떤 사람인지 더욱 궁금했다. 그런데 G는 Y가 생각한 것과는 다소 상반된 사람이었다. 그리고 생각보다 재미난 사람이었다.&lt;/p&gt;
&lt;p&gt;베가스 답게 G가 처음 한 얘기는 겜블링이었다. 안타깝게도 G와 B를 제외한 나머지 사람들인 Y의 일행 중에는 도박을 하는 사람이 없었다. 대체로 명절 고스톱 정도 치는 사람들이었다. K는 심지어 그마저도 하지 않는 사람이었다. 나름 뼈대 있는 집안의 자손인 그는 집안 대대로 내려오는 집안의 룰이 있었기 때문이다. 그 중에 하나가 도박을 하지 말라는 것이었다. 여튼 그렇게 도박에는 하등 관심 없는 사람들을 상대로 G는 구구절절 도박 예찬론을 늘어놨다. G의 논지는 이랬다.&lt;/p&gt;
&lt;p&gt;일단 카지노의 슬롯 머신 룰렛 따위는 겜블이 아니다. 그건 그저 돈을 카지노에 가져다 바치는 행위다. 그가 겜블이라고 말하는 것은 포커와 블랙잭이었다. 일종의 마인드 스포츠로써 어느 정도 실력에 따라 승부가 결정되는 게임이라고 그는 주장했다. 그러면서 특히 포커에 대해서 많은 이야기를 했다. 그는 기업가는 반드시 겜블링을 해야 하는데 그 이유는 흥망성쇠를 간접적으로 짧은 시간에 느낄 수 있기 때문이라고 했다. 그가 포커를 하면서 배운 가장 큰 교훈은 상황이 좋지 않을 때 견디는 방법, 또 상황이 좋을 때 자만하지 않는 법이라고 했다. 그리고 특히나 포커를 하면서 한없이 패가 계속 좋지 않아서 하염없이 돈을 잃으면서 이 상황이 언제 끝날까, 라는 생각을 하며 게임을 할 때. 그때 그는 가장 많이 배웠다고 했다. 그 상황을 견뎌 내는 것이 사업에서 좋지 않은 상황이 계속 이어질 때 견뎌내는 것과 같다는 지론이었다. 그러면서 우리에게 꼭 겜블을 해볼 것을 권했다.&lt;/p&gt;
&lt;p&gt;겜블 이야기 다음은 연예인 이야기가 이어졌다. Y가 바라본 G는 정말 신기한 사람이었다. 그렇게 바쁘고 시간이 없을 것 같은 사람이 알고 봤더니 아이돌 전문가였기 때문이었다. 뒤쪽 스크린에 나오는 아이돌의 이름을 줄줄이 꿰고 있었다. 정말이지 신기했다. 그리고 드라마 이야기가 이어졌다. 역시 줄줄꿰고 있는 G. 그 자리에 있던 어린 친구들보다 훨씬 더 많은 연예인 정보를 알고 있었다.&lt;/p&gt;
&lt;p&gt;그렇게 이어지던 가십 이야기가 끝나고 CES 이야기가 나왔다. 그러다 VR 이야기가 테이블에 올라왔다. G는 요즘 사업들이 모두 초거대기업들의 문샷 배틀을 제외하고는 돈이 될만한 사업 아이템이 없다는 이야기를 했다. 그러면서 VR 또한 그런 것 중에 하나라는 이야기를 한다. K는 반대다. 그는 VR에 기회가 있을 거라는 입장이었다. G는 아직 기술이 덜 무르익었다는 생각이고, K는 지금부터 준비해야 하는 입장. G의 집요한 공격이 이어졌다. 그래서 뭐할거냐? 특정 분야를 제외하고 VR이 의미 있는 경우를 설명해 보라. 그래서 지금 사업에서 VR 쪽에 어느 정도 비율로 투자하고 있는가? G는 면접관이자 심판이었고, K는 면접자이자 플레이어였다. 하지만 K도 말빨로 어디가서 딸리는 사람은 아니기에 그렇게 이어지는 공격을 주구장창 막아냈다. 이야기가 길어지고 있었다.&lt;/p&gt;
&lt;p&gt;그들이 담배 피러 나간 사이 대화에 끼지 못하고 듣고 있던 S와 T와 Y는 잠시 서로 대화를 나눌 수 있었다. 셋의 마음은 똑같았다. 언제 끝날까? 우리는 언제쯤 침대에 누울 수 있을까? K를 다년간 수행한 T가 예언을 했다. 우리가 오늘 잘 시간은 3시라는 예언이었다. S는 소스라쳤고, Y는 정확하다는 생각을 했다.&lt;/p&gt;
&lt;p&gt;VR에 대한 열띤 토론이 끝나고 잠시 최순실 박근혜 얘기가 나올 즈음 1차가 끝이났다. 많이 아쉬워하는 G를 뒤로한체 J의 일행은 다시 집으로 돌아왔다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./ces_2017_d01_07.jpg&apos; data-alt=&apos;Figure 7. 뒷마당에서의 술자리, 불이 있어 몽환적인 분위기. 애어비앤비 집의 유일한 장점이었다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/7eca4866729e7d1d607b622035a38f0f/7fbea/ces_2017_d01_07.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMFAf/EABUBAQEAAAAAAAAAAAAAAAAAAAIA/9oADAMBAAIQAxAAAAGfShaGwQK//8QAGRAAAgMBAAAAAAAAAAAAAAAAAQMCEBIR/9oACAEBAAEFAlcEnyVjVE1//8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQMBAT8Bqv/EABYRAQEBAAAAAAAAAAAAAAAAAAASAf/aAAgBAgEBPwGdS//EABgQAAIDAAAAAAAAAAAAAAAAAAAxICEi/9oACAEBAAY/ArMscP/EABgQAQEBAQEAAAAAAAAAAAAAAAEAERDx/9oACAEBAAE/IcytOGPjDkrz/9oADAMBAAIAAwAAABAf7//EABYRAAMAAAAAAAAAAAAAAAAAAAABEf/aAAgBAwEBPxBLCz//xAAXEQADAQAAAAAAAAAAAAAAAAAAAREh/9oACAECAQE/EHTGQf/EABkQAQEBAQEBAAAAAAAAAAAAAAERACExUf/aAAgBAQABPxA8LfEt3EiIPzLYonCLnXMBFct3/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 7. 뒷마당에서의 술자리, 불이 있어 몽환적인 분위기. 애어비앤비 집의 유일한 장점이었다.&apos; title=&apos;&apos; src=&apos;/static/7eca4866729e7d1d607b622035a38f0f/7fbea/ces_2017_d01_07.jpg&apos; srcset=&apos;/static/7eca4866729e7d1d607b622035a38f0f/8ccab/ces_2017_d01_07.jpg 190w,
/static/7eca4866729e7d1d607b622035a38f0f/ea4c8/ces_2017_d01_07.jpg 380w,
/static/7eca4866729e7d1d607b622035a38f0f/7fbea/ces_2017_d01_07.jpg 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 7. 뒷마당에서의 술자리, 불이 있어 몽환적인 분위기. 애어비앤비 집의 유일한 장점이었다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;도착한 K는 뒷마당에 있는 파이어 스테이션에 불을 붙이고 블루투스 스피커로 노래를 틀었다. 하지만 그의 핸드폰 인터넷이 불안정했다. 결국 S의 로밍 인터넷으로 음악을 들었다. 그의 취향에 적합한 거미의 목소리가 백야드에 울려퍼졌다. 불이 있고, 술이 있고, 음악이 있는 약간 몽환적인 분위기의 술자리가 이어졌다. 심지어 의자도 제법 편했다. 그렇게 일행은 거미의 노래가 수도 없이 이어져서 결국은 도저히 알 수 없는 거미의 노래가 나올때까지 맥주를 마셨다. 그리고는 라면으로 지친 속을 달래고 각자 방으로 갔다. Y는 방에 누워 시계를 보았다. T의 예언은 정확했다. 침대에 누운 그 시간이 새벽 3시 30분이었기 때문이다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] CES 2017 DAY #0]]></title><description><![CDATA[내가 본 것들, 경험한 것에 대한 기억을 보존하기 위해서 이 기행을 남긴다. 한국시간 2017.01.04 12:00 - 15:00 pm 그들이 탈 비행기는 LA행 3시 출발 대한항공 KE0017편이다. A380 기종이다. J와 Y는 1…]]></description><link>https://jiniya.net/ng/2017/01/ces-2017-day-0/</link><guid isPermaLink="false">https://jiniya.net/ng/2017/01/ces-2017-day-0/</guid><pubDate>Wed, 04 Jan 2017 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;내가 본 것들, 경험한 것에 대한 기억을 보존하기 위해서 이 기행을 남긴다.&lt;/p&gt;
&lt;h3&gt;한국시간 2017.01.04 12:00 - 15:00 pm&lt;/h3&gt;
&lt;p&gt;그들이 탈 비행기는 LA행 3시 출발 대한항공 KE0017편이다. A380 기종이다. J와 Y는 11시쯤 회사에서 택시를 타고 출발해 인천 공항에 열두시쯤 도착했다. S는 집에서 바로 공항으로 오기로 했다. J와 Y가 공항에서 10분 남짓 기다리자 S가 왔다. 한국은 영하의 겨울이지만 LA는 봄날씨다. 이런 사실을 잘 알고 있는 J는 공항에서 패딩 점퍼를 간절기의 가벼운 옷차림으로 갈아 입었다. Y와 S에게도 갈아 입을지 물었지만 둘은 괜찮다는 답변을 한다.&lt;/p&gt;
&lt;p&gt;J의 트렁크를 다시 정비하고 티켓팅을 하러 갔다. 줄이 길다. 약간 지루해지는 찰나 그들의 차례가 됐다. 티켓팅 중에 사소한 문제가 생겼다. J가 SSSS라는 일명 랜덤 체크에 걸린 것이다. J는 제법 여러차례 미국을 다녔지만 이런 것을 당해보기는 처음이다. Y와 S도 처음 보긴 마찬가지다. 티켓팅을 하는 직원이 친절하게 설명해주면서 난처해 한다. 그도 그럴것이 그들은 LA 공항에서 다시 베가스행 비행기로 갈아타야 하는데 그 시간이 무척 촉박했기 때문이다. Y와 S의 베가스행 티켓은 미리 발권해 주었지만 J는 랜덤 체크라 그러지 못했다. 1시간 남짓한 시간 안에 입국 심사를 마치고 다음 비행기를 타야 하는데 이제는 현지 티켓팅 작업까지 추가된 것이다. 업친데 덮친격. SSSS에 대한 네이버 검색 결과는 그들을 더 멘붕에 빠트리기에 충분했다. 모두가 약간 긴장했다.&lt;/p&gt;
&lt;p&gt;J와 Y는 로밍을 하고 보조 배터리를 받았다. J는 필요가 없다며 배터리를 S에게 건낸다. J의 기업인 카드 덕분에 공항의 빠른 검색대를 사용할 수 있었다. 인천 공항의 가장자리에 있는 검색대였다. 기업인 카드를 가진 사람과 그 일행은 해당 검색대를 사용할 수 있다. 공항은 엄청난 인파로 붐볐지만 빠른 검색대는 놀라울만큼 한산했다. 검색대를 지나 J와 Y가 출국 심사대 줄을 선다. S는 자동 심사대로 향했다. 그가 그것을 통과할즈음 J와 Y도 이제 더이상 사전 등록을 하지 않아도 자동 심사대를 쓸 수 있다는 사실을 알게 되었다. 그들도 줄을 떠나 자동 심사대로 빠르게 통과했다.&lt;/p&gt;
&lt;p&gt;J가 면세점 쇼핑을 할 것인지를 묻는다. Y, S 모두 그닥 살게 없다는 표정을 짓는다. 칼라운지로 직행한다. Y는 작년 GDC 갈때에도 이곳을 왔다. 작년 보다는 조금 더 사람이 많다고 느꼈다. 셋이 자리를 찾아 헤매다 결국 의자를 돌려서 테이블을 마주보고 앉도록 한 후에 음식을 가지러 간다. Y는 이것 저것 떠와서 먹었지만 음식 품질이 작년보다 덜하다고 느꼈다. 빵들이 지나치게 오래된 느낌이었기 때문이다. 셋다 빵을 조금씩 먹었고, S와 Y는 추가로 컵라면도 하나씩 끓여 먹었다. 정신 없이 오느라 모두 점심을 먹지 못해 배가 고팠다. 대충 끼니를 때우고 J는 담배를 피우고, S는 핸펀을 하고, Y는 노트북을 켜서 메일 확인을 하고 중요한 메일에 회신을 한 통 해주었다. 골치아픈 문제의 답을 알려주는 반가운 메일이었다.&lt;/p&gt;
&lt;p&gt;라운지에서의 시간은 금방 간다. 2시 10분 즈음에 내려와서 게이트 앞에 섰다. J는 그사이 담배를 사왔다. 곧이어 탐승한다. 프레스티지란 말이 무색하게 줄이 길었다.. 불행중 다행은 셋다 일찌감치 줄을 섰기에 빠르게 탈 수 있었다는 점이다. 옆에 일등석 손님이 한 명 있다. 평소 Y는 어떤 사람들이 일등석을 타나 궁금했기에 그를 면밀히 살펴본다. 지나칠정도로 너무나 평범한 사람이었다. 정말 평범하다는 생각을 했다. 비행기로 올라타는 길목에서는 J는 정밀 검색을 받으러 갔다. S와 Y는 먼저 탄다.&lt;/p&gt;
&lt;h3&gt;한국시간 2017.1.4 15:00 pm - 미국시간 2017.1.4 09:00 am&lt;/h3&gt;
&lt;p&gt;A380는 이층으로 되어있다. 스튜어디스가 Y에게 이층으로 가라고 안내했다. S도 따라간다. Y는 스튜어디스가 안내해 준 11E 자리에 앉았다. 비행기는 뭔가 산만한 분위기다. 스튜어디스가 S와 Y의 외투를 받아서 걸어준다. 이내 J가 도착했다. 걱정했던 것만큼 심각하진 않았던 것 같다. 다들 자리에 앉아 실내화로 갈아 신고 USB를 연결한다. 스튜어디스가 안전 설명을 하는 사이 Y는 잠이 들었다. 어제 먹었던 소주의 숙취 때문인지 피곤했다. 이내 비행기가 이륙한다.&lt;/p&gt;
&lt;p&gt;J와 S는 모니터를 꺼내서 둘러본다. Y는 주구장창 볼거라 핸펀을 꺼내서 책을 읽는다. 조금 있다 스튜어디스가 식사 메뉴를 묻는 질문을 한다. Y는 스테이크를 J와 S는 불고기 비빔밥을 선택했다. 프레스티지석의 식사 시간은 지나칠 정도로 장황하다. 스테이크는 이랬다. 전채가 나오고 빵이 나오고 수프가 나오고 와인이 나오고 스테이크가 나오고 치즈. 과자. 과일이 나오고. 이어서 커피와 차가 나왔다. 다 먹는데 거의 꼬박 한 시간이 걸렸다. Y는 시험한다는 생각으로 죄다 달라고 해서 모두 먹어 본다. 치즈가 세 종류가 나왔는데 말랑말랑한 젤 맛있게 생긴 녀석의 반전에 당했다. 말랑한게 달달하게 생겨서는 엄청 역한 맛을 내는 치즈였기 때문이다. 이름이 궁금했지만 물어보진 않았다.&lt;/p&gt;
&lt;p&gt;식사가 끝나고 스튜어디스가 물과 세관 신고서를 나눠준다. J와 S가 먼저 작성하고 Y는 S의 펜과 신고서를 받아 베꼈다. 이내 다들 모니터 삼매경이 빠진다. 여기 영화를 죄다 섭렵할즈음 도착하리라, 라고 Y는 생각했다. Y는 &quot;잭 리처&quot;라는 톰 크루즈 주연의 영화를 틀었다. 뻔한 내용의 뻔한 전개지만 재미있다. 그즈음 기내에 불이 꺼진다. 자는 사람도 한둘 보인다.&lt;/p&gt;
&lt;p&gt;Y가 보던 영화가 끝났다. 탑승한지 꼬박 다섯 시간이 지난 시점, J와 S는 여전히 모니터 삼매경에 빠져있다. Y는 찌뿌둥한 몸을 좀 풀러 밖으로 나간다. 바가 있는 곳에 드러 눕는다. 세상 편하다고 그는 생각한다. 그 상태로 다시 핸펀 책읽기를 시작한다. 결국 가벼운 책을 완독했다. 난기류가 있으니 안전 벨트를 착용하라는 방송이 나온다. 흔들리지도 않는데 계속 방송은 나오는 상황이었다. Y는 버텨보다가 비행기가 조금 흔들리자 잽싸게 자세를 고쳐 앉아서는 벨트를 맨다.&lt;/p&gt;
&lt;p&gt;벨트를 하고 있기를 십여분 좀이 쑤신다. Y는 반대편 끝 칵테일 바가 있는 곳까지 걸어가서 스트레칭을 하고는 자리로 돌아왔다. S가 헤드셋을 빼고 앉아 있다. 영화를 많이 봤냐고 묻자 라면을 시키고 기다리는 중이라는 대답을 한다. Y는 수면 자세로 자리를 조정했다. 조금 있다 S의 라면이 왔다. 냄새가 향기롭다. 아까 비빔밥을 많이 안 먹더니 배가 고팠던 것 같다. 라면도 많이 먹지는 않는 눈치다. Y도 따라 시키려다 속이 좋지 않을 것 같아서 참는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./ces_2017_d0_01.jpg&apos; data-alt=&apos;Figure 1. 아침으로 나온 기내식 죽&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/06d8fe0fbb89c2ea5a374eb4940c55e9/7fbea/ces_2017_d0_01.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 56.315789473684205%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQGAQL/xAAVAQEBAAAAAAAAAAAAAAAAAAABAP/aAAwDAQACEAMQAAAB3ploo8pQf//EABoQAQEAAwEBAAAAAAAAAAAAAAIBAxITABH/2gAIAQEAAQUCRT9tzL+123vjk0WINf/EABcRAAMBAAAAAAAAAAAAAAAAAAEQETH/2gAIAQMBAT8Bg1f/xAAXEQADAQAAAAAAAAAAAAAAAAAAAREC/9oACAECAQE/AXpyFP/EAB4QAAEDBAMAAAAAAAAAAAAAAAABAhEDECIxEiFh/9oACAEBAAY/Ak5YkbFnZV8Z1bJqH//EABoQAQEBAAMBAAAAAAAAAAAAAAERACExQbH/2gAIAQEAAT8hecKSOPVV8MkbE7tXyaRxmihON//aAAwDAQACAAMAAAAQjx//xAAWEQEBAQAAAAAAAAAAAAAAAAABEFH/2gAIAQMBAT8QCdT/xAAWEQEBAQAAAAAAAAAAAAAAAAABEDH/2gAIAQIBAT8QUFkf/8QAHhABAQACAgIDAAAAAAAAAAAAAREAITFBUWGRofD/2gAIAQEAAT8QOPdCW3Zx3htbqqz9rLRpUed7xBrhs921PeCCHQV2/OMdSFJDx95//9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 1. 아침으로 나온 기내식 죽&apos; title=&apos;&apos; src=&apos;/static/06d8fe0fbb89c2ea5a374eb4940c55e9/7fbea/ces_2017_d0_01.jpg&apos; srcset=&apos;/static/06d8fe0fbb89c2ea5a374eb4940c55e9/8ccab/ces_2017_d0_01.jpg 190w,
/static/06d8fe0fbb89c2ea5a374eb4940c55e9/ea4c8/ces_2017_d0_01.jpg 380w,
/static/06d8fe0fbb89c2ea5a374eb4940c55e9/7fbea/ces_2017_d0_01.jpg 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 1. 아침으로 나온 기내식 죽&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;J는 두번째 CES 참관이고, S와 Y는 처음이다. S는 생애 처음 미국을 가보는 것이고, Y는 미국은 가봤지만 베가스는 처음이다. 이래저래 설레는 새해 첫 비행이다. 항상 그렇지만 모든 여행은 그 출발의 설레임이 좋다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] VS 2015의 magic statics 구현 세부 사항]]></title><description><![CDATA[최근에 좀 골치 아픈 문제를 겪어서 여기에다 정리해 놓는다. 컴파일러를 업그레이드하면서 알게 된 문제인데 정적 지역 변수의 초기화와 관련이 있었다. 문제의 발단은 이랬다. 컴파일러 업그레이드 후 이상하게 싱글턴 등을 구현하기 위해서 사용된 static…]]></description><link>https://jiniya.net/ng/2016/11/magic-statics/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/11/magic-statics/</guid><pubDate>Thu, 24 Nov 2016 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;최근에 좀 골치 아픈 문제를 겪어서 여기에다 정리해 놓는다. 컴파일러를 업그레이드하면서 알게 된 문제인데 정적 지역 변수의 초기화와 관련이 있었다. 문제의 발단은 이랬다. 컴파일러 업그레이드 후 이상하게 싱글턴 등을 구현하기 위해서 사용된 static 지역 변수 코드가 정상적으로 동작하지 않는 문제가 있었다. 구글 형님들께서도 POD를 제외하고 전역 객치를 만들지 말라는 조언을 하셨기에 우리가 만든 코드는 대체로 포인터를 사용하도록 변경했다. 그러다 급기야 어제는 부스트 라이브러리 코드를 디버깅 하기에 이르렀다. 잘 알겠지만 부스트 같은 템플릿 라이브러리는 쓰기는 편리하지만 디버깅은 지옥이다. 문제는 property_tree에서 발생했다. property_tree가 내부적으로 사용하는 rapidxml을 쓰면 잘 동작했는데 property_tree 코드만 쓰면 xml을 정상적으로 파싱하지 못했다. 여기저기 printf를 추가해서 따라간 마지막 장소에는 static 객체가 있었다.&lt;/p&gt;
&lt;p&gt;여기까지만 읽고 마치 새로운 컴파일러가 문제가 있다고 생각할 사람들이 있을까봐 노파심에 이야기를 하자면 컴파일러가 생성한 코드를 그냥 그대로 사용하면 문제가 되지 않는다. 우리가 그대로 사용하지 않고 별도의 처리를 해서 사용하면서 발생하는 문제였다.&lt;/p&gt;
&lt;p&gt;이 문제의 원인은 지역 static 객체 생성과 관련이 있었다. C++11 부터는 지역 static 객체 생성이 스레드 안전하게 보장하도록 표준에 추가되었다. 이 기능을 magic statics라 부르는 듯하다. 그간에는 이 기능에 대한 지원이 되지 않다가 VS2015에서 이 기능을 구현하면서 문제가 된 것이다. 그러면 VS2015가 내부적으로 스레드 안전한 초기화를 보장하기 위해서 어떻게 구현을 했는지 살펴보도록 하자. 그래야 왜 문제가 발생했는지도 알 수 있고, 어떻게 고칠 수 있는지도 알 수 있을테니 말이다. VS2015가 static 지역 객체 초기화를 스레드 안전하게 하기위해서 사용하는 전략은 단순하다. 락과 TLS다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Uninitialized    &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; BeingInitialized &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; EpochStart       &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; INT_MIN&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// Access to these variables is guarded in the below functions.  They may only&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// be modified while the lock is held.  _Tss_epoch is readable from user&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// code and is read without taking the lock.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;C&quot;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; _Init_global_epoch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; EpochStart&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;__declspec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; _Init_thread_epoch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; EpochStart&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; CRITICAL_SECTION   _Tss_mutex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; CONDITION_VARIABLE _Tss_cv&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; HANDLE             _Tss_event&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;decltype&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SleepConditionVariableCS&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; encoded_sleep_condition_variable_cs&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;decltype&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WakeAllConditionVariable&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; encoded_wake_all_condition_variable&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;컴파일러가 동기화를 위해서 사용하는 자원이다. 크리티컬 섹션으로 동기화하고 조건 변수나 조건 변수를 지원하지 않는 시스템이면 이벤트를 통해서 초기화 완료를 알리겠다는 생각이다. 위에 적힌 전역 변수는 모두 DLL이나 EXE가 실행될 때 최초에 초기화 된다. 위와는 별개로 정적 지역 객체가 존재하면 컴파일러는 해당 객체의 초기화 상태를 트래킹하기 위한 전역 변수를 추가한다. 이제 간단한 싱글턴 객체를 만들어보자.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Single&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;Single&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ctor\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Single&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;dtor\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; Single&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Instance&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; Single s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;핵심은 멀티스레드에서 Single::Instance를 미친듯이 호출한다고 할 때 그 내부에 있는 s 객체의 초기화를 단 한번만 하도록 만드는 것이다. VS2015는 다음과 같은 형태로 코드를 만든다. 여기서 우리에게 문제가 된 부분은 최초 락 없이 생성됐는지를 체크하는 조건문 if(g_single_once &gt; _Init_thread_epoch)에 있었다. g_single_once는 단순히 0으로 초기화 되지만 _Init_thread_epoch은 0x80000000으로 초기화 된다. 문제는 이게 TLS 변수라는 점에 있다. VS2015는 이를 위해서 __declspec(thread)를 사용해서 암시적 TLS로 처리했는데 이를 정상적으로 지원하지 않아서 _Init_thread_epoch이 0으로 함께 초기화됐고 그러면서 생성도 되지 않은 객체가 생성됐다고 판단이 이루어진 것이었다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; g_single_once &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Uninitialized&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; SIngle&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;Single&lt;/span&gt;&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Instance&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;g_single_once &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; _Init_thread_epoch&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;_Init_thread_header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;g_single_once&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;g_single_once &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; BeingInitialized&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;token comment&quot;&gt;// 생성자 호출&lt;/span&gt;
			&lt;span class=&quot;token class-name&quot;&gt;Single&lt;/span&gt;&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Single&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

			&lt;span class=&quot;token comment&quot;&gt;// 종료 시에 소멸자 호출되도록 등록&lt;/span&gt;
			&lt;span class=&quot;token function&quot;&gt;atexit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Single&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;Single&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;token function&quot;&gt;_Init_thread_footer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;g_single_once&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;동기화 구현의 핵심은 _Init_thread_header와 _Init_thread_footer에 있다. 해당 함수의 구현은 다음과 같다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Control access to the initialization expression.  Only one thread may leave&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// this function before the variable has completed initialization, this thread&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// will perform initialization.  All other threads are blocked until the&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// initialization completes or fails due to an exception.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;C&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; __cdecl &lt;span class=&quot;token function&quot;&gt;_Init_thread_header&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pOnce&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;_Init_thread_lock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pOnce &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; Uninitialized&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pOnce &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; BeingInitialized&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pOnce &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; BeingInitialized&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// Timeout can be replaced with an infinite wait when XP support is&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// removed or the XP-based condition variable is sophisticated enough&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// to guarantee all waiting threads will be woken when the variable is&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// signalled.&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;_Init_thread_wait&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;XpTimeout&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pOnce &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; Uninitialized&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pOnce &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; BeingInitialized&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;_Init_thread_unlock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        _Init_thread_epoch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; _Init_global_epoch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;_Init_thread_unlock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Called by the thread that completes initialization of a variable.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// Increment the global and per thread counters, mark the variable as&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// initialized, and release waiting threads.&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;C&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; __cdecl &lt;span class=&quot;token function&quot;&gt;_Init_thread_footer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pOnce&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;_Init_thread_lock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;_Init_global_epoch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pOnce &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; _Init_global_epoch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    _Init_thread_epoch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; _Init_global_epoch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;_Init_thread_unlock&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;_Init_thread_notify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 모든 구현을 살펴보고 나면 의문이 든다. 왜냐하면 암시적 TLS를 사용하는 엄청난 결정을 한 반면 그 암시적 TLS가 가져다주는 이점은 Single::Instance 구현의 첫번째 조건문 if(g_single_once &gt; _Init_thread_epoch) 앞에 메모리 장벽이 없어도 된다는 것 밖에는 없어 보이기 때문이다. Interlocked 함수 하나 안 쓰겠다고 암시적 TLS 지원이 정상적으로 안 되는 XP 시스템을 포기한 셈이다. 실제로 이 구현을 사용한 DLL을 XP 시스템에서 LoadLibrary 등으로 동적 로딩하면 정상적으로 동작하지 않는다.&lt;/p&gt;
&lt;p&gt;그러니 더 고민이 되었다. 이 신박한 구현에는 내가 생각하지 않은 다른 이유가 있을거야. Interlocked 함수 하나 안 쓰겠다고 이렇게 만든 것은 아닐거야. 뭔가 다른 이유가 있을거야 라면서 엄청 고민을 해봤다. 심지어 실행 카운트를 추적하는 기법 같아 보여서 이게 혹시 ABA 문제 등과 연관된 것은 아닐까 싶어 이것 저것 예외 케이스를 많이 생각해 보았지만 그 또한 아닌 것 같았다. thread local storage, lock optimizing, double checked 등과 같은 키워드로 겁나 검색했지만 걸리는 건 아무것도 없었다.&lt;/p&gt;
&lt;p&gt;그렇게 이틀을 고민하며 보낸 끝에 어이없는 곳에서 이 구현의 원본을 찾게 되었다. Mike Burrows라는 구글에 계신 형님께서 A Fast Implementation of Synchronized Initialization 이름으로 전파한 복음이었다. 그 상세한 알고리즘 분석 내용에는 내가 찾던 정답 또한 들어 있었다. &quot;The technique is useful only if such an access is faster than a memory barrier.&quot; 이 테크닉은 TLS 접근이 메모리 배리어보다 빠를 때에만 의미가 있다는 말.&lt;/p&gt;
&lt;p&gt;lock cmpxchg 보다는 mov 몇 개 더 있는게 더 빠르겠지? 아마도? 하지만 여전히 남는 의문은 그 차이가 XP를 포기할만큼 그리 컸을까 싶은 생각…​ 지원 중단된 과거 보다는 미래를 더 중요하게 생각해서 내린 결정인지도 모르겠다. 어쨌든 XP에서 돌릴 수 있도록 해당 기능을 끌 수 있는 플래그는 존재하니 말이다.&lt;/p&gt;
&lt;h3&gt;참고한 것들&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;There is a way to access thread-specific data or thread-local storage. The technique is useful only if such an access is faster than a memory barrier. For the disassembly above, the compiler used its ability to access thread-local storage using variables declared with __thread, so the thread-local access is a normal &quot;mov&quot; instruction with a different segment register.&lt;/p&gt;
&lt;p&gt;-- &lt;a href=&quot;http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm#Appendix&quot;&gt;http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm#Appendix&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a known limitation with Windows XP and thread-safe local static initialization. The thread-safe local initialization code relies on thread-local storage for efficient lock-free checking in many cases. Unfortunately, XP contains bugs that prevent loading DLLs with thread-local storage variables from working correctly when the DLL is loaded through LoadLibrary. Since XP is out of its service lifetime these bugs are unlikely to be fixed.&lt;/p&gt;
&lt;p&gt;As a workaround, you can compile the program with /Zc:threadSafeInit-, which disables the thread-safe implementation. The old implementation does not rely on thread-local storage and will work on XP even in the presence of LoadLibrary, but is, of course, not thread-safe. If the function containing the local to initialize may be called from multiple threads you will need to handle appropriate synchronization manually when using /Zc:threadSafeInit-.&lt;/p&gt;
&lt;p&gt;-- &lt;a href=&quot;https://connect.microsoft.com/VisualStudio/Feedback/Details/1941836&quot;&gt;https://connect.microsoft.com/VisualStudio/Feedback/Details/1941836&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Starting in C++11, a static local variable initialization is guaranteed to be thread-safe. This feature is sometimes called magic statics. However, in a multithreaded application all subsequent assignments must be synchronized. The thread-safe statics feature can be disabled by using the /Zc:threadSafeInit- flag to avoid taking a dependency on the CRT.&lt;/p&gt;
&lt;p&gt;-- &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/y5f6w579.aspx&quot;&gt;https://msdn.microsoft.com/en-us/library/y5f6w579.aspx&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[[시스템] WSL 환경에서 asciidoctor-pdf 설치하기]]></title><description><![CDATA[윈도우 bash 환경에서 asciidoctor-pdf를 설치해서 asciidoc 파일을 pdf로 변환하는 방법을 알아보자. 우선 설치를 위해서는 cmd에서 bash…]]></description><link>https://jiniya.net/ng/2016/11/install-asciidoctor-pdf-on-wsl/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/11/install-asciidoctor-pdf-on-wsl/</guid><pubDate>Tue, 01 Nov 2016 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;윈도우 bash 환경에서 asciidoctor-pdf를 설치해서 asciidoc 파일을 pdf로 변환하는 방법을 알아보자. 우선 설치를 위해서는 cmd에서 bash 치고 들어가서 아래 명령어를 순서대로 입력해 주면 된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; software-properties-common
$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; apt-add-repository ppa:brightbox/ruby-ng
$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; update

$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; ruby2.1
$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; ruby2.1-dev

$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; gem &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; asciidoctor
$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; gem &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; coderay pygments.rb
$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; gem &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--pre&lt;/span&gt; asciidoctor-pdf
$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; gem &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; asciidoctor-pdf-cjk-kai_gen_gothic
$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; asciidoctor-pdf-cjk-kai_gen_gothic-install&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;설치가 모두 성공했다면 아래 명령어를 통해서 adoc 파일을 pdf로 변환할 수 있다. 아래 명령을 실행하면 example.adoc을 변환해서 example.pdf 파일이 생성된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ asciidoctor-pdf &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; asciidoctor-pdf-cjk-kai_gen_gothic &lt;span class=&quot;token parameter variable&quot;&gt;-a&lt;/span&gt; pdf-style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;KaiGenGothicKR example.adoc&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;작업에 참고한 고마운 페이지들…​&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://stackoverflow.com/questions/39011459/how-to-change-versions-of-ruby-1-9-to-ruby-2-0-in-the-new-windows-10-bash-shell&quot;&gt;http://stackoverflow.com/questions/39011459/how-to-change-versions-of-ruby-1-9-to-ruby-2-0-in-the-new-windows-10-bash-shell&lt;/a&gt;
&lt;a href=&quot;http://java.ihoney.pe.kr/430&quot;&gt;http://java.ihoney.pe.kr/430&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;그냥 윈도우 환경에서도 설치가 잘 되는데 마지막 폰트 설치 작업에서 SSL 에러가 나서 폰트를 다운로드 받지를 못했다. 귀찮아서 그냥 bash에다 설치하는걸로…​&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] MSVC 왜 wprintf는 되고 printf는 되지 않는 것일까?]]></title><description><![CDATA[아래와 같은 간단한 코드를 살펴보자. 1252 코드페이지로 '안녕’을 변환해서 출력하는 예제다. 출력을 해보면 printf는 begin까지만 출력되고 wprintf는 end까지 모두 출력된다. 이를두고 printf…]]></description><link>https://jiniya.net/ng/2016/10/msvc-wprintf-printf/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/10/msvc-wprintf-printf/</guid><pubDate>Thu, 13 Oct 2016 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;아래와 같은 간단한 코드를 살펴보자. 1252 코드페이지로 &apos;안녕’을 변환해서 출력하는 예제다. 출력을 해보면 printf는 begin까지만 출력되고 wprintf는 end까지 모두 출력된다. 이를두고 printf는 안시 함수라 유니코드 문자열을 정상적으로 출력하지 못하고, wprintf는 유니코드 함수라 정상적으로 출력한다면 오산이다. 왜냐하면 둘다 출력은 틀렸기 때문이다. wprintf가 출력한게 한글 &quot;안녕&quot;이 아니라는 의미다. 한글은 우리가 잘 아는 문자라 이런 오류를 쉽게 인지할 수 있지만 모르는 문자 속에 섞여 있으면 자칫 wprintf는 제대로 출력한다는 오해를 할수도 있다. 그렇다면 왜 printf는 실패하고, wprintf는 끝까지 출력할까?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// windows-1252	ANSI Latin 1; Western European (Windows)&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// 한글 변환이 불가능한 코드 페이지&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;setlocale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LC_ALL&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.1252&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;wchar_t&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;msg &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;안녕&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;printf begin %ls end&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;wprintf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;wprintf begin %ls end&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이유는 간단하다. 그렇게 만들었기 때문이다. 먼저 printf부터 살펴보자. 결국 아래 코드로 들어간다. _WCTOMB_S가 변환에 실패하면 루프를 제어하는 변수 charsout이 -1로 설정되고 루프가 종료되어 더 이상 출력이 진행되지 않는다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;_output_l&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;format&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;\0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; charsout &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;count&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                        e &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_WCTOMB_S&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;retval&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L_buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_countof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L_buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; retval &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                            charsout &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                            &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                        &lt;span class=&quot;token function&quot;&gt;WRITE_STRING&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L_buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; retval&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;charsout&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;반면 wprintf는 아래와 같이 전개되고, 변환에 실패하면 ?를 출력하고 성공인 척 하도록 되어 있다. 즉, wprintf라고 정상 출력을 해내는 것이 아니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;_output_l&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;format&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;\0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; charsout &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;WRITE_STRING&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;wz&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; textlen&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;charsout&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;LOCAL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;write_string&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    _TCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;string&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; len&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    FILE &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;f&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pnumwritten
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;f&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;_flag &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; _IOSTRG&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; f&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;_base &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pnumwritten&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; len&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;len&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;write_char&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;string&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; f&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pnumwritten&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pnumwritten &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;errno &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; EILSEQ&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 변환 실패로 빠지면 ?를 출력하고 성공인척 한다.&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;write_char&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;?&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; f&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pnumwritten&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위 코드에는 변환하는 부분이 나와 있지 않은데 write_char 함수를 따라가보면 결국 _fputwc_noblock으로 이어지고 콘솔인 stdout은 텍스트 모드라 printf와 동일하게 wctomb_s로 변환을 시도한다. 다만 여기서 실패해도 위쪽에서 살펴본 if문에 의해서 ?를 출력하고 계속 출력을 이어가도록 만들어둔 것이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;wint_t __cdecl &lt;span class=&quot;token function&quot;&gt;_fputwc_nolock&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;wchar_t&lt;/span&gt; ch&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        FILE &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;str
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;


        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;str&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;_flag &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; _IOSTRG&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_textmode_safe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_fileno&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;str&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; __IOINFO_TM_UTF16LE
                    &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_textmode_safe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_fileno&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;str&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; __IOINFO_TM_UTF8&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token comment&quot;&gt;/* binary (Unicode) mode */&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;str&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;_cnt &lt;span class=&quot;token operator&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;wchar_t&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wint_t&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0xffff&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;wchar_t&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;str&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;_ptr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;wchar_t&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;ch&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wint_t&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_flswbuf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ch&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; str&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_osfile_safe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_fileno&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;str&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; FTEXT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;token comment&quot;&gt;// stdout은 이쪽으로 빠진다.&lt;/span&gt;
				&lt;span class=&quot;token comment&quot;&gt;// 결국 wctomb_s 함수로 printf와 동일하게 변환을 시도한다.&lt;/span&gt;

                &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; mbc&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;MB_LEN_MAX&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

                &lt;span class=&quot;token comment&quot;&gt;/* text (multi-byte) mode */&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wctomb_s&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mbc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MB_LEN_MAX&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ch&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;token comment&quot;&gt;/*
                         * Conversion failed; errno is set by wctomb_s;
                         * we return WEOF to indicate failure.
                         */&lt;/span&gt;
                        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; WEOF&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;간혹 깨진 문자열을 보고 UTF-16으로 바로 출력됐다는 소리를 하는 황당한 경우도 있다. UTF-16으로 바로 출력하고 싶다면 printf와 같은 텍스트 계열 함수가 아닌 fwrite 같은 바이너리 계통의 함수를 사용해야 한다. 아래와 같이 출력하면 UTF-16으로 출력된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;fwrite&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wcslen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(사족) 가끔 느끼는 거지만 자기가 지금 짜고 있는 코드가 정확하게 무슨 일을 하고 있는지 알고 있는 프로그래머가 생각보다 드문 것 같다. 토이 프로그램만 만들게 아니라면 자기가 짠 코드나 라이브러리가 정확하게 무슨 일을 하는지 알고 있는 것은 무척 중요하다. 컴퓨터는 복잡하고 코드는 추상적이기 때문에 프로그래머는 공부를 열심히 해야 한다. 내가 생각하는 프로그래머라는 업의 본질은 그런 것 같다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 마이크로소프트는 왜 setlocale에서 UTF-8을 지원하지 않을까?]]></title><description><![CDATA[지난 글에서 우리는 setlocale에서 UTF-7이나 UTF-8을 지정할 경우 실패한다는 것을 알게 되었다. 하지만 여전히 의문은 남는다. 왜 MS는 setlocale에서 흔해빠진 UTF-…]]></description><link>https://jiniya.net/ng/2016/10/msvc-setlocale-utf8/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/10/msvc-setlocale-utf8/</guid><pubDate>Thu, 13 Oct 2016 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;/ng/2016/10/printf-and-unicode/&quot;&gt;지난 글에서&lt;/a&gt; 우리는 setlocale에서 UTF-7이나 UTF-8을 지정할 경우 실패한다는 것을 알게 되었다. 하지만 여전히 의문은 남는다. 왜 MS는 setlocale에서 흔해빠진 UTF-8 따위를 지원하지 않을까? 도대체 무엇이 우리를 가로 막는 것일까? 안 될 이유가 없는게 안되면 한번쯤은 내부가 궁금해지게 마련이다. 그래서 이런 간단한 코드를 디버깅 해보기로 했다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%p\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setlocale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LC_CTYPE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Korean_Korea.65001&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;디버깅 결과 총 세 지점에 우리를 가로막는 허들이 존재한다는 사실을 알게 되었다. 첫번째는 아래 지점이다. 대놓고 CP_UTF7과 CP_UTF8은 안 된다는 소리다. 재미난 사실은 if 문에 이 코드가 들어간 것이 Visual Studio의 특정 버전 부터라는 점이다. Visual C++ 6.0에는 CP_UTF7과 CP_UTF8을 검사하는 코드가 없다. 단지 IsValidCodePage로만 체크한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;BOOL __cdecl &lt;span class=&quot;token function&quot;&gt;__get_qualified_locale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; LPLC_STRINGS lpInStr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPLC_ID lpOutId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                                    LPLC_STRINGS lpOutStr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;//  verify codepage validity&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;iCodePage &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; iCodePage &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; CP_UTF7 &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; iCodePage &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; CP_UTF8 &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;IsValidCodePage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WORD&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;iCodePage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;다음 허들은 아래 지점이다. 현재 코드페이지로 변환 되는 최대 글자 개수가 MB_LEN_MAX보다 크면 안 된다는 소리다. MB_LEN_MAX의 경우 Visual Studio 2015는 5로 정의되어 있다. 따라서 이 코드는 넘어간다. 반면에 Visual C++ 6.0에서는 MB_LEN_MAX가 2고 CP_UTF8은 이 구문을 넘지 못하고 실패한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; __cdecl &lt;span class=&quot;token function&quot;&gt;__init_ctype&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        pthreadlocinfo ploci
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lpCPInfo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;MaxCharSize &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; MB_LEN_MAX&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;goto&lt;/span&gt; error_cleanup&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;마지막 허들은 아래 지점이다. MultiByteToWideChar 함수를 통해서 버퍼가 얼마나 커야 하는지 구하는 부분이다. code_page에 CP_UTF8이 들어 있으면 플래그로 0이나 MB_ERR_INVALID_CHARS가 전달되어야 하지만 여기에서는 MB_PRECOMPOSED가 합쳐서 전달된다. MSDN 페이지에 나와 있는 것처럼 ERROR_INVALID_FLAGS로 실패한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; BOOL __cdecl &lt;span class=&quot;token function&quot;&gt;__crtGetStringTypeA_stat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        _locale_t plocinfo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        DWORD    dwInfoType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        LPCSTR   lpSrcStr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;      cchSrc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        LPWORD   lpCharType&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;      code_page&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;      lcid&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        BOOL     bError
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;/* find out how big a buffer we need */&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buff_size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MultiByteToWideChar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; code_page&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                                                    bError &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;
                                                        MB_PRECOMPOSED &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;
                                                        MB_ERR_INVALID_CHARS
                                                        &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; MB_PRECOMPOSED&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                                                    lpSrcStr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                                                    cchSrc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                                                    &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                                                    &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;여기까지 따라오면 대충 뭔가 감이 잡힌다. 마지막 MSDN의 주석에 있던 코드페이지를 넘기면 setlocale은 죄다 실패한다. 그리고 그 코드 페이지가 가지고 있는 대체적인 특징은 한 글자가 2바이트가 넘는 3바이트, 4바이트 등으로 변환되는 코드페이지라는 점이다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For the code pages listed below, dwFlags must be set to 0. Otherwise, the function fails with ERROR_INVALID_FLAGS.&lt;br&gt;
&lt;br&gt;
50220&lt;br&gt;
50221&lt;br&gt;
50222&lt;br&gt;
50225&lt;br&gt;
50227&lt;br&gt;
50229&lt;br&gt;
57002 through 57011&lt;br&gt;
65000 (UTF-7)&lt;br&gt;
42 (Symbol)&lt;br&gt;
&lt;br&gt;
Note For UTF-8 or code page 54936 (GB18030, starting with Windows Vista), dwFlags must be set to either 0 or MB_ERR_INVALID_CHARS. Otherwise, the function fails with ERROR_INVALID_FLAGS.&lt;br&gt;
&lt;br&gt;
— MultiBytesToWideChar MSDN&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;다시 setlocale의 MSDN 페이지를 살펴보자. UTF-7과 UTF-8을 넣으면 실패한다는 앞 문장에 의미심장한 설명이 있다. 한 글자당 두 바이트를 넘게 사용하는 코드 페이지는 예외라는 설명이다. 예외~ 즉, UTF-8이 안 되는 것이 아니라 한 글자에 두 바이트를 넘게 쓰는 코드페이지는 죄다 setlocale로 지정할 수 없고, wcstombs나 mbstowcs 함수로 변환할 수 없다는 것을 의미한다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The set of available locale names, languages, country/region codes, and code pages includes all those supported by the Windows NLS API except code pages that require more than two bytes per character, such as UTF-7 and UTF-8.&lt;br&gt;
&lt;br&gt;
— setlocale MSDN&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;그렇다면 MS는 왜 한 글자당 두 바이트 이상을 사용하는 코드페이지는 예외 처리를 했을까? 이 페이지에 약간의 힌트가 나와 있다. 수많은 레거시 코드가 멀티바이트에서 한 글자에 사용할 수 있는 저장 공간이 최대 두 바이트라고 가정하고 작성했기 때문이란다. 말 그대로 레거시 코드와의 호환성을 위해서 MS는 setlocale로 UTF-8을 지정할 수 없도록 만들었다. 미래 세대의 불편함 따위보다는 과거 세대와의 호환성 유지가 더 중요했기 때문이리라…​&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] printf와 유니코드 출력]]></title><description><![CDATA[이 코드는 유니코드 문자열 "안녕하세요. 끝."을 출력한다. 단순한 이 출력 속에도 복잡한 변환이 숨겨져 있다. printf는 내부적으로 유니코드 문자열을 멀티바이트 문자열로 변환을 시도한다. 이 변환에는 wcstombs…]]></description><link>https://jiniya.net/ng/2016/10/printf-and-unicode/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/10/printf-and-unicode/</guid><pubDate>Wed, 05 Oct 2016 12:00:01 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;wchar_t&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;안녕하세요.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%ls 끝.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 코드는 유니코드 문자열 &quot;안녕하세요. 끝.&quot;을 출력한다. 단순한 이 출력 속에도 복잡한 변환이 숨겨져 있다. printf는 내부적으로 유니코드 문자열을 멀티바이트 문자열로 변환을 시도한다. 이 변환에는 wcstombs와 같은 계열의 함수들이 사용된다. 이 함수는 현재 설정된 로케일을 참조한다. 해당 로케일은 setlocale 등으로 지정할 수 있다. 해당 로케일 정보에 포함된 코드 페이지로 변환한다. 특정 유니코드 문자가 해당 코드페이지로 적절하게 변환이 되지 않을 수도 있다. 그런 일이 발생하면 printf 함수는 실패하고 &quot;안녕하세요&quot; 다음에 있는 &quot;끝&quot;은 출력되지 않는다.&lt;/p&gt;
&lt;p&gt;따라서 printf로 유니코드 문자열을 출력할 때에는 로케일이 굉장히 중요하다. 해당 로케일은 앞서도 살펴보았듯이 setlocale로 지정할 수 있다. 일반적으로 UTF-8로 변환해서 출력하기 위해서는 다음과 같이 사용한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;setlocale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;en_US.UTF-8&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;wchar_t&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;안녕하세요.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%ls 끝.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;하지만 안타깝게도 Visual Studio를 사용한다면 위 코드를 통해서 UTF-8 출력을 사용할 수 없다. setlocale MSDN 페이지를 참고하면 다양한 형태로 로케일을 지정할 수 있는 것을 볼 수 있다. 그리고 en_US.UTF-8은 해당 페이지에서 언급하는 규칙에도 부합하는 것으로 보여진다. 혹시나 하는 마음으로 UTF-8에 해당하는 코드페이지인 65001을 사용해서 en_US.65001을 전달해 보아도 setlocale은 실패한다. 그리고 MSDN 페이지를 좀 더 꼼꼼하게 읽어보면 왜 그런지가 나와 있다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you provide a code page value of UTF-7 or UTF-8, setlocale will fail, returning NULL.&lt;br&gt;
&lt;br&gt;
— setlocale MSDN&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Visual C++을 사용해서는 setlocale을 통해서 UTF-8을 코드페이지로 지정할 방법은 없는 것으로 추정된다. 이뭐병?&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] Visual Studio 2015에서 stdio 라이브러리 오류 해결 방법]]></title><description><![CDATA[Visual Studio 2015를 사용해서 오픈 소스를 빌드해보면 종종 링크 단계에서 vsnprintf를 찾을 수 없다거나 황당하게 printf를 찾을 수 없다는 링크 오류가 발생한다. 해당 문제는 해당 함수들이 Visual Stduio 201…]]></description><link>https://jiniya.net/ng/2016/08/stdio-link-error-in-msvc-2015/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/08/stdio-link-error-in-msvc-2015/</guid><pubDate>Sat, 06 Aug 2016 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;Visual Studio 2015를 사용해서 오픈 소스를 빌드해보면 종종 링크 단계에서 vsnprintf를 찾을 수 없다거나 황당하게 printf를 찾을 수 없다는 링크 오류가 발생한다. 해당 문제는 해당 함수들이 Visual Stduio 2015에서 인라인 구현으로 변경되었기 때문이다. &amp;#x3C;stdio.h&gt;나 &amp;#x3C;conio.h&gt;를 포함하고 관련 함수를 사용하면 상관이 없는데 해당 헤더를 인클루드 하지 않고 컴파일한 다음 링크를 하면 심벌을 찾을 수 없다는 오류가 발생한다.&lt;/p&gt;
&lt;p&gt;해결 방법은 두 가지인데 1) 파일을 일일이 뒤져서 헤더 파일을 추가해주는 방법 2) legacy_stdio_definitions.lib을 링크 단계에서 포함시켜주는 방법이 있다. 당연지사 그 많은 소스 파일을 수정할 수 없기 때문에 legacy_stdio_definitions.lib을 추가해 주는 것이 편리하다.&lt;/p&gt;
&lt;p&gt;이것 외에도 Visual Studio 2015에서 호환성을 저해하는 변경 사항이 궁금하다면 아래 페이지를 참고하도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://msdn.microsoft.com/en-us/library/bb531344.aspx&quot;&gt;https://msdn.microsoft.com/en-us/library/bb531344.aspx&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] Visual Studio 2015 명령줄에서 XP 타겟 사용하기]]></title><description><![CDATA[Visual Studio 2012부터 XP 타겟을 사용하기 위해서는 툴체인을 XP가 들어간 것을 선택해야 한다. Visual Studio 2015는 v140_xp를 선택하면 된다. IDE…]]></description><link>https://jiniya.net/ng/2016/08/using-xp-target-in-msvc-2015/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/08/using-xp-target-in-msvc-2015/</guid><pubDate>Fri, 05 Aug 2016 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;Visual Studio 2012부터 XP 타겟을 사용하기 위해서는 툴체인을 XP가 들어간 것을 선택해야 한다. Visual Studio 2015는 v140_xp를 선택하면 된다. IDE에서는 그렇게 사용하면 되는데 명령 프롬프트에서 직접 빌드 해야 할때에는 어떻게 해야 할까? 컴파일러에 주는 뭔가 옵션이 있는 것일까, 아니면 CRT 라이브러리를 다른걸 선택하면 되는건가, 라는 여러가지 의문이 생긴다. 당황하지 않게 어떡하는지 살펴보도록 하자.&lt;/p&gt;
&lt;p&gt;우선 Visual Studio 2012부터 생긴 XP 타겟이 해주는 역할은 크게 두 가지다. 1) XP 호환되는 플랫폼 SDK를 사용해서 컴파일한다. 7.1A 버전이 마지막 호환되는 SDK다. 2) XP 호환되는 플랫폼 SDK를 사용해서 링크한다. 마찬가지로 7.1A에 포함된 라이브러리를 말한다. 3) 링크 옵션으로 실행 가능한 운영체체를 XP 버전으로 지정한다. 이걸 하지 않으면 6.0으로 선택되서 Vista부터 실행 가능한 이미지가 생성된다.&lt;/p&gt;
&lt;p&gt;XP 타겟이 하는 일을 알았으니 결론은 간단하다. 1은 cl에다 옵션을 주면 되는 것이고, 2, 3은 link에다 옵션을 추가하면 된다. 이미 만들어진 빌드 스크립트를 사용한다면 빌드 옵션을 조정하는 것도 일이기 때문에 환경 변수를 이용하면 편리하다.&lt;/p&gt;
&lt;p&gt;cl에 추가되는 옵션을 조정하기 위해서는 아래 환경 변수를 추가하면 된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bat&quot;&gt;&lt;pre class=&quot;language-bat&quot;&gt;&lt;code class=&quot;language-bat&quot;&gt;set INCLUDE=%ProgramFiles(x86)%\Microsoft SDKs\Windows\7.1A\Include;%INCLUDE%
set PATH=%ProgramFiles(x86)%\Microsoft SDKs\Windows\7.1A\Bin;%PATH%&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;link에 사용되는 라이브러리를 변경하기 위해서는 아래 환경 변수를 추가하면 된다. 32비트 빌드라면 아래 환경 변수를 추가하면 된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bat&quot;&gt;&lt;pre class=&quot;language-bat&quot;&gt;&lt;code class=&quot;language-bat&quot;&gt;set LIB=%ProgramFiles(x86)%\Microsoft SDKs\Windows\7.1A\Lib;%LIB%&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;64비트라면 아래 환경 변수를 추가한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bat&quot;&gt;&lt;pre class=&quot;language-bat&quot;&gt;&lt;code class=&quot;language-bat&quot;&gt;set LIB=%ProgramFiles(x86)%\Microsoft SDKs\Windows\7.1A\Lib\x64;%LIB%&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;32비트 콘솔 프로그램을 빌드하면 아래와 같이 환경 변수를 추가한다. 윈도우 프로그램이라면 subsystem을 windows로 지정하면 된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bat&quot;&gt;&lt;pre class=&quot;language-bat&quot;&gt;&lt;code class=&quot;language-bat&quot;&gt;set LINK=/SUBSYSTEM:CONSOLE,5.01 %LINK%&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;64비트 콘솔 프로그램을 빌드하면 아래와 같이 추가하면 된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bat&quot;&gt;&lt;pre class=&quot;language-bat&quot;&gt;&lt;code class=&quot;language-bat&quot;&gt;set LINK=/SUBSYSTEM:CONSOLE,5.02 %LINK%&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그런데 여기까지 하고 나면 함정이 하나 있다. Visual Studio 2015는 과거 버전이 그랬던것처럼 빌드 가능한 명령 프롬프트를 시작 메뉴에 등록하지 않는다는 점이다. 어디서 빌드를 시작해야 난감해진다. 당황할 필요 없다. 배치 파일은 동일한 경로에 있다. 아래와 같이 실행하면 각각 32비트 64비트 빌드 환경으로 진입할 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bat&quot;&gt;&lt;pre class=&quot;language-bat&quot;&gt;&lt;code class=&quot;language-bat&quot;&gt;C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat x86
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat amd64&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;전체적인 메커니즘에 대해서 더 궁금한 분은 &lt;a href=&quot;https://blogs.msdn.microsoft.com/vcblog/2012/10/08/windows-xp-targeting-with-c-in-visual-studio-2012/&quot;&gt;여기 글을&lt;/a&gt; 참고하도록 하자. 해당 글을 보면 CL 옵션으로 &lt;em&gt;USING_V110_SDK71&lt;/em&gt; 매크로 정의를 추가하는 것을 볼 수 있는데 그건 잘못된 SDK가 빌드되는 것을 막기 위한 용도로 현재는 사용되지 않는다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[시스템] Linux 서브 시스템, 윈도우 대격변의 서막]]></title><description><![CDATA[윈도우를 배울 때 누구나 그러하듯이 서브시스템이란 것이 존재하고, OS/2, POSIX, WIN32가 있다고 배운다. 하지만 그 존재를 알아채기란 쉽지 않다. 그저 그런가 보다 한다. 왜냐하면 그나마 명맥을 유지하는 거라곤 WIN3…]]></description><link>https://jiniya.net/ng/2016/08/windows-subsystem-for-linux/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/08/windows-subsystem-for-linux/</guid><pubDate>Fri, 05 Aug 2016 11:00:01 GMT</pubDate><content:encoded>&lt;p&gt;윈도우를 배울 때 누구나 그러하듯이 서브시스템이란 것이 존재하고, OS/2, POSIX, WIN32가 있다고 배운다. 하지만 그 존재를 알아채기란 쉽지 않다. 그저 그런가 보다 한다. 왜냐하면 그나마 명맥을 유지하는 거라곤 WIN32밖에 없기 때문이다. 그러다 윈도우의 역사를 좀 알게되고 데이비드 커틀러란 걸출한 프로그래머를 인식하게 되면 개발 초기에는 WIN32보다 OS/2를 지원하는 것이 무척이나 중요했다는 사실을 그나마 알게 된다. 그랬거나 말거나 OS/2는 역사의 뒤안길로 사라졌고 남은건 WIN32 밖에 없다. Windows NT가 출시되고 거의 20년간 그랬다.&lt;/p&gt;
&lt;p&gt;그랬던 거의 존재조차 유명무실했던 서브시스템이란 존재가 20년 만에 다시 재조명되고 있다. WIN32 밖에 보지 못해 있는거야 없는거야 라고 느꼈던 많은 프로그래머들도 이제는 그것이 단지 역사가 아닌 실제 존재한다는 사실을 온몸으로 느낄 수 있게 됐다. 바로 8/2일자로 진행된 윈도우 10 1주년 업데이트로 말이다. 20년 만에 윈도우가 리눅스를 품었다. 바로 리눅스 서브시스템이 생긴 것이다. Cygwin 정도를 상상했다면 잊어도 괜찮다. ELF 바이너리가 네이티브로 돌아가는 신세계가 펼쳐지니 말이다.&lt;/p&gt;
&lt;p&gt;인사이더 빌드 때부터 꾸준히 말이 많았지만 나이가 들어서 그런지 그래도 어느 정도 완성된 다음에 구경하고 싶은 마음에 정식 출시 하기를 기다렸다. 하지만 정식 출시에서도 베타 딱지는 아직 떼지못한 것으로 보여진다.&lt;/p&gt;
&lt;p&gt;윈도우 10 1주년 업데이트는 &lt;a href=&quot;https://support.microsoft.com/ko-kr/help/12387/windows-10-update-history?ocid=update_setting_client&quot;&gt;여기서&lt;/a&gt; 다운로드 받아서 설치하면 된다. bash쉘을 활성화하는 법은 &lt;a href=&quot;http://www.sysnet.pe.kr/2/0/11009&quot;&gt;정성태 님의 글을&lt;/a&gt; 참고 하자. 그저 여기서는 맛배기로 대격변의 서막이 어떻게 진행되고 있는지만 살펴보기로 하자.&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./wsl1.png&apos; data-alt=&apos;Figure 1. 프로세스 트리&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/b6674fcfe6021b37b0eee1a5f512a54f/6e34c/wsl1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAB2HAAAdhwGP5fFlAAADMklEQVR42iXK6W/adhzHcf+ZmzblwVRNmqY+2ONpWjK6SttU7aiqPpq6lqWQcYS0gRwc4QoQwhGCAWN8/2xjbP98cduG36xNeumr90f6YrQkqDpUNF2ezVRo6IZp2LbpONCyN76/3e9d3/cQ+p8bzN1+7Xm+53HLFcbwhALAFAg8w0iCMDfNpW1buja3LBtCy1msNAW5nu+6e89bLxaOYZoQbmybMiyM0jUKOpSmsxByhilYNqND3rIYCFnDGMsyOZ0GgG3zhjkQhOBhttmarjuCBtbd+9eqFSfHOV1poV3FsQtQ7yB057uBc4FNMdQpS6bYSUbkExTxEXCXM+nG0HqOg+WAfz5ehG+pN1Uq3tdPh/ZJVz0jFsFN4tb7phhu8G9vmTflSbghhOvcu1vmryp1XBeaUwvLz3Znk3WkIyYI85zfnlGLU9LOaSg7QxeSH+nK//SV913puC1Ge0q4Jf4daIsnD2pTsTFrV5PnV7iUttz8FtW11ZVsp1eo4uxL832R0ZJ9LjIE0YEQFYwU3F7qmwt1nbHdNO3wmO63Z5vyA8ji4IPqlsVFgYZXDmqaqAF3NRyctchYj0s2iehI/jBd55X1DdzVF6hGOQCrLPwkrSUm0qW6LK3QNVylZaO6RcXlruC48QkIRIdsZEDHxiAyYE8IIUaKSVq5100s27cjBZBsWDkCZUfoordN1s10z7voeeed9Ul5Fi1Oj/MgnOWjRfk4L/5HiJfVO2BiUB4Q91UdL+/kAdLGK66rj2pLrhP0FjxK3RvuPis/3IBOXh1UhXaObV47VBuJ+JCnMYMJdcrf0KVPtMcvkfTUwp+o3S98/iniv97SXwn1g1HhU7ry+aT8GWgcBMHXD4z+E3980KOymK392Sp+yz6GlsofaPnakV5A7mfkvEbzV67+OxiEJp1DYRCiH47A8Bnb+0EaPbfAC7R++cg3MGMT7pI/4tyh6f66Qq9k+xfR/CmIOXpper8R4lFv8h0BjnD2+4kcCmIsHZLKM235HFeaWJ64KkxOS3yqyCZKXKJAJ7JkrMjGC0ysIqRqYqbCZ6pCuipkbkGmLmda2uWdenk/+1iWyX8BIQrvEA93fbQAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 1. 프로세스 트리&apos; title=&apos;&apos; src=&apos;/static/b6674fcfe6021b37b0eee1a5f512a54f/efd7b/wsl1.png&apos; srcset=&apos;/static/b6674fcfe6021b37b0eee1a5f512a54f/08678/wsl1.png 190w,
/static/b6674fcfe6021b37b0eee1a5f512a54f/2edd7/wsl1.png 380w,
/static/b6674fcfe6021b37b0eee1a5f512a54f/efd7b/wsl1.png 760w,
/static/b6674fcfe6021b37b0eee1a5f512a54f/dc896/wsl1.png 1140w,
/static/b6674fcfe6021b37b0eee1a5f512a54f/78873/wsl1.png 1520w,
/static/b6674fcfe6021b37b0eee1a5f512a54f/6e34c/wsl1.png 1578w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 1. 프로세스 트리&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;우선 프로세스 트리다. bash.exe가 일종의 게이트를 하는 것으로 보여진다. 윈도우 실행 파일인데 이 녀석을 실행하면 동시에 svchost.exe 밑에 init, bash가 같이 실행된다. 화면은 쉘에서 vi를 실행시켜서 bahs의 자식으로 vim.basic까지 실행된 것을 볼 수 있다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./wsl2.png&apos; data-alt=&apos;Figure 2. 실행된 vim.basic의 기본 정보&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/6513c40c09e0a0277a29cf24e33d94a9/bbbf7/wsl2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 98.94736842105263%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAB2HAAAdhwGP5fFlAAABw0lEQVR42qVS2W7bMBDk/39bgT40SeOoSXVbFEWJFE+ROjqy28Co08BGBxSxWHFml9wheS9Z3zecV207WhvXbVpWPy9hXU/BPC17PG8bduRdjNp7F+JgHeFC5GmapSltGta2RZG3lHLOkTkej33P66p6e309PD/vv9qWd92PJEl/vrWck0GNcuDWuqqqBiEopXVdCykRMMaQYaxjDKLFMAyQE0JghyL6JVzptB2BeUZrd8CGQIR1h5I3lMYYkVpPuA7ecc78JmvvqjxFq1prZJcbgJNKDsY7kL3WZj7hFjLOsI53tNLOEmk03tliSJjBH5XPAb4QcrR7ZVcWRZZlUkpMYpqmcIHpCuf80PfSGKKsReUQIiQxg6bB21GMGoplWeJ6f0k45/Y2QzDeE+X2ykrpeZkpbXAaF4v/QIixR82TC6Q1Oxl1lFLGWjghL3LYwH8ENICCkIB5kiSBl4l2ripL2At66FArqLn1Gtv2ktVfvh3yI4NVHx8ezTQRzBrzOb/h55YybpLKOL/fHPV3k+B7N81lcJM9z+RbANn1Qvs+8n9V/oCsjAneT/csYwyGIkZFso7XvK/uWYcs+/r09L0ofgF+L4MW2uYJaQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 2. 실행된 vim.basic의 기본 정보&apos; title=&apos;&apos; src=&apos;/static/6513c40c09e0a0277a29cf24e33d94a9/efd7b/wsl2.png&apos; srcset=&apos;/static/6513c40c09e0a0277a29cf24e33d94a9/08678/wsl2.png 190w,
/static/6513c40c09e0a0277a29cf24e33d94a9/2edd7/wsl2.png 380w,
/static/6513c40c09e0a0277a29cf24e33d94a9/efd7b/wsl2.png 760w,
/static/6513c40c09e0a0277a29cf24e33d94a9/dc896/wsl2.png 1140w,
/static/6513c40c09e0a0277a29cf24e33d94a9/bbbf7/wsl2.png 1280w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 2. 실행된 vim.basic의 기본 정보&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;실행된 vim.basic 프로세스의 기본 정보를 살펴보자. 기본 정보가 표시되어야 하는 곳에 아무 정보도 표시되지 않는 것을 알 수 있다. 고로 우리는 망했어요 ㅠㅜ~&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./wsl3.png&apos; data-alt=&apos;Figure 3. 실행된 vim.basic의 메모리 정보&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/c0d27cd2de69801d96bc919dcfa02d76/bbbf7/wsl3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 98.94736842105263%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAB2HAAAdhwGP5fFlAAACmElEQVR42oVTiW7bMAzN/39XBnTogCVN4SO+ZNmyJV+S7yt29ux2xXpsIxiFovlI6ok6BEWVSSnynImk6rp5vY/LOtyWaV134zYum327w79g281zMwz9NMuuPyR5TlzX9/1EJGmSBAEVAqlyn5A4josijxhzHcfU9YhFahdsKeLz4iCyjBKSpKlPfaXKJEmAKasKRpqmCM2yDEYQhFVVRXFc1zUqObaNqodcqTRBhrTvumWX2ybzuiz394IA4rmyKBIhwoDKuj6kqtItj+dyut99JhzKLBJcXUpCXnWTagZZ96rpZdOrdqj7qeymephl1fIsP8h+/H7Wz6ZXL3edRI8X0/S55rFnJzwZ3kn34IHxE7bhwni26fnqmx5jQhzaYbBNw7qaaAyEhWGQCg7CsF3X9f5JXpw4ecj5AbzrmnY6n+GKOfd9yjkH8dgue+AHXT6ATcN4enqCK4oj1/XAR7KDv6z8ItM05WX5DoxLAlgI/l8wrkQ1DcAj2n4Bo2GPEME5rvjfYFymrHewbVmarsOVbBMWYCSynTDc+fqVfAJrr2AaBDhz9ne2P1QeAL5cLuM4JYnwyHZmgIdxbHdpmqbrunbTttn2bd/38zwrgOt+wKA+/njcTiuEZVvonDGGY8cxB4V4A1gx1ZCQsTAM0eA4jDth/WBdr9++HYFBjKZplPqIiKLI9TaxLIsQ4m3quZ6Lf6Qeesxsu1W2bet4PIYhQyVd15GcRQy0sV2IT5ALqbFQSvFDCzt4r2zb9sPDg0+plMowDMu6uq6L+i+VHcfZ6C8KEJFmWHKpFFjYXlUFDuq6VKqpazw6GJsizW+FDdK6tn3TqixVUUhMGM0KLmUsZVQUUV7Eu/2HqtdPb5oXV5+eMBg0+AXU4lroD/tZTAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 3. 실행된 vim.basic의 메모리 정보&apos; title=&apos;&apos; src=&apos;/static/c0d27cd2de69801d96bc919dcfa02d76/efd7b/wsl3.png&apos; srcset=&apos;/static/c0d27cd2de69801d96bc919dcfa02d76/08678/wsl3.png 190w,
/static/c0d27cd2de69801d96bc919dcfa02d76/2edd7/wsl3.png 380w,
/static/c0d27cd2de69801d96bc919dcfa02d76/efd7b/wsl3.png 760w,
/static/c0d27cd2de69801d96bc919dcfa02d76/dc896/wsl3.png 1140w,
/static/c0d27cd2de69801d96bc919dcfa02d76/bbbf7/wsl3.png 1280w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 3. 실행된 vim.basic의 메모리 정보&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;메모리 정보를 살펴보자 vim.basic이 0x400000에 매핑되어 있는 것을 볼 수 있다. 어떤 이유에서인지 MS는 역사적으로 0x400000을 좋아하는 것으로 보여진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./wsl4.png&apos; data-alt=&apos;Figure 4. vim.basic의 매핑된 메모리 영역&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/56e167eb0eac174aa8234c37969ef7ee/dc992/wsl4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 84.21052631578947%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAIAAABSJhvpAAAACXBIWXMAAB2HAAAdhwGP5fFlAAACHUlEQVR42lWS2W7bMBBF9f8f1gIBgvTBjZ3ASWNTJCXu2mU5tntn6KUlhOGmM8sdFjvva+e0pU9ora2tnC+reliW+XyaT6f5my1/43Icj9+h78d5lsNYaGOsMZv12juXYgzew8YQYJuUUsgW24TFNI7jMEzTdF6WnXPFXkophFLK8bDWepry0mJBW2O898MwtG0bY1qOx8v5vNVVAU6WpTUW1wjrrPHu6gc4phBwaIMPXdd2XZdSXJblcrmoti2EVIpgg1QxwMBD5skXWw84BETuhwH8NM+AZWoKWVWQCT9FHvg1e6H6ERQLKhlz7PseGFwcOPINVirwTzc4ZjjTBHvfpGaaoDGNB1xqraQiYTwF9DlP3tDkKBFuRILIIKH3A96jZCEgCSOehOWCac2aBSrZwBd0mngsd1hIibSpK46VIi/u3rarbCzYPE85+ANGn5WUhgNSrNwqxrjTlBF7DBM9kRH84XC41axUjswa32vOmbt7zVCupzFAv/kOQ21T1/+1KuuM5vCc0nXbNBCcoi//tqquqnwHr/4Gw+Dk6jHgMOFtZsEeagulK34kaAa9MJbXcyLwhdy5FioqkwiRYdUgclnut1ujpK+qqhSwNV6rUgZC7nZa0ImvdBfj1HXR2o6ctn1qP2tXrMvyabV63e3fhHh+XW+V/vX+/vr1tfr8fFr9fnl7fxPlh9YyRlw9rzfrffnyp/y52vzYqb/W5rNk2CsgPQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 4. vim.basic의 매핑된 메모리 영역&apos; title=&apos;&apos; src=&apos;/static/56e167eb0eac174aa8234c37969ef7ee/efd7b/wsl4.png&apos; srcset=&apos;/static/56e167eb0eac174aa8234c37969ef7ee/08678/wsl4.png 190w,
/static/56e167eb0eac174aa8234c37969ef7ee/2edd7/wsl4.png 380w,
/static/56e167eb0eac174aa8234c37969ef7ee/efd7b/wsl4.png 760w,
/static/56e167eb0eac174aa8234c37969ef7ee/dc896/wsl4.png 1140w,
/static/56e167eb0eac174aa8234c37969ef7ee/dc992/wsl4.png 1178w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 4. vim.basic의 매핑된 메모리 영역&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;그럼 최종적으로 0x400000 메모리를 열어보면 이와 같다. 7f 45 4c 46, ELF 실행 파일이 그대로 매핑된 걸 볼 수 있다. 망했어요2 ㅠㅜ~&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;ps
Figure 5. ps -A 결과
서브시스템 내의 세계는 어떨까? ps -A를 해보면 우리가 bash 쉘에서 실행한 것만 출력된다는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;그렇다면 새로운 bash 쉘은 새로운 리눅스를 의미할까? bash 쉘을 여러개 띄워서 실행해본 결과 동일한 init의 자식으로 생성되는 것을 알 수 있었다. 더불어 격리된 bash 쉘들에서 실행된 내용은 접근할 수 있는 것으로 보여졌다.&lt;/p&gt;
&lt;p&gt;ps -A에서 출력된 pid는 원래 윈도우에서 보여지는 pid와 일치할까? 확인결과 일치하지 않는 것으로 보여진다.&lt;/p&gt;
&lt;p&gt;이 정도 결과를 토대로 알 수 있는 것은 리눅스 서브시스템에서는 윈도우로의 접근이 불가능한 샌드박스 같은 구조인 것으로 유추해 볼 수 있겠다. 은막 뒤에서 펼쳐지는 마법의 보다 자세한 사항은 &lt;a href=&quot;https://blogs.msdn.microsoft.com/wsl/&quot;&gt;여기를&lt;/a&gt; 참고하자. 피코 프로세스라뉘…​ 그리고 이 핫한 기능의 가장 &lt;a href=&quot;https://github.com/Microsoft/BashOnWindows&quot;&gt;핫한 지점은&lt;/a&gt; 깃허브로 추정된다.&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;WSL(Windows Subsystem for Linux)의 존재를 우리가 처음 알게 됐을 때 가장 우려한 것은 WSL을 이용한 윈도우 세계로의 접근이었다. 하지만 잠깐 살펴본 바에 의하면 기본적으로는 막혀 있는 것으로 보여진다. 하지만 WOW64를 토대로 보건데 뭔가 강을 건너는 숨겨진 문이 있을지도 모를 일이다. 어쨌든 판도라의 상자 밖으로 나와 버린 PEB도 없는 이 애들을 어떡할지 걱정이다.&lt;/p&gt;
&lt;p&gt;번외 얘기긴 하지만 CEO 한 명 바꼈을 뿐인데 MS 참 열심히 일한다. 이 작품을 감상하면서 다시금 느꼈다. 이러니 저러니 해도 MS가 명실상부한 지구상에서 소프트웨어를 제일 잘 만드는 기업 중에 하나긴 하다는 사실을 말이다. 그런 의미에서 이제 안드로이드도 네이티브로 돌려주는 신기원을 열어주기를 ㅋㅋㅋ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[시스템] FreeBSD에서 BOM 제거를 위한 삽질기]]></title><description><![CDATA[각 메이저 진영은 모두 마치 약속이나 한 것처럼 미묘한 차이로 우리를 괴롭힌다. 마이크로소프트와 오픈소스 진영 간의 차이는 역사적으로 더 골이 깊다. UTF16과 UTF32, 파라미터를 UTF16으로 변경하는 것과 기존 함수에 UTF…]]></description><link>https://jiniya.net/ng/2016/07/remove-utf8-bom-on-freebsd/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/07/remove-utf8-bom-on-freebsd/</guid><pubDate>Fri, 29 Jul 2016 11:00:01 GMT</pubDate><content:encoded>&lt;p&gt;각 메이저 진영은 모두 마치 약속이나 한 것처럼 미묘한 차이로 우리를 괴롭힌다. 마이크로소프트와 오픈소스 진영 간의 차이는 역사적으로 더 골이 깊다. UTF16과 UTF32, 파라미터를 UTF16으로 변경하는 것과 기존 함수에 UTF8 변환 기능을 추가하는 것, 64비트 지원을 위해서 LLP64냐 LP64냐 등의 차이는 유명하다. 여기에 또 하나의 골치아픈 차이가 있다. UTF8 소스에 대한 BOM이다. msvc는 BOM이 있는 것만 컴파일을 해주고, gcc는 BOM이 없는 것만 컴파일을 해준다. 둘이서 짜고 우리를 괴롭히는 것 같다. 어떤걸 선택해도 우리는 양쪽 다 만족시킬 수가 없다. 결국 양쪽 다 만족시키기 위해서는 한쪽에다 변환기를 설치해야 한다. 우리는 gcc를 위해서 BOM을 제거하기로 결정했다.&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-type&lt;/span&gt; f &lt;span class=&quot;token parameter variable&quot;&gt;-exec&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1 s/^\xef\xbb\xbf//&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;우리는 이 명령어를 이용해서 UTF8 BOM을 제거했다. 한동안 잘 사용했는데 이게 유닉스 진영에서도 문제가 될지는 몰랐다. FreeBSD를 만나기 전까지는 말이다. FreeBSD에서는 위 명령어가 제대로 동작하지 않았고 그 미묘한 차이로 인해 결국 나는 몇 시간을 허비했다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-type&lt;/span&gt; f &lt;span class=&quot;token parameter variable&quot;&gt;-exec&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; .bak &lt;span class=&quot;token string&quot;&gt;&apos;1 s/^\xef\xbb\xbf//&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;처음 구글 신이 나에게 알려준 것은 sed의 -i 옵션이 리눅스와 BSD가 다르다는 것이었다. BSD는 -i의 옵션 다음에 원본을 저장할 확장자를 지정해야 한다는 것이었다. 위의 커맨드는 그렇게 변경한 것이다. .bak 파일에 원본을 백업하고 편집된 파일을 원본에다 덮어씌우는 기능을 한다. 명령어 오류가 없이 잘 돌아가는 것 같았다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-type&lt;/span&gt; f &lt;span class=&quot;token parameter variable&quot;&gt;-exec&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; .bak &lt;span class=&quot;token string&quot;&gt;&apos;1 s/^\xef\xbb\xbf//&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-exec&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;.bak &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;1차 시도에 백업 파일을 제거하는 기능을 덧붙인 것이다. 여기까지 하고는 이제는 빌드가 잘 되겠지 하고는 돌렸다. 하지만 빌드는 여전히 되지 않았다. 파일을 열어보니 BOM은 그 자리에 그대로 존재했다. 여기서 가장 많은 시간을 허비했다. 도대체 왜 BOM 제거가 안 되는 것이지? 구글님도 딱히 뾰족한 답을 주지 않았다. 삽질 끝에 알아낸 사실은 FreeBSD에 포함된 sed가 \xef등의 16진수 표현을 지원하지 않는다는 것이었다. \xef등이 아닌 멀쩡한 문자를 넣으면 잘 제거됐다. 구글님은 너가 8진수를 쓰면 될지도 모를껄 이라고 알려줘서 \oNNN을 사용한 표기로 변경해 보았으나 소용이 없었다.&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-type&lt;/span&gt; f &lt;span class=&quot;token parameter variable&quot;&gt;-exec&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; .bak &lt;span class=&quot;token string&quot;&gt;$&apos;1 s/^&lt;span class=&quot;token entity&quot; title=&quot;\xef&quot;&gt;\xef&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;\xbb&quot;&gt;\xbb&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;\xbf&quot;&gt;\xbf&lt;/span&gt;//&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-exec&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;.bak &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;bash핵을 사용한 변칙 방법이다. bash에서 $&apos;&apos; 안에 포함된 문자를 변환시킨다는 것을 이용한 방법이다. 여기서 깔끔하게 끝낼 수 있었는데 나는 이때까지 이 명령어를 makefile에 결합해서 사용하는 방법을 몰랐다. 그래서 16진수 표현을 지원하는 awk로 돌아섰다.&lt;/p&gt;
&lt;h3&gt;#4&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-type&lt;/span&gt; f &lt;span class=&quot;token parameter variable&quot;&gt;-exec&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;NR==1{sub(/^\xef\xbb\xbf/, &quot;&quot;)}{print}&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위 명령은 앞선 우리의 sed와 동일한 기능을 한다. 단지 파일에 저장하는 것이 아니라 변경된 내용을 화면에 출력할 뿐이다. awk에서 제자리 편집(in-place edit)를 하는 방법을 찾아 보았다. -i 옵션이 있었지만 FreeBSD에서는 응당 지원하지 않았다. 출력물을 결국 리다이렉션 시켜서 저장하는 방법 밖에는 없었다.&lt;/p&gt;
&lt;h3&gt;#5&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-type&lt;/span&gt; f &lt;span class=&quot;token parameter variable&quot;&gt;-exec&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;NR==1{sub(/^\xef\xbb\xbf/, &quot;&quot;)}{print &gt; {}}&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;find가 엮여 있어서 그냥 리다이렉션 시키기는 쉽지 않았다. 그러다 발견한 것이 awk의 위와 같은 문법이다. print 안에서 리다이렉션 구문을 쓸 수 있었다. 하지만 이렇게 하자 뭔가 잘 동작하지 않았다.&lt;/p&gt;
&lt;h3&gt;#6&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-type&lt;/span&gt; f &lt;span class=&quot;token parameter variable&quot;&gt;-exec&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;NR==1{sub(/^\xef\xbb\xbf/, &quot;&quot;)}{print &gt; out}&apos;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그러다 -v를 사용해서 변수 값을 지정해서 사용하면 정상 동작한다는 것을 알아냈다. 여기서 FreeBSD를 정복하는 줄 알았지만 여전히 문제가 있었다. 정확한 원인은 모르겠지만 이렇게 저장된 파일은 원본의 전체가 아니라 일정한 길이 이후로 파일이 잘렸다. 전체 버퍼가 다 저장되지 않는 것처럼 보였다.&lt;/p&gt;
&lt;h3&gt;#7&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-type&lt;/span&gt; f &lt;span class=&quot;token parameter variable&quot;&gt;-exec&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sh&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;awk &apos;NR==1{sub(/^&lt;span class=&quot;token entity&quot; title=&quot;\xef&quot;&gt;\xef&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;\xbb&quot;&gt;\xbb&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;\xbf&quot;&gt;\xbf&lt;/span&gt;/, &lt;span class=&quot;token entity&quot; title=&quot;\&amp;quot;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;\&amp;quot;&quot;&gt;\&quot;&lt;/span&gt;)}{print}&apos; {} &gt; {}&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;결국 다시 쉴이다. 진작 알았으면 좋을 뻔 했다. &quot;sh -c&quot;로 특정 명령을 쉴로 실행할 수 있다는 사실이었다. 그래서 위와 같은 것을 생각해냈지만 결과는 참혹했다. 빈 파일만 덩그러니 남았다.&lt;/p&gt;
&lt;h3&gt;#8&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-type&lt;/span&gt; f &lt;span class=&quot;token parameter variable&quot;&gt;-exec&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sh&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;awk &apos;NR==1{sub(/^&lt;span class=&quot;token entity&quot; title=&quot;\xef&quot;&gt;\xef&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;\xbb&quot;&gt;\xbb&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;\xbf&quot;&gt;\xbf&lt;/span&gt;/, &lt;span class=&quot;token entity&quot; title=&quot;\&amp;quot;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;\&amp;quot;&quot;&gt;\&quot;&lt;/span&gt;)}{print}&apos; {} &gt; {}.tmp&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;임시 파일로 리다이렉션 시킬 수 밖에 없었다. 이 명령은 정확하게 동작했다.&lt;/p&gt;
&lt;h3&gt;#9&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-type&lt;/span&gt; f &lt;span class=&quot;token parameter variable&quot;&gt;-exec&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sh&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;awk &apos;NR==1{sub(/^&lt;span class=&quot;token entity&quot; title=&quot;\xef&quot;&gt;\xef&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;\xbb&quot;&gt;\xbb&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;\xbf&quot;&gt;\xbf&lt;/span&gt;/, &lt;span class=&quot;token entity&quot; title=&quot;\&amp;quot;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;\&amp;quot;&quot;&gt;\&quot;&lt;/span&gt;)}{print}&apos; {} &gt; {}.tmp; mv {}.tmp {}&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;임시 파일을 원본으로 덮어씌우는 것을 추가한 이 명령은 완벽했다. 이제 빌드 할 수 있게 되었다.&lt;/p&gt;
&lt;h3&gt;#10&lt;/h3&gt;
&lt;p&gt;몇 시간의 삽질 끝에 동작하는 두 가지 명령어를 알아냈다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-type&lt;/span&gt; f &lt;span class=&quot;token parameter variable&quot;&gt;-exec&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sh&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;awk &apos;NR==1{sub(/^&lt;span class=&quot;token entity&quot; title=&quot;\xef&quot;&gt;\xef&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;\xbb&quot;&gt;\xbb&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;\xbf&quot;&gt;\xbf&lt;/span&gt;/, &lt;span class=&quot;token entity&quot; title=&quot;\&amp;quot;&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;\&amp;quot;&quot;&gt;\&quot;&lt;/span&gt;)}{print}&apos; {} &gt; {}.tmp; mv {}.tmp {}&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 명령은 bash가 필요하지는 않다. 다만 매칭된 파일 개수만큼 sh, awk, mv가 실행된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;bash&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;find . -type f -exec sed -i .bak $&apos;1 s/^&lt;span class=&quot;token entity&quot; title=&quot;\xef&quot;&gt;\xef&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;\xbb&quot;&gt;\xbb&lt;/span&gt;&lt;span class=&quot;token entity&quot; title=&quot;\xbf&quot;&gt;\xbf&lt;/span&gt;//&apos; {} \; -exec rm {}.bak \;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 명령은 bash가 필요하다. 다만 sed, rm만 실행되기 때문에 sh가 추가로 실행되는 앞선 명령 보다는 효율적이다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] Visual Studio 2008로 nss 빌드 하기]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2016/07/build-nss-with-vs-2008/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/07/build-nss-with-vs-2008/</guid><pubDate>Fri, 29 Jul 2016 10:00:01 GMT</pubDate><content:encoded>&lt;p&gt;오픈 소스가 없었다면 우리같이 작은 소프트웨어 기업은 시작도 못했을 것이다. 모든 것을 다 만드려면 사람이 많아야 하고, 필요한 것들을 다 사려면 돈이 많아야 하기 때문이다. 어쨌든 우리같이 작은 기업에게 오픈 소스는 축복이다. 하지만 늘 그렇듯이 버튼 하나 누르면 마법처럼 동작하는 상용 소프트웨어와는 다르게 오픈 소소는 시키는대로 해도 뭔가 안 되는 경우가 많은 것 같다. 물론 요즘은 정확하게 시키는 대로 하면 대체로 비슷한 결과를 얻을 수 있지만, 항상 사람 일이란게 시키는 대로만 하고 살수는 없는 노릇이다. 최근에 mozilla nss를 윈도우에서 빌드하면서도 비슷한 경험이 있었다. Visual Studio 2008을 이용해서 정적 CRT로 빌드를 하려고 했으나 몇 가지 이유로 쉽지 않았다. 여기에 그 기록을 남겨 본다.&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Build_Instructions/Windows_Prerequisites&quot;&gt;여기서&lt;/a&gt; MozillaBuild를 받아서 설치한다. 그러면 기본 설치 경로인 mozilla-build에 가보면 start-shell-msvc2013.bat 파일이 존재한다. 해당 파일을 복사해서 2008으로 변경해준다. 해당 파일을 내용을 아래와 같이 수정하면 된다. 64비트를 빌드하고 싶으면 MOZ_MSVCBITS를 64로 변경해주면 된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bat&quot;&gt;&lt;pre class=&quot;language-bat&quot;&gt;&lt;code class=&quot;language-bat&quot;&gt;@ECHO OFF

SET MOZ_MSVCBITS=32
SET MOZ_MSVCVERSION=9
SET MOZ_MSVCYEAR=2008

REM Switch CWD to the current location so that the call to start.shell-bat
REM doesn&amp;#39;t fail if invoked from a different location.
pushd &amp;quot;%~dp0&amp;quot;

CALL start-shell.bat&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;수정했으면 배치파일을 실행한다. 명령 프롬프트가 뜬다. 소스를 다운로드 받을 폴더로 이동한다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;해당 소스 파일 폴더에서 아래 명령어를 입력하면 최신 nspr과 nss 소스 코드를 클론할 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ &lt;span class=&quot;token function&quot;&gt;hg&lt;/span&gt; clone https://hg.mozilla.org/projects/nspr
$ &lt;span class=&quot;token function&quot;&gt;hg&lt;/span&gt; clone https://hg.mozilla.org/projects/nss&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;디버그, 정적 CRT를 사용하기 위해서는 아래와 같이 환경 변수를 선언해 준다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ &lt;span class=&quot;token builtin class-name&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;USE_DEBUG_RTL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
$ &lt;span class=&quot;token builtin class-name&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;USE_STATIC_RTL&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그 다음 nss 폴더로 이동해서 아래와 같이 입력하면 nspr과 동시에 빌드를 진행해 준다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; nss
$ &lt;span class=&quot;token function&quot;&gt;make&lt;/span&gt; nss_build_all&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;우리가 정적 라이브러리를 사용해서 빌드를 하면서 한 가지 문제가 있었다. 아직 수정되지 않은 문제로 보여진다. &lt;a href=&quot;https://hg.mozilla.org/projects/nss/file/3ed709ba186a/cmd/shlibsign/shlibsign.c#l97&quot;&gt;이 함수가&lt;/a&gt; 문제였다. 전체적으로 아래와 같은 코드 흐름이다. 문제는 output_file이라는 변수가 PL_strdup와 PR_Malloc에 의해서 할당되는데 해제는 항상 PL_strfree로 한다는 점에 있다. 물론 PL_strdup와 PR_Malloc이 동일한 DLL에 있거나 정적으로 이 프로그램과 결합한다면 문제가 되지 않는다. 심지어 DLL 형태의 CRT를 사용해도 문제가 되지 않는다. 우리 케이스에서는 이게 문제였다. PL_strdup와 PR_Malloc은 서로 다른 DLL에 있는 함수였고, 이는 서로 다른 힙에 할당된다는 것을 의미했다. PL_strfree에서 크래시가 발생했다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;mkoutput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;output &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;PR_Malloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; output&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;output_file &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;some_cond&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		output_file &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;PL_strdup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;optstate&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;output_file &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		output_file &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mkoutput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input_file&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;output_file&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/* allocated by mkoutput function */&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;PL_strfree&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;output_file&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;코드를 아래와 같이 수정해주면 된다. 결국 PL_strdup만 할당한 변수를 사용하도록 통일해 주는 것이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;mkoutput&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; in_len &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;output &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;PR_Malloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;in_len &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SGN_SUFFIX&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; index &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; in_len &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.&quot;&lt;/span&gt; SHLIB_SUFFIX&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;index &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;PL_strncmp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;index&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;.&quot;&lt;/span&gt; SHLIB_SUFFIX&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.&quot;&lt;/span&gt; SHLIB_SUFFIX&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        in_len &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;output&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; input&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; in_len&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;output&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;in_len&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SGN_SUFFIX&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SGN_SUFFIX&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;PL_strdup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;output&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;PR_Free&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;output&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; result&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;하지만 여기까지 수정을 하면 대체로 빌드가 상당히 진행이 되는데 테스트 빌드를 하는 도중에 오류가 발생한다. 대체로 C11, C14 기능들을 활용한 부분인데 Visual Studio 2008에서 그런걸 기대하기는 힘드니 아래와 같이 환경 변수를 선언해서 해당 부분은 빌드를 하지 않도록 한 다음 빌드를 하면 모두 성공시킬 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ &lt;span class=&quot;token builtin class-name&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;NSS_DISABLE_GTESTS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
$ build nss_build_all&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[일상] 자존심]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2016/07/self-esteem/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/07/self-esteem/</guid><pubDate>Thu, 21 Jul 2016 10:00:01 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;하이고. 내 자슥인데 얼굴 보믄 모르것나. 영욱아. 내 말 잘 들으래이. 자존심은 미친년 머리에 꽂아놓은 꽃하고 같은 기다. 그 와, 마을마다 미친 아가 하나씩 안 있었나. 머리에 꽃을 꽂고 댕깄다 이가. 그칸데 희한하제? 얼굴을 만지고 때리고 밀고 그캐도 헤헤 거리고 웃던 아가, 머리에 꽃만 만지믄 살쾡이처럼 변해가 덤비는 기라. 지한테는 머리에 꽃이 지 몸보다 더 중요한기라. 사람들은 저기 미치가 저라는갑다 요라지만은, 내가 볼 때는 다 똑같데이. 사람들은 다 지 머리에 꽃 하나씩 꽂고 사는 기라. 아무 쓸모 없는 건데도, 지 몸보다 더 중하다고 착각하고 사는 기 있는 기라. 영욱가, 니한테는 그기 자존심이데이. 니는 가마이 있어도 서동환이 아들이고, 한오그룹 회장이 될 끼다. 동윤이 점마가 아등바등 기가 와도 대통령이 되고 뭐가 되도, 니 발꿈치도 못 따라오는 기다. 그카이 영욱아. 인자 마음 가라앉히고…​&lt;br&gt;
&lt;br&gt;
-- 드라마 추적자&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;종종 사람들이 정말 엉뚱한 거래를 할 때가 있다. 손해 볼 것이 뻔한 상황에서도 불나방처럼 달려드는 상황. 대체로 그때 이유는 한결같다. 자.존.심. 아무것도 아닌 그거 하나 지키려고 너무 피곤하게 사는 건 아닌지하는 생각이 절로 든다. 머리에 꽂은 꽃은 꽃이고 나는 난데 말이다. 그 꽃에 지나치게 에고를 투영하면 투영할수록 투영하는 본인만 피곤해질 뿐이다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] 리디북스 PC용]]></title><description><![CDATA[여렸을 적에는 컴퓨터 책을 많이 읽었었다. 새뱃돈으로 내가 부린 거의 유일한 사치는 컴퓨터 책을 사는 것이었고, 여자 친구랑 영화를 보러 가서도 컴퓨터 책을 끼고 보면서 눈총을 받기도 했었다. 그 책은(The Art Of Unix Programming…]]></description><link>https://jiniya.net/ng/2016/07/ridibooks-for-pc/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/07/ridibooks-for-pc/</guid><pubDate>Mon, 18 Jul 2016 10:00:01 GMT</pubDate><content:encoded>&lt;p&gt;여렸을 적에는 컴퓨터 책을 많이 읽었었다. 새뱃돈으로 내가 부린 거의 유일한 사치는 컴퓨터 책을 사는 것이었고, 여자 친구랑 영화를 보러 가서도 컴퓨터 책을 끼고 보면서 눈총을 받기도 했었다. 그 책은(The Art Of Unix Programming) 눈물 없이는 볼 수 없다는 항변을 하는 바람에 더 욕을 먹기도 했었다. 어쨌든 그랬던 나도 언제부턴가 기술 서적을 많이 읽지 않게 되었다. 그러면서 기술 서적에 대한 취향도 다소 바뀌었는데 어렸을 때에는 특정 기술에 대한 세부 사항을 설명하는 책을 많이 읽었다면 지금에서는 그런 책보다는 실용주의 프로그래머, 조엘 온 소프트웨어, 프로그래밍 심리학, Old New Thing, 이펙티브 프로그래밍 등의 이념서나 에세이 류로 분류되는 책을 더 많이 선호한다. 물론 새로운 기술을 접할 때면 개요를 정리한 튜토리얼 성격의 책을 읽기는 하지만 최근에 딱히 새로운 기술이랄만한 것을 접한 기억은 없는 것 같다.&lt;/p&gt;
&lt;p&gt;여튼 자랑은 아니지만 고백컨데 기술 서적을 읽은지가 제법 오래된 것 같다. 간간히 아마존에서 영어 공부한답시고 원서 사서는 조금 보다 말고 한게 전부라 마지막으로 감동적으로 읽은 기술 서적이 뭐였는지도 까마득하다. 배꼽잡고 반성을 많이 해야 하는 상황인 것이다. 그랬던 차에 오늘 우연히 삘이 확 꼽히는 책 제목을 보게 되었다. &quot;7가지 동시성 모델&quot;이라는 책이다. 벌써 제목에서 뭔가 반드시 읽어야 할 것 같은 강한 냄새를 풍긴다. 거기다 번역을 무려 임백준님께서 하셨으며, 목차마저도 깨알같았다. 벌써 나는 리디북스에서 구매하기 버튼을 누르고 있었다. PDF라는 표기가 다소 나를 찜찜하게 하긴 했었다. 그리고 구매해서는 폰으로 책을 열었는데 PDF였다. 폰에서 보기에는 너무 조악한 화면.&lt;/p&gt;
&lt;p&gt;시원시원하게 27인치 모니터로 흡입해 버리겠어, 라는 마음과 함께 PC용 리디북스 버전을 설치했다. 설치하고 계정 로그인을 했다. 하지만 난 곧 실망할 수 밖에 없었다. 그 책은 아래 화면과 같이 어떠한 이유(아마도 저작권이나 유출등의 문제)로 PC용 버전은 지원이 되지 않는다고 나왔기 때문이다. 이뭐병 ㅠㅜ~ 혹시나 하는 마음에 단 한 차례도 들어가 보지 않았던 윈도우 스토어를 들어가 보았다. 그리고 거기다 리디북스를 쳤지만 그런 앱은 존재하지 않았다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./ridibooks.png&apos; data-alt=&apos;Figure 1. 리디북스 PC용 버전&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 736px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/27e225f7cd5e324aad52f76eabe30532/bc563/ridibooks.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 52.63157894736842%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACgUlEQVR42iWSzU8TURTFZ+XGv8CVO/8CE+OKmLjTxIQFAn4lGk0XLsAISiq1IRHBUAIxKUICopIAERQVI1AwBaW0ldIPKG3ndT7evJk3M2+mnYFCpdBpHSS5Obk3+Z2cxblULuI2Iu1GxGVsuE7UjLpIyEkvtgqrzuTiU+63E4faSbjdjPwH1l3axjNu/Ml230NK+1tFZql4aFUqlbJlWRWrdFgydncPi4WYfFD76aBp6ej+gjWVKVerFZuyuXL5qGRVTXWT4rABJSJIRJR1AWuKbhLdxCSvkDyUjRg0E9BcS+M4kARR5W0Sa0maD0QBpIMUxIaNYm0HExOKagaqKV6lBZVBqigTCQmQ5wCdYXiU5UUA2CzNbm3T4S02ueGjaF5ZXg34/Cu+XwE77WswPfYjMDG3nMgwAoTrvneR+cHJASdg4E4OFhKzcKxbWJsje5WUbQ6G4s5rtd7G628cD7IQc6KsKNJ2JoUwBgBEl96+flzf21wHOERQssjN7ydmFG4dkf1U1EfF/YGWK5dbujqnHzXxLOJlVcRisUA0ndAAfB7ucFw856qrETRja348/LIh01af/j4q5UsCvUYFVoLuC+fbLtV4Gm5wAp7xh4emvq0G5mKbUZoG3g5Hv9vx3tNMDHPkhfvmmVO3z57uuXeLFCwxG6LiKa6rx9P6vKOzt0+QtQ/Ts939fa/6PQv+ZR6iPz8/fpkYmp0cJLoxPDJaV3v17p1G74BXNUrHZojzWRYJkookIqn5NM0CVmR4LGsmL6qxZDYFIMQ5uwtOkFkBq/puztyTSEFiwhRSdnhRFpXcyTBQsgkk6+j/edz/8aLbar8DlFS7ZzsJa3sSE/4HHdMJ98V2vdUAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 1. 리디북스 PC용 버전&apos; title=&apos;&apos; src=&apos;/static/27e225f7cd5e324aad52f76eabe30532/bc563/ridibooks.png&apos; srcset=&apos;/static/27e225f7cd5e324aad52f76eabe30532/08678/ridibooks.png 190w,
/static/27e225f7cd5e324aad52f76eabe30532/2edd7/ridibooks.png 380w,
/static/27e225f7cd5e324aad52f76eabe30532/bc563/ridibooks.png 736w&apos; sizes=&apos;(max-width: 736px) 100vw, 736px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 1. 리디북스 PC용 버전&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;그나마 옆에 있는 7인치 태블릿에 리디북스를 설치했다. 폰보다는 볼 만하지만 여전히 만족스럽지는 않다. 그러다 리디북스 페이퍼를 잠깐 살펴봤는데 6인치, 역시 조악할게 뻔하다. 이참에 PDF에 최적화된 태블릿을 사야하나 고민중…​ 리디북스가 윈도우 스토어를 어서 빨리 지원해 줬으면 하는 바램이다. 애매하긴 하다. 윈도우 스토어도 PC인가?…​&lt;/p&gt;
&lt;p&gt;심심해서 킨들에서 원서 샘플 다운로드 받아봤는데 퐌타스틱하게 보여진다. 기냥 원서를 샀어야 하는건가? PDF가 만악의 근원인건지 그걸 제대로 보여주지 않는 리디북스 뷰어가 만악의 근원인건지. 내가 그걸 깔끔하게 볼 디바이스를 가지지 않은게 잘못된건지 킁. 여튼 간만에 컴퓨터 책 한 번 읽으려다 심히 좌절중 ㅠㅜ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] Visual Studio Developer Assistant 플러그인]]></title><description><![CDATA[MS에서 Developer Assistant 플러그인이 이제 C++도 지원한다고 발표했다. Developer Assistant…]]></description><link>https://jiniya.net/ng/2016/07/developer-assistant/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/07/developer-assistant/</guid><pubDate>Wed, 13 Jul 2016 10:00:01 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://blogs.msdn.microsoft.com/visualstudio/2016/07/13/developer-assistant-supports-cpp/&quot;&gt;MS에서 Developer Assistant 플러그인이 이제 C++도 지원한다고 발표했다.&lt;/a&gt; Developer Assistant 뭐 이름 그대로 개발자 보조 도구 정도지만 그 녀석이 제공하는 기능을 보면 약간 섬뜩하기도 하다. 기본저인 컨셉은 알려진 접근 가능한 모든 소스 코드의 정보를 토대로 우리가 어떤 일을 Visual Studio에서 코딩하면 되는지 알려주겠다는 것이다. 거창하게 설명하면 이런데 좀 더 쉽게 말하자면 Visual Studio랑 크롬이랑 같이 쓰던거 Visual Studio만 쓰면 되도록 하주겠다는거다. 거기다 크롬에서 검색하는 것보다 좀 더 편하고, 유용하고, 카피하기 편하게 알려주겠다는 취지다.&lt;/p&gt;
&lt;p&gt;크롬, 정확하게는 구글이 우리를 대신해서 코딩하기 시작한지는 제법 됐다. 최근에 들어온 한 신입 직원은 거침없이 &quot;구글에 다 있잖아요&quot;라는 이야기를 했었다. 사실 틀린 말은 아니다. 솔직히 까놓고 말해서 구글의 한계가 우리의 한계인 경우가 다반사다. 그런 지경에서 이제와 크롬 대신 그저 IDE에서 조금 편하게 조금 더 씹어먹기 좋게 결과를 보여주겠다는 것 뿐인데 뭐가 대수인가, 라고 생각할지도 모르겠다. 그런데 내가 나이가 들어서 그럴수도 있겠지만 막연한 느낌인데 마냥 좋아보이진 않는다.&lt;/p&gt;
&lt;p&gt;내 프로그래머로 경력 초기에는 Visual Studio 버전이 6.0이었다. 지금 생각하면 아주 투박한 프로그램이었다. 거기다 윈도우의 온갖 구조체는 많은데 그놈에 IDE는 점(.)을 찍어도, 화살표를 붙여도(→) 제깍제깍 나에게 어떤 것들이 그 다음에 존재하는지를 알려주지를 않았다. 그 당시에도 Visual Basic은 인텔리센스가 광속이었다. 점을 찍기가 무섭게 너가 그럴줄 알았다는 듯이 목록이 떴었다. 하지만 C++은 달랐다. 마치 C++ 프로그래머는 모든 걸 다 외우라는 MS의 계시처럼 느껴졌다. 그래서 그 당시에 나는 흔한 신입 프로그래머들이 그러듯이 VisualAssist라는 도구를 사용했다. 어시스트를 설치하면 인텔리센스가 그나마 좀 똑똑해졌던 것이다. 게다가 파랑과 검정 밖에 없는 단조로운 Visual Studio의 문법 강조 기능도 훨씬 풍부한 색상으로 변했다.&lt;/p&gt;
&lt;p&gt;나는 VisualAssist에 굉장히 만족했었고 내가 작업하는 어떤 환경이든 그걸 설치해서 사용했다. 하지만 회사라는 생태계는 그리 녹록치 않았다. 그시절 그런 툴을 달갑지 않게 바라보는 팀장님이 계셨던 것이다. 그분은 주구장창 나와 같은 프로그래머에게 비난의 화살을 보냈다. 그 편리함에 익숙해지다가 넌 아무것도 모르는 바보 프로그래머가 될 거라고 말이다. 그러면서 자신은 그런 도구 없이 vim, 아니 노트패드로 코딩해도 모든 것을 다 외워서 타이핑 할 수 있다는 이야기를 덧붙였다. 물론 팀장님은 나에게 그리 강력하게 말하진 않았다. 하지만 직속 학교 후배가 몇 분 회사에 있었는데 그 후배들에게는 학교때부터 엄청난 갈굼을 했다는 이야기를 전해들었다. 그때나 지금이나 나는 철학적으로 그 생각에 동의하지 않기에 그러거나 말거나 VisualAssist를 썼다. 그러다 2008 정도 부터는 Visual Studio IDE도 그럭저럭 괜찮은 인텔리센스를 보여줘서 굳이 외부 도구를 설치하진 않는다.&lt;/p&gt;
&lt;p&gt;앞선 일화에서 내가 그 팀장님에게 동의하지 않았던 기본 전제는 그것이었다. 외워서 그것을 통째로 타이핑 할 수 있는 능력이 프로그래밍의 본질이 아니라는 것이다. 나는 그것보다는 그 근간에 흐르는 논리적 사고가 더 중요하다고 생각했다. 구조체 멤버를 외우는 것과 외우지 않는 것이 중요하지 않다. 하지만 그 구조체 멤버를 통해서 무엇을 할 수 있을지, 없을지를 판단하는 것이 더 중요하다고 생각했다. 물론 기본적인 사고 회로를 동작시키기 위해서 암기는 필수다. 아무것도 외우지 않고서는 어떠한 사고도 할 수 없을테니 말이다. 즉, 그 팀장님과 나의 결정적 견해 차이는 엄밀하게 말해서 필수적으로 암기해야 하는 것의 범위에 대한 차이였다고 볼 수 있겠다.&lt;/p&gt;
&lt;p&gt;그랬던 내가 Developer Assistant를 보면서는 이제 꼰대가 되나보다, 라는 생각을 무척 많이 하게 됐다. 캡처 화면 중에 &quot;How do I …​&quot;이란 창을 보고는 말이다. 이제는 프로그래머가 IDE에게 뭘 어떻게 해야 하는지를 물어봐야 하는 세상이 열리려는 순간인 것처럼 보였기 때문이다. 신입 프로그래머들은 그럴지도 모르겠다. 구글에서 검색하던 것이 조금 편리해졌을 뿐이라고. 물론 나는 지금 거기 동의하지만 뭔가 위험한 냄새가 나는 것을 감출 수는 없다. 내 경력 초기에 그 팀장님이 그랬던 것처럼 말이다. 너무 편리한 도구가 프로그래머들의 생각하는 법을 빼앗아갈까봐 두려운 것이다.&lt;/p&gt;
&lt;p&gt;전화가 발명됐을 때 사람들은 그랬다. 이제 사람들은 마주보고 이야기하는 법을 까먹게 될거야. 이메일이 발명됐을 때 사람들은 그랬다. 이제 사람들은 서로 음성으로 대화하는 법을 까먹게 될거야. 메신저가 등장했을 때 사람들은 그랬다. 이제 사람들은 뭔가를 기다리는 법을 까먹게 될거야. 하지만 아직 우리는 살아남았고, 더 편리한 세상에서 살고 있다. Developer Assistant를 사용하는 지금의 프로그래머들이 10년 후에는 나랑 비슷한 글을 쓰고 있기를 바란다. 물론 아마도 그때 그들은 알파고에 대한 우려를 표명하고 있겠지만 말이다 ㅋㅋ~&lt;/p&gt;
&lt;p&gt;여담이지만 앞선 기술의 진보에 대한 우려가 전혀 기우였던 것은 아니다. 우리는 살아남았지만 어느 정도 그 걱정이 반영된 세상에서 살고 있다. 지금 사람들은 과거 사람들보다 덜 마주보고 이야기하며, 덜 음성으로 대화하고, 덜 기다린다. 그리고 분야에 따라서는 완전히 우리의 기능을 마비시키고 있는 것들도 있다. 큰 누나는 후방 카메라가 없으면 후방 주차를 하지 못한다. 나는 네비게이션 없이는 낮선 장소를 정확하게 찾아갈 수 없다. 그리고 내 가족을 넘어서 우리 모두가 느끼고 있는 분명한 사실은 이제 더이상 그 누구도 전화번호를 기억하지 않는다는 사실이다. 예전에 2-30개씩은 외우고 다니던 것이랑은 정말 대조적이다. 우리는 기술의 혜택을 받았지만 동시에 일정 부분 기계가 대신해 주는 부분에 대해서는 불능 상태가 되고 있다. 그런 점에선 10년전 그 팀장님도 우리가 외우는 걸 양보하는 순간 생각하는 법까지 양보하게 될거라 생각한 것인지도 모르겠다.&lt;/p&gt;
&lt;p&gt;언젠가 회사 부장님께서 운전은 장기적으로 승마와 같은 스포츠가 될 것이라는 이야기를 하셨다. 미래 세대는 지금 우리가 승마를 즐기는 것처럼 운전은 서킷에서나 하는 활동에 지나지 않을 것이라는 말씀이었다. 지나가는 농담처럼 한 말이었지만 나는 굉장히 통찰력 있는 이야기라고 생각했다. 또 아마도 그렇게 될 것 같은 느낌이다. 그런 점에서 우리가 기계가 대신해주는 모든 것을 포기했을 때 과연 우리는 무엇을 하고 있을지가 궁금해졌다. 우리 세대는 승마가 없어지고 운전이 생겼다면, 미래 세대는 운전이 없어지고 비행이 생길까? 지금 분위기로 봐서는 그럴 가능성은 별로 없어 보인다. 그저 월e의 한 장면처럼 모두 아무런 활동도 하지 않고 그저 주어진 삶을 사소한 쾌락으로 채우고 있을 것 같다는 느낌 밖에는…​&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] 봇 전성시대]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2016/06/bot-era/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/06/bot-era/</guid><pubDate>Fri, 10 Jun 2016 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;일전에 &lt;a href=&quot;http://news.khan.co.kr/kh_news/khan_art_view.html?artid=201604172105005&amp;#x26;code=990100&quot;&gt;조환규 교수님의 칼럼을&lt;/a&gt; 굉장히 인상적으로 읽었던 적이 있었다. 로봇을 사람에게 맞추기 보다는 사람을 로봇에게 맞추는 것이 훨씬 쉽다는 관점. 그리고 우리가 조만간 로봇들에게 잘 보여야 할 시대가 올지도 모른다는 이야기. 어쩌면 조금 무시무시한 담론이다. 그러나 어쩌겠는가? 세상이 그렇게 변해가는 것을…​&lt;/p&gt;
&lt;p&gt;오늘은 또 &lt;a href=&quot;http://agile.egloos.com/m/5873169&quot;&gt;김창준님의 감동적인 글을&lt;/a&gt; 한토막 읽게 되었다. 어쩌면 지금부터 준비해야할지도 모르겠다는 생각이 팍팍 들었다. 그래서 봇 전성시대를 대비해서 나도 몇 자 끄적여 보려고 한다.&lt;/p&gt;
&lt;p&gt;서버 공간이 부족한 관계로 자세한 내용은 다음에 서버 공간 늘리고 차차 채우는걸로 ㅠㅜ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[py] pip 환경 배포하기]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2016/06/pip-distribute/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/06/pip-distribute/</guid><pubDate>Wed, 08 Jun 2016 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;파이썬을 사용하면 귀찮은 작업 중에 하나가 환경 바뀌면 라이브러리를 일일이 수동으로 설치해줘야 한다는 점이다. 운영체제를 새로 설치해도 그렇고, 다른 사람에게 알려줄 때에도 그렇다. 그래서 도커를 써야 하나 싶다가도 뭔가 모기 잡으려고 화염방사기 쓰는 것 같은 느낌도 들고, 결정적으로 도커를 모르기도 하고 ㅋㅋ~&lt;/p&gt;
&lt;p&gt;물론 이런 경우만 있는 것은 아니다. 이번에 2.7에서 3.5로 갈아타는 것과 같이 다른 환경으로 이동하는 경우도 있다. 이때에는 진짜 정말 찾아서 설치하는 수 밖에 없다. 그래서 스크립트 돌려보고 오류가 발생할 때마다 찾아서 설치하고 있었다. 그런데 &quot;~ 수 밦에 없다&quot;는 나의 착각이었다. pip는 이미 퐌타스틱한 기능을 내장하고 있었다. 잠시 살펴보도록 하자.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;pip freeze &gt; requirements.txt&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위와 같은 커맨드를 날리는 순간 pip로 설치된 모든 라이브러리의 목록이 requirements.txt에 저장된다. 내가 갈아탄 3.5에서 실행해보니 아래와 같이 나왔다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;click==6.6
Flask==0.11.1
itsdangerous==0.24
Jinja2==2.8
MarkupSafe==0.23
pycrypto==2.6.1
PyExcelerate==0.6.7
PyMySQL==0.7.5
requests==2.10.0
six==1.10.0
slackclient==1.0.0
websocket-client==0.37.0
Werkzeug==0.11.10&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이제는 이 requirements.txt만 있으면 일일이 그걸 설치하고 있을 필요가 없다. 바로 &quot;install -r&quot;이라는 마법같은 커맨드가 있기 때문이다. 아래와 같이 입력하면 일괄 설치된다. 넘나 편한것. pip 설치 지원 안 하는 라이브러리는 버려도록 해야겠다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;pip install -r requirements.txt&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[py] Python 3.5에서 MySQL 사용하기]]></title><description><![CDATA[파이썬에서 대체로 오라클에서 공개한 mysql.connector라는 것을 사용해서 MySQL 처리를 했었다. 이번에 파이썬 2.7.x에서 3.5로 갈아타면서 라이브러리 설치할 일이 있어서 다운로드를 받으러 갔다. 어랏. 3.3버전용, 3.…]]></description><link>https://jiniya.net/ng/2016/06/python-mysql/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/06/python-mysql/</guid><pubDate>Tue, 07 Jun 2016 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;파이썬에서 대체로 오라클에서 공개한 mysql.connector라는 것을 사용해서 MySQL 처리를 했었다. 이번에 파이썬 2.7.x에서 3.5로 갈아타면서 라이브러리 설치할 일이 있어서 다운로드를 받으러 갔다. 어랏. 3.3버전용, 3.4버전용은 있는데 3.5버전용이 없다. 뭐 3.4 버전용으로 되겠지라는 안일한 생각으로 그걸 받으려고 하는데, 로그인에 내 개인 정보까지 요구하는 오라클. 순순히 모든 정보를 바쳐가며 다운로드를 받았건만 그건 3.5를 지원하지 않았다. 괜히 3.3, 3.4 이런식으로 세부적으로 있는게 아니었다. 괜한 시간 낭비…​&lt;/p&gt;
&lt;p&gt;그래서 검색을 좀 해봤더니 오라클 따위거를 쓰지 않아도 대체제가 있었다. 그 중에 하나가 pymysql이다. 설치도 넘나 간단하다. pip에 다음과 같이 입력하면 끝.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;pip install pymysql&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;사용 방법은 뭐 mysql.connector와 거의 유사하다. 아니 똑같다고 생각하면 될 정도? 아래와 같은 느낌으로 사용하면 된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;py&quot;&gt;&lt;pre class=&quot;language-py&quot;&gt;&lt;code class=&quot;language-py&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; pymysql

conn &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; pymysql&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;connect&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;host&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;호스트&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; port&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;포트&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; user&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;유저&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; password&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;비번&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; database&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;디비&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
cursor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; conn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cursor&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
cursor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;execute&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;sql 쿼리&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
res &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cursor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fetchall&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
conn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;close&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[py] Python 3.5의 pycrypto 임포트 문제 해결]]></title><description><![CDATA[파이썬에서 암호화를 하려면 pycrypto 라이브러리를 사용하면 된다. pip install pycrypto 하면 문제없이 설치되는데 사용하는데 약간의 문제가 있다. Python 3.5가 설치된 환경에서 pip로 인스톨을 하고 아래와 같이 Random…]]></description><link>https://jiniya.net/ng/2016/06/pycrypt-winrandom/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/06/pycrypt-winrandom/</guid><pubDate>Mon, 06 Jun 2016 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;파이썬에서 암호화를 하려면 pycrypto 라이브러리를 사용하면 된다. pip install pycrypto 하면 문제없이 설치되는데 사용하는데 약간의 문제가 있다. Python 3.5가 설치된 환경에서 pip로 인스톨을 하고 아래와 같이 Random을 임포트 하려면 winrandom을 찾을 수 없다는 오류가 발생한다. 파이썬3로 변경되면서 모듈 포함하는 규칙이 바뀌어서 그런 것 같은데 수정하는 방법은 간단하다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;py&quot;&gt;&lt;pre class=&quot;language-py&quot;&gt;&lt;code class=&quot;language-py&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# c:\Python35&gt;python&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 25 2016, 22:18:55) [MSC v.1900 64 bit (AMD64)] on win32&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# Type &quot;help&quot;, &quot;copyright&quot;, &quot;credits&quot; or &quot;license&quot; for more information.&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; Crypto &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Random
Traceback &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;most recent call last&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  File &lt;span class=&quot;token string&quot;&gt;&quot;&amp;lt;stdin&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; line &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;module&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
  File &lt;span class=&quot;token string&quot;&gt;&quot;c:\Python35\lib\site-packages\Crypto\Random\__init__.py&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; line &lt;span class=&quot;token number&quot;&gt;28&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;m
odule&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; Crypto&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Random &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; OSRNG
  File &lt;span class=&quot;token string&quot;&gt;&quot;c:\Python35\lib\site-packages\Crypto\Random\OSRNG\__init__.py&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; line &lt;span class=&quot;token number&quot;&gt;34&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;module&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; Crypto&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Random&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;OSRNG&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;nt &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; new
  File &lt;span class=&quot;token string&quot;&gt;&quot;c:\Python35\lib\site-packages\Crypto\Random\OSRNG\nt.py&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; line &lt;span class=&quot;token number&quot;&gt;28&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;m
odule&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; winrandom
ImportError&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; No module named &lt;span class=&quot;token string&quot;&gt;&apos;winrandom&apos;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;우선 문제가 된 위치의 파일을 찾아간다. c:\Python35\lib\site-packages\Crypto\Random\OSRNG\nt.py 이 파일이다. 해당 파일을 열면 아래와 같이 임포트를 하고 있는 것을 볼 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;py&quot;&gt;&lt;pre class=&quot;language-py&quot;&gt;&lt;code class=&quot;language-py&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; winrandom&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위 코드 앞에 &quot;from . &quot;을 붙여주면 된다. 고치면 아래와 같은 코드가 된다. 수정된 내용을 저장하고 다시 임포트시켜 보면 잘 되는 것을 알 수 있다. 배터리는 준비돼 있지만 자질구레하게 손이 가는 곳이 많다. 그래도 배러뤼가 있는게 어딘가?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;py&quot;&gt;&lt;pre class=&quot;language-py&quot;&gt;&lt;code class=&quot;language-py&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; winrandom&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[소고] 천재성에 관한 통찰]]></title><description><![CDATA[회사를 시작한지 한 1…]]></description><link>https://jiniya.net/ng/2016/06/about-genius/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/06/about-genius/</guid><pubDate>Sun, 05 Jun 2016 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;회사를 시작한지 한 10년 되다보니 만난 직원이 이제는 제법 된다. 그 중에서도 엔지니어로 일하는 직원들에게는 동병상련같은 감정을 많이 느낀다. 나도 그들과 같은 길을 지나왔고, 어쩌면 지금도 그 길을 가고 있기에 비슷한 생각을 많이 하고 또 유사한 고민도 많이 했기 때문이리라. 그런 직원들의 흔한 고민 거리 중에 하나가 주위의 똑똑한 사람과 자신을 비교하면서 생기는 자괴감이다. 한 직원은 이렇게 말하기도 했었다. 한달 내도록 주위를 보면서 &apos;나는 뭔가’라는 생각에 멘탈이 탈탈 털리다가 그나마 입금되는 월급보고 충전된다고…​&lt;/p&gt;
&lt;p&gt;사실 누구나 쉽게 예상하겠지만 우리 회사에는 다들 고만고만한 사람들이 모여서 일을 한다. 물론 경쟁 업체보다는 많이 똑똑한 엔지니어들을 가려 뽑았다는 자부심은 있다. 하지만 대다수가 비슷비슷하지 크게 다르지 않다. 그런데도 직원들의 상당수, 예외적인 사람 일부를 제외한 거의 대부분은 그 사이에서 비교를 하고 그 과정에서 자연스레 발생하는 불필요한 열등감으로 자신을 갉아 먹는다. 나는 대체로 김난도 선생의 비유를 들어 저마다의 시간이 있으니 굳이 비교할 필요 없이 각자의 길을 가면 된다는 조언을 당당하게 해주지만 어쩌면 이 또한 위선적인 모습인지도 모르겠다. 왜냐하면 나도 제법 프로그래밍을 했을 무렵 비슷한 고민에 빠졌었기 때문이다.&lt;/p&gt;
&lt;p&gt;최근에 &quot;사피엔스&quot; 이후로 엄청난 감탄을 하면서 읽은 책이 있었는데 &quot;틀리지 않는 법&quot;이라는 수학 책이다. 그 책의 천재성에 관한 저자의 견해 일부가 워낙 감탄스러워 여기 발췌해 본다. 아마 저자의 말처럼 이 교훈은 분야를 막론하고 비슷한 고민을 하는 거의 모든 사람들에게 적용되는 조언인 것 같다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;수학을 오래 하다 보면 깨닫게 되는 것은(그리고 나는 이 교훈이 훨씬 더 폭넓게 적용될 것이라고 생각한다) 당신보다 앞선 사람은 늘 있다는 사실이다. 당장 같은 교실에 있든 아니든 말이다. 이제 막 시작한 사람은 좋은 정리를 증명한 사람을 바라보고, 좋은 정리를 증명한 사람은 좋은 정리를 많이 증명한 사람을 바라보고, 좋은 정리를 많이 증명한 사람은 필즈상을 받은 사람을 바라보고, 필즈상을 받은 사람은 수상자들 중에서도 〈핵심〉에 속하는 사람을 바라보며, 그런 사람은 또 언제나 죽은 사람들을 바라볼 수 있다. 거울을 보면서 〈인정하자, 나는 가우스보다 똑똑해〉라고 중얼거리는 사람은 세상에 한 명도 없다. 그런데도 가우스에 비하면 전부 바보인 사람들이 지난 백 년 동안 힘을 합쳐 노력함으로써 역사상 가장 풍성한 수학 지식을 일구어 냈다.&lt;br&gt;
&lt;br&gt;
수학은 대체로 공동 사업이다. 공통의 목표를 추구하는 거대한 지적 네트워크가 만들어 낸 산물을 각자가 조금씩 더 발전시킨다. 비록 아치를 완성하는 최후의 돌을 얹은 사람이 특별한 영예를 누리기는 하지만 말이다. 마크 트웨인은 이 점을 다음과 같이 잘 표현했다. &amp;#x3C;전신이나 증기 엔진이나 축음기나 전화처럼 중요한 물건을 발명하는 데는 천 명의 사람이 필요했지만, 공은 마지막 사람이 다 차지하고 우리는 나머지 사람들을 잊어버립니다.&lt;br&gt;
&lt;br&gt;
이것은 풋볼과도 비슷하다. 물론 한 선수가 경기를 완전히 장악하는 순간이 있기는 하다. 우리가 이후 오래도록 기억하고 기념하고 회상하는 것은 그런 순간들이다. 그러나 그것은 풋볼에서 보통의 상태가 아니고, 이기는 경기라도 대부분은 그런 순간 때문에 이기는 게 아니다. 쏜살같이 달려 나가는 와이드 리시버에게 쿼터백이 눈부신 터치다운 패스를 하는 데 성공했을 때, 우리는 많은 사람들의 협동 작업을 보는 것이다. 쿼터백과 리시버뿐 아니라 수비팀이 뚫고 들어오는 것을 막아서 쿼터백이 제대로 자세를 잡고 던지도록 시간을 벌어 준 공격팀 라인맨들이 있었고, 그 방어는 또 결정적인 순간에 수비팀의 주의를 흩뜨리기 위해서 핸드오프를 하는 척했던 러닝백 덕분에 가능했으며, 그 밖에도 경기를 조직한 공격팀 감독, 클립보드를 든 그의 많은 조수들, 선수들이 잘 뛰고 던질 수 있도록 돌봐 준 훈련 스태프들… 우리는 이 사람들을 다 천재라고 부르진 않는다. 그러나 그들은 천재성이 벌어질 수 있는 조건을 만들었다.&lt;br&gt;
&lt;br&gt;
테리 타오는 이렇게 썼다.&lt;br&gt;
&lt;br&gt;
흔히 떠올리는 고독한(게다가 약간 미쳤을 수도 있는) 천재의 이미지, 즉 기존 문헌을 비롯한 관습적인 지혜들을 무시한 채 남에게 설명할 수 없는 영감에 따라(어쩌면 듬뿍 가해진 고통이 그 영감을 더욱 강화할 수도 있다) 모든 전문가가 골머리를 썩였던 문제에 대해서 놀랍도록 독창적인 해답을 찾아내는 사람의 이미지는 매력적이고 낭만적이지만, 한편으로는 터무니없이 부정확하다. 적어도 현대 수학의 세계에서는 그렇다. 우리는 물론 수학에 대해서 근사하고 심오하고 놀라운 결과들과 통찰들을 갖고 있지만, 그것은 많은 훌륭하고 위대한 수학자들이 수 년, 수십 년, 심지어 수백 년에 걸쳐서 착실히 연구하고 발전시켜 온 끝에 힘들게 얻어낸 누적적 성과이다. 이해의 한 단계에서 다음 단계로 넘어가는 발전은 굉장히 중대한 사건일 수도 있고 심지어 누구도 예상하지 못했던 사건일 수도 있지만, 그래도 그것은 완전히 새롭게 시작된 작업이 아니라 이전 연구들의 토대 위에 구축된 작업이다. …나는 오늘날 수학 연구의 현실이, 즉 직관과 자료와 약간의 행운에 따라 열심히 노력한 결과로 발전이 자연스럽게, 또한 누적적으로 생겨나는 현실이 내가 학생 때 품었던 낭만적 이미지, 즉 수학은 주로 희귀한 〈천재들〉의 신비로운 영감에 따라 발전한다는 이미지보다 훨씬 만족스럽다고 느낀다.&lt;br&gt;
&lt;br&gt;
힐베르트를 천재라고 부르는 건 틀린 말이 아니다. 그러나 그보다는 힐베르트가 해낸 일이 천재적이었다고 말하는 게 더 옳다. 천재성은 어떤 발생한 사건이지, 어떤 종류의 사람이 아니다.&lt;br&gt;
&lt;br&gt;
-- 틀리지 않는 법&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;조금 실용적인 관점에서 다른 분야에 관한 조언이지만 조엘의 이야기도 곁들여 보면 좋겠다. 조엘은 작은 회사를 운영하는 것에 관해서 쓴 것이지만 나는 개인적으로 이 견해가 개인의 발전과 성장에 관한 것이어도 무관하다고 생각한다. 오늘 하루 아주 조그마한 것이라도 새로운 것을 알아냈다면 그걸로도 만족할만한 일이다. 굳이 거창할 필요도 없고, 조급할 필요도 없다. 안그래도 짧은 인생, 스트레스 받으면서 살지는 말자.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;저처럼 작은 회사를 운영한다면, 쏘면서 움직이는 방법은 두 가지 사항을 의미합니다. 장기적인 안목을 키워야 하며, 매일 조금씩 앞으로 나아가야 합니다. 이렇게 하다보면 조만간 당신이 이길 것입니다. 어제 하루동안 제가 한 일이라고는 FogBUGZ에서 컬러 정책을 조금 개선한 사항뿐입니다. 이 정도면 충분합니다. 조금씩 발전해 나가는 겁니다. 날이 갈수록 우리 소프트웨어는 점점 더 좋아지며, 더 많은 고객을 확보할 수 있다는 점을 노릴 뿐입니다. 오라클 정도로 큰 회사가 되고 난 다음에 거대한 전략을 생각해도 늦지 않습니다. 매일 아침 출근해서 에디터를 여는 것만으로도 충분합니다.&lt;br&gt;
&lt;br&gt;
-- 조엘 온 소프트웨어&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[[시스템] 엑셀의 한계]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2016/06/excel-limits/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/06/excel-limits/</guid><pubDate>Sat, 04 Jun 2016 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;대체로 잘 짜여진 프로그램의 많은 부분들의 한계는 대체로 메모리 한계로 주어지는 경우가 많다. 심지어 스와핑해가며 메모리 한계보다 더 많은 데이터를 처리할 수 있도록 해주는 프로그램들도 있다. 그래서 그랬는지 늘 그저 엑셀은 잘 만든 프로그램이니까 행의 개수나 셀에 들어간 글자수 따위에는 제한이 없을거야, 라는 생각을 많이 했었다. 최근에 회사에서 사용하는 엑셀 시트 생성 파이썬 스크립트의 문제를 수정하면서 나는 내 가설이 옳지 않다는 것을 알게 되었다. 생각보다 엑셀에는 제약이 많았다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://support.office.com/en-us/article/Excel-specifications-and-limits-16c69c74-3d6a-4aaf-ba35-e6eb276e8eaa&quot;&gt;여기를&lt;/a&gt; 참조하면 MS에서 발표한 엑셀의 공식 한계치들을 알 수 있다. 별 대수롭지 않게 생각할 수 있는데 우리 시트가 깨지는 문제의 원인은 행의 개수때문이었다. 행 개수 제한이 대략 105만개인데 실제로 테스트 해 본 바에 의하면 이것보다 적은 데이터도 엑셀이 정상적으로 열지 못하는 경우가 있어서 100만개로 제한을 걸어두었다. 그 다음으로 다소 황당했던 제한은 셀에 포함될 수 있는 글자수다. 이는 32767개로 제한하고 있다. 그런데 지금 해당 페이지에서 보여주고 있는 제약 사항은 그마나 최신 엑셀 프로그램의 제약 사항들이다. 신뢰할 수 있는 자료인지는 모르겠으나 &lt;a href=&quot;http://superuser.com/questions/366468/what-is-the-maximum-allowed-rows-in-a-microsoft-excel-xls-or-xlsx&quot;&gt;이 페이지를&lt;/a&gt; 보면 과거 버전은 더 많은 제약 사항을 가지고 있었던 것 같다.&lt;/p&gt;
&lt;p&gt;사족: 대략 생성된 엑셀 파일은 80메가 정도 크기였다. 정상이라면 통상적으로 엑셀 실행 시에 데이터가 손상되었다는 메시지가 뜨는데, 테스트 과정 중에 이 메시지 만큼이나 자주 엑셀이 잘못된 연산으로 종료되는 것을 목격했다. 지구상에서 소프트웨어를 가장 잘 만드는 회사 중 하나인 MS 제품도 이 정도다. 소프트웨어 개발은 실제로는 우리가 생각하는 것보다 훨씬 어려운 것 같다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[py] retr에서 발생한 line too long 예외 처리하기]]></title><description><![CDATA[파이썬에서 poplib을 사용해서 POP3로 메일을 받아올 때 retr 함수를 사용한다. 보통은 잘 되는데 어쩔 때 이 함수에서 웃기게도 "line too long…]]></description><link>https://jiniya.net/ng/2016/06/python-poplib-maxline/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/06/python-poplib-maxline/</guid><pubDate>Fri, 03 Jun 2016 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;파이썬에서 poplib을 사용해서 POP3로 메일을 받아올 때 retr 함수를 사용한다. 보통은 잘 되는데 어쩔 때 이 함수에서 웃기게도 &quot;line too long&quot;이란 예외가 발생한다. 찾아가보면 아래와 같은 지점에서 예외를 던지는 것을 발견할 수 있다. 이 경우에 옵션은 두 가지다. 하나는 그냥 그 메시지를 무시하거나 다른 하나는 라인을 더 늘리거나.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;py&quot;&gt;&lt;pre class=&quot;language-py&quot;&gt;&lt;code class=&quot;language-py&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_getline&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
	line &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;readline&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_MAXLINE &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;line&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; _MAXLINE&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;raise&lt;/span&gt; error_proto&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;line too long&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;서버가 던져주는 메시지를 무시하기는 힘들다. 그래서 라인을 늘리려고 찾아가보면 아래와 같이 자뻑형 주석과 함께 있는 상수 선언 부분을 찾을 수 있다. RFC 1939는 512글자로 제한하고 있지만 우리는 더 안전하게 하기 위해서 2048을 택했지라는 ㅋㅋㅋ 하지만 행님들 현실 세계에서는 2048로는 부족하긔~ 나는 대인배니까 값을 그냥 20480으로 변경했다 ㅋㅋㅋ~ 당연한 얘기겠지만 고치고 나자 서버로부터 모든 메시지를 안전하게 수신할 수 있었다. 지금으로썬 딱히 이 상수를 변경하는 것 외에는 방법이 없는 것 같다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;py&quot;&gt;&lt;pre class=&quot;language-py&quot;&gt;&lt;code class=&quot;language-py&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# maximal line length when calling readline(). This is to prevent&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# reading arbitrary length lines. RFC 1939 limits POP3 line length to&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# 512 characters, including CRLF. We have selected 2048 just to be on&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;# the safe side.&lt;/span&gt;
_MAXLINE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2048&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[py] 이메일 시간(Date) 타입 다루기]]></title><description><![CDATA[파이썬에서 email.message_from_bytes(데이터)로 획득한 메시지의 시간을 다루는 방법을 알아보자. message_from_bytes로 메일 객체를 msg에 저장했다고 가정한다. 우선 시간은 msg['Date…]]></description><link>https://jiniya.net/ng/2016/06/python-email-date/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/06/python-email-date/</guid><pubDate>Thu, 02 Jun 2016 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;파이썬에서 email.message_from_bytes(데이터)로 획득한 메시지의 시간을 다루는 방법을 알아보자. message_from_bytes로 메일 객체를 msg에 저장했다고 가정한다.&lt;/p&gt;
&lt;p&gt;우선 시간은 msg[&apos;Date&apos;]에 들어있다. 늘 그렇듯이 RFC 형식에 맞춰진 필드 정보지만 바로 datetime으로 바꾸기는 쉽지가 않다. 이때 쓸 수 있는 함수들이 email.utils에 있다. 바로 parsedate_tz와 mktime_tz다. 조합해서 만들어보면 msg 객체의 Date를 안전하게 datetime으로 변환하는 방법은 다음과 같다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;py&quot;&gt;&lt;pre class=&quot;language-py&quot;&gt;&lt;code class=&quot;language-py&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; email&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;utils &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; parsedate_tz&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mktime_tz
timestamp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; mktime_tz&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;parsedate_tz&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;Date&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이렇게 획득한 타임스탬프 갚은 datetime의 fromtimestamp로 변환해서 사용하면 된다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] UTF-8 INI 파일 다루기]]></title><description><![CDATA[A/W 함수 윈도우 API는 문자열을 다루는 경우에 크게 두 종류의 함수를 제공한다. A/W 함수가 그것이다. A 함수는 멀티바이트로 문자열을 처리하는 함수를 의미하고, W 함수는 UTF-16 방식으로 문자열을 처리하는 함수를 의미한다. A…]]></description><link>https://jiniya.net/ng/2016/06/utf-8-ini-file/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/06/utf-8-ini-file/</guid><pubDate>Wed, 01 Jun 2016 15:00:01 GMT</pubDate><content:encoded>&lt;h3&gt;A/W 함수&lt;/h3&gt;
&lt;p&gt;윈도우 API는 문자열을 다루는 경우에 크게 두 종류의 함수를 제공한다. A/W 함수가 그것이다. A 함수는 멀티바이트로 문자열을 처리하는 함수를 의미하고, W 함수는 UTF-16 방식으로 문자열을 처리하는 함수를 의미한다. A 함수는 파라미터 타입으로 char를 W 함수는 wchar_t를 사용하기 때문에 크게 헷갈릴 일도 없고 직관적이다.&lt;/p&gt;
&lt;p&gt;윈도우는 기본적으로 제공하는 ini 파일 조작 API 관련해서 아래와 같이 이런 두 종류의 API를 제공하고 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;WINBASEAPI
DWORD
WINAPI
&lt;span class=&quot;token function&quot;&gt;GetPrivateProfileStringA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    __in_opt LPCSTR lpAppName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    __in_opt LPCSTR lpKeyName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    __in_opt LPCSTR lpDefault&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;__out_ecount_part_opt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nSize&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; LPSTR lpReturnedString&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    __in     DWORD nSize&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    __in_opt LPCSTR lpFileName
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

WINBASEAPI
DWORD
WINAPI
&lt;span class=&quot;token function&quot;&gt;GetPrivateProfileStringW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    __in_opt LPCWSTR lpAppName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    __in_opt LPCWSTR lpKeyName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    __in_opt LPCWSTR lpDefault&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;__out_ecount_part_opt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nSize&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; LPWSTR lpReturnedString&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    __in     DWORD nSize&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    __in_opt LPCWSTR lpFileName
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;그렇다면 ini 파일의 포맷은?&lt;/h3&gt;
&lt;p&gt;GetPrivateProfileStringA 함수를 사용하면 멀티바이트 형태로 내가 원하는 값들을 지정하고 거기에 해당하는 결과 값을 멀티바이트 형태로 받을 수 있다. 반대로 GetPrivateProfileStringW 함수를 사용하면 UTF-16 형태로 지정하고 결과를 받을 수 있다. 여기까지만 생각하면 심플하고 복잡할 것도 없지만 조금만 더 호기심을 가져보면 뭔가 애매모호한 것들이 많다. 바로 파일의 형태다.&lt;/p&gt;
&lt;p&gt;lpFileName으로 지정하는 파일은 어떤 형태여야 할까? 어떤 코드페이지로 작성된 멀티바이트 ini 파일도 딱딱 맞춰서 읽을 수 있을까? UTF-8 UTF-16 등으로 작성된 유니코드 파일도 마법처럼 인식해줄까? 아니면 A 함수는 멀티바이트 ini 파일에만 써야 하고 W 함수는 UTF-16 ini 파일에만 써야 할까? 등등의 무수히 많은 질문이 올 수 있다.&lt;/p&gt;
&lt;p&gt;아마 대부분의 프로그래머가 해당 API를 사용하면서 그런 의문을 품지는 않았을 것 같다. 왜냐하면 대충 쓰면 적당히 동작하기 때문이다. 그래서 그런지 MSDN에도 lpFileName으로 지정할 수 있는 파일의 형태에 대해서는 어떠한 언급도 없다. 하지만 컴퓨터의 세계에서 적당히 대충은 항상 문제를 일으킨다. 그래서 조금 깊이 있게 살펴보자.&lt;/p&gt;
&lt;p&gt;윈도우에서 제공하는 ini 파일을 다루는 API는 딱 두 종류의 파일에 대해서만 처리할 수 있도록 설계되어 있다. 하나는 시스템 코드페이지로 작성된 멀티바이트(ANSI) ini 파일이고, 다른 하나는 UTF-16으로 작성된 ini 파일이다. 이는 A/W 함수에 상관 없이 사용된다. ini API 내부적으로 파일을 열 때에 RtlIsTextUnicode를 사용해서 파일에서 읽은 내용이 UTF-16인지 아닌지를 판별한다. UTF-16인 경우에 A 함수를 호출하면 파라미터를 RtlAnsiStringToUnicodeString 함수를 사용해서 변환해서 사용하고, 멀티바이트 파일이 인 경우에 W 함수를 호출하면 반대로 RtlUnicodeStringToAnsiString 함수를 사용해서 파라미터를 내부적으로 변환한다.&lt;/p&gt;
&lt;h3&gt;UTF-8 ini 파일을 다루는 방법&lt;/h3&gt;
&lt;p&gt;그렇다면 윈도우 ini API를 사용해서 UTF-8 ini 파일을 다룰 수는 없는 것일까? 결과론적으론 그렇다. 왜냐하면 API 내부적으로 UTF-8 변환을 지원하지 않기 때문이다. 하지만 대체로 많은 경우에 섹션 이름이나, 키 이름 같은 경우는 영어를 사용하는 것이 관례이고, 키에 해당하는 값에만 ANSI 문자가 아닌 다른 문자가 포함되는 경우가 많다. 이렇게 한정된 조건을 가진 UTF-8 ini 파일의 경우에는 윈도우 ini API를 사용해서 조작하는 것이 가능하다.&lt;/p&gt;
&lt;p&gt;사용하는 방법은 간단하다. W 함수를 사용하면 안 된다. 왜냐하면 내부적으로 UTF-8로 인코딩 된 것을 UTF-16으로 디코딩하려고 시도할 것이기 때문이다. 그러니 무조건 A 함수를 사용하고 받은 멀티바이트 결과 값을 MultiBytesToWideChar 등의 함수로 UTF-8을 디코딩해서 UTF-16 문자열로 처리하면 된다.&lt;/p&gt;
&lt;p&gt;요약하면 저장할 때에는 유니코드 문자열을 UTF-8로 인코딩한 다음 ini A계열 함수를 사용해서 저장하면 되고, 읽을 때에는 ini A계열 함수를 사용해서 읽은 값을 UTF-8로 디코딩해서 유니코드 문자열로 변환해서 사용하면 반쪽짜리 UTF-8 ini 파일을 처리할 수 있다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[정보] XIGNCODE에 관한 오해 2]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2016/03/misunderstanding-about-xigncode-4/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/03/misunderstanding-about-xigncode-4/</guid><pubDate>Mon, 28 Mar 2016 15:00:01 GMT</pubDate><content:encoded>&lt;h3&gt;듀얼 프로텍션&lt;/h3&gt;
&lt;p&gt;게임사의 고유 보안 프로그램과 외부 보안 프로그램을 같이 쓰는 것은 어느 한 쪽의 성능이 나쁘기 때문만은 아닙니다. 당연한 일이겠지만 여러분이 집을 보호한다고 할 때 보안은 여러 단계에 걸쳐서 이루어지면 이루어질수록 좋기 때문입니다. 대문에도 경비를 두고, 거실 입구에도 경비를 두고, 안방 문 앞에도 경비를 둘 때, 단순히 대문 앞에만 경비를 둔 것 보다는 도둑이 침입하기 더 어려운 것과 같은 이유입니다. 거기다 외부 보안 솔루션의 경우 게임 내부를 볼수는 없기 때문에 일정 수준 게임 내부와 밀접하게 연계된 부분을 검사하는데에는 한계가 있을 수 밖에 없습니다. 이런 부분에 대해서는 게임사 내부에서 직접적으로 보안 코드를 작성하는 것이 효율적이기 때문에 두개의 보안 장치를 만들어서 사용하고 있는 추세입니다.&lt;/p&gt;
&lt;h3&gt;스팀 연동&lt;/h3&gt;
&lt;p&gt;XIGNCODE3는 스팀 게임과 연동을 지원합니다. 과거에 스팀에 연동된 게임이 있으며 현재에도 연동해서 사용하는데에 아무런 문제가 없습니다. 현재에도 스팀에서 서비스 중인 게임이 있습니다. 스팀 연동이 불가능하다는 것은 사실이 아닙니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./se.png&apos; data-alt=&apos;게임을 삭제해도 xhunter1.sys는 계속 상주한다?&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 480px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/0a126a0413acf6ac418935efcc15afb0/9aebd/se.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 60.526315789473685%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACvUlEQVR42kVRW0hTcRj/GxXRQ+BDteipt4SMIDVGPRUahhI+pD6I4IxMG5g2pFGaq6UIdqOSrCjB1C4PJZk3yhvonLudbWcXze24ne3MnXN2zs7Zztn1bB0t8sfHd+P3fR/8PuBevEOtKMIrzYyuhTO1iR5baF6fbrJ9vWr+VGf6WOcZb/BPX/dOXMPn5ME5uX/mhm+q0aqS2e7LQJJBUnE2wYfiHMnSmJDikzEqSpMtZ561Fj5tO/u88URvS8GTuxf6yve2XQStpUBxKUdRAhS1R26BdIzMZLdgg63lxdK6mqqKy2VhOjo3uPbzvW12cHXyDTz9Fp774PzctTLUqRlRLY+oNEMd2i/qCZDiycWFidcvVLLa6mNHc3fvypFIJAxDewNuFEO9PsSHoSEGD+A+r9+9iaMev4sMB3Aaj0UCIBOn9HpNe0dDWYlUWlSUe2A/AECpVJohs8EAmQxGnU4MEAzbpiannXYnBFm0Gg1sW01yBIBc9gHIvbRBDo/NvuruLM6T5B3c0/WgE0Hcer3e4XAgCKJb0dpsjoX5eYvFAkFmixkiQoyQCIFHP8bW4umHKvWpUrn6Zv1Aj7K/reZdr8rucC5rlkRARqPVCuu02mWt1mQ0oj6fH0U3g2QqRoCF+XGtaf10xeP8giq1vLq/XX7lXL6sXiZKGCRCdJglSIplI5EIy/G8GARB2NY3KyoNOBod/jZfWtFUeb6wUnq8u6Hq0D6gUquDsazBE/2NJ9xkMi38fcgWMpmMOC/WW5eTHC62Xt6uP3l4X1/PPZZlf83MUiFym5cVSTtzO8j8u5ziCTELU/To6HecJP+vR30BLIBH+QQb4UXbxEM4QUe5eCTKB/EQFeZYyg8SzHo6QQspJpsVhERY3CV+PskTXrfVh8A0jpABF4UjKAJjXgdNbFBBBPPYccxFYeY/fk8ddBDbbioAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;게임을 삭제해도 xhunter1.sys는 계속 상주한다?&apos; title=&apos;&apos; src=&apos;/static/0a126a0413acf6ac418935efcc15afb0/9aebd/se.png&apos; srcset=&apos;/static/0a126a0413acf6ac418935efcc15afb0/08678/se.png 190w,
/static/0a126a0413acf6ac418935efcc15afb0/2edd7/se.png 380w,
/static/0a126a0413acf6ac418935efcc15afb0/9aebd/se.png 480w&apos; sizes=&apos;(max-width: 480px) 100vw, 480px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;게임을 삭제해도 xhunter1.sys는 계속 상주한다?&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;xhunter1.sys 드라이버는 게임을 켜면 로드되고 게임을 종료하면 언로드 됩니다. 해당 사실은 &lt;a href=&quot;http://www.nirsoft.net/utils/driverview.html&quot;&gt;driverview&lt;/a&gt; 등의 프로그램을 이용하면 손쉽게 확인할 수 있습니다. 게임 실행 후에 목록을 보면 xhunter1.sys가 로드돼 있고, 게임 종료 후에 보면 xhunter1.sys가 시스템에서 언로드 됩니다. 시스템에 지속적으로 남아서 모니터링을 하거나 CPU 자원을 소모하거나 하지 않습니다.&lt;/p&gt;
&lt;h3&gt;차단 근거 미표시&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/ng/2016/03/misunderstanding-about-xigncode/&quot;&gt;지난 글에서도&lt;/a&gt; 적었지만 현재 서비스 중인 게임 중에도 아래와 같이 차단 근거가 표시되도록 설정된 게임도 존재합니다. 따라서 차단 근거를 무조건적으로 표시하지 않는다는 사실은 잘못된 사실입니다. 해당 사항은 옵션으로 처리돼 있으며 표시할 수도 있고, 하지 않을 수도 있는 사항입니다.&lt;/p&gt;
&lt;p&gt;se
Figure 1. CheatEngine이 차단된 경우의 표시 화면
윈도우 10 지원
윈도우 2000을 제외한 윈도우 XP부터 윈도우 10까지 모든 윈도우 버전을 정식 지원하고 있습니다. 따라서 XIGNCODE3 때문에 윈도우 10에서 게임을 정상적으로 구동할 수 없다는 것은 사실이 아닙니다.&lt;/p&gt;
&lt;h3&gt;스플래시 이미지&lt;/h3&gt;
&lt;p&gt;스플래시 이미지는 고객사에서 설정할 수 있는 옵션 사항입니다. &lt;a href=&quot;http://www.wellbia.com/home/ko/pages/xigncode3-reference/&quot;&gt;홈페이지에&lt;/a&gt; 소개된 상당수 이미지가 고객사에서 직접 제작한 스플래시 화면입니다. 스플래시 화면을 지정하지 않을 경우 기본 이미지가 출력되며, 고객사에서 스플래시 이미지를 설정을 원하는 경우 해당 이미지를 사용하고 있습니다. 이 또한 옵션 사항입니다. &quot;대표 이미지 채택 이벤트&quot;라는 이벤트는 진행된적이 없습니다.&lt;/p&gt;
&lt;h3&gt;출시일?&lt;/h3&gt;
&lt;p&gt;XIGNCODE는 2007년 2월에 개발 시작하였으며, 2008년 3월에 1.0 버전이, 2009년 3월에 2.0 버전이, 2010년 6월에 지금의 XIGNCODE3 버전이 출시되었습니다. 2013년 3월에는 안드로이드 제품인 &quot;XIGNCODE for Android&quot;가 출시되었습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[정보] XIGNCODE 디지털 서명에 관한 오해]]></title><description><![CDATA[커널 모드 드라이버 개발을 하는데에 디지털 서명은 필수적입니다. 왜냐하면 6…]]></description><link>https://jiniya.net/ng/2016/03/misunderstanding-about-xigncode-3/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/03/misunderstanding-about-xigncode-3/</guid><pubDate>Mon, 28 Mar 2016 14:00:01 GMT</pubDate><content:encoded>&lt;p&gt;커널 모드 드라이버 개발을 하는데에 디지털 서명은 필수적입니다. 왜냐하면 64비트 운영체제 부터는 합법적으로 서명이 되지 않은 드라이버는 동작하지 않기 때문입니다. 즉, 아무리 잘 만들어 놓은들 디지털 서명을 받지 않았다면 컴퓨터에서 로드해서 사용할 수 없다는 이야기입니다. 그러니 응당 디지털 서명은 기본 중의 기본이겠지요. 저희가 제공하는 파일 중에 사용자가 접할 수 있는 모든 파일은 VeriSign 인증서를 통해서 서명이 된 후에 배포됩니다. 그러니 적합하지 않은 형태로 디지털 서명이 되어 있다거나 디지털 서명이 되어 있지 않다거나 하는 이야기는 사실이 아닙니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./cert1.png&apos; data-alt=&apos;Figure 1. xhunter1.sys 파일의 등록 정보&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 484px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/bfe6d551fa2e283f9979384c0e8b83d9/6ad3c/cert1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 121.05263157894737%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAYCAIAAAB1KUohAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACP0lEQVR42u1UyW4TQRD1n3ILESSII2cO/AKfEAkJzmFREic4jrFBJI6dzDiz9Cw9q2ezZ+2N8jgEGSVSzoinp1aVpl5XTXdXdfDgdTJ6Ffefx4Pd5NuLaLCbjV463WfS/rbycVv59FTe3zIPtpPB7ry/EwFPd+LRjvZ26+LNk45z9V6enAXmuXUzRFLfVoba9SnYs/GxLg3meBriSeRsEl9mc8WVPnQ89QTZ8TIvF3mZLYtlXmA3iNPc8cJwnlU1Lyv2F4uSlES4Nyed2OxRLhxsI6QzShkDMs6oEJxzMBislJJNNlwITznsRMZXBpbr6qBGKC+KhtA0yxaLZRCECBmmZdWENC1r0jQNqaqKMOEr3ZVYCKFp6uV4MpvNTNO0bcvzfdO0wJ4CJlPQS7IsyZKqqbCbYZq34tjoQYlVVdIWpAVti1u7TYt6hWqVF/LX1YYYQsSjAXs2f8RcBL5nPQzbtjHGTgvP87IkIVT4avf2wPJ8mT6MMIpdP7QcD5m24wVRkhIOmY9WYr6qhd1bIW+/RYtSt4NLSe0Pf05kXcdB3oigzdyDAEYJexiEsqJq1szLuijr9p6PVv/cpmCPP7B18H/xvyLm6/f127tHHKETygRtKmiVDcKbgznC1t1J+J1NGs7AhTF00AlRPy1EmhXporpjkpVhtNAQxu58Hi9hmOkGNFQUJTmMN+yGUUYdmGHe9F1oj0NjFJrf7xgYI6z05fPP6uTQUc+sWe9m/AVdH7vawEdD46rroR/Wxd4v0pVIixWqrgIAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 1. xhunter1.sys 파일의 등록 정보&apos; title=&apos;&apos; src=&apos;/static/bfe6d551fa2e283f9979384c0e8b83d9/6ad3c/cert1.png&apos; srcset=&apos;/static/bfe6d551fa2e283f9979384c0e8b83d9/08678/cert1.png 190w,
/static/bfe6d551fa2e283f9979384c0e8b83d9/2edd7/cert1.png 380w,
/static/bfe6d551fa2e283f9979384c0e8b83d9/6ad3c/cert1.png 484w&apos; sizes=&apos;(max-width: 484px) 100vw, 484px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 1. xhunter1.sys 파일의 등록 정보&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./cert2.png&apos; data-alt=&apos;Figure 2. xhunter1.sys 디지털 서명 정보&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 484px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/def56b1d18141516d31dacd49e685887/6ad3c/cert2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 115.26315789473685%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAXCAIAAACEf/j0AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAC/ElEQVR42o1Ty27bRhTVXzabOkAKufmMfEmAFGgXRVEkQRZdNIlai1KMLGyjdhw9LIqcofgQ3+8Zzgx7KMZyHBtJri6GI4nnzjnn3hlsx8No+nOoHcbTx+HkMNCG4WRoj366eHnw8dXB5auDixc/ktePosmhPx6G2nA7Ga6fPzx5/MPpkweD7Ydf6WwUGOP1+V9YY/ousY5Dc7pda13qmqdr/loLzclNGuOIvN+c/TLwDS1MWFXXyxVxtlGS1WFcZCWvuaqYLCuBLKomLz/LgpW8da6OBgnViloRohd5upjPlovF6cmJ69hVVSKlkm2rvkwl2rZ1r94OYjKpWJunsWiaNE1c17Vt2/M8atGt7zdN096NriLAo0FkathxzmrGhLjv1bvYGzDRGtlSYm5s27KshuMw6GQVa8qaVzWvGb8TTPXg0Bx3O9dphOgLEzf+bbT6Y2r9+d79/Z1zdOlzxko4cBOl2tMWqvW3HvBgDnCWZfPlamUQg1h04yRpXl/H/eA4CqMwRMMAzvNM11cUjhECIYHvJ2kaRlEcx3mel10Ut2gH/hb/QU1/skWp57nw3HHsta5TSh0HffCyPJdSNQ2/BW5b+RV74SF4maZJLZSlcRxJBfA/n8BKCXUdch8Kny6hFo7ouk4IMQwjCHzRgzEkjHeGIdI07cEdRqlulpTcF90TkVLcMgzF0Gd7Y6OpRVGkO4fgE/bwIgxDNAITsLOcwXWxp41iMGa+WFwtl34QodCHy8vl1Wqz2SRpgt9n8zlKw2qxC7Sdi9ZbdWBN7tqTJAnWNMsYY0EQYCqwgQSwyLMMhhVF3tPGFHPZeji5p80Z34np7eoE9lsh5BeCOzDc78G922I3013snvzTN7HLTiqU+76PVoMULp/8/j5DJwQDj45EcVRgVHpwYPwL9awuWXcp70/c14YzEJIC1wcrE7J1lm8GgTmNCxUneZyWX88kLd2oIk56MTeoz9azowE9e2avNHvx1l6OvpnmfDT77++z45fz89Hs+On/ce/9eRE4ijUAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 2. xhunter1.sys 디지털 서명 정보&apos; title=&apos;&apos; src=&apos;/static/def56b1d18141516d31dacd49e685887/6ad3c/cert2.png&apos; srcset=&apos;/static/def56b1d18141516d31dacd49e685887/08678/cert2.png 190w,
/static/def56b1d18141516d31dacd49e685887/2edd7/cert2.png 380w,
/static/def56b1d18141516d31dacd49e685887/6ad3c/cert2.png 484w&apos; sizes=&apos;(max-width: 484px) 100vw, 484px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 2. xhunter1.sys 디지털 서명 정보&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./cert3.png&apos; data-alt=&apos;Figure 3. xhunter1.sys 디지털 서명 인증 경로&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 484px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/85e0b60027a93ae7bb135127cc04ca83/6ad3c/cert3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 122.63157894736842%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAZCAIAAAC+dZmEAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACPUlEQVR42t1Sy27aQBT1Z3bDqiTtvst+SldV1UWkpmmqVIrUKA8SQheVShLAgAGDwRjjGY9tbIzn2bEJFQkQkm2Pjsfj0Zz78D2K/es9Kr1FxbxXeoOud1BpF13vusU8uHqtfs+pRzlYzC8TXObR7x39Q6787pVi1Q6M2s+RdqLfHVnNk37teKAew17BNS4dvSApNyssIKMEGoeK2fnT6tkO9FqdPnQDAD0AvHCKwynZyAiHsYBWUwlB3fPDgdHTO3oQ+FxwSinGOMGYYExJSoKTZeIkZlz4tqpMnIY/iQa9lt7uIAiEoJxhwYlgOEmS2UwuMg6mS0hDE+6PG0owVhMiJj4w9MbBRfXzRXevaHwq6B9PtVqzBx0HAOAHgVgCYxT/E2OSHoWBW6jDw7vpt9tw/yb6Wg5AMJPnnItHYIxJyUJM5Q0mVsAXkNutYs7ki8umBWXyhtiEZ2X+n8Vyzi8UL82ZUCG9hJ/E3GrzNY7jBGdif6yKtVZ4WKfruoZhmMOhaZrjsT1L6H1mWTFlqWlZNly+DqmfM5MnWQXSDp5dT8VDy5HxNK0JIZQ+mUd5hAeR5KfIxN6oqrW7zWaj3dL0TqdvmlEUTVcQLSEMJ/GMpGJo3sYJy4q9f7b/7uxOKkZWJZ0zW1PqRsi+xKLnLNgL5jzP7Gc9VwjheDbFctTPIU4oJTI1GlUVaNVRyJAfoSB+ml4Q2yg2xuFNvdcehv2+pjj1L7B7BfUzqJ9vpd0+NxqnWvlHVz3rV/b/AmPrh6Le9gnhAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 3. xhunter1.sys 디지털 서명 인증 경로&apos; title=&apos;&apos; src=&apos;/static/85e0b60027a93ae7bb135127cc04ca83/6ad3c/cert3.png&apos; srcset=&apos;/static/85e0b60027a93ae7bb135127cc04ca83/08678/cert3.png 190w,
/static/85e0b60027a93ae7bb135127cc04ca83/2edd7/cert3.png 380w,
/static/85e0b60027a93ae7bb135127cc04ca83/6ad3c/cert3.png 484w&apos; sizes=&apos;(max-width: 484px) 100vw, 484px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 3. xhunter1.sys 디지털 서명 인증 경로&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;더욱이 64비트 윈도우 부터는 오브젝트 필터링 콜백이라는 것을 사용하기 위해서는 마이크로소프트에 용도를 통보한 후에 고도를 할당 받아서 사용해야 합니다. 이것은 상기 디지털 서명처럼 반드시 해야 하는 일은 아니지만 정상적인 업체라면 해야 하는 그런 일 입니다. 당연히 저희 또한 마이크로소프트 측에 드라이버의 용도에 관한 통보를 했고 해당 고도를 할당 받아서 사용하고 있습니다. 이는 마이크로소프트 홈페이지를 참고하시면 아래와 같이 정보가 노출되는 것을 알 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./altitude.png&apos; data-alt=&apos;Figure 4. xhunter1.sys 오브젝트 필터링 콜백 고도&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 699px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/b1cda3cee7d4a8ae374aa9e4277bfa95/6a959/altitude.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 18.421052631578945%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAcUlEQVR42nWO2RYDIQhD/f9vrbiw2LGITWdea54CnBuSiKiUUms1s/WTMzOW7i7MY4xY4QclUVGVa87lHhF7b1WrtcEjDrf5mXFQKkStd8QAe2BhyZngReSVM0q9r+sI9xu+O6+HwWfMZtpag0f6+qcvIaTpdvImFRQAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 4. xhunter1.sys 오브젝트 필터링 콜백 고도&apos; title=&apos;&apos; src=&apos;/static/b1cda3cee7d4a8ae374aa9e4277bfa95/6a959/altitude.png&apos; srcset=&apos;/static/b1cda3cee7d4a8ae374aa9e4277bfa95/08678/altitude.png 190w,
/static/b1cda3cee7d4a8ae374aa9e4277bfa95/2edd7/altitude.png 380w,
/static/b1cda3cee7d4a8ae374aa9e4277bfa95/6a959/altitude.png 699w&apos; sizes=&apos;(max-width: 699px) 100vw, 699px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 4. xhunter1.sys 오브젝트 필터링 콜백 고도&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;추가로 인증서 유효 기간에 대해서 말씀 드리면 인증서의 동작 방식은 인증서가 유효한 기간 내에 서명이 된 것인지를 체크하는 구조입니다. 따라서 아래 파일을 보면 인증서가 2014.1.23부터 2016.3.24까지 유효한데 파일은 2015.6.4에 인증되었다는 것을 나타냅니다. 이 파일의 경우 인증서 유효 기간이 지난 후에도 정합성을 인정 받는 파일입니다. 따라서 드라이버 코드가 변경되지 않는 이상 인증서 때문에 새로운 파일을 배포 하거나 할 필요는 없습니다. 더 자세한 내용이 궁금하신 분들은 마이크로소프트 설명 페이지를 참고하시면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./cert4.png&apos; data-alt=&apos;Figure 5. xhunter1.sys 디지털 서명 인증서 유효기간&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/7f94af0715657b52ed4801a93e1717d9/dface/cert4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 60%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACEUlEQVR42j1Ry04UQRSdX/MT3Ctx6cb4Fy5QE3Vn3BlCBBcKigs3hpCwGCAKgyYGAaVfM931nnpXdZW3Z4CTm+ru3Dr3nHt6xH49x2fr/Hyd/VmrJ2+K49f47C07X2t+rU3Hj8nhI3Tyanb0BP1YbY6GopNnZPIUf39Zbz8ckenPKfZFheqZoCJw1UuTlemVz+zqC73YYDLVdYOJMDZo44fSxoQs652R7I7hm1HEKDFG5wEppwgPXW2x83fNFJfFpdLKOWsWsEb5PqvyM5BPmNDOD535fK61dnDL6pCgvc0vN8FIVRVt17Zt10ybqqqEoDBaVUBGEyFtjAEhVBQFnMC3Zkne4hcbKecYnPfeLRBCTAtfqtoZKTSxLgFZSokxJgR3gHZm/FJ5g8vUtjNCaYcQIcRaG4OPt2TnUwwh3wD8I9QOsZXb4u8mZMMZATtCCGD6AfZaWePTDjFwSwnFS2lCYh9gtiy2xOWm67PgbC4lJMIY45w7Z25tnxrXaw1xKkj7WgF27q/JsLPRylgbFgDdvg835O5k8XdiTv1QOYErzjGspcqP8ur90FwkBPqzpqZclNO2xkYUOyPe/pYuz3WCJYfSCd6FDB3P+OKTKj7AvNjH2GfrkzLRQpDGD5Ty60ju35XjB3K8og5W1OGKXNbBPTa+L/fv0NNVUh6Qf9/I1S4t9li5Byctdquz3Xby4j8B8ZAbMewZkgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Figure 5. xhunter1.sys 디지털 서명 인증서 유효기간&apos; title=&apos;&apos; src=&apos;/static/7f94af0715657b52ed4801a93e1717d9/dface/cert4.png&apos; srcset=&apos;/static/7f94af0715657b52ed4801a93e1717d9/08678/cert4.png 190w,
/static/7f94af0715657b52ed4801a93e1717d9/2edd7/cert4.png 380w,
/static/7f94af0715657b52ed4801a93e1717d9/dface/cert4.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Figure 5. xhunter1.sys 디지털 서명 인증서 유효기간&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;그리고 더 많은 기술적인 설명이 필요한 내용인데 드라이버를 정상적인 방식으로 로드하기 위해서는 반드시 레지스트리에 그 값을 기록해야 합니다. 그래야 윈도우에서 그 정보를 알고 드라이버를 로드해 주기 때문입니다. 더 자세한 내용을 설명하기 위해서는 너무 많은 기술적인 내용을 설명해야 하기에 이쯤에서 줄이도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;그러니 더 이상 디지털 서명이 잘못된 파일이라던지 드라이버가 잘못된 형태로 운용되고 있다는 오해는 가지지 않았으면 하는 바램입니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[정보] XIGNCODE 요구 권한에 관한 오해]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2016/03/misunderstanding-about-xigncode-2/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/03/misunderstanding-about-xigncode-2/</guid><pubDate>Sat, 26 Mar 2016 14:00:01 GMT</pubDate><content:encoded>&lt;p&gt;권한에 관해서 궁금해 하시는 분들이 많이 계신 것 같습니다. 도대체 왜 일게 서드파티 보안 프로그램이 그것도 시스템의 모든 곳에 접근할 수 있는 &quot;관리자 권한&quot;을 요구하는지에 대해서 의문이 없다면 그게 더 이상한 일일 겁니다. 저라도 당연히 의문을 가졌을 것 같습니다. 그래서 오늘은 그런 권한에 얽힌 오해를 조금 풀어보려고 합니다.&lt;/p&gt;
&lt;h3&gt;권한이란 무엇이고 왜 필요할까?&lt;/h3&gt;
&lt;p&gt;이 글을 컴퓨터에 관한 전문 지식이 없는 분들도 보실 수 있기에 권한 이라는 것이 정확하게 어떤 것이고 왜 필요한지에 대해서 먼저 설명을 드려야겠습니다. 권한은 쉽게 말하면 방문을 여는 키와 같다고 보시면 됩니다. 집에 방이 세 개 있다고 가정해 봅시다. A, B, C라는 방이죠. 여기에서 아빠는 A, B, C에 모두 들어갈 수 있는 키를 가지고 있고, 아들은 C 방에 들어가는 키만 가지고 있습니다. 이 상황에서 모든 방을 다 들어가 볼 수 있는 사람(여기에서는 아빠)를 관리자 권한이라고 부르며, 일부 제한된 자신의 접근 구역에만 접근할 수 있는 사람(여기에서는 아들)을 사용자 권한이라고 통상적으로 부릅니다. 집에서는 아빠는 잠겨 있는 모든 방에 접근할 수 있지만, 아들은 C에만 접근할 수 있습니다. A, B가 궁금해도 키가 없으니 접근을 하지 못하는 것이죠. 컴퓨터에서도 마찬 가지입니다. 어떤 파일을 읽기 위해서는 권한이 필요합니다. 거의 대부분의 파일을 읽을 수 있는 권한이 관리자 권한, 자신의 파일만 읽을 수 있는 것이 사용자 권한이죠.&lt;/p&gt;
&lt;p&gt;자 이제 앞의 상황에서 도둑이 들어서 어떤 방에 숨어있다는 다소 엉뚱하면서도 황당한 상상을 해 봅시다. 도둑이 A나 B 방에 숨고, 문을 잠궈버렸다면 아들은 도둑을 발견할 수 있을까요? 없을까요? 당연히 없을 겁니다. 반대로 C 방에 숨었다면 아들도 발견할 수 있습니다. 하지만 아빠의 입장은 다릅니다. 도둑이 어디에 숨어있든지 방문을 열고 볼 수 있기 때문에 도둑을 찾을 수 있습니다. 결국 권한이 높다는 것은 더 많은 것을 찾고 발견할 수 있다는 것을 의미합니다.&lt;/p&gt;
&lt;p&gt;게임 보안 솔루션이 권한을 요구하는 것도 동일합니다. 매크로나 해킹툴을 사용하여 게임 경험을 해치는 불법 사용자를 가려내는 것이 저희의 임무입니다. 권한이 낮다면 앞에서 아들과 같이 불법 사용자가 C방에 숨은 경우만 찾아낼 수 있습니다. 반대로 관리자 권한을 가졌다면 어디에 숨어있든지 찾아낼 수 있을 겁니다.&lt;/p&gt;
&lt;h3&gt;빈대 잡으려다 초가삼간 태우는게 아닌가?&lt;/h3&gt;
&lt;p&gt;이런 권한의 메커니즘을 이해한 다음의 문제는 조금 철학적입니다. 높은 권한이 있다면 더 많은 부분을 검사해서 발견해 낼 수 있다는 건 알겠지만 그게 과연 옳은 결정이냐는 것입니다. 여기에 대한 가치 판단은 저마다 다르고 상황마다 다를 수 있습니다.&lt;/p&gt;
&lt;p&gt;일반적으로 해킹툴이 별로 없고 거의 대다수 사용자가 정상 플레이를 하고 있는 게임이라면 당연히 권한을 최소한으로 요구하는 것이 맞을 겁니다. 왜냐하면 게임 플레이를 하면서 해킹툴 사용자를 만날 일도 별로 없는데 높은 권한으로 많은 검사를 할 필요가 없기 때문입니다. 반면에 해킹툴이 너무 많고 거의 대부분의 사용자가 어떻게든 불을 켜고 해킹툴을 사용하려는 게임이라면 관리자 권한을 요구할 수도 있을 겁니다. 물론 관리자 권한을 요구한다고 그런 모든 것을 발견하고 막을 수는 없겠지만 어쨌든 발견할 수 있는 확률은 높아지니까요.&lt;/p&gt;
&lt;p&gt;결국 요약하면 이런 겁니다. 높은 권한은 해킹툴을 발견할 가능성이 높아지지만 사용성이 떨어지고, 낮은 권한은 해킹툴을 발견할 가능성은 낮아지지만 사용성은 높아지는 겁니다. 즉, 이는 어떤 한 가지를 일방적으로 고수할 문제가 아니라 그 사이에서 게임 운영자가 자신들의 게임에 맞게 적당히 절충하면 되는 문제입니다. 음, 우리 게임은 해킹툴 사용자가 너무 많으니까 지금 당장은 높은 권한을 유지해서 발견 가능성을 높이자라던지, 아니면 우리 게임은 거의 대부분이 선량한 사용자니까 낮은 권한으로 하돼 추후 문제가 생기면 다시 조정하겠다는 것과 같이 말이죠. 결국 여기에는 절대적으로 옳은 정답은 없으며 각각의 상황에 맞춰서 해킹툴 발견 가능성과 사용성 중에서 어느 것을 더 중시할지를 고르면 되는 문제입니다.&lt;/p&gt;
&lt;h3&gt;옵션&lt;/h3&gt;
&lt;p&gt;결국 앞의 절충의 문제라는 것 까지 이해했으면 솔루션 개발자 입장에서의 정답은 무엇일까요? 옵션입니다. 게임 운영자가 자신의 게임 특성에 맞춰서 적절하게 설정해서 사용할 수 있도록 만들어 주는 것이죠. 고정해 놓는 것이 아니라 변동 가능하도록 구성하는 겁니다. XIGNCODE3도 마찬가지 입니다. 다양한 고객사들의 입맞에 맞추기 위해서 권한 레벨을 아래와 같이 세 분류로 조정해서 적절하게 설정해서 사용할 수 있도록 가이드를 해드리고 있습니다. 낮음으로 사용하시길 원하는 경우에는 게임 권한 설정에 따라서는 아예 &quot;관리자 권한&quot;을 요구하지도 않으며 &quot;커널 모드 드라이버&quot;를 설치 및 로드하지도 않습니다. 보통 단계는 얻을 수 있는 상황인데 얻지 못하면 페널티가 주어지는 것이며, 높음 단계는 항상 &quot;관리자 권한&quot;을 요청하는 단계입니다. 그러니 저희가 무조건적으로 &quot;관리자 권한&quot;을 요구한다는 것은 정확한 사실이 아니라는 점 꼭 기억해 주셨으면 좋겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./auth-level.png&apos; data-alt=&apos;XIGNCODE3 권한 범위&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 568px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f9e6a209b7ef4b64b2adf9595e137375/d63a8/auth-level.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 61.578947368421055%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAB3UlEQVR42oVSS5KiQBDljC4M2nbhCZgzeAmvMh1h9Ah0qIvpcOcngOL/VaCKls+ATDiv0FnMal4FSVZmVuarzBKiKIqjaLlcbrfb729vlLLr9fr1PxRFUde1wBgLggApggFDKo44jv+Rj/XXFYYhpVRYLBaz2UySvkmSNB6PXx+YTERRxF8UXyBfJhNue/pep9PpaDSaz+fC8XDY7/e73W6z2cjySlVVWVF+vL/LsgzLh6oqisIllvqBq8mr1Xq9Rtjnz08B1O/3e5LEWZZBr6uyLKuqrH5xNG3bVnXVNE1VcQkT3M2gIVCAte97XADW2+3WdV2L1XWIw8nuibbvuQ8WKFz+7hHwrBxFoW3bjus4jqvruqHr2JqmSUzi2Lbne3DYtgULWuW5rmVZvu8L6DsywWfohmEQdDLP80uaUsag4C6UUYyG8W3GCoYhMcoBl+AHweVywQA0TTscDoSYvu+BBIrEceIBvoe0tmWhNDihJiEEdRzXfdJGQYSBGjFNx7Y0TcdhHuE4aZalAyjN0zRDZc4nzXLMGQ8DDuQ7no66pmFsBiGn0wknTdDg9WNcD+yCwE/i5Hw+o0ySJGEUCWBfVTXcPJq3iBTFF+jwOeFrmnIAhoLuPHS838f2Dw/XatY41aJeAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;XIGNCODE3 권한 범위&apos; title=&apos;&apos; src=&apos;/static/f9e6a209b7ef4b64b2adf9595e137375/d63a8/auth-level.png&apos; srcset=&apos;/static/f9e6a209b7ef4b64b2adf9595e137375/08678/auth-level.png 190w,
/static/f9e6a209b7ef4b64b2adf9595e137375/2edd7/auth-level.png 380w,
/static/f9e6a209b7ef4b64b2adf9595e137375/d63a8/auth-level.png 568w&apos; sizes=&apos;(max-width: 568px) 100vw, 568px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;XIGNCODE3 권한 범위&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[정보] XIGNCODE에 관한 오해들]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2016/03/misunderstanding-about-xigncode/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/03/misunderstanding-about-xigncode/</guid><pubDate>Fri, 25 Mar 2016 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;최근 게임 커뮤니티에서 저희 제품에 대한 오해가 많이 생기고 있는 것 같습니다. 게이머들이 좋아하는 보안 제품을 만드려고 했는데 오해만 잔뜩 키운것 같아서 한 명의 게이머로써 착찹한 생각이 많이 듭니다. 건설적인 비판은 새겨 들어야겠지만 원색적인 비난이나 잘못된 사실로 인한 오해는 바로 잡을 필요가 있다고 생각됩니다. 특히나 최근 제 개인 메일이나 블로그 댓글로 문의가 많이 와서 여기에 최근 게이머들 사이에서 유통(?!)되고 있는 대표적인 몇 가지 오해에 대한 해명을 해볼까 합니다.&lt;/p&gt;
&lt;h3&gt;SSD 수명을 단축시킨다.&lt;/h3&gt;
&lt;p&gt;일반적으로 SSD의 경우 재기록 가능 회수가 한정되어 있습니다. 재기록 가능 회수란 쉽게 말하면 점토판에 쓰여진 내용을 지우고 다른 내용을 기록하는 것을 말합니다. 그 회수가 10번이라면 지우고 새로운 내용을 기록하는 것을 10번하고 나면 새 점토판을 사야 한다는 의미입니다. 여기에서 중요한 것은 내용을 지우고 새로 기록하는 회수가 한정되어 있다는 의미입니다. 따라서 적혀져 있는 내용을 읽는 것과 수명은 크게 상관이 없습니다.&lt;/p&gt;
&lt;p&gt;일반적인 보안 프로그램의 경우 디스크에 존재하는 프로그램의 정체(?!)를 파악하기 위해서 해당 파일의 내용을 읽습니다. 단순히 읽기 동작만 있을 뿐 랜섬웨어처럼 해당 파일의 내용을 변경하고 새로 기록하는 등의 행위를 하지는 않습니다. 따라서 이는 앞선 비유에 따르면 순수하게 점토판의 내용을 읽는 것과 동일하므로 SSD의 수명과는 크게 상관이 없습니다.&lt;/p&gt;
&lt;p&gt;요약해보면 여러분이 사용하는 SSD의 수명은 토렌트나 랜섬웨어, 다운로드 프로그램에 의해서 단축될 수 있지만 파일의 내용을 주로 읽기만 하는 보안 제품 때문에 수명이 일반적이지 않은 수준으로 단축되는 일은 없습니다. 저희 제품도 마찬가지구요. 그러니 안심하셔도 됩니다.&lt;/p&gt;
&lt;h3&gt;동영상 파일에 접근 하고 심지어는 그 파일을 외부 서버로 전송한다.&lt;/h3&gt;
&lt;p&gt;여러분의 동영상 파일이나 개인 데이터 파일에 아무 이유 없이 접근하지는 않습니다. 일부 조건들이 충족될 경우 해당 파일들이 검사 대상 목록에 추가되기도 합니다. 하지만 이렇게 말해도 여전히 실행 파일도 아닌 동영상 파일에 접근하는 이유가 이해가 되지 않으실 수 있습니다. 아이러니하게도 저희가 동영상 파일을 읽은 이유는 해당 파일이 진짜 동영상 파일이 맞는지 확인하기 위함입니다.&lt;/p&gt;
&lt;p&gt;일반적으로 avi, mp4 등의 확장자는 동영상이라고 생각하지만 사실 해당 파일들의 내용물이 동영상이 아닌 실행 가능한 코드인 경우도 존재합니다. 그리고 그런 것들이 탐색기에 의해서는 실행되지 않지만 특수한 목적으로 제작된 프로그램에 의해서는 실행이 가능해 지기도 합니다. 따라서 파일의 확장자가 아닌 진짜 파일의 정체를 알아내기 위해서는 해당 파일의 일부를 읽는 동작을 할 수 밖에 없습니다. 이는 로컬 PC에 존재하는 파일의 형태를 파악하기 위함이지 다른 목적은 전혀 없습니다. 더욱이 많은 사용자 분들께서 오해하고 있는 것처럼 해당 파일을 외부 서버로 전송하거나 하는 일은 없습니다.&lt;/p&gt;
&lt;h3&gt;개인 정보를 유출시킨다.&lt;/h3&gt;
&lt;p&gt;인터넷을 통해서 연결이 가속화될수록 개인 정보는 점점 더 중요한 이슈로 부각됩니다. 연결을 위한 욕망 만큼이나 개인 정보를 보호하고 싶은 욕망도 강하지요. 어쨌든 이런 이유로 많은 국가에서 다양한 형태로 개인 정보에 대한 법적 규제를 가지고 있습니다. 잘 아시겠지만 우리가 즐기고 있는 게임도 더 이상 주먹구구식 코흘리게 사업이 아닙니다. 그말인즉 개인 정보에 관한 법적 규제를 엄격하게 받고 있다는 의미입니다.&lt;/p&gt;
&lt;p&gt;게임에 함께 포함되는 서드파티 제품도 동일한 규제를 적용 받습니다. 개인 정보 보호에 관한 감사를 받으며, 제품 도입 시에 서비스 지역에서 시행되고 있는 개인 정보 보호법에 부합하는지에 대한 법률 검토 또한 함께 받습니다. 따라서 여러분께서 우려하시는 것처럼 개인 정보를 무단 수집하거나 함부로 유출하는 일은 없습니다. 게임이 서비스 되는 지역의 개인 정보 보호법과 게임 내에서 출력되는 최종 사용자 라이선스 계약(EULA)을 엄격하게 준수하고 있습니다. 안심하셔도 됩니다.&lt;/p&gt;
&lt;h3&gt;듀얼 클라이언트를 차단한다.&lt;/h3&gt;
&lt;h3&gt;VMWare, VirtualBox, SandBoxie 등의 정상 프로그램이 탐지된다.&lt;/h3&gt;
&lt;h3&gt;게임에 특정 키보드, 마우스를 사용할 수 없다. (게임사 정책에 의해 사용이 제한된 하드웨어)&lt;/h3&gt;
&lt;p&gt;차단 근거를 표시하지 않는다.
저희는 게임사에 게임 보안에 사용할 수 있는 도구를 제공할 뿐 정책을 제공하지는 않습니다. 위와 같은 내용들은 모두 게임사의 정책에 기인한 것이지 저희가 임의로 설정하는 내용이 아닙니다. 저희가 하는 일은 게임사에서 수립한 정책대로 동작하는 프로그램을 공급하는 것이 전부입니다. 나머지는 모두 저희 권한 밖의 일이랍니다.&lt;/p&gt;
&lt;h3&gt;윈도우 커널 모드 드라이버를 설치한다. 따라서 루트킷이다.&lt;/h3&gt;
&lt;p&gt;보안 제품이 완전한 검사를 수행하기 위해서는 관리자 권한이 필요합니다. 당연한 이야기이겠지만 권한이 낮은 상태에서 권한이 높은 대상을 검사할 수는 없기 때문입니다. 그냥 단순 비유를 들자면 선생님이 학생을 검사할 수는 있지만, 학생이 선생님을 검사하기는 힘든 뭐 그런 것이라고 이해하시면 됩니다. 이러한 완전한 권한을 가지기 위해서 저희 제품 또한 커널 모드 드라이버를 설치하여 로드하고 있습니다.&lt;/p&gt;
&lt;p&gt;여기에 대해서는 기술적인 많은 이야기들이 필요하지만 몇 가지 사실들만 나열하겠습니다. 1) 여러분께서 알고 계시는 거의 모든 게임 보안 제품은 커널 모드 드라이버를 설치합니다. 2) 해당 제품들 중의 일부는 프로세스를 숨기거나 강제 종료를 막거나 키보드 후킹을 하는 등의 루트킷스러운 기능을 가지고 있기도 합니다. XIGNCODE3의 드라이버는 일반적인 윈도우 사용자 경험을 위배하는 이와 같은 기능은 전혀 포함하고 있지 않습니다. 3) XIGNCODE3에 포함된 커널 모드 드라이버 또한 앞서 기술한 것과 마찬가지로 게임사의 정책을 따르고 있습니다. 커널 모드 드라이버 설치를 원하지 않는 게임의 경우에는 게임 실행 시점에 커널 모드 드라이버를 설치 및 로드 하지 않습니다.&lt;/p&gt;
&lt;h3&gt;게임이 끝나도 남아서 계속 모니터링한다.&lt;/h3&gt;
&lt;p&gt;해외 게임 보안 제품 중에 일부 이러한 제품이 있습니다. 하지만 저희 제품은 아닙니다. 여러분이 게임을 종료하는 순간 저희의 모든 기능은 중단됩니다. 남아서 모니터링을 한다거나 시스템 자원을 소모 한다거나 하지 않습니다. 자동 재시작 프로그램으로 등록되지도 않습니다. 저희 제품의 생명 주기는 게임과 완전히 동일합니다. 여러분이 게임을 구동하면 XIGNCODE3가 함께 구동되며 게임을 종료하면 XIGNCODE3도 함께 종료됩니다.&lt;/p&gt;
&lt;h3&gt;해외에서는 사장되었다.&lt;/h3&gt;
&lt;p&gt;이 글을 작성하는 현 시점을 기준으로 저희 제품은 국내보다 해외에 더 많이 공급되어 있습니다. 아프리카를 제외한 거의 모든 지역에서 서비스되는 게임에 탑재되어 있습니다. 따라서 해외에서 사장되었다는 이야기는 정확한 사실이 아닙니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[시스템] 신뢰할 수 있는 루트 인증서 자동 업데이트]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2016/02/disable-root-auto-update/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/02/disable-root-auto-update/</guid><pubDate>Fri, 26 Feb 2016 14:00:01 GMT</pubDate><content:encoded>&lt;p&gt;윈도우에서 신뢰할 수 있는 루트 인증서를 삭제 했음에도 마법처럼 루트 인증서가 계속 생기는 경우가 있다. 신뢰할 수 있는 루트 인증서와 없는 인증서에 대한 업데이트가 자동으로 이뤄지기 때문에 발생하는 현상이다. 테스트를 위해서 이 기능을 꺼버려야 하는 경우가 있는데 그때는 레지스트리에서 설정을 변경해주면 된다. 아래 레지스트리 값들을 이용하면 해당 기능을 오프시킬 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\AuthRoot\DisableRootAutoUpdate&lt;/code&gt;&lt;br&gt;
값 1은 신뢰할 수 있는 CTL의 Windows 자동 업데이트를 사용하지 않도록 설정합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\SystemCertificates\AuthRoot\EnableDisallowedCertAutoUpdate&lt;/code&gt;&lt;br&gt;
값 1은 신뢰할 수 없는 CTL의 Windows 자동 업데이트를 사용하도록 설정합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SystemCertificates\AuthRoot\AutoUpdate\RootDirUrl&lt;/code&gt;&lt;br&gt;
공유 위치(HTTP 또는 FILE 경로)를 구성합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;더 자세한 설명이 필요하다면 아래 페이지를 참고하면 되겠다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://technet.microsoft.com/ko-kr/library/dn265983.aspx&quot;&gt;https://technet.microsoft.com/ko-kr/library/dn265983.aspx&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] 빈 배]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2016/02/empty-boat/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/02/empty-boat/</guid><pubDate>Mon, 15 Feb 2016 14:00:01 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;한 사람이 배를 타고 강을 건너다가&lt;br&gt;
빈 배가 그의 작은 배와 부딪치면&lt;br&gt;
그가 비록 나쁜 기질의 사람일지라도&lt;br&gt;
그는 화내지 않을 것이다.&lt;br&gt;
&lt;br&gt;
그러나 그 배 안에 사람이 있으면&lt;br&gt;
그는 그에게 피하라고 소리칠 것이다.&lt;br&gt;
그래도 듣지 못하면 다시 소리칠 것이고&lt;br&gt;
마침내 욕설을 퍼붓기 시작할 것이다.&lt;br&gt;
&lt;br&gt;
이 모든 일은 그 배안에 누군가 있기 때문에 일어난다.&lt;br&gt;
그러나 그 배가 비어 있었다면&lt;br&gt;
그는 소리치지 않을 것이고 화내지도 않을 것이다.&lt;br&gt;
&lt;br&gt;
세상의 강을 건너는 그대 자신의 배를&lt;br&gt;
그대가 빈 배로 만들 수 있다면&lt;br&gt;
아무도 그대와 맞서지 않을 것이다.&lt;br&gt;
아무도 그대를 상처 입히려 하지 않을 것이다.&lt;br&gt;
&lt;br&gt;
— 장자, 빈 배&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;오늘 발견한 울림이 있는 장자의 글. 장자는 진짜 천재임에 틀림이 없다. 어떻게 저런 생각을 한거지 ㅋㅋ~ 부딪힌 배를 비었다 생각하면 화낼 일도 없고, 내 배를 비우면 싸울 일도 없겠지…​ 하지만 비어 있지 않은걸 비었다 생각하고, 가득 차 있는 것을 비우는 것이 참 쉽지 않다는 게 함은정 ㅋ~ 또 반대로 생각하면 무관심이면 싸울 일도 없겠지만, 애정이 있으니 그나마 치고 박는 건 아닐까라는 생각도 들공…​ 인생 살이라는게 참 쉽지는 않다. 맘대로 되지도 않공.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] PIC 옵션의 정체]]></title><description><![CDATA[gcc에 보면 -fPIC이란 옵션이 있다. PIC 코드를 생성한다는 옵션이다. PIC라는건 Position Independent Code…]]></description><link>https://jiniya.net/ng/2016/01/position-independent-code/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/01/position-independent-code/</guid><pubDate>Mon, 04 Jan 2016 14:00:01 GMT</pubDate><content:encoded>&lt;p&gt;gcc에 보면 -fPIC이란 옵션이 있다. PIC 코드를 생성한다는 옵션이다. PIC라는건 Position Independent Code, 직역하면 위치 독립적인 코드 정도로 나온다. 난 지금껏 이 옵션이 재배치에 관한 옵션인줄 알았다. 즉, -fPIC을 지정하면 재배치 정보가 있어서 아무 주소에나 로드할 수 있고, 지정하지 않으면 고정 주소로 로드되는 뭐 그런걸 상상한 것이다. 한동안 그렇게 잘못된 지식을 가지고도 별 문제 없이 지냈는데 최근에 한 업체와 일을 하면서 잘못 알고 있었다는 것을 깨닫게 되었다. 반성하는 차원에서 PIC 옵션에 관한 내용을 정리해 놓는다.&lt;/p&gt;
&lt;p&gt;우선 PIC라는건 재배치랑은 상관이 없다. gcc에서 so로 모듈을 생성하겠다고 하면 기본적으로 재배치 정보를 포함해서 아무 주소에나 로드할 수 있도록 모듈을 만들어 준다. 그럼 재배치랑 연관 있어 보이는 위치 독립적인 코드란 무엇일까? 결론만 말하면 재배치가 필요 없는 코드라고 보면된다. 그렇다면 재배치가 필요 없는 코드는 어떻게 만들까라는 의문을 가질 수 있다. 그건 &lt;a href=&quot;http://www.jiniya.net/lecture/maso/pe5.pdf&quot;&gt;바이러스&lt;/a&gt; 라는 글의 재배치 섹션에 나와 있는 것과 같은 방법을 사용한다고 보면 된다. 컴파일러가 그 일을 대신해 주는 것이다. RealOffset 같은 함수가 절대 주소 참조 시마다 들어가야 하기 때문에 -fPIC 옵션을 지정할 경우 코드가 커지는 것이다.&lt;/p&gt;
&lt;p&gt;여기까지 읽고 도대체 뭔 소리야, 라고 할지도 모르겠다. 더 자세한 설명은 아래 글을 참고하자.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://eli.thegreenplace.net/2011/08/25/load-time-relocation-of-shared-libraries&quot;&gt;http://eli.thegreenplace.net/2011/08/25/load-time-relocation-of-shared-libraries&lt;/a&gt;&lt;br&gt;
&lt;a href=&quot;http://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries&quot;&gt;http://eli.thegreenplace.net/2011/11/03/position-independent-code-pic-in-shared-libraries&lt;/a&gt;&lt;br&gt;
&lt;a href=&quot;http://eli.thegreenplace.net/2011/11/11/position-independent-code-pic-in-shared-libraries-on-x64&quot;&gt;http://eli.thegreenplace.net/2011/11/11/position-independent-code-pic-in-shared-libraries-on-x64&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] 더 행복한 한 해를 꿈꾸며...]]></title><description><![CDATA[난 내가 하고 싶은 것만 한다. 하기 싫은 건 하지 않는다. 
2…]]></description><link>https://jiniya.net/ng/2016/01/being-happy/</link><guid isPermaLink="false">https://jiniya.net/ng/2016/01/being-happy/</guid><pubDate>Mon, 04 Jan 2016 12:00:01 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;난 내가 하고 싶은 것만 한다. 하기 싫은 건 하지 않는다.&lt;br&gt;
&lt;br&gt;
25년 그리 긴 시간은 아니지만…​
내가 살아오면서 지킨 단 한가지의 원칙이 있다면 저것일 것 같다.
난 하고 싶은 것만 했다. 재밌는 일들만 했고, 재미없는 것들은 하지 않았다.&lt;br&gt;
&lt;br&gt;
거기에 특별한 가치관이나 판단 기준은 없었다.
단지 하고 싶고 재밌으면 하는 것이고, 그렇지 않으면 하지 않는 것이다.&lt;br&gt;
&lt;br&gt;
하지만 오늘 문득 든 생각은 점점 하루하루 더해질수록 저러한 나의 생활 방식에
많은 가치관이 더해진다는 점이다. 하기 싫지만 xx때문에 해야 하고,
하고 싶지만 yy때문에 못하는 일들이 점점 늘어나는 것이다.&lt;br&gt;
&lt;br&gt;
이런 생각이 들자 순간 기분 나빴다.
그래서 난 과감하게 14만원, 계절학기 6학점을 머릿속에서 지워버렸다.
없던 일로 하기로 했다. 재미없는 수업이고 그다지 하고 싶지 않아서였다.&lt;br&gt;
&lt;br&gt;
포기하면 이렇게도 마음이 가벼워 지는 것을 왜 굳이 꼭 쥐고 있었나 모르겠다…​
그 일 외에도 즐길만한 일들이 산더미 처럼 쌓여 있는데…​ ㅡ.ㅡ#&lt;br&gt;
&lt;br&gt;
— 사탕... 2005&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;25살에 당차게 저런 생각을 했던 나의 35살, 2015년은 그때와는 사뭇 달랐다. 이유가 붙어서 어쩔 수 없이 해야만 하는 일이 줄기차게 늘어났고 나를 위한 시간은 정말 쥐꼬리만큼도 없었다. 게다가 그 모든 일들은 계절학기처럼 쉬이 포기할 수 있는 일들도 아니었다. 더러 잠깐 포기하는 경우에는 주변에서 엄청난 비난과 원망을 들어야 했다. 그런 시간이 오래되니 나중에는 마치 내가 무얼 좋아하는지도 모르는 사람처럼 돼 버렸다. 무엇을 할 때 행복한지도 기억하지 못하는 좀비처럼 말이다. 그런 내가 측은해 보였다. 남이야 뭐라든 나라도 재밌어야 주변 사람도 재밌게 해줄 수 있지 않을까? 내가 호흡기를 해야 내 아이도 해 줄 여유가 생기는 법처럼 말이다. 그래서 새해 벽두엔 모든 핀잔과 원망을 뒤로한체 드라마 정주행을 했다. 물론 상당한 외압이 있었지만 나는 행복했다.&lt;/p&gt;
&lt;h3&gt;리멤버: 아들의 전쟁&lt;/h3&gt;
&lt;p&gt;포토닉메모리(본 것은 죄다 기억하는)를 가진 주인공이 알츠하이머에 걸린 아버지의 누명을 풀기 위해서 변호사가 되어서 복수를 하는 내용의 법정 드라마다. 포토닉메모리를 가진 주인공으로 훈훈한 유승호 나와 주시고, 히로인으로 더 훈훈한 박민영씨가 출연해 주신다. 일단 주연 배우들의 비주얼이 훈훈해서 먹고 들어가는데 내용 또한 그렇게 구리진 않다. 퍼즐 조각을 엮기 위한 억지스러운 설정으로 보여지는 부분들도 있지만 대체로 개연성있게 스토리가 진행된다. 스토리 진행이 엄청 빠르다는 건 덤. 거기다 와이프 말마따나 코리안 멜로 코드가 아직까지는 많지 않다. 끝으로 최신 유행하고 있는 베테랑 흥행 코드가 깔려 있다. 유승호가 싸우는 세력이 재벌2세다. 그리고 조연으로 나오는 박성웅씨 의상, 연기가 압권이다, 황정민삘난다. 여튼 이런 전차로 1회 보고 나서 냅다 6회까지 정주행했다. 7회 분이 이번주 수욜 방영하는데 본방 사수할 것 같은 드라마…​&lt;/p&gt;
&lt;h3&gt;블러드&lt;/h3&gt;
&lt;p&gt;뱀파이어 + 의학물 정도의 드라마. 주연 배우는 알 수 없는 하이틴 스타로 추정되는 남자 배우고 악역으로 지진희씨가, 히로인으로 구혜선이 나온다. 왠만하면 지진희씨가 나오는 드라마는 피하는 편인데 구혜선이 나와서 봤다는 썰이 있다. 1회 보고는 접을려고 하다가 본게 아까워서 몇 편 더 봤는데 냅다 정주행하게 되었다. 그 여파로 와이프에게 캐갈굼, 캐욕, 급기야 네번째 50일 촬영에 끌려가는 비극이 있었지만 최선을 다해서 20회까지 사수했다. 끝에는 지루해서 빨리감기를 좀 많이 했다.&lt;/p&gt;
&lt;p&gt;스토리 설정이 참신한데 한 감염학자(의학자)가 해외 어딘가에서 뱀파이어 이야기를 듣고 시체를 발굴해서 뱀파이어 바이러스를 만들어 낸다는데서 출발한다. 그 바이러스에 감염되면 뱀파이어가 되는데, 뱀파이어는 뭐 우리가 익히 알고 있는 그 뱀파이어다. 밝은거 못 보고, 체온 낮고, 심박 빠르고, 피 보면 환장하고, 20대의 젊음을 한 250년 정도 유지하다가 죽는 그런…​ ㅋㅋ~ 그렇게 연구를 하던 랩실의 3명이 감염자가 되는데 다른 사람들은 이걸 폐기하자 그러고 지진희는 세상 밖으로 꺼내야 한다고 하면서 싸움이 난다. 늘 그렇듯이 악역이 교수와 친구 2명을 모두 죽이고 독차지 하면서 이야기가 시작된다. 그런데 그 죽인 친구 둘은 캠퍼스 커플이고, 감염된 뱀파이언데 그 사이에서 자식이 태어났으니 그게 주인공이다. 그렇게 둘이서 세월이 흘러 흘러 한국의 한 병원에서 만나서 지지고 볶는 그런 썰이다.&lt;/p&gt;
&lt;p&gt;첨에는 의학물적인 내용이 더러 나와서 우왕 내가 안 본 의학 드라마도 있었넴, 게다가 액션까지 했는데,…​ 가면 갈수록 코리안 멜로와 알 수 없는 뱀파이어 호러물로 변질되면서 쩜쩜점했다. 끝은 이미 뻔했지만 본 게 아까워서 끝까지 정주행하는 예를 갖췄다.&lt;/p&gt;
&lt;h3&gt;행복의 기원&lt;/h3&gt;
&lt;p&gt;새해 벽두를 그냥 드라마만 냅다 정주행한것처럼 보이지만 와이프의 눈총과 육아를 병행해야 했던 시간에는 책도 읽었다. 한권은 행복에 관한 how보다는 why에 대한 답을 담고 있는 &quot;행복의 기원&quot;이란 책이다. 그냥 단순한 싸구려 자기계발서의 주장을 담고 있는 책은 아니고 과학적인 연구 결과를 바탕으로 써진 책이다. 그래서 그런지 내용이 팍팍 와 닿았다. 성격이 중요하고 유전이 상당한 영향을 미친다는 것에 다소 충격을 받았지만 말이다.&lt;/p&gt;
&lt;p&gt;그리고 책에서 밝히는 또 하나의 충격적인 사실 중에 하나가 있다. 윤종신씨인지 유희열씬지가 방송에서 음악 열심히하고 그러는게 다 여자한테 잘 보이려고 하는거라고 했었던 말이 팩트라는 것이다. 진화론적 근거가 있는 이야기라는 사실. 공작새의 꼬리처럼 생존과는 별 상관 없어보이지만 이성에게 어필하기 위해서 그러는게 맞다는 다소 어이없지만 황당한 이야기. 인생 뭐 별 거 없다. 베토벤도 모짜르트도 여자한테 잘 보이려고 밤을 새며 작곡했다는 썰~ 그럼 혹시 토발즈와 카맥도? ㅋ~&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;유학 시절, 지도 교수가 쓴 논문을 읽은 적이 있다. 제목은 &apos;행복은 기쁨의 강도가 아니라 빈도다&apos;. 나는 이것이 행복의 가장 중요한 진리를 담은 문장 중 하나라고 생각한다.&lt;br&gt;
&lt;br&gt;
지금 나는 왜 이모양으로 살고 있는가? 우리는 이런저런 이유를 떠올린다. 부모를 잘 만나서, 혹은 잘못 만나서, 대학 전공 때문에, 기타 등등. 조금씩은 모두 관련이 있겠지만 무엇을하며 어떤 인생을 사느냐를 결정하는 데 상당히 큰 몫을 차지하는 것은 바로 자신의 성격이다.&lt;br&gt;
&lt;br&gt;
다시 말하지만 행복의 원인 중 사람들이 가장 과대 평가하는 것이 돈과 같은 외적 조건이다. 이 챕터에서는 반대로 행복에 절대적인 영향을 미치지만, 대부분이 미처 생각지 않는 요인에 대해 살펴보려 한다. 어떤 것이 그렇게 중요할까? 오랫동안 행복을 연구한 석학들을 한 자리에 모아놓고 그 질문을 한다면 대답은 거의 비슷할 것이다.&lt;br&gt;
&quot;유전. 더 구체적으로는 외향성.&quot;&lt;br&gt;
&lt;br&gt;
행복의 핵심을 한 장의 사진에 담는다면 어떤 모습일까? 이 책의 내용과 지금까지의 다양한 연구 결과들을 총제적으로 생각했을 때, 그것은 좋아하는 사람과 함께 음식을 먹는 장면이다. 문명에 묻혀 살지만, 우리의 원시적인 뇌가 여전히 가장 흥분하며 즐거워하는 것은 바로 이 두가지다. 음식, 그리고 사람.&lt;br&gt;
&lt;br&gt;
행복은 거창한 것이 아니다. 모든 껍데기를 벗겨내면 행복은 결국 이 한 장의 사진으로 요약된다. 행복과 불행은 이 장면이 가득한 인생 대 그렇지 않은 인생의 차이다. 한마디 덧붙인다면 &quot;The rest are details.&quot; 나머지 것들은 주석일 뿐이다.&lt;br&gt;
&lt;br&gt;
-- 행복의 기원, 서은국&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;가끔은 겪하게 외로워야 한다&lt;/h3&gt;
&lt;p&gt;김정운 교수의 신간이다. 왠만하면 자기계발서는 읽지 않는 편인데, 김정운 교수가 쓴 책이라 재미 삼아 읽었다. 내용도 그냥 가볍게 읽기 좋은 책으로 보여진다. 김정운 교수 팬이긴 한데 그의 &quot;에디톨로지&quot;는 정말 읽기 힘들어서 읽다 말았었다. 가볍게 개념만 편식하는 걸로 ㅋㅋ~ 근데 이 책은 그냥 심심풀이로 읽기 좋다. 김정운 교수는 이런 책이 어울린다는 개인적인 생각…​&lt;/p&gt;
&lt;h3&gt;행복하자~&lt;/h3&gt;
&lt;p&gt;할아버지는 주당이셨다. 평생 반주를 하셨는데, 나중에는 술이 주고 밥이 부가 될 지경이었다. 노환으로 병원에 입원해 계섰을 때 엄마가 첨으로 와인을 사드렸는데 이런 술이 있냐며, 왜 진작 자신에게 사주지 않았냐는 이야기를 했다고 한다. 병원에서도 노환이니 좋아하시면 그냥 드리는 것도 괜찮다고 해서 와인을 종종 드시면서 마지막 병원 생활을 하셨다.&lt;/p&gt;
&lt;p&gt;아빠는 내기 바둑과 장기, 고스톱에 빠져서 평생을 살았다. 돌아가시고 엄마한테 들어서 안 사실이지만 아빠의 도박 편력이 장난이 아니었다. 그렇게 평생을 좋아하더니 마지막 까지도 집 앞 공원에서 내기 장기를 두고는 가셨다. 병원에서 칼륨 수치를 관리해야 한다고 짠 걸 드시지 말라고 하셨을 때 한 말씀이 생각난다. 죽으면 죽었지 먹고싶은건 먹어야겠다고 말이다. 여튼 그렇게 아빠는 자기가 하고 싶은 걸 다 하시고 가셨다.&lt;/p&gt;
&lt;p&gt;어떤게 정답인지는 모른다. 당장의 쾌락을 따르며 사는게 좋은건지, 아니면 근엄하게 사는게 좋은건지 말이다. 하지만 이것 저것 따질것 없이 그냥 지금 행복하게 사는게 중요한 건 아닐까? 얼마간 더 사는 것보다 오늘 재미난 일을 하고 행복하게 사는게 더 소중하지 않을까? 내일은 오지 않을 수도 있으니 말이다. 당장 가진 오늘을 더 재미있고 행복하게 영위하는게 훨씬 더 좋지 않을까라는 생각. 생각이 여기까지 미치니 참으로 유전이란 걸 무시못하는건가 싶기도 하다. 여튼 2016년은 행복한 일로 가득한 한 해가 되길 소망해 본다. 맛집블로그로 전환될지도 모르겠다 ㅋㅋㅋ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[블로그 이동]]></title><description><![CDATA[어느날 갑자기 워드프레스가 너무 복잡한 것 같은 생각이 들어서 블로그를 옮겼습니다. 링크가 이곳으로 돼 있어서 이곳으로만 오는 분들이 계신 것 같아서 포스팅합니다. 새로운 주소는 http://www.jiniya.net/ng…]]></description><link>https://jiniya.net/wp/archives/15217</link><guid isPermaLink="false">https://jiniya.net/wp/archives/15217</guid><pubDate>Mon, 04 Jan 2016 12:00:01 GMT</pubDate><content:encoded>&lt;p&gt;어느날 갑자기 워드프레스가 너무 복잡한 것 같은 생각이 들어서 블로그를 옮겼습니다.&lt;/p&gt;
&lt;p&gt;링크가 이곳으로 돼 있어서 이곳으로만 오는 분들이 계신 것 같아서 포스팅합니다.&lt;/p&gt;
&lt;p&gt;새로운 주소는 &lt;a href=&quot;http://www.jiniya.net/ng%EC%9E%85%EB%8B%88%EB%8B%A4&quot;&gt;http://www.jiniya.net/ng입니다&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;혹시 즐겨찾기를 사용하시는 분이라면 &lt;a href=&quot;http://www.jiniya.net%EC%9D%84&quot;&gt;http://www.jiniya.net을&lt;/a&gt; 추가해 두시면 됩니다.&lt;/p&gt;
&lt;p&gt;해당 주소로 가시면 알아서 새로운 주소로 이동시켜 준답니다.&lt;/p&gt;
&lt;p&gt;늦었지만 새해 복 많이 많이 받으세요 !!!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 모던 C++에서 훅 코드란?]]></title><description><![CDATA[다른 블로그 구경하다가 재미난 코드를 발견해서 옮겨봅니다. 훅 루틴인데요. 모던 C++을 사용하니 정말 간결하네요. C++의 르네상스가 다시 오는건지 ㅋㅋ~ 신세계군요. 망할 XP만 없다면 빨리 넘어갈텐데 ㅠㅜ~ decltype(A)는 A…]]></description><link>https://jiniya.net/ng/2015/12/hook-with-modern-cpp/</link><guid isPermaLink="false">https://jiniya.net/ng/2015/12/hook-with-modern-cpp/</guid><pubDate>Wed, 30 Dec 2015 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;다른 블로그 구경하다가 재미난 코드를 발견해서 옮겨봅니다. 훅 루틴인데요. 모던 C++을 사용하니 정말 간결하네요. C++의 르네상스가 다시 오는건지 ㅋㅋ~ 신세계군요. 망할 XP만 없다면 빨리 넘어갈텐데 ㅠㅜ~&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;decltype&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;timeGetTime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; HooktimeGetTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; DWORD &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;decltype(A)는 A의 타입을 반환합니다. 예전에 훅 루틴 만들때마다 원형 복사해서 함수 포인터 다시 typedef하던 때를 떠올리면 정말 심플합니다.&lt;/p&gt;
&lt;p&gt;&quot;&lt;a href=&quot;&quot;&gt;&lt;/a&gt; {}&quot;는 람다 함수입니다. &quot;&lt;a href=&quot;&quot;&gt;&lt;/a&gt; -&gt; DWORD {}&quot;는 파라미터는 없고 리턴 값은 DWORD인 람다 함수라는 말이죠.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 윈도우에서 llvm-obfuscator 사용하기]]></title><description><![CDATA[Clang은 LLVM을 백엔드로 사용하는 C 계통의 언어를 컴파일해주는 컴파일러다. LLVM을 백엔드로 사용하기 때문에 컴파일 타임에 뭔가를 해줄 수 있다는 장점이 있다. 그런 것 중에 하나로 난독화를 들 수 있다. obfuscator-llvm…]]></description><link>https://jiniya.net/ng/2015/12/clang-with-mingw-w64/</link><guid isPermaLink="false">https://jiniya.net/ng/2015/12/clang-with-mingw-w64/</guid><pubDate>Fri, 18 Dec 2015 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;Clang은 LLVM을 백엔드로 사용하는 C 계통의 언어를 컴파일해주는 컴파일러다. LLVM을 백엔드로 사용하기 때문에 컴파일 타임에 뭔가를 해줄 수 있다는 장점이 있다. 그런 것 중에 하나로 &lt;a href=&quot;https://github.com/obfuscator-llvm/obfuscator&quot;&gt;난독화를&lt;/a&gt; 들 수 있다. obfuscator-llvm은 LLVM에 난독화 기능을 추가한 버전이라고 보면 된다. 소개 페이지에 나와 있는 것처럼 LLVM IR레벨에서 작업하고 있기 때문에 LLVM을 백엔드로 사용하는 언어와 타겟 머신을 모두 지원한다는 장점이 있다. 제작자들이 첨에는 학교에서 &lt;a href=&quot;http://crypto.junod.info/spro15.pdf&quot;&gt;논문으로 쓰다가&lt;/a&gt; 아이디어가 괜찮아서 &lt;a href=&quot;https://strong.codes/&quot;&gt;스타트업을 차린 것으로 보여진다.&lt;/a&gt; 어쨌든 이걸 쓰면 컴파일 타임에 나의 코드에 난독화를 적용할 수 있는 것이다. 응당 사용하지 않을 이유가 전혀 없다. 그럼 한 번 살포시 시작해보자.&lt;/p&gt;
&lt;p&gt;우선은 Clang을 윈도우에서 어떻게 쓸지부터 알아야 한다. 정말 많은 글들이 있지만 &lt;a href=&quot;http://blog.johannesmp.com/2015/09/01/installing-clang-on-windows-pt2/&quot;&gt;이 글에&lt;/a&gt; 나와있는 방법이 가장 좋았다. Clang에다 런타임라이브러리와 링커는 mingw-w64껄 쓰는 방법이다. 글에 나와 있는 방법대로 하면 대체로 모두 잘 된다. 내가 조금 골탕먹은 것은 mingw-w64를 선택할 때 스레딩 모델을 Win32로 선택했던 것이었다. Win32로 선택하면 C++11부터 추가된 스레드 기능을 사용하지 못한다. 그러니 POSIX로 선택하는 것이 바람직하다 하겠다. 예외의 경우 64는 SEH로 32는 Dwarf를 받아서 썼다. 그렇게 했더니 아래 코드가 깔끔하게 컴파일이 되었다. &quot;clang++ -std=c++14 hello.cpp -lpthread&quot;라는 명령어로 아래 코드가 깔끔하게 컴파일이 되었다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;thread&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;chrono&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;PrintMsg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; try_cnt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; sec&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; try_cnt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;[%03d] %s\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;this_thread&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sleep_for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;chrono&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;seconds&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sec&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;thread &lt;span class=&quot;token function&quot;&gt;thread1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;PrintMsg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;dog&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;thread &lt;span class=&quot;token function&quot;&gt;thread2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;PrintMsg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;cat&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;thread &lt;span class=&quot;token function&quot;&gt;thread3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;PrintMsg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;monkey&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	thread1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	thread2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	thread3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이렇게 컴파일한 결과물을 사용하면 별 문제는 없는데 덕지덕지 온갖 이상한 DLL을 많이 임포트하는 경향이 있다. 그래서 용량이 큰 C++ 라이브러리를 제외하고 정적으로 컴파일하고 싶으면 &quot;clang++ -std=c++14 hello.cpp -static -static-libgcc -lpthread -Wl,-Bdyanmic -lstdc++&quot;와 같이 입력하면 된다. 여튼 뭐 컴파일은 그렇다. 그렇다면 이제 llvm-obfuscator를 써보자.&lt;/p&gt;
&lt;p&gt;난독화 함수를 찾기 쉽도록 아래와 같이 익스포트 되도록 함수를 선언해주자. 뒤에 속성으로 따라 붙는 것이 fla, bcf, sub 난독화 기법을 이 함수에 적용하겠다는 것을 의미한다. 오픈소스 버전은 세 가지 기능만 제공하고 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;__declspec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dllexport&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;PrintMsg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; try_cnt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; sec&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;__attribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;__annotate__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;fla&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;__attribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;__annotate__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;bcf&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;__attribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;__annotate__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;sub&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./normal.png&apos; data-alt=&apos;난독화가 적용되지 않은 PrintMsg 함수. 코드만큼 어셈도 단순하다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/b0e18ac996e6f3bfe2ef91379cf14984/dface/normal.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 102.10526315789474%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAB/ElEQVR42o1UiY7aMBTk//+p2u2FWs6FkjsQQg7i+IpzOuTYfQtoVbULwXqyZMWjNzNvnNHrefV9D7tpkijKoTQd76OIl7w4Fa+31+hv8G7H47hgTGpmND0svCTABTl/eQDsOJzzirHKdZPZL6T4lhpabdMPgt/3/T4BcMKloqGfa1VFuuZvGZXdje7/0oa2lFSThft9N9aIpruuouDTqR3uHIZZmsosPRkWUiPdSw8+iREVXd99Dqa09DwBaruur+u2abq27auqLfImKUVW5zazTWwf8yOvuMPhohMXMRxpSUcXzl3XnUdFoyhjrNxs0POzM9n+MYhpIScv5ZXgO8Vr/a+ZAREoQydPX1zvCF5VPBWM0fS87hlm2/QKNsnvxX68nS385ca3uCg+7tybM3CGUU2X7jd7rBNNCUzDoISUH6bedBuygXHBuXxZheO1FrAIZ5TRUspmeFSHQ3JJGPBXNhgLyHaeyxIGMQy+0AbNuo7Xa6R6ji+Co0CVPA0nbLtl8DAAPJ37T/OVGlgH6nshE2n1SLY5QjmANwoy7RgnomwKqKZthzuDVEIKRqv5yvuqT5bhy8xdKZaPSX7f7Stt+BNA5/ki+DEzjcCNBMJMPKQZDANkkkjLJvsgDhOEshhnrCjrR0YFSSyFqBU1mmkmEgTeBmSmlp9rfgMTK3hYYtTRwgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;난독화가 적용되지 않은 PrintMsg 함수. 코드만큼 어셈도 단순하다.&apos; title=&apos;&apos; src=&apos;/static/b0e18ac996e6f3bfe2ef91379cf14984/dface/normal.png&apos; srcset=&apos;/static/b0e18ac996e6f3bfe2ef91379cf14984/08678/normal.png 190w,
/static/b0e18ac996e6f3bfe2ef91379cf14984/2edd7/normal.png 380w,
/static/b0e18ac996e6f3bfe2ef91379cf14984/dface/normal.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;난독화가 적용되지 않은 PrintMsg 함수. 코드만큼 어셈도 단순하다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./obfuscated.png&apos; data-alt=&apos;난독화가 적용된 PrintMsg 함수. 함수가 점프 코드로 분산되고 길고 어려워진다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/628f81a88e7b905e5f4434ce8f9e4960/dface/obfuscated.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 151.05263157894737%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAIAAACjcKk8AAAACXBIWXMAAA7DAAAOwwHHb6hkAAADoUlEQVR42pVVyXLjNhTkZ+cLcs0HJKcccssllcolU5maSmzLHo8tWYu1UaJEUSIJrtgBAlAeRXvKdnliB0KpQJENovt1P3nHJ2O7rRnTCLHDgWhtjm8N7+nF3V1SFGKzqdbrUin7/8D9fpwkdB+RBBF9FEQRZdR7wdMpYkwdInY5mt9Gg7AKM5bD7w4+b4LH45RzHUV4NEIX59Htvr+Kd868783jMRKiiXakd+P3pqNBPBiHSziINuZt8HyeK9VEIf10PQHkIl+Mt6vZfdE0nXj2NN23wJlSBsBnt7O7w2iWTYfBMkDRnkRY4VfeTIgqCp7nHC6gPM65RlsulLCcacakjOrIL/yYxlR/QOzngs+olkRh1jCvqmRZCpgA7rxRVWIf0f2OIZqnNJmli4JXTFOmzxH7DTEfS1pL+IW9NAk4bBfim+Hmy+Zukc+JYErCcd6h9mSClDbhhvz5z/DM/zxKx5PtejkvdWNeF8y127bTWtsJFifYD9IMcWNaCdzDex8X7gEOlx5ogrEgRNrH4Zx9BMCWjimGJaaSchXUYkIEYgrIMKGFBzqDn9OUwaOwhpISomERHrJNGcYknqazPT7kPKvlLzv8fUSuK0ELnkHxXppEygakvhouz1dX19EXHwWQMzjN64LBATteMCGJ8Fwc04vLzefbTc2oUJpS3XJp758YHe2JdYvwrDUAhdvGmLLkYE8hVJ6zsuAGXPmw9WnYpp2A72SxzgPCux1OUwrHAMKwoTFOawvlFQ04iSyyxbZqyef8p1XxXVCeIVYlNAZneVCPbn6NZLglt+PNp9nlh+VfS7RaHw5Sg2+hbqKxtLGwtoCA72eC3d8jsGcY4vPrZX/hI5oVpCZV803BToVtCQHnJCHAmVBOOXf26Kx7NlqeJ6G+cs4yDq0DItGZ5tEbR8iWNpprEVa7Pd4jhkrxa1j/sMc3hcCnsteeEAa6B0zArFYlLBDiYM9BMIdIgz2CLGSKKyO1nTJ9RXWiTCONgK2fcfb9tmmc2tCqNxuuiyDDVZmr/zDJg++BfBCUIFiWsUE/7t/EoPxJDNc1UPcime7oYSwh/V0wOrc8SdIRSkIkqXndZkNdFOz3kq+p5ERiyIYH1gU/QieCR6MI1DZlIfYHvI6SSTIFqUbxBJgXvKjlHxH58UCGlaSFyME/L/u2kM02wH9fzT7e93rh5TaLcqSMeSMYrlMbBEtS0jaDVLTOaz3vTv8YrXHdsXkajH8B19u12n8tR7AAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;난독화가 적용된 PrintMsg 함수. 함수가 점프 코드로 분산되고 길고 어려워진다.&apos; title=&apos;&apos; src=&apos;/static/628f81a88e7b905e5f4434ce8f9e4960/dface/obfuscated.png&apos; srcset=&apos;/static/628f81a88e7b905e5f4434ce8f9e4960/08678/obfuscated.png 190w,
/static/628f81a88e7b905e5f4434ce8f9e4960/2edd7/obfuscated.png 380w,
/static/628f81a88e7b905e5f4434ce8f9e4960/dface/obfuscated.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;난독화가 적용된 PrintMsg 함수. 함수가 점프 코드로 분산되고 길고 어려워진다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;내가 사용한 버전은 llvm-3.6.1 브랜치 코드를 기준으로 작업했다. 사용해보면 윈도우에서 /dev/random을 찾을 수 없다는 버그가 있는데 lib/Transform/Obfuscation/CryptoUtils.cpp 파일의 prng_seed 함수를 아래와 같이 수정해주면 정상 동작하도록 만들 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;_WIN32&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;_WIN32_LEAN_AND_MEAN&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;Windows.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;Ntsecapi.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CryptoUtils&lt;/span&gt;&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;prng_seed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;_WIN32&lt;/span&gt;&lt;/span&gt;

	LLVMContext &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;ctx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; llvm&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getGlobalContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	HCRYPTPROV prov&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CryptAcquireContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;prov&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PROV_RSA_FULL&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; CRYPT_VERIFYCONTEXT &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; CRYPT_SILENT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CryptGenRandom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prov&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BYTE &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
			ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;emitError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Twine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;CryptGenRandom fail&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;token function&quot;&gt;CryptReleaseContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prov&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;token function&quot;&gt;memset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;token comment&quot;&gt;// Once the seed is there, we compute the&lt;/span&gt;
		&lt;span class=&quot;token comment&quot;&gt;// AES128 key-schedule&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;aes_compute_ks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ks&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

		seeded &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;emitError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Twine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;CryptAcquireContext fail&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;else&lt;/span&gt;&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;// ... 기존 코드 ...&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[cpp] API 세트 DLL 이름 바인딩하기]]></title><description><![CDATA[윈도우 7이 등장하면서 kernel32.dll을 살펴보면 이상한 부분이 하나 생겼습니다. 바로 IAT 부분인데요. api-ms-win-core-console-l1-1-0.dll 같은 이상한 DLL로 부터 우리가 원래 익히 알고 있는 API…]]></description><link>https://jiniya.net/ng/2015/12/api-set-dll-name-binding/</link><guid isPermaLink="false">https://jiniya.net/ng/2015/12/api-set-dll-name-binding/</guid><pubDate>Thu, 17 Dec 2015 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;윈도우 7이 등장하면서 kernel32.dll을 살펴보면 이상한 부분이 하나 생겼습니다. 바로 IAT 부분인데요. api-ms-win-core-console-l1-1-0.dll 같은 이상한 DLL로 부터 우리가 원래 익히 알고 있는 API들을 임포트 하고 있는 것이죠. 그런데 api-ms-win-core-console-l1-1-0.dll 같은 것에 실제 코드가 포함돼 있냐하면 그것도 아닙니다. 헐~ 멍밍하게 되는데요. &lt;a href=&quot;http://www.nirsoft.net/articles/windows_7_kernel_architecture_changes.html&quot;&gt;그 당시에 발견한 문서에서&lt;/a&gt; 기본적인 메커니즘을 알게 되어서 해당 문서에 나와 있는 DLL 이름들만 하드 코딩해서 사용을 했었습니다.&lt;/p&gt;
&lt;p&gt;이후에 윈도우 8이 나왔고, 8.1이 출시됐고, 윈도우 10이 나오고, 이제는 윈도우 10 TH2까지 나왔습니다. 저 문서에 있는 내용 만으로 뭔가가 정상 동작하기에는 뭔가 한참 모자랄만큼 운영체제가 많이 나왔죠. 어제 해킹툴을 테스트하다가 코드가 정상적으로 동작하지 않는 것을 발견했습니다. 바로 위에서 우리가 하드 코딩한 DLL 말고도 온갖 요상한 DLL이 많이 생긴게 원인이었습니다. 그래서 이 많은 DLL 이름을 어쩌지 하는 찰나에 관련 설명을 담고 있는 &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/windows/desktop/hh802935(v=vs.85).aspx&quot;&gt;MSDN 문서를&lt;/a&gt; 발견하게 되었습니다. 목록이 엄청 길죠. API 세트에 사용되는 온갖 DLL 이름이 다 나와있습니다. 이 테이블을 기초로 DLL 이름을 매핑해주는 함수를 확장시켰더니 마법같이 잘 동작했습니다. 역시 MSDN ㅋㅋ~ 그런데 뭔가 좀 아쉽죠. 모두 입력 시켜서 동작하게는 만들었지만 도대체 이 이름들은 어디서 오며 운영체제는 어떻게 그걸 매핑시키는지 궁금한거죠~ 은막 뒤의 비밀이 궁금하다랄까요.&lt;/p&gt;
&lt;p&gt;자동으로 될 일은 없고, 운영체제도 어디에선가는 매핑을 시킬텐데 그 자료를 알게 되면 굳이 이걸 일일이 입력하고 있지 않아도 되지 않을까라는 생각이었습니다. 그 생각으로 오늘 LoadLibrary 코드를 좀 살펴봤는데요. 비밀을 알아냈습니다. LoadLibrary 내부에서 PEB에 저장된 ApiSetMap이란 자료 구조를 참조해서 DLL 이름을 리다이렉트 시키고 있었습니다. 풉. 역시 마법은 없었습니다. ApiSetMap이란 걸 알게 되었으니 관련 키워드로 검색을 해봤습니다. 자료가 많지는 않은데 친절하게 리버싱해 둔 자료가 있었습니다.&lt;/p&gt;
&lt;p&gt;전체적인 메커니즘은 런타임 DLL 이름 해석 &lt;a href=&quot;http://blog.quarkslab.com/runtime-dll-name-resolution-apisetschema-part-i.html&quot;&gt;Part 1&lt;/a&gt;, &lt;a href=&quot;http://blog.quarkslab.com/runtime-dll-name-resolution-apisetschema-part-ii.html&quot;&gt;Part 2&lt;/a&gt;에 잘 나와 있습니다. 관련 자료를 토대로 만든 실제 코드는 &lt;a href=&quot;http://www.xchg.info/wiki/index.php?title=ApiMapSet&quot;&gt;위키 글을&lt;/a&gt; 참고하면 됩니다.&lt;/p&gt;
&lt;p&gt;간략하게 전체 구조를 리뷰해보면 모든 데이터의 근간은 apisetschema.dll에 있습니다. 윈도우는 부팅할 때 그 DLL의 .apiset 섹션 데이터를 토대로 메모리에 API 세트 이름 매핑 자료를 로드합니다. 그리고 이후 프로세스가 생성되면 PEB의 ApiSetMap에다가 해당 자료를 참조할 수 있도록 데이터를 매핑시켜줍니다. 이제 LoadLibrary를 호출하면 PEB의 ApiSetMap을 뒤져서 매칭되는 DLL이면 이름을 리다이렉트 시켜주는 것이죠. 결국 하드코딩한 테이블을 사용할 것이 아니라면 ApiSetMap을 어떻게 뒤지는지 알아야 합니다.&lt;/p&gt;
&lt;p&gt;앞선 위키 글의 경우 윈도우 7을 기초로 작성해서 제가 사용하는 윈도우 8.1에서는 동작하지 않는 문제가 있었습니다. 그래서 윈도우 8.1에서 동작하도록 코드를 한 번 만들어 보았습니다. 런타임 DLL 이름과 매핑되는 실제 DLL 이름을 출력해 줍니다. 위키 글에 있는 코드는 ApiSetMap 구조체 버전이 2인 환경입니다. 아래는 버전이 4인 환경일 때의 구조체 정보랍니다. 윈도우 10은 또 업그레이드가 되었겠죠?&lt;/p&gt;
&lt;p&gt;덧) 현재까지 알려진 ApiSetMap 자료 구조 버전은 총 세 개입니다. 윈도우 7에 포함된 구조가 2버전이고, 윈도우 8에 포함된 구조가 4버전입니다. 윈도우 10에는 6버전 구조로 변경이 되었네요. 아래 코드는 윈도우 8의 ApiSetMap 버전 4를 출력하는 기능을 합니다. 당연히 2나 6에서는 정상 동작하지 않습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;windows.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name function&quot;&gt;ADD_PTR&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG_PTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG_PTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;pragma&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token function&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_API_SET_MAP_DATA_ENTRY&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ULONG flags&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG name_offset&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG name_length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG value_offset&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG value_length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; API_SET_MAP_DATA_ENTRY&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PAPI_SET_MAP_DATA_ENTRY&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_API_SET_MAP_DATA&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ULONG flags&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG count&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	API_SET_MAP_DATA_ENTRY entries&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ANYSIZE_ARRAY&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; API_SET_MAP_DATA&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PAPI_SET_MAP_DATA&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_API_SET_MAP_ENTRY&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ULONG flags&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG name_offset&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG name_length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG alias_offset&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG alias_length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG data_offset&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; API_SET_MAP_ENTRY&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PAPI_SET_MAP_ENTRY&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;



&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_API_SET_MAP&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ULONG version&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG flags&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG count&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	API_SET_MAP_ENTRY entries&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ANYSIZE_ARRAY&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; API_SET_MAP&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PAPI_SET_MAP&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;pragma&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token function&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	PVOID name_ptr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG_PTR api_set_map&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	PAPI_SET_MAP pasm&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	PAPI_SET_MAP_DATA pasmd&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	WCHAR name&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;MAX_PATH&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	api_set_map &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__readfsdword&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0x30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	api_set_map &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG_PTR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;api_set_map &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x38&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


	pasm &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PAPI_SET_MAP&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; api_set_map&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; pasm&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;count&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		name_ptr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ADD_PTR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pasm&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pasm&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;entries&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name_offset&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;token function&quot;&gt;memset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name_ptr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pasm&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;entries&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name_length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

		pasmd &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PAPI_SET_MAP_DATA&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ADD_PTR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pasm&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pasm&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;entries&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data_offset&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%ls =&gt; [%d]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pasmd&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;count&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG j &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; j &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; pasmd&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;count&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			name_ptr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ADD_PTR&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pasm&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  pasmd&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;entries&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value_offset&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

			&lt;span class=&quot;token function&quot;&gt;memset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;token function&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name_ptr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pasmd&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;entries&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value_length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

			&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot; %ls&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

		&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[시스템] 블록 암호화의 연산 모드란?]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/ng/2015/12/blcok-cipher-mode-operation/</link><guid isPermaLink="false">https://jiniya.net/ng/2015/12/blcok-cipher-mode-operation/</guid><pubDate>Sat, 12 Dec 2015 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;암호는 용어도 많고 알고리즘도 어렵고, 구조도 복잡합니다. 그런 암호 중에서도 블록 암호화를 공부하면 연산 모드란 것을 만나게 됩니다. 어떤 거냐구요? &lt;a href=&quot;https://msdn.microsoft.com/ko-kr/library/system.security.cryptography.ciphermode(v=vs.110).aspx&quot;&gt;바로 이런 겁니다.&lt;/a&gt; 이런 상수를 만나면 으례 그냥 아무거나 넣거나 디폴트 값을 사용하곤 하지만 오늘은 한 걸음 더 파헤쳐보는 시간을 가져보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;블록 암호화는 기본적으로 블록 단위로 특정 키를 사용해서 암호화를 하는 것을 의미합니다. 특별한 언급이 없는한 대칭키를 사용하는 구조가 대부분이죠. 암호화를 수행한 키를 암호를 해독할 때에도 사용한다는 겁니다. 그렇다면 이런 대칭형 블록 암호화 기법의 가장 큰 문제점은 무엇일까요? 네, 맞습니다. 똑같은 블록, 똑같은 키라면 결과물이 똑같다는 거죠. 어느 정도 패턴이 드러날 수 밖에 없다는 이야깁니다. 아래 이미지를 보면 이해가 빠릅니다. 세 가지 그림이 있는데 왼쪽이 원본, 가운데가 연산 모드 없이(ECB) 블록 암호화를 수행한 것, 오른쪽은 ECB가 아닌 연산 모드를 선택해서 블록 암호화를 수행한 겁니다. 어떤가요? 기본적인 ECB의 경우 이미지가 변형되었지만 우리는 이 이미지가 펭귄이란 것을 인식할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./modeop.png&apos; data-alt=&apos;기본인 ECB 연산 모드가 왜 위험한지를 보여주는 짤. 암호화를 했지만 우리는 펭귄을 볼 수 있다는거~&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/0421859522ad948e79d1513a5ca1f39d/dface/modeop.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 56.315789473684205%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACSElEQVR42iVSz1PTQBTOn+TR8eqMM3r3inovCElL2yS7mx+km4DIwbMHZbw4OnoHO4wOo/woTSHCtE1JmpRxZChNAi2koYkP/Obt7nv7vm/evjfLJEmcZdneXn17eydNE/APDy2EkCzL5VJZEEVJklRVXVlZ0RaoXtEpBasYlL5efsXc3IxB8GLq6YP794IgAH9/v8Fy3Pz8/OzMy+lcLp/neJ6nBuWRgEQRYYQJBneBKkyWjoPoauMzJ7EPf2zu/BcXCoVisUgwznMAFiHRMBZFRGRCZAlhjCRCKKUMsKvVb0dHVqNhPn82BaFlHYA4z+XZ2QI7x03P5ARB0A2KsEgQISImBGqLVKswyXj04d2bIIig4SePH52e/m23mqAtFUrsrMCxfG56RuAFQ18kSJJhALCgvEg0XWcu3Y+tVeb72vvN6pf1JWYyWP995JTLBVmV5uZKLFsUsQiPNHQDkVtHkmVFkSQsGxWNuQrt0130c+3t10+rf3ZwlgUH1mGZLwGpzPPQOUweI7S0vLSgSBVFUzVF0xRZVXVqMP1+eBbEYTRM0/QqyW4maf/srFar1ev1fdM0YRKm6TjHlmVt/dqq1XYBjboJt62WzVxE0UU0uIAjCoeX0Wg0HI1GcRxfx9eAeDy+juMkSSDb758P7jC8I0zSCdPtuh2747qw267rdDp2u9Vut227bTebzWNApwMXQOh6HhiEx44DjPNBcCv27wBp3/cc1/E9z/M9v9t13K7fg+g22+v1HAeS7snJSRiGwQA+VPAPUD3Rrx7Za58AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;기본인 ECB 연산 모드가 왜 위험한지를 보여주는 짤. 암호화를 했지만 우리는 펭귄을 볼 수 있다는거~&apos; title=&apos;&apos; src=&apos;/static/0421859522ad948e79d1513a5ca1f39d/dface/modeop.png&apos; srcset=&apos;/static/0421859522ad948e79d1513a5ca1f39d/08678/modeop.png 190w,
/static/0421859522ad948e79d1513a5ca1f39d/2edd7/modeop.png 380w,
/static/0421859522ad948e79d1513a5ca1f39d/dface/modeop.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;기본인 ECB 연산 모드가 왜 위험한지를 보여주는 짤. 암호화를 했지만 우리는 펭귄을 볼 수 있다는거~&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;이렇게 패턴이 드러나는 문제를 해결하기 위해서 나온 것이 연산 모드입니다. 거창하게 설명했지만 대단한 건 아니고 블록 암호화의 연산 전후에 규칙적으로 변형을 가하는 것을 의미합니다. 아래는 많이 사용하는 CBC 연산 모드에 대한 이미지 입니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 601px; margin-bottom: 16px;&apos; data-url=&apos;./601px-CBC_encryption.svg.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/20017187563e47a19455cb871ac8be40/f6e13/601px-CBC_encryption.svg.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 40.526315789473685%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAyklEQVR42nWRiw6CMAxFUREGioCAAQV14Ov/v9COHE1d4pKTQOntbi9B8HsWwl44CsarF8JJ2HiaHfXtp+AaciEVDsJDsDyv6Em45Cp0wpp6xLvVJi7CS7gLA4MqBAaRI1P1WOF6GnX5vE6CZbfWhMuOddygEhdPxIXijKGei+cTsobBoWVgRt05qVUUOb0xQwfch16+s0uX001oVUOKg4kfoDPsVVzGH7hEMOIooikl9JGVdX41miL4c0rWahG3rN8grtS3nvy/5w1yfwlPRgjG9QAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;601px CBC encryption svg&apos; title=&apos;&apos; src=&apos;/static/20017187563e47a19455cb871ac8be40/f6e13/601px-CBC_encryption.svg.png&apos; srcset=&apos;/static/20017187563e47a19455cb871ac8be40/08678/601px-CBC_encryption.svg.png 190w,
/static/20017187563e47a19455cb871ac8be40/2edd7/601px-CBC_encryption.svg.png 380w,
/static/20017187563e47a19455cb871ac8be40/f6e13/601px-CBC_encryption.svg.png 601w&apos; sizes=&apos;(max-width: 601px) 100vw, 601px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;보면 일반적인 블록 암호화보다 입력 파라미터가 하나 더 있습니다. IV라는 건데요. 직역하면 초기 벡터로 암호에 영향을 주는 또다른 팩터라고 이해를 하면 되겠습니다. CBC 모드를 보면 그냥 블록 암호화를 하는 것이 아니라 암호화를 하기 전에 IV와 XOR을 수행한 다음 그 결과물을 블록 암호화를 시킵니다. 다음 블록의 경우에는 IV가 그 전 블록의 암호화한 결과 값이 됩니다. 따라서 블록 별로 어떤 컨텍스트에서 암호화가 되느냐에 따라 동일한 소스에 동일한 키로 암호화를 하더라도 결과 값이 달라집니다. 그말은 궁극적으로 기본적인 블록 암호화 기법보다 패턴을 알아내기가 훨씬 어려워진다는 걸 의미합니다.&lt;/p&gt;
&lt;p&gt;연산 모드를 설명한 &lt;a href=&quot;https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation&quot;&gt;위키 페이지를&lt;/a&gt; 참고하면 다양한 연산 모드가 소개되어 있으니 한번 살펴보도록 합시다. 연산 모드 설명 옆에 병렬 처리, 랜덤 읽기 지원 여부를 비교해 둔 표도 같이 있으니 함께 살펴보면 더 많은 공부가 될 것 같기도 합니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 부스트 라이브러리 CRC32 계산하기]]></title><description><![CDATA[부스트에는 참 많은 기능이 있죠. CRC 계산하는 루틴도 포함되어 있습니다. 그것도 사용하기가 너무 너무 쉬워요.
그럼 일반적으로 많이 사용하는 32비트 CRC를 계산 루틴을 한 번 살펴볼까요 ㅋ~ crc.hpp 일단 인클루드 해 주시구요. crc…]]></description><link>https://jiniya.net/ng/2015/12/calc-crc32-using-boost/</link><guid isPermaLink="false">https://jiniya.net/ng/2015/12/calc-crc32-using-boost/</guid><pubDate>Thu, 10 Dec 2015 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;부스트에는 참 많은 기능이 있죠. CRC 계산하는 루틴도 포함되어 있습니다. 그것도 사용하기가 너무 너무 쉬워요.
그럼 일반적으로 많이 사용하는 32비트 CRC를 계산 루틴을 한 번 살펴볼까요 ㅋ~&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;boost/crc.hpp&quot;&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	boost&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;crc_32_type crc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; bytes&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;hello world!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	crc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;process_bytes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bytes&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bytes&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%08x\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; crc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;checksum&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;crc.hpp 일단 인클루드 해 주시구요.&lt;/li&gt;
&lt;li&gt;crc_32_type이 우리가 계산할 32비트 CRC를 계산하는 클래스 타입입니다.&lt;/li&gt;
&lt;li&gt;process_bytes로 CRC 계산할 버퍼를 계속 공급해 주시면 됩니다. 버퍼 포인터와 크기라는 건 뭐 그냥 아시겠지요?&lt;br&gt;
참고로 한번에 넘기기 큰 데이터는 분할해서 process_bytes를 호출하면 됩니다.&lt;/li&gt;
&lt;li&gt;checksum 메소드를 사용하면 계산된 32비트 CRC 값이 넘어 옵니다.&lt;/li&gt;
&lt;/ol&gt;</content:encoded></item><item><title><![CDATA[[cpp] 16진수 헥사 인코딩의 정석]]></title><description><![CDATA[최근에 퍼지 해시(fuzzy hash), 롤링 해시(rolling hash), 지역 민감 해시(Locality-sensitive hash) 등으로 불리는 코드를 좀 찾아보고 있었습니다. 대체로 ssdeep을 많이 사용하는 것 같은데 ssdeep…]]></description><link>https://jiniya.net/ng/2015/11/hex-encoding/</link><guid isPermaLink="false">https://jiniya.net/ng/2015/11/hex-encoding/</guid><pubDate>Thu, 26 Nov 2015 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;최근에 퍼지 해시(fuzzy hash), 롤링 해시(rolling hash), 지역 민감 해시(Locality-sensitive hash) 등으로 불리는 코드를 좀 찾아보고 있었습니다. 대체로 ssdeep을 많이 사용하는 것 같은데 &lt;a href=&quot;http://ssdeep.sourceforge.net/&quot;&gt;ssdeep&lt;/a&gt;의 경우 안타깝게도 GPL 이더군요. 그래서 다른 종류는 뭐가 있나 하고 알아보던 중에 트렌드마이크로에서 공개한 TLSH를 찾았습니다. &lt;a href=&quot;https://en.wikipedia.org/wiki/Locality-sensitive_hashing#TLSH&quot;&gt;위키피디아에는 TLSH란&lt;/a&gt; 보안과 디지털 포렌직 프로그램을 위해 설계된 지역 민감 해싱 알고리즘이라고 나와 있습니다. 그쵸. 바로 우리가 찾던 그 녀석이죠. 걔다가 착하게도 아파치 2.0 라이선스라는 ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;형님들이 작성한 코드를 좀 보다가 재미난 부분이 있어서 올려봅니다. 바이너리 데이터를 16진수 헥사 코드로 인코딩하는 코드입니다. 아래처럼 작성되어 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;to_hex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; psrc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; len&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; pdest &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; HexLookup&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;513&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token string&quot;&gt;&quot;000102030405060708090A0B0C0D0E0F&quot;&lt;/span&gt;
	&lt;span class=&quot;token string&quot;&gt;&quot;101112131415161718191A1B1C1D1E1F&quot;&lt;/span&gt;
	&lt;span class=&quot;token string&quot;&gt;&quot;202122232425262728292A2B2C2D2E2F&quot;&lt;/span&gt;
	&lt;span class=&quot;token string&quot;&gt;&quot;303132333435363738393A3B3C3D3E3F&quot;&lt;/span&gt;
	&lt;span class=&quot;token string&quot;&gt;&quot;404142434445464748494A4B4C4D4E4F&quot;&lt;/span&gt;
	&lt;span class=&quot;token string&quot;&gt;&quot;505152535455565758595A5B5C5D5E5F&quot;&lt;/span&gt;
	&lt;span class=&quot;token string&quot;&gt;&quot;606162636465666768696A6B6C6D6E6F&quot;&lt;/span&gt;
	&lt;span class=&quot;token string&quot;&gt;&quot;707172737475767778797A7B7C7D7E7F&quot;&lt;/span&gt;
	&lt;span class=&quot;token string&quot;&gt;&quot;808182838485868788898A8B8C8D8E8F&quot;&lt;/span&gt;
	&lt;span class=&quot;token string&quot;&gt;&quot;909192939495969798999A9B9C9D9E9F&quot;&lt;/span&gt;
	&lt;span class=&quot;token string&quot;&gt;&quot;A0A1A2A3A4A5A6A7A8A9AAABACADAEAF&quot;&lt;/span&gt;
	&lt;span class=&quot;token string&quot;&gt;&quot;B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF&quot;&lt;/span&gt;
	&lt;span class=&quot;token string&quot;&gt;&quot;C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF&quot;&lt;/span&gt;
	&lt;span class=&quot;token string&quot;&gt;&quot;D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF&quot;&lt;/span&gt;
	&lt;span class=&quot;token string&quot;&gt;&quot;E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF&quot;&lt;/span&gt;
	&lt;span class=&quot;token string&quot;&gt;&quot;F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF&quot;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;short&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; pwHex &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;short&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;HexLookup&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;short&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; pwDest&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;short&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;pdest&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;len&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pwDest&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; pwHex&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;psrc&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		pwDest&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; psrc&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;pwDest&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// terminate the string&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;사실 뭐 특별할 건 없지만 00부터 FF까지 테이블을 작성한 형님들의 노고에 박수를 ㅋㅋㅋ~ 통상적으로 배열을 만들면 &quot;0123456789ABCDEF&quot; 정도 만들어서 사용하기 마련인데요. 한땀한땀 성능을 생각하신 형님들께서는 친히 00부터 FF까지를 모두 테이블에 담아버렸습니다.&lt;/p&gt;
&lt;p&gt;테이블을 룩업 하는 과정은 더 C언어 스러운데요. 문자열 테이블을 USHORT 포인터로 변환해서 2바이트씩 한번에 복사해 버림으로써 불필요한 연산을 최소화해주셨습니다. 0을 넣는 부분에는 깨알같이 &quot;terminate the string&quot;이란 주석까지 ㅋ~ 장인 정신이 묻어나는 코드가 이닐수가 없네요. 코드를 보면서 &quot;0123456789ABCDEF&quot;만 만들어서는 쉬프트와 더하기를 남발했던 저는 배꼽 반성을 했습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/trendmicro/tlsh&quot;&gt;TLSH GitHub 저장소를&lt;/a&gt; 보면 코드와 함께 발표한 논문 자료와 다른 알고리즘(ssdeep, sdhash)과의 비교 자료도 함께 있는데요. 굉장히 인상적입니다. 이런게 바로 리서치가 아닐까 싶네요. 사족을 하나 더 달자면 그간 트렌드마이크로를 그닥 의미 없는 백신 제품이라 생각했는데 이 코드 하나로 저에게는 기업 이미지가 굉장히 좋아졌습니다. 물론 그렇다고 트렌드마이크로 백신을 산다는 소리는 아닙니다 ㅋㅋㅋ&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] 출산 이모저모]]></title><description><![CDATA[#…]]></description><link>https://jiniya.net/ng/2015/11/about-childbirth/</link><guid isPermaLink="false">https://jiniya.net/ng/2015/11/about-childbirth/</guid><pubDate>Wed, 11 Nov 2015 15:00:01 GMT</pubDate><content:encoded>&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./chaerin1.jpg&apos; data-alt=&apos;여긴 어디? 난 누구?&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f8e21cedf6c81b9e3a4a86ba2f70264d/953fe/chaerin1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 56.315789473684205%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAMCBAX/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQP/2gAMAwEAAhADEAAAAXuyJwXBwdf/xAAcEAABAwUAAAAAAAAAAAAAAAABAAIDBBAREjH/2gAIAQEAAQUCp5GNUsYJ1dbCHP/EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAEDAQE/ARn/xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAgEBPwFX/8QAHRAAAQIHAAAAAAAAAAAAAAAAAgARARIgMTJRkf/aAAgBAQAGPwJivtOJSvxZRo//xAAZEAADAQEBAAAAAAAAAAAAAAAAARExQVH/2gAIAQEAAT8hVdNrYUKbwGzChD0WIf/aAAwDAQACAAMAAAAQ7w//xAAXEQEBAQEAAAAAAAAAAAAAAAABABEh/9oACAEDAQE/EGONhf/EABURAQEAAAAAAAAAAAAAAAAAABAR/9oACAECAQE/EKP/xAAbEAEAAgMBAQAAAAAAAAAAAAABABEhMVFBcf/aAAgBAQABPxAGqJsQeByHDvbhUO8+ymdHxuUtIYoUcOWAI4T/2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;여긴 어디? 난 누구?&apos; title=&apos;&apos; src=&apos;/static/f8e21cedf6c81b9e3a4a86ba2f70264d/953fe/chaerin1.jpg&apos; srcset=&apos;/static/f8e21cedf6c81b9e3a4a86ba2f70264d/8ccab/chaerin1.jpg 190w,
/static/f8e21cedf6c81b9e3a4a86ba2f70264d/ea4c8/chaerin1.jpg 380w,
/static/f8e21cedf6c81b9e3a4a86ba2f70264d/953fe/chaerin1.jpg 500w&apos; sizes=&apos;(max-width: 500px) 100vw, 500px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;여긴 어디? 난 누구?&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;지난주 할머니와 음력 생일이 똑같은 기염을 토하면서 어여쁜 딸이 세상 밖으로 나왔다. 누나들에게 매번 애들한테 왜그리 집착하며 사는지 점쩜쩜이라고 말을 하면, 누나들은 항상 니 애 낳아 보라는 대꾸를 했었다. 아직 일주일도 안 된 딸을 보면서 그말이 틀리지 않았음을 실감한다. 세상의 모든 부모들이 왜 그런지 말이다. 아이와 자식은 다른 느낌이다. 그냥 자고 있는 것만 보고 있어도 열심히 살아야겠다는 생각이 절로 든다. 뭔가 잘해줘야 할 거 같다는 느낌이 팍팍든다. 위험한 생각이 들때면 와이프랑 그래도 우린 맘충이, 빠충이는 되지 말자며 다짐한다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;출산은 정말 시트콤 같았다. 와이프가 점심 때쯤 진통이 온다며 병원에 전화를 했다. 대략 5-10분 간격으로 온다고 말을 하고는 남편 퇴근하고 가도 되냐고 물으니 간호사가 지금 당장 오라고 했다는 것이다. 와이프의 콜을 받고 부리나케 병원으로 달려갔다. 원래 검사를 하던 의사는 없어서 다른 의사가 태동 검사를 하고 내진을 했는데, 뭐 자궁이 하나도 안 열렸고 진통도 별로 없는거 같다며 아직 한참이나 남았을 거 같은데 왜 왔냐는 늬앙스로 이야기를 했다.&lt;/p&gt;
&lt;p&gt;누구나 한번쯤 겪는다는 빠꾸를 맞고는 앞에서 항정살에 7분 김치찌게를 먹었다. 밥을 먹는데도 와이프는 연신 배가 아푸다고 했다. 의사가 하도 완강하게 이야기해서 설마 벌써 그렇겠냐며 5분 간격으로 정확하게 오면 가자고 했다. 그리고는 내심 오늘은 아니라는 생각을 많이 했었다. 엄마는 눈이 뒤집힐정도로 아플 때 병원을 가야 한다는 말을 했었다. 그런데 와이프는 너무 평온해 보였다. 진통이 올때 아파했지만 눈이 뒤집힐 지경은 아니었다.&lt;/p&gt;
&lt;p&gt;회사 들어가기도 애매하고 혹시 몰라 집에 있었다. 앱으로 계속 시간 측정을 했다. 5분 내로 진통은 계속 왔지만 우리는 아니라고 생각했다. 설마 의사가 그랬는데 불과 2-3시간 지났는데 시작됐겠어? 이건 아닐꺼야 그런 생각이었다. 저녁 먹을즈음에도 진통은 3-4분 간격으로 계속 왔다. 엄마가 뭐라도 먹어야 애도 낳는다는 말에 일단 밥을 먹자고는 배달 음식을 시켰는데, 그 배달 음식이 딱 도착하기가 무섭게 양수가 터졌다.&lt;/p&gt;
&lt;p&gt;병원을 향해 달려갔다. 퇴근 시간인데다 서울대입구 4거리는 늘 헬게이트, …​ 와이프는 정말 눈이 뒤집히고 있었다. 눈물을 흘렸다. 어쨌든 병원에 도착했고 바로 분만실로 갔다. 간호산지 조산산지 뚱땡이가 왜 이제 왔냐며 뭐라고 했다. 아침에 있었던 일을 이야기 했지만 의미는 없었다. 벌써 자궁이 5cm이나 열렸다고 했다. 30분쯤 지나자 7cm, 한시간 좀 넘어서는 8cm가 열렸다고 했다. 무통은 의미가 없다고 했다. 일찍 와야 맞을 수 있는데 이미 다 지나가서 지금은 맞을 수가 없다는 이야기. 와이프는 절규를 했다. 무통과 제왕절개를 욕과 함께 미친듯이 요구했지만 그저 바라볼 수 밖에 없었다.&lt;/p&gt;
&lt;p&gt;뚱땡이 간호사는 정말 불친절했다. 틱틱거리며 와이프에게 시종일관 명령과 지시의 태도를 보였다. 아픈데 그러니 말이 통할리가 없다. 난감한 상황. 하지만 3시간쯤 지나 출산이 임박했을 때 해결사가 들어왔다. 벌써 사람 다루는 폼새가 남달랐다. 특히나 목소리가 너무 좋았는데 마치 최면에 걸려서 그 말을 꼭 따라야 할 것 같은 그런 목소리였다. 와이프는 어렵지 않게 그 사람의 말을 따라했고, 몇 분 지나지 않아서 아이가 나왔다. 병원온지 3시간 50분 만에 순산했다. 의사가 오고 아기가 너무 쉽게 나와 좀 어이가 없었다. 힘주세요. 한 번 더 하는데 나왔다. 엉겹결에 탯줄을 끊었다. 채린이가 그렇게 태어났다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./chaerin2.jpg&apos; data-alt=&apos;어서와, 이런 세상은 처음이지&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/1556b980ed49b0c8fce4c95bf4807b66/953fe/chaerin2.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 56.315789473684205%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAQBAgX/xAAWAQEBAQAAAAAAAAAAAAAAAAADAQL/2gAMAwEAAhADEAAAAXKMKmmaSXP/xAAaEAEBAAMBAQAAAAAAAAAAAAABAgADEhEi/9oACAEBAAEFApPM2kpsPrmQq6Mqnr//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAbEAABBAMAAAAAAAAAAAAAAAAAAQIhMSJBUf/aAAgBAQAGPwLhWbiChZ2Kf//EABgQAQEBAQEAAAAAAAAAAAAAAAERIQBB/9oACAEBAAE/IT3SPFx5XFCk7WYnGSOcBExyEXV7/9oADAMBAAIAAwAAABCjP//EABYRAQEBAAAAAAAAAAAAAAAAAAEQEf/aAAgBAwEBPxDRn//EABYRAQEBAAAAAAAAAAAAAAAAAAABQf/aAAgBAgEBPxDUf//EAB0QAAIBBAMAAAAAAAAAAAAAAAERACFBUWExkbH/2gAIAQEAAT8QfgTkui0FQiqVHvVIFYqAg5UuhcsP2IhEIBQR2FglT//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;어서와, 이런 세상은 처음이지&apos; title=&apos;&apos; src=&apos;/static/1556b980ed49b0c8fce4c95bf4807b66/953fe/chaerin2.jpg&apos; srcset=&apos;/static/1556b980ed49b0c8fce4c95bf4807b66/8ccab/chaerin2.jpg 190w,
/static/1556b980ed49b0c8fce4c95bf4807b66/ea4c8/chaerin2.jpg 380w,
/static/1556b980ed49b0c8fce4c95bf4807b66/953fe/chaerin2.jpg 500w&apos; sizes=&apos;(max-width: 500px) 100vw, 500px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;어서와, 이런 세상은 처음이지&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;의사가 그랬다. 상위 10% 들 정도로 순산했다고. 물론 거기 순위를 메긴다는게 우습긴 하지만 정말 쑨풍 나온 것 같긴 했다. 와이프 한테도 채린이한테도 고맙다. 옆에서 지켜보는 것도 보통 고통이 아니기 때문이다. 무통과 제왕절개를 외치는 것을 가슴으로는 백번도 더 시켜주고 싶지만 머리로 말려야 한다는게 결코 편하지는 않기 때문이다. 나도 힘들었는지 그날 새벽 옷을 갈아 입으로 집으로 가서는 씻겠다고 욕조에 물을 받아놓고 그 안에서 잠이 들어버렸다 ㅋㅋㅋ~&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;사실 난 대한민국 복지에 대해서 크게 느낀 바가 없다. 내 급여에서 상당한 금액의 의료보험료와 고용보험료가 나가지만 크게 병원을 간 적도, 실업 급여를 받은 적도 없다. 더 많은 국민연금을 내지만 그 연금을 잘 수령할지는 미지수다. 더 (체감상) 천문학적인 소득세를 내고 있지만 정말 이렇게까지 뜯어가야 하나 싶은 생각만 있었다. 그나마 약간 느낀게 엄마가 암 수술을 했을 때 중증 환자로 5%의 비용으로 치료를 받는 걸 보고는 의료보험은 그나마 제구실을 한다는 생각을 했었던게 전부였다.&lt;/p&gt;
&lt;p&gt;그런데 이번에 아이를 낳고 보니 생각보다 우리나라가 그리 구리지는 않다는 생각이 많이 들었다. 우선 부탁한적도 없는데 자연분만에 드는 일체의 비용을 국가에서 부담해 주었다. 거기다 청각 검사와 대사 증후군 검사를 무료로 해주고, 그것도 모자라 결핵 예방접종도 해줬다. 병실료와 영양제 값만 나온 청구서를 보고는 참 고맙다는 생각을 했다. 관악구에 출생신고를 하러 가서는 선물을 안 줘서 조금 실망했지만 육아수당을 준다는 이야기를 듣고는 좋다는 생각이 들었다. 그것도 소득수준에 관계없이 준다는 데 감사한 마음이 많이 들었다. 물론 여기서 끝이 아니다. 아이를 어린이집에 보낼 경우 모든 비용을 국가에서 부담한다. 그것도 초등학교 입학할때까지 모든 비용을 말이다.&lt;/p&gt;
&lt;p&gt;보건소도 나쁘지 않다. 임신 중에도 각종 검사와 약을 지원해주고, 출산 후에도 상당히 많은 신생아 예방 접종을 지원해준다. 그것도 보건소에 가서 맞아야 된다고 생각을 했었는데 대부분의 큰 병원이 모두 제휴가 되어 있어 그냥 병원에서 맞아도 비용을 다 국가에서 지불해준다. 참 편리한 시스템이라는 생각이 들었다.&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;프로그래머는 숙명적으로 무엇인가의 이름을 지으며 살아간다. 언젠가 인터넷 설문조사에서는 프로그래머가 느끼는 고충 중에 당당하게 1위로 이름짓기(Naming)가 올라와 있었다. 어쨌든 그렇게 이름을 수도 없이 지으며 산다. 그래서 그랬을까? 와이프의 임신 소식을 들었을 때 이름이 뙇 떠올랐다. 딸이면 채린이라 짓고, 아들이면 태성이라 지으리라. 심지어 아들 이름은 한자까지 떠올랐다. 클 태에 이룰 성으로 지어야지 ㅋ~&lt;/p&gt;
&lt;p&gt;병원에서 퇴원하는 날 난 엘티이급으로 출생신고를 했다. 하지만 이름을 가지고 잡음이 좀 있었다. 엄마가 어디서 지었냐는 출처를 계속 캐물었기 때문이다. 어디서 지었냐? 그렇다 우리나라 사람들은 이름을 대체로 스스로 짓지 않는다. 어딘가에 위탁한다. 철학관, 작명소 같은 곳 말이다. 사주도 풀고 그런단다. 내가 지었다는 말을 결코 신뢰하지 못할 우리 엄마를 위해서 월정사 명월스님에게 지었다는 이야기를 했다. 그러자 엄마가 조금 안심을 한다. 대기업 회장님들도 찾아가는 유명한 스님이라고 하자 더욱 신뢰를 하셨다. 우습지만 그게 현실이었다.&lt;/p&gt;
&lt;p&gt;결혼을 하는 날짜도, 이사를 가는 날짜도, 이사를 가는 방향도, 애 이름도, 사업을 할지 말지도, 유학을 갈지 말지도, 우리 나라 사람들은 대체로 스스로 뭔가를 결정하지 못하는 것 같다. 다 좋은게 좋은거고 조심해서 나쁠건 없다는 이야기를 한다. 그렇게 잡은 결혼 날짜에는 미친듯이 비가 왔다. 그제야 하는 말. 비 오는 날 결혼하면 잘산다는 이야기. 이건 뭐 피할 수가 없다 ㅠㅜ~&lt;/p&gt;
&lt;p&gt;이것도 좋고, 저것도 좋고, 다 좋은데 이름 하나쯤은 내가 지어주고 싶었다. 내가 생각하는 딸에 대한 애정이랄까? ㅋ~&lt;/p&gt;
&lt;h3&gt;#4&lt;/h3&gt;
&lt;p&gt;산후조리원과 산후도우미, 어린이집에 관해서도 할 이야기가 많지만 시간 관계상 이쯤에서 마치는 걸로 ㅋ~&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; margin-bottom: 16px;&apos; data-url=&apos;./chaerin3.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/700fcfb749715b01b52675383f2d7e18/0eb09/chaerin3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 56.315789473684205%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACpUlEQVR42hXPyU4TAQCA4XkET140GhO8GDUeNIYLEo0SDTHgATVoJVIRlKAitlKsQFukC0tL0g1K9226Tfdpp8u0022mlO7DdGMzGuNbWB/gS/4fQEzcBCT2mwQ25UIuCqYR0KXgmliv7Et09fdxnWDGs7MUtm5EnDLUq/Fp2HreiHi6jzF0abL/DODZZYYsfI9iAZIxIuAm6pCirp00DO1h0SKOVfeJapEoF/AikS7mccQutolfq9hDPNqNDw/OAqqFARX7iXn5pV/+KaznxUFJPuqp5DNkqUDVylS1RJYLtXKhuJft+rBt3SmdsghpWzN35ocvAKLxq3x6n45DQ/ScOLiZcusiFn0lEepU949b1OlR55CsHGDRaipWLuSjDgmkmLaujykY95eeXQZ4tGsrE3fVnDHEICACaiFrVidaacCOZhLuZNGT5sHpYbuVQcmIr7uQhrUxJz9oYFpET0UT1wHWyBUuvV/+bTSgWS3FHHz2vJz5kbJISUhH2TT/fafRyBNVNFxEQynfLuaXxaG1kHnOtjEIvH/UwxztnRnpdcgWi8lAhcDKmSQOakm7qgHbj8jySeuA9JlLYXfSaUxA8lRAhrrXQsbPDskw8Hbg4tzzW5zJe04pk4DN+USoXsi0qVp39ZiqHVP1Tq1cQ9ylqD/ltSa9yi6OQ0LYOJsKioDZh+d/0HtlXx+b1yZTRj4OaXDYVUwiZAGv7+FVHMuFPXGPOe4xRJwqzLed9G7FXMJsTNVuE8Dy6LnNdzeVrEHV8guXlBtULjpl7JBtJ+bWRSFNFFKhXjXm12ABTRpWp4PbaXi7kLG32viv3xQgmOqRMm4bV4dByRvz1heHmhuyihLdvKAWR0z5OJiPgXjElEMM2bA2FzOUCE+zmTn9Wf/z9+gfvTCoWK8QzGMAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;chaerin3&apos; title=&apos;&apos; src=&apos;/static/700fcfb749715b01b52675383f2d7e18/0eb09/chaerin3.png&apos; srcset=&apos;/static/700fcfb749715b01b52675383f2d7e18/08678/chaerin3.png 190w,
/static/700fcfb749715b01b52675383f2d7e18/2edd7/chaerin3.png 380w,
/static/700fcfb749715b01b52675383f2d7e18/0eb09/chaerin3.png 500w&apos; sizes=&apos;(max-width: 500px) 100vw, 500px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] 100인 기업은 얼마나 많을까?]]></title><description><![CDATA[언젠가 모 회사 분과 이야기를 하다 그런 말을 들었다. 회사가 어려운데 구조조정을 하지 않는 이유 중에 하나가 대표의 욕심 때문이라는 이야기였다. 대표가 일정 수준 이상이 되는 규모로 회사를 유지하려는 욕심이 있다는 말이었다. 100인 기업, 10…]]></description><link>https://jiniya.net/ng/2015/10/company-size/</link><guid isPermaLink="false">https://jiniya.net/ng/2015/10/company-size/</guid><pubDate>Fri, 30 Oct 2015 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;언젠가 모 회사 분과 이야기를 하다 그런 말을 들었다. 회사가 어려운데 구조조정을 하지 않는 이유 중에 하나가 대표의 욕심 때문이라는 이야기였다. 대표가 일정 수준 이상이 되는 규모로 회사를 유지하려는 욕심이 있다는 말이었다. 100인 기업, 100억 매출 이런 상징적인 이미지를 가지고 싶어한다는 말이었다. 난 상징적인 이미지보다는 실속을 더 따지는 편이라 100명이서 100억 버는 회사 보다는 2명이서 3억 버는 기업이 더 좋을텐데라는 생각을 했었다. 그리고 막연하게 100명, 100억 하는 회사가 흔하지는 않아도 자부심을 가질만큼 귀하지는 않을 것 같다고 상상했다.&lt;/p&gt;
&lt;p&gt;그런데 현실은 아니었다. 어제 팩트 체크를 보다가 우연히 아주 충격적인 사실을 알게 되었기 때문이다. 사업 분야를 불문하고 우리나라에 존재하는 모든 기업 중에 100인 이상의 종업원을 고용한 기업이 무려, 당황스럽게도 0.8%밖에 되지 않는다는 사실이었다. 아래 그림처럼 말이다. 8%도 아니고, 무려 0.8%다. 소프트웨어 기업은 일반적인 기업보다 보통 작은 규모인 경우가 많으니 100인 기업은 비율이 훨씬 더 낮을지도 모른다. 더 충격적인 사실은 10명 이상 고용한 사업체도 전체 기준으로 봤을 때는 상위 15% 안에 포함된다는 사실이다. 30인 이상은 상위 4%에 포함된다. 헐~&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./fact.png&apos; data-alt=&apos;JTBC 팩트 체크&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 620px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/0242affe62f6b0674437b3d03c4031ca/abf7b/fact.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 56.315789473684205%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACoElEQVR42g3NWVMSAQAA4H1qSkcF1AFxCTmWc9ldlt0F9uDYhRVYBUTlyPJOLcYmtWk8OkZrPDJNm3RQ0RRRQaemhx6cmuq9XvtB9f2BD2hkMy1CrhWhdUab2e6EUdKBERjFuDmeCUVpIeIT42IinUjf684OxNP9fEdPT99Ifno2EEkCtcHBW/bADTlYpzTKWi1KHarSOUALHklke3P3pa676Tsjmezo6PCjXGZQSmZ87fFYKjc4lmdDMaABIhqbNQqVXqW1tuhgvY3S2wkT5vV4BEGMBMPhcLSjMx4NiqLH1y6E40EpyYUlDy9yYgyQN2uaWoxylb4RNKvbHHoLobcREEozDN+V8UUSnNQd6skEYx1iwBfj+RgdijJCOxuKUD4ekCvb5Ep9g1IHQYjGTEJsh4HrNOKsi+RpJkYSQkBMsH6JcPlJyo9QHOr1O+mAiw0iHgaok6lr5aBaY1mcGNfaGXNyzNQ9biB5C85hdNiJe5GJBTQ1ALsYs5MyO90OinN6AzgdQN0MIFOA9XJQJleBoLZJbYK4JCT1G3DO4WJxgsMeLCBf/+LH310Dk1hIsqGEHSUR3I2RtBUjAEVTW0OjpuZmPW5z/H9UEGnkU/DUGrZZxdfLyPFPR+mX8+q36+jatV2xbn+yTjyDo70wI1gdOFBTo6iTqfRa02gmm+0bum3EUMqPh1NoNAuL3UYqqMVZHeEzuHkdGVBTghqmWo1wi9bUrASBz+fl4rs326srS/OzB1tb5f2948JueW/n4qBQOdy7OCpWSh+rpyfV01K1VKqclC7PL66ql6en5WLxEPjz49v1WWH9ydDK9NDy1PDazOjG3MON+fzb2fzm/OTW88fvX858WHy682pu9/V8YflFYW2puLl6vr/75eLsH2lZwszRX5DdAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;JTBC 팩트 체크&apos; title=&apos;&apos; src=&apos;/static/0242affe62f6b0674437b3d03c4031ca/abf7b/fact.png&apos; srcset=&apos;/static/0242affe62f6b0674437b3d03c4031ca/08678/fact.png 190w,
/static/0242affe62f6b0674437b3d03c4031ca/2edd7/fact.png 380w,
/static/0242affe62f6b0674437b3d03c4031ca/abf7b/fact.png 620w&apos; sizes=&apos;(max-width: 620px) 100vw, 620px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;JTBC 팩트 체크&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;팩트 체크니까 구라 자료는 아닐꺼라 생각했지만 0.8%는 다소 충격적이었다. 그리고 화면에는 나오지 않은 30-49인, 50-99인의 세부적인 비율도 궁금해서 좀 찾아봤는데 아마도 JTBC의 자료는 고용노동부에서 발표한 아래 자료에 기반하고 있는 것으로 보였다. 아래 자료 수치대로하면 30-49인은 전체 사업체 중에 2%를, 50-99인은 전체 사업체 중에 1.25%를 차지한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./company.png&apos; data-alt=&apos;고용노동부 2013 기업 규모별 사업체수 통계&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 608px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f0f301ff88cc78e2aa2ecb56fbb3958d/5db90/company.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 56.84210526315789%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACAUlEQVR42h2QW3ObMBCF+f9/og996XT60Jm0nThtpqmbPnQy9qRxwAYkgYQkJAQGgy9cBOniF420R7vn2+OgpApoudpmz1u5dsUW5ztiXJRvsdkEektyP8pdlMHTQ8Yn5mWnCS9V3ghdOx8WwbuP6/efXz/dbW5+rJZP0cNf9OX++fsf//cq/vrz5XbpPq7p3aP37eFlsfQWy9eb+3+3S+/XE3HWm9ALWBjrmOdptidUECqlKnwUB5gpU3FpcMRFmku99xHFVPDUeD6mSeqQmAqZZnlRHuphGLgQ8JymKUl4FMXjOB2PxyBEzfE0TW+cC50ZuMAvyhInIDGOmdAmK6q+twmXjMu2GxjjUUwv7dA0J4RJVTWzmgiRalBBYolwAhztQiRUZvbVYMdUacZF1w/gT+bmvu16+FkdGijCRaa6Hyy0ylQ5IY4CRKTKgBt4TF5A1doRThjfdb21FjI41A0UZ2xtrmqqlHYQoT7CEeP7qh6nab+vIJwZIVUkopeuh7WVNmV1GGFnIcEZVEoTSpnjI7IFa5YUZT3at7I8CKkAAdwwidoWnCdIswR1nIupyuDCkjkRZxdidwepMcCGkZAqONtxguUxic8Qjh2BubxyKZ1xOavQjKN4dnZ3fpyIoqphmfOl1VkOkQAn5xICs+PY9f3p3EJzdai1yWGcuPL/B6lCU0tngZ2VAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;고용노동부 2013 기업 규모별 사업체수 통계&apos; title=&apos;&apos; src=&apos;/static/f0f301ff88cc78e2aa2ecb56fbb3958d/5db90/company.png&apos; srcset=&apos;/static/f0f301ff88cc78e2aa2ecb56fbb3958d/08678/company.png 190w,
/static/f0f301ff88cc78e2aa2ecb56fbb3958d/2edd7/company.png 380w,
/static/f0f301ff88cc78e2aa2ecb56fbb3958d/5db90/company.png 608w&apos; sizes=&apos;(max-width: 608px) 100vw, 608px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;고용노동부 2013 기업 규모별 사업체수 통계&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;그런데 뭔가 좀 이상하다. 100인 이상 기업이 전체의 0.8% 밖에 되지 않는데 내 주변 사람들은 거의 대다수가 100인 이상 기업에 다니기 때문이다. 그건 사업체 수가 아닌 해당 사업체에서 근로하는 근로자수를 비교해야 비로소 의문이 풀린다. 옆에 있는 상용 근로자를 기준으로 데이터를 뽑아보면 아래와 같이 나온다. 100인 이상 기업체 수는 전체 기업체에서 0.8%를 차지하지만 해당 업체에 근무하는 상용 근로자 수는 전체 근로자에서 27%를 차지한다. 그러니 100인 이상 기업에 근무하는 사람은 쉽게 찾을 수 있는 것 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./employee.png&apos; data-alt=&apos;기업 규모별 종사자수 계산&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 292px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/e3fc24458a67fc4126e041fe5c565495/73e11/employee.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 83.6842105263158%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAIAAABSJhvpAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACOklEQVR42mWT25qjIBCEff/3m3gW8DgCCqImnmK2kJl8u1mvRPqnqujWO/Z9HEczjo/H4/n77Pt+HAdeluUxzdM8zyhYluU8z33f7vc7vjwei/c89vDm34KgquvX6+UYB5/PoyyLKI7TJP66+XowKJiMTtI0jqNeaQ9Fxgx1XQkh/4bxYKmVisKwFSLLMmNGfIGYEDxKUq21h6JBK0aZkBZ+27bweSqFLdo0DWP58AvLThZlhbDeui6C84xQwcV/yhaGQ5Dwr5S+4K2THRcSwT2Ucv7NWx6EkRQ/4m/bfScpo0r1sN07eN84bxOkgDKkmqbGOk3Trus/4GEYKKV1XcLncF3Y83kgJqEMW8i8FXnBOY/jWMruA0ZLoFkWOaEUF3Zez6A1WmOM8bZtLYqirqqbH/RKfcLTnCBzngdR5JQBm0FHUYyltV2WJTLj+Cwj0zSjYNu2X+WJMYZG5nmBkE55NMjCrDIWdVXWTSMl9/3AxX7D0zjiaDQ2I2Qw5uVsDxopLuV9h2Bd13nOfD/se/WGXc9hm2QkSZJrwk58gZ00zawyYEItXFVlEITqXxihKMmwSxlzth0cx4kbzx2dhO1rjBM3CQ5GKY7GdUoh0DBr+7pOp6w1WrVt6LA9m5Cv263r+w/baZIUeR6GkR1Pq3zO04h/A2fZCYMmeMwwYT8T/lbGDLZtKwVPU5fZKuOHJITidmyrsFeURVVW39+t7Dow67qCt3X3GZOktcqL3IyTu4V1WfCraD38ATMqvgsROxpOAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;기업 규모별 종사자수 계산&apos; title=&apos;&apos; src=&apos;/static/e3fc24458a67fc4126e041fe5c565495/73e11/employee.png&apos; srcset=&apos;/static/e3fc24458a67fc4126e041fe5c565495/08678/employee.png 190w,
/static/e3fc24458a67fc4126e041fe5c565495/73e11/employee.png 292w&apos; sizes=&apos;(max-width: 292px) 100vw, 292px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;기업 규모별 종사자수 계산&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;다시 앞으로 돌아와 보면 몇 해 전 내가 했던 상상은 현실이 아니었다. 100인 이상 종업원을 가진 기업은 나의 상상보다 훠얼씬 더 작았다. 0.8%라니, 거기다 그 인원으로 100억 매출을 하는 회사는 훠얼씬 더 작을지도 모른다. 대표 입장에서는 충분히 가지고 싶을 만한 상징적인 이미지라는 생각이 들었다. 물론 회사 외형이나 규모가 전부는 아니지만 말이다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 실시간 자식 윈도우 크기 조정]]></title><description><![CDATA[위에서 정의된 상수들은 WM_SYSCOMMAND의 WPARAM으로 전달될 때 그 진가가 발휘됩니다. 상수가 의미하는 바는 위의 주석에 잘 나와있습니다. 위에서부터 표준 윈도우의…]]></description><link>https://jiniya.net/ng/2015/08/child-window-resize-magic-message/</link><guid isPermaLink="false">https://jiniya.net/ng/2015/08/child-window-resize-magic-message/</guid><pubDate>Tue, 18 Aug 2015 15:00:01 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt;    &lt;span class=&quot;token macro-name&quot;&gt;SC_SZLEFT&lt;/span&gt;           &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0xF001&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;              &lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;// resize from left&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt;    &lt;span class=&quot;token macro-name&quot;&gt;SC_SZRIGHT&lt;/span&gt;          &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0xF002&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;              &lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;// resize from right&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt;    &lt;span class=&quot;token macro-name&quot;&gt;SC_SZTOP&lt;/span&gt;            &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0xF003&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;              &lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;// resize from top&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt;    &lt;span class=&quot;token macro-name&quot;&gt;SC_SZTOPLEFT&lt;/span&gt;        &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0xF004&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;              &lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;// resize from top left&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt;    &lt;span class=&quot;token macro-name&quot;&gt;SC_SZTOPRIGHT&lt;/span&gt;       &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0xF005&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;              &lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;// resize from top right&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt;    &lt;span class=&quot;token macro-name&quot;&gt;SC_SZBOTTOM&lt;/span&gt;         &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0xF006&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;              &lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;// resize from bottom&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt;    &lt;span class=&quot;token macro-name&quot;&gt;SC_SZBOTTOMLEFT&lt;/span&gt;     &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0xF007&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;              &lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;// resize from bottom left&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt;    &lt;span class=&quot;token macro-name&quot;&gt;SC_SZBOTTOMRIGHT&lt;/span&gt;    &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0xF008&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;              &lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;// resize from bottom right&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt;    &lt;span class=&quot;token macro-name&quot;&gt;SC_DRAGMOVE&lt;/span&gt;         &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0xF012&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;              &lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;// move by drag&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위에서 정의된 상수들은 WM_SYSCOMMAND의 WPARAM으로 전달될 때 그 진가가 발휘됩니다. 상수가 의미하는 바는 위의 주석에 잘 나와있습니다. 위에서부터 표준 윈도우의 8방향에서 사이즈를 변경하는 것과 마우스 이동 시 사용할 수 있는 메시지입니다.&lt;/p&gt;
&lt;p&gt;그럼 도대체 위 메시지를 윈도우에 전달하면 어떤 일이 일어나는지 살펴봅시다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;SendMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hwnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WM_SYSCOMMAND&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SC_DRAGMOVE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;만약 위와 같이 메시지를 보낸다면, hwnd라는 핸들을 가진 윈도우의 위치는 그때부터, 마우스를 드래그 하는 방향으로 위치가 변경됩니다. 윈도우가 자식이든 아니든 상관 없습니다. 단지 메시지를 받은 윈도우는 마우스의 변화에 맞게 저절로 위치가 변경되는 겁니다.&lt;/p&gt;
&lt;p&gt;이러한 방법은 자식 윈도우의 위치를 제어할때에도 유용하지만, 캡션과 프레임을 없앤 스킨이 들어간 다이알로그를 제어할때에도 유용하게 사용할 수 있습니다. 제공되는 샘플 소스에는 실행 시간에 8방향에서 사이즈를 변경하는 것과 마우스 드래그에따라 움직이는 Static 윈도우를 보여주고 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;//! Static에서 WM_LBUTTONDOWN이 발생했을때 오는 통시 메시지&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \param wParam 은 컨트롤 아이디 이다.&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \param lParam 은 사용되지 않는다.&lt;/span&gt;
LONG &lt;span class=&quot;token class-name&quot;&gt;CdynresizeDlg&lt;/span&gt;&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;OnMsgStLBDn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WPARAM wParam&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPARAM lParam&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wParam&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; IDC_MOVE&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;ReleaseCapture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// 드래그하면서 움직이는 메시지를 날린다.&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;SendMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WM_SYSCOMMAND&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SC_DRAGMOVE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; IDC_RESIZERB&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;ReleaseCapture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// 오른쪽 아래를 드래그 하면서 사이즈가 변경되는 메시지를 날린다.&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;SendMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WM_SYSCOMMAND&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SC_SZBOTTOMRIGHT&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[시스템] 엄격함과 느슨함 그 사이 어디쯤...]]></title><description><![CDATA[몇 해 전 지인이 앱스토어 카테고리…]]></description><link>https://jiniya.net/ng/2015/06/between-strictness-and-looseness/</link><guid isPermaLink="false">https://jiniya.net/ng/2015/06/between-strictness-and-looseness/</guid><pubDate>Mon, 29 Jun 2015 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;몇 해 전 지인이 앱스토어 카테고리 1등을 먹어서 아주 수입이 짭짤했다는 이야기를 들었다. 사촌이 땅을 사면 배가 아프게 마련이고, 주변에서 누군가 뭔가를 이루면 자연스레 나도 할 수 있을 것 같다는 근자감에 불타오르게 된다. 야심차게 앱스토어 개발자 등록을 했었다. 소녀시대 퍼즐 앱을 만들겠다는 포부를 가지고는 자료를 수집하기 시작했는데 딱 거기서 끝났다. 한줄의 코딩도 없었고, 공부도 하지 않았다. 내가 개발자 등록을 하고 유일하게 한 거라곤 iOS 베타 버전을 먼저 설치해 보는 정도였다. 돈이 아까워서 설치한 베타 버전이었다. 하지만 엎친 데 덮친 겪으로 베타 버전에 버그가 많아서 그마저도 계륵같은 존재였다. 돈이 아까웠지만 맥북을 사지 않았다는데 마지막 위안을 삼았다. 그렇게 앱 개발은 레드오션이라며 여유가 신포도를 다루듯 나의 머릿속에서 영영 멀어졌다.&lt;/p&gt;
&lt;p&gt;그렇게 영원히 잊혀질 것 같았던 앱 개발을 작년 말부터 친구 녀석이 나에게 다시 세뇌시키기 시작했다. 자기 주변에서는 다 앱 개발을 해서 대박을 쳤다는 이야기였다. 처음 한두번은 그냥 웃어 넘겼지만 녀석의 집요한 이야기 끝에 난 세뇌돼 버렸다. 그러던 한 날 밤이었다. 핸드폰을 만지작 거리며 침대에서 다큐를 보고 있는데, 이놈에 다큐 홈페이지 네비게이션 시스템이 당췌 어이가 없을 정도로 불편한 것이었다. 평소 좋아하던 다큐였기에 그날 코딩에 들어갔다. 그래 이 다큐를 나처럼 편하게 보고 싶어 하는 사람이 얼마나 많겠어 하면서 코딩을 했고 몇 일 사이 베타 버전이 나왔다. 풉, 혼자 만족해 하면서 스토어에 올렸다. 반응은 냉랭했다.&lt;/p&gt;
&lt;p&gt;친구 녀석한테 하소연을 했더니 그런건 너같은 사람이나 보는 거고, 게임 동영상을 보는 게 훨씬 잘 될 거라는 이야기를 했다. 똑같은 앱에 컨텐츠만 바꿔서 올렸다. 다큐가 게임으로 바뀐 앱이었다. 어랏, 그런데 제법 사람들이 다운 받기 시작했다. 광고 수입도 올라온다. 노트북을 질렀다. 설 연휴에 본격적으로 개발해 보겠다는 심산이었다. 그런데 거기서 끝났다. 생각보다 잔손이 너무 많이 갔고, 좀 하다 보니 재미가 없어졌다. 재미난 사실은 그렇게 앱 업데이트를 끊은지가 어언 몇 달이 지났는데도 지금도 꾸준히 광고 수입이 발생한다는 점이다. 이대로 계속 간다면 손익 분기점은 40개월 남았다. 올레, 핡~&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;돈은 못 벌었지만 안드로이드 앱 프로그래밍은 나에게는 신선한 충격이었다. 충격이었다는 말은 배울 것도 많았고, 생각할 거리도 여럿 제공을 했다는 말이다. 그 중에 한 가지를 이야기 하려고 한다. 최근에 페북 앱이 링크를 브라우저로 돌리지 않고 직접 내장 웹뷰에서 보여주는 방식으로 변경해서 테스트를 해보았는데 페북 웹뷰에도 이 처리는 포함되지 않은 것으로 보여진다.&lt;/p&gt;
&lt;p&gt;거창하게 말했지만 사실 요는 간단하다. 아래 페이지처럼 페북 내장 웹뷰에서 제대로 렌더링이 되지 않는 페이지가 있다는 것이다. 지금 모바일 환경이라면 여기서 테스트를 해볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./inven.png&apos; data-alt=&apos;웹뷰에서 인벤 동영상 링크는 어디로 사라진 것일까???&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 308px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/2a375177778e5b64a4f0b3b8885e042f/9e38b/inven.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 136.31578947368422%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAbCAIAAADzvTiPAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAErElEQVR42qVUWU8bVxSeB6h4QKIgCqimLAG6EIggCQkoghhDwNQspRiwkqZpq25QEUpC0yRVWvEbKBKQqA9pIlJZqVkLFLBZjG0IRNhmvOExqwFjbGPjBeyxb884UJGEPvXTp6NP58y5c88yg9FotITExHhaVByNFhgYiPkREREB/tjYWLAhISFhYWFgIyMjk5OTQYf6ERQUhIlEIolYIhZOTE5Ojo6O8vl8gUAwNjYGetwPEGKxGMTExMTU1LRAMApReBgs5vGQdrvLarWqVKrNzU2LxWIybev1q0tLiwRBGI1GvV6PEPL5kMWF7B7kJEH77A4nOLHtbZNGswBQKpUajUar1arUalyhwXEljs/LZPL5+XmFQqGmnGqlSq0jdAB43mw2Y21tbVBGQkJCXFwcFBkTExsfH8e8FF3EPJ+bm19ZyWaxWPn5+dnZ2XQ6ncHIjY6Ojo8/AYW3t7djzc3NAQEBUVFR0I+IiLfCwiLTToVfrQ7Oy8tks6tv3Gioqampra2tq6urrq4uZrHeDA6OCg9/IyCgpaUFW1tbk0ql09NUJ4TCCT5/bHL84dxsx8DgMI/3J6Cjo4PL5f7x5Mlvjx8/+fmXjov0h2fP9Tc1rZtM2N7+PpRuMBgUOL6xsUHoCLF4Si5XLC7qoFSoDcYBgtBqF7TadUK3v2rwrOtJm23P7caEEuFPd3+4d+f2ndu37jY2NDXdu/Vj47VrVysrK69cvgKWw+GwAZXs8rLy8qryr66XlX5cQc9jwKWwnl5eAaugoJTJZDHLigsrPiopZhWnpqTQaG9DFxkMBvQpKyvrIj3nTNq5pAuhBez0zIzMpHcTW1tbsT7BIIdTcfnzT77+7NP6L78oL2GVlBQXFlx6PykJjmhoaGi8ebPmm2+/q62tv17PriqvYnPAZGZk3X9wH3v0+6PUrDNppTmJ9LMnsk7nZNM/LGR9kJHyHvNkamFaSlF6alF6csGpk0zQaadLzsdcSEj9PuYdZmjbrw8w7QLB7eJ1jvR3Dg10D/8NPR8VjP81PNAvGRwQD/H4XUf5dITXKegeUUK0h9DqMPQ/gMGikl6f1+vzkF4S6AX4yAMNIcq6PaQb4Dmk1+0m3RDAjEaDTDYjkz3f2FjxL/g8WLn8uVarUavnYdNlslmTyej/Nnyvvlmv3+fzdyQSq1jskkh2pVI7jjumpqwymUMkss3MWCEkkbxYJfRKOuZ0os1NtL2NdDrYM2Q2U3p9nXKurFAaxOoqIsnjavZbONBLWZ+f6HX+Z8OgcvLFlXyHF/MdnuP1HvD45D2vfcewsjkntSwvbSkURqVyC8dBrM/NmQnimEKPJpMk6XK67BaLfWcHrANoszmsVsfOjnN3dw/gcr3EI6DmDGM+KM4/Da/PdyD8muK/AngE/oZBl589Q4uLVH/lcrS1heDCIMCjUiH4AUqlaHkZLSxQTo/n5W6Dl8tFIhGamUFjY2h6GvH5aHiY8giFaHYWdXWhyUnqBd3d1NwOG+hPVihQby/q60M9PdTZkDk3h4aGkFpNiYEBKnlwEI2PIxx/bc57e8hup2izURoOdrvR7i6CBXK5KAEhWDGHg/IfSf4HqF+vuMqBAWsAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;웹뷰에서 인벤 동영상 링크는 어디로 사라진 것일까???&apos; title=&apos;&apos; src=&apos;/static/2a375177778e5b64a4f0b3b8885e042f/9e38b/inven.png&apos; srcset=&apos;/static/2a375177778e5b64a4f0b3b8885e042f/08678/inven.png 190w,
/static/2a375177778e5b64a4f0b3b8885e042f/9e38b/inven.png 308w&apos; sizes=&apos;(max-width: 308px) 100vw, 308px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;웹뷰에서 인벤 동영상 링크는 어디로 사라진 것일까???&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;원래 저 비어있는 자리에는 유튜브 동영상이 나와야 함에도 나오지 않고 있는 것이다. 아마 첨에 이런 일을 당하면 아 모바일을 지원하지 않나 보구나 라고 생각하기 쉽상인데, 크롬으로 들어가보면 기가막히게 보인다. 도대체 왜? 그래서 웹뷰는 뭐 한계가 있나보다 하고 넘어가려고 해도 뭔가 찜찜하다. 왜냐하면 오페라나 파이어폭스에서도 정상적으로 보이지 않기 때문이다. 그렇다면 크롬이 무슨 특수한 처리를 해주고 있다는 것인데…​ 도대체 크롬은 무슨 짓을 하고 있는 것일까?&lt;/p&gt;
&lt;p&gt;그냥 크롬이 외계인과 접촉했다고 넘어가기에는 용납이 되지 않았다. 난 너무 장인이니까 ㅋㅋㅋ~ 거기다 누구도 신경쓰지 않았지만 경쟁 앱에게 보여주고 싶었다. 난 웹뷰에서 인벤 동영상 페이지도 렌더링 하지롱, 이라고 말이다. 하지만 집요하게 검색했으나 관련 글을 찾기가 쉽지 않았다. 그렇게 한동안 이 문제에 대해서 제법 고민을 했는데 신이 가엽게 여기셨는지 어느날 갑자기 계시가 내리듯이 어떤 생각이 머리를 스쳤다. 그리곤 그 상상대로 만들어 봤는데 얼추 크롬과 비슷하게 동작하는 것을 볼 수 있었다. 하지만 그 결과는 날 재차 의문에 빠트렸다. 이게 과연 옳은 길일까라는 생각이 들었기 때문이다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;우선 인벤의 동영상 링크를 보면 아래와 같은 구조로 소스가 코딩되어 있다. 플래시 플레이어를 사용하는 유튜브 링크다. 지금 유튜브 링크는 모두 iframe 형식으로 변경이 되었다. 즉, 인벤이 만든 이 코드는 예전 유튜브 코드로 모바일 환경에서는 적합하지 않은 코드다. 그러니 응당 보이지 않는 것이 정상일 것이다. 그러면 도대체 크롬은 어떻게 보여주고 있는 것일까?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;embed&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;allowscriptaccess&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;never&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;650&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;366&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token attr-name&quot;&gt;pluginspage&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://www.macromedia.com/go/getflashplayer&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://www.youtube.com/v/l9yD5r1AsNo?version=3&lt;span class=&quot;token entity named-entity&quot; title=&quot;&amp;amp;&quot;&gt;&amp;amp;amp;&lt;/span&gt;hl=ko_KR&lt;span class=&quot;token entity named-entity&quot; title=&quot;&amp;amp;&quot;&gt;&amp;amp;amp;&lt;/span&gt;rel=0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;application/x-shockwave-flash&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;wmode&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;transparent&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;allowfullscreen&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;true&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token attr-name&quot;&gt;allow&amp;amp;#83;criptaccess&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;never&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 650px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 366px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;내가 생각해 본 방법은 저걸 그대로 보여주는 건 말이 안 되니 저걸 통째로 고쳤을거란 생각이 들었다. 왜냐하면 어차피 저 코드에 렌더링할 페이지 주소는 모두 나와 있기 때문에 iframe으로 대체 시키는 것이 어렵지 않기 때문이다. 바로 아래와 같이 말이다. 아래 코드는 문서에 있는 embed를 죄다 찾아서 iframe으로 변경하는 일을 한다. 실제로 안드로이드 웹뷰에서 인벤 페이지를 로딩한 다음 아래 자바스크립트를 샤샥 돌려주면 깔끔하게 비디오 화면이 출력되고 재생도 된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; elem &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;embed&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; elem&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; obj &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;iframe&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	obj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; elem&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	obj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; elem&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	obj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;frameBorder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; elem&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/v/&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;/embed/&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	obj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	elem&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;parentNode&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replaceChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;obj&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; elem&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;그냥 단편만 살펴본다면 크롬의 이 재치있는 생각은 나쁠게 없어 보인다. 모바일 준비가 되지 않은 유튜브 링크를 포함한 거의 모든 사이트를 정상적으로 렌더링할 수 있게 만들어주니까 말이다. 하지만 다른 한편으론 나빠 보이기도 한다. 페이지 제작자가 자신이 실수했다는 사실을 인지하기까지 시간을 오래 걸리도록 만든다는 점을 첫번째 문제로 들 수 있다. 왜냐하면 잘못됐다는 사실을 즉각 알려줘야 빨리 고칠 수 있는데 저런 식으로 내부적으로 변형시키는 과정을 통해서 페이지가 정상적으로 렌더링돼 버리면 제작자 입장에서는 문제가 없는 것으로 오해할 수 있기 때문이다. 두번째 문제는 더 심각한데 이런 문제들이 심화되면 사용자들이 특정 브라우저에 강하게 종속될 수 있다는 점이다. 에고가 강한 페이지 제작자가 크롬에 최적화 됐고 다른 브라우저가 이상하다고 말하는 상황을 예로 생각해 볼 수 있겠다. 그렇다면 그 페이지를 꼭 이용해야 한다면 크롬을 사용할 수 밖에 없다. 어디서 많이 본 장면 같지 않은가? 맞다. 인터넷 익스플로러의 몇 년전 모습이다. 그때도 IE는 모질라에서 주구장창 오류를 뿜어대는 스크립트들도 무슨 재준지 기가 막히게 오류 없이 돌려주곤 했었다. ActiveX는 말할 것도 없다. 이제는 그 자리를 크롬이 메우고 있는게 아닐까라는 생각이 잠시 들었다.&lt;/p&gt;
&lt;p&gt;가용성과 하위호환성을 위해서 얼마만큼 느슨해져야 하는 것일까? 또 표준을 지키기 위해서 얼마만큼 엄격해져야 하는 것일까? 물론 여기에 답은 없다. 어떤 사람들은 가용성과 하위호환성에 더 높은 가치를 두기도 하고, 또 어떤 사람들은 순결한 상태에 더 높은 가치를 두기도 한다. 다만 프로그래머 입장에서 한 가지 바램이 있다면 업계를 주도하는 키 플레이어들은 좀 엄격해졌으면 하는 바램이다. 왜냐하면 그들만이 사용자를 변화시킬 힘이 있기 때문이다. 하지만 실상은 메이저 업체들은 계속 알 수 없는 파편화를 주도하고 정작 힘없는 오픈소스들만 표준을 잘 지키는 형국인것 같아 씁쓸한 기분이 든다.&lt;/p&gt;
&lt;p&gt;-- 2014.06.20&lt;/p&gt;
&lt;p&gt;다행이도 이 글을 쓰는 사이 (적어도 12개월+) 인벤은 페이지를 고쳤다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] MmProbeAndLockPages/MmMapLockedPages 함수에 관한 고찰]]></title><description><![CDATA[일반적으로 커널 모드 드라이버에서 사용자 영역의 주소를 고정시키기 위해서는 아래와 같은 함수 호출을 사용한다. MmProbeAndLockPages/MmMapLockedPages 두 함수 모두 인자에 KernelMode/UserMode…]]></description><link>https://jiniya.net/wp/archives/14045</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14045</guid><pubDate>Fri, 26 Jun 2015 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;일반적으로 커널 모드 드라이버에서 사용자 영역의 주소를 고정시키기 위해서는 아래와 같은 함수 호출을 사용한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;mdl &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;IoAllocateMdl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;address&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
&lt;span class=&quot;token function&quot;&gt;MmProbeAndLockPages&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mdl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; UserMode&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;KernelMode&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
kptr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MmMapLockedPages&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mdl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; UserMode&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;KernelMode&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
  
&lt;span class=&quot;token comment&quot;&gt;// kptr을 통해서 유저 메모리 address에 접근할 수 있음  &lt;/span&gt;
  
&lt;span class=&quot;token function&quot;&gt;MmUnmapLockedPages&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;kptr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mdl&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
&lt;span class=&quot;token function&quot;&gt;MmUnlockPages&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mdl&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
&lt;span class=&quot;token function&quot;&gt;IoFreeMdl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mdl&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;MmProbeAndLockPages/MmMapLockedPages 두 함수 모두 인자에 KernelMode/UserMode가 들어간다. 그런데 그 친절한 MSDN 조차도 이 값을 어떻게 지정해야 하며, 그게 어떤 효과를 가져오는지에 대해서 자세히 설명을 해주지 않고 있다. 단지 MmMapLockedPages의 두 번째 인자는 드라이버라면 대체로 KernelMode를 지정하면 된다 정도의 코멘트만 있다. 심각한 문제는 설명이 이렇다보니 블루스크린이 발생하면 이 값을 막 바꿔주다 발생하지 않는 값이 있다면 아 이렇게 쓰는거구나 하면서 엉뚱하게 변경해 버리는 일이 생긴다는 점이다. 헐~ 대박… 여튼 그래서 각 함수의 KernelMode/UserMode의 의미에 대해서 살펴보는 시간을 가져볼까 한다.&lt;/p&gt;
&lt;p&gt;MmProbeAndLockPages에 두번째 인자는 mdl이 가리키는 영역이 사용자 주소 공간인지 커널 공간인지를 판별하기 위해서 사용된다. UserMode를 넣게 되면 MmProbeAndLockPages 함수가 실질적인 동작을 하기 전에 mdl이 가리키는 영역이 사용자 영역을 벗어나는지 벗어나지 않는지를 점검하는 코드가 추가적으로 실행된다. 만약 사용자 접근 공간(일반적으로 4G 32비트 시스템에서 2G까지)을 벗어나는 영역을 포함하고 있으면 실질적인 동작을 수행하지 않고 ACCESS_VIOLATION 예외를 발생시킨다.&lt;/p&gt;
&lt;p&gt;MmMapLockedPages 함수의 모드 파라미터는 MmProbeAndLockPages와는 다른 목적이다. 이 함수에서 KernelMode/UserMode가 결정하는 일은 최종적으로 생성될 kptr이 유저 영역에 매핑될지 커널 영역에 매핑될지 결정하는 역할을 한다. 즉, 이 파라미터는 mdl이 가리키는 메모리 공간과는 전혀 상관이 없다. 최종적으로 우리가 사용할 포인터를 어느 영역 주소로 정할 것인지를 지정하는 역할을 한다. 그러니 드라이버라면 응당 KernelMode를 쓰는 것이 일반적일 것이다.&lt;/p&gt;
&lt;p&gt;여기서 벌어지는 BSOD의 관전 포인트는 MmProbeAndLockPages 함수로 커널 영역을 가리키는 쓰레기 포인터가 넘어간 경우에 발생한다. 이 경우에 KernelMode가 인자로 넘어갔다면 논페이지드 영역에서 잘못된 참조가 발생할 수 있고 그랬다면 BSOD로 이어진다. 반면에 쓰레기 포인터가 넘어오더라도 UserMode를 지정했다면 커널 영역을 가리키는 포인터이기 때문에 ACCESS_VIOLATION 예외가 발생하고 __try/__except로 예외를 잡아서 동작을 지속시킬 수 있다. 이 경우에 설명이 부실하다보니 쓰레기 포인터가 넘어온 걸 고쳐야 함에도 UserMode로 파라미터를 바꾸고는 아주 이상한 경우에 발생하는 커널 모드 문제를 해결했다며 커밋을 하는 어처구니 없는 경우가 발생한다. 뉴요커 프로그래머라면 이런 실수를 하지 않도록 주의하자~~~ @.@&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./dp.png&apos; data-alt=&apos;의외로 이런 경우가 많다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 520px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5642ad9b69de58a3af34cba1232491db/407f2/dp.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 74.21052631578947%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAA7DAAAOwwHHb6hkAAADdUlEQVR42mMImHQ/ad6jhDmP4uc8Spj7KG72QyAjaubD2DmPUuY/jgYyZj8CkklzH4MEZz1MW/A4bjZIgf+k+wwWdWfCJlyKmHg5buqV+KlXUmZeTZ5xNaT/UtSkSwnTLidOA4pfjpxwMXnGlchJIMHUmVeTpl8L7rtkUn2KoW39/aY198DoQf3q+w2r7zeueQBkN6191LLhafumZ83rnrSsf9K49lHzukdNax83rH4IVNy89j5QI8OBqx8OXPuw/+qnPScuHDt76vTFCxu27VizadvOA7sXLp0/ceqkLVvXrtuw8vCJg6fPHjl9csexsxcOXP984Op7oEaGQ1ffH7r67uDVjweO7r96ce+pY1sOH1i7Z/faY0fW5mf4Whkq5Ce51BSF7N859dy+6ae2tZ44uuXg9a9ALUCNDOfvfTh/7/35+5+PnTowZ1Z3TEx4RnpcbXXR6tWz+jrzI4Pso0PsCtP8J5X6bZ6QcGJr55mTO84/+Hr+7nugRoZbTz7dfPzh9rPvR45sjIu0FxDgERHk5uRg8vOxWDK3sroyMczL0tdc3dNMI8pUZEmN6+ljm28/+3Hr8QegRob7zz/fffrx2bvfk6dO8fJyVlSQFhcTlpIU1VSX93E393Y3tzIz0dXSsjAzsVEXjbUU7Omoe/7x/92nH4AaQZrvPP306u2XpAknJYJblBTEZWUl1FSktLUULUw0vF0Mw/3sbEzN9ZXkgrQk/HWFi8qK33z5f+cJTPPdZ59fvfqUseOb4ZL75vZ2QgJcUrLSSooy8jKiyjJyphqGVupKMSYy/UGqZa6iMfGJb76iaX75MWHlba19P0yC42SkZNLjw6I9Df1M1KwUNe10NV315Tx0xOKtJcocuLuqsp6hOfv1+5/RhY2iy89rePjLScvZmmo1pTrURpvneGvF2ymkuyo5aApbKIlG67DObcl+iqL5yQegSwL8QxgsPVQN9WUk+Pn5Of3cDSJ8jPwsZKzV+V10+QylWDVE2LW4GMrSYl6B/PwepPneM2Bof3r0+sfaTTu7u/sXLVm2cvXqeQsWLly8ZNmKFdNmzp0+e96EqbP6J03r65/c0ty8dv3mx29+ASMIqJHhyeuvQPT41ZdXH3+///H/9ed/rz7+ff3pL5Dx5vPfd1/+A9H7b//fff3/9ss/IPnyw2+gYoguAG06EBzXQ2dwAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;의외로 이런 경우가 많다.&apos; title=&apos;&apos; src=&apos;/static/5642ad9b69de58a3af34cba1232491db/407f2/dp.png&apos; srcset=&apos;/static/5642ad9b69de58a3af34cba1232491db/08678/dp.png 190w,
/static/5642ad9b69de58a3af34cba1232491db/2edd7/dp.png 380w,
/static/5642ad9b69de58a3af34cba1232491db/407f2/dp.png 520w&apos; sizes=&apos;(max-width: 520px) 100vw, 520px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;의외로 이런 경우가 많다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[시스템] 변태 패커, Upack]]></title><description><![CDATA[PE 포맷의 각종 잘(?!) 사용되지 않는 Size 필드들을 가지고 장난쳐서 파일을 오버레이 시키곤 하는 변태 패커 중에 Upack…]]></description><link>https://jiniya.net/wp/archives/15072</link><guid isPermaLink="false">https://jiniya.net/wp/archives/15072</guid><pubDate>Fri, 26 Jun 2015 14:00:01 GMT</pubDate><content:encoded>&lt;p&gt;PE 포맷의 각종 잘(?!) 사용되지 않는 Size 필드들을 가지고 장난쳐서 파일을 오버레이 시키곤 하는 변태 패커 중에 Upack이 있다. 자세한 설명은 &lt;a href=&quot;http://www.reversecore.com/53&quot;&gt;이 글을&lt;/a&gt; 참고하도록 하고,… 언젠가 나도 한 번 당했었는데 웬만한 필드는 다 계산해서 사용하기에 문제가 없다고 생각했는데 섹션 헤더를 구하는 부분에 문제가 있었다. 흔히 별 생각 없이 아래와 같은 코드를 사용하고 있었는데 이게 Upack으로 패킹된 파일에는 문제가 된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;PIMAGE_NT_HEADERS nt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 적절한 NT 헤더 포인터&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
PIMAGE_SECTION_HEADER sec&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
sec &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PIMAGE_SECTION_HEADER&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;nt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;OptionalHeader에 SizeOfOptionalHeader 필드가 있는데 그 값이 일반적인 값이라면 위 코드는 큰 문제 없이 동작한다. 그런데 Upack은 다르다. SizeOfOptionalHeader를 가지고 장난질을 치기 때문에다. 그래서 아래와 같이 해당 필드 값을 토대로 계산을 해 주어야 정확한 섹션 헤더 위치를 얻을 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;\  &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;GetSectionHeaderFromNt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; \  
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PIMAGE_SECTION_HEADER&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; \  
&lt;span class=&quot;token function&quot;&gt;GetPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;OptionalHeader&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;FileHeader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SizeOfOptionalHeader&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;덧) 자매품 &lt;a href=&quot;http://www.jiniya.net/wp/archives/4250&quot;&gt;UPX의 함정도&lt;/a&gt; 있다 ㅋㅋ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 시작하는 프로그래머를 위한 10원짜리 조언 몇 개…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/10460</link><guid isPermaLink="false">https://jiniya.net/wp/archives/10460</guid><pubDate>Mon, 22 Jun 2015 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;개인적인 경험에 기반에 쓴 것이니 너무 심각하게 받아들이진 말자. 모든 글이 그렇지만 취할건 취하고 버릴건 버리면 된다. 직접 해보니 도움이 된 것들도 있고, 지금 시점에 돌아보니 했었으면 더 좋았을 것 같다고 느낀 것들도 있고 그렇다. 참고로 태생적으로 머릿속에 포인터와 재귀 호출 스택 프레임이 내장된 프로그래머들을 위한 글은 아니라는 점 명심하자!!! (자매품 &lt;a href=&quot;http://www.jiniya.net/tt/675&quot;&gt;개발자를 위한 드래곤볼&lt;/a&gt;)&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;연애를 하자. 일반적으로 프로그래머들의 커뮤니케이션 스킬이 다른 직종 사람들에 비해서 떨어지는 것은 사실이다. 인정할 건 인정하자. 그런 점들을 보완해주는데 연애만큼 좋은게 없다. 자신의 바닥도 보고 겸손해지기도 한다는 점에서 여러 좋은 점들이 있으니 프로그래밍 공부만큼 연애에도 관심을 가지고 꼭 해보기를 추천하고 싶다. 특히 요즘은 돈 든다고 안 하는 추세도 있는것 같은데 그 돈 투자해 보는게 손해는 아닌 것 같다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;빨리 시작하는 편이 유리한 건 어쩔 수가 없다. 대학교때 컴퓨터 학원에서 C언어를 일년정도 가르친 경험이 있다. 그때 난 어른과 어린 학생들 사이의 명백한 차이가 있는 걸 알게 되었다. 어른들은 무엇인가 자신이 납득할 수 있는 이유가 없다면 잘 받아들이지를 못하고, 또 지루한 과제를 반복하지 못한다는 특징이 있다. 천재 프로그래머인 리누스 토발즈도 그의 자서전에서 밝혔지만 처음 작성한 프로그램은 Hello, World였다. 어린 학생들은 그 단순한 Hello, World 조차도 글자를 바꿔가면서 만드는 과정에서 재미를 느끼는데 어른들은 그렇지가 않다. 그래서 연습이 부족해질수밖에 없고 그러니 당연히 진도가 더디다. 어리다는 것은 지루한 것도 반복할 만큼 호기심이 많다는 것을 의미하기 때문에 지루한 초반 과정을 버티는데 정말 좋다. 더불어 시간이 많다는 것도 장점이다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;늦게 시작했더라도 체력이 좋다면 다행이다. 고등학교 때 알던 녀석 중에 한 명이 2년 내도록 놀다가 3학년 때 일년 바짝 공부 해서 의대를 갔었다. 사실 그 누구도 그 친구가 의대에 진학할 것이라고는 생각지도 못했었기에 다소 충격이었다. 물론 같이 놀았던 친구 녀석들은 부러워 한 정도로 끝났지만 3년 내도록 공부하고 수능을 망친 친구들의 상실감은 이루 말할 수가 없었다. 그 의대에 간 녀석의 장점은 강철 체력이라는 점이었다. 남들이 하루 밤샐 수 있다면 녀석은 3일쯤은 거뜬히 멀쩡하게 밤샐 수 있었다. 대학교 때에도 비슷한 선배가 있었다. 늦게 프로그래밍을 시작했는데 전산소에서 일주일씩 밤새는건 기본인 선배였다. 이상엽씨가 쓴 Visual C++ 6.0 바이블 한글 파일을 들고 다니면서 하루종일 전소에 앉아서 코딩을 하곤 했었다. 난 다소 의아했었는데 지금은 MIT에 유학을 갔던 정말 똑똑한 형이 옆에서 그랬다. 저렇게 체력이 좋은 아이들은 이길 수가 없다고… 그러니 체력 관리가 중요하다.&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;책을 많이 읽는 것이 여러모로 도움이 된다. 책을 읽는다는 사실이 여러분을 더 똑똑하고 유능한 프로그래머로 만들어준다는 것을 의미하진 않는다. 하지만 적어도 바보같은 프로그래머가 되지 않도록은 만들어 준다는 점에 50원 정도는 걸 수 있을 것 같다. 그러니 책을 부지런히 읽자.&lt;/p&gt;
&lt;p&gt;책을 많이 읽지 않는 사람들이 하는 흔한 실수 중에 하나가 이해가 되지 않는다고 &lt;a href=&quot;http://www.jiniya.net/wp/archives/2539&quot;&gt;계속 1장만 보는 것이다.&lt;/a&gt; 모든 것은 유기적으로 연결되어 있으니 당장 이해가가지 않는 부분이 있더라도 냅두고 끝을 향해 달려가자. 끝을 보고 나면 자연스레 1장은 저절로 이해가 되기 마련이다. 참고로 그때도 이해가 되지 않으면 한번더 끝까지 보면된다.&lt;/p&gt;
&lt;h3&gt;#4&lt;/h3&gt;
&lt;p&gt;영어를 잘하는 것이 막판 광역 버프를 받는 지름길이다. 직업 프로그래머를 하면서 다양한 프로그래머들을 만났다. 그중에 더러는 늦게 프로그래밍을 시작한 사람도 있었고, 나보다 훨씬 더 일찍 시작한 사람도 있었다. 그런데 한 가지 신기한 사실은 처음에는 실력 차이가 많이 나는데 한 3년 정도가 지나면 거의 실력이 비슷해진다는 점이었다. 그때부터는 누가 언제 시작했는지 보다는 해당 도메인 지식을 누가 더 빨리 습득할 수 있는가가 실력을 결정짓는 주요한 요소가 된다. 안타깝게도 거의 모든 프로그래밍 자료는 영어인 경우가 대부분이다. 따라서 나중에 줄창나게 버프를 받기 위해서는 영어는 필수적으로 할 수 있어야 한다.&lt;/p&gt;
&lt;h3&gt;#5&lt;/h3&gt;
&lt;p&gt;대학 교육을 받은 프로그래머들 중 상당수가 기본적인 전산 지식을 중요하게 여기고 도메인 지식을 가볍게 여기는 경향이 있다. 하지만 아이러니하게도 대부분의 경우에는 기본적인 전산 지식보다는 도메인 지식이 중요하다. MS나 구글같은 회사에서 도메인 지식보다 기본 지식을 가진 똑똑한 직원을 뽑는다는 소리를 듣고 그게 중요하다고 생각하는 경우가 많다. 그런데 정말 아주 많이 안타까운 사실은 우리 대부분은 그런 똑똑한 사람들이 아니라는 것이다. 현실을 직시하자. 평범한 우리에겐 기본적인 전산 지식만 가지고 있는 상태에서 도메인 지식을 스펀지처럼 빠르게 빨아들이는 능력이 없는 경우가 상당수다. 그러니 자신이 하고 싶은 도메인을 일찍 정하고 해당 지식을 빨리 습득하는 것이 중요하다. 백신 업체에 취직하고 싶은데 그림판만 매일 만들고 있는건 도움이 되지 않는다는 말이다. 물론 이 말이 기본 지식이 중요하지 않다는 것을 의미하진 않는다. 컴퓨터 공학과에서 열심히 공부한 대다수 졸업생의 기본적인 전산 지식은 도찐개찐인 경우가 많기 때문에 그게 여러분을 돋보이게 만들어주지 않는다는 의미다.&lt;/p&gt;
&lt;h3&gt;#6&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/tt/609&quot;&gt;코드를 많이 읽는 것이 중요하다.&lt;/a&gt; 대학을 졸업한 대부분의 프로그래머가 오픈소스 프로젝트 코드를 수정하는 것은 둘째치고 읽지도 못하고 심지어는 빌드도 못하는 경우가 많다. 이는 정말 큰 문제다. 적어도 여러분이 직업 프로그래머를 하려고 한다면 기본적인 코드는 읽고 이해하고 수정하는 것이 가능해야 한다. 여러분의 경력 대부분의 시간 동안 새로운 코드를 쓰는 시간보다는 다른 사람이 이미 만들어둔 코드를 수정하고 고치는 작업을 하는 경우가 많기 때문이다. 남이 작성한 코드를 읽고 이해하는 능력이 없다면 직장 생활 자체가 매우 힘겨워질 수 있다. 자신이 주력하는 분야의 오픈 소스 코드를 매일 일정 분량 이상씩 읽도록 하자. 물론 참여하기까지 한다면 금상첨화다.&lt;/p&gt;
&lt;h3&gt;#7&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/tt/405&quot;&gt;코드를 읽는 것 만큼이나 쓰는 것도 중요하다.&lt;/a&gt; 많은 사람들이 생각을 잘 하면 코딩도 잘 할거라 전제하는데 생각하는 것과 코딩하는 것은 조금 다른 측면이 있다. 머리보다 손이 기억한다는 말이 있다. 그러니 알고 있는 것이라도 반복적으로 구현해 보는 것이 좋다. 그리고 심심할 때 유용하진 않더라도 작은 프로그램을 직접 많이 만들어 보도록 하자. 코딩도 연습할 수 있고 전체 프로젝트를 기획부터 릴리즈까지 해볼 수 있는 좋은 훈련이 된다.&lt;/p&gt;
&lt;h3&gt;#8&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.codinghorror.com/the-ultimate-code-kata/&quot;&gt;블로그나 위키를 만들자.&lt;/a&gt; 그리고 그곳에 자신이 공부한 것들을 정리해서 올려놓자. 이건 정말이지 여러가지 장점이 있는데 1) &lt;a href=&quot;http://www.jiniya.net/wp/archives/13258&quot;&gt;세상 사람들이 내가 무슨 일을 했는지 알 수 있게 해준다&lt;/a&gt;, 2) 긴 글을 작성하는 훈련을 할 수 있다, 3) 나만의 지식 기반을 구축할 수 있다, 등등 장점은 수도 없이 많다. 그러니 꼭 이 활동을 지속적으로 하자. 보는 사람이 없어도 꾸준히 하는 것이 중요하다. 그리고 본인 생각에 정말 보잘것 없는 것들도 무조건 올리도록 하자. 우리가 구글링해서 알 수 있는 대부분의 지식은 다른 사람들이 그렇게 별 볼 일 없다고 생각하면서 올려둔 지식인 경우가 대다수다. 하찮다 생각하지 말고 꾸준히 정리하고 공개하는 습관을 들이도록 하자.&lt;/p&gt;
&lt;h3&gt;#9&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/wp/archives/10719&quot;&gt;다양한 문화 생활을 경험해 보자.&lt;/a&gt; 드라마도 보고, 영화도 보고, 미술관도 가고, 뮤지컬도 보고, 음악회도 가고, 콘서트도 가고, 만화책도 보고, 게임도 하자. 다 피가 되고 살이 된다. 개그콘서트와 웃찾사를 보는게 꼭 시간 낭비만은 아니다. 오히려 컴퓨터만 주구장창 하는 사람들보다 더 넓은 시각을 가질 수 있게 만들어 준다는 점에 100원은 걸 수 있다. 파이썬 개발자 귀도 반 로섬도 몬티 파이썬의 팬이었다. 그러니 맘놓고 보자. 스트레스 해소도 하고… ㅋㅋㅋ~&lt;/p&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/ylsiAy8azFo?si=cSxI2glNkTxV9hNE&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;h3&gt;#10&lt;/h3&gt;
&lt;p&gt;컴퓨터 공학과를 졸업한다고 모두 프로그래머가 되어야 하는 것은 아니다. 컴퓨터를 좋아한다고 프로그래머가 되어야 하는 것도 아니다. 그리고 심지어는 프로그래밍이 좋다고 직업 프로그래머가 될 필요가 있는 것도 아니다. 직업 프로그래머가 되는 것에 관해서 진지하게 생각해보자. 그리고 학교에서 시간이 있을 때 아르바이트던 인턴이던 직업 프로그래머로써의 경험을 조금은 가져 보는 것이 좋을 것 같다. 돈을 받고 프로그래밍을 한다는 것이 어떤 느낌인지에 대해서 약간은 알아둘 필요가 있기 때문이다. 아마도 재미삼아 만들때와는 사뭇 다른 느낌인 경우가 많을 것 같다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 와우와 롤은 불법 프로그램이 없을까?]]></title><description><![CDATA[SNS에 모 분이 게임업계 `불법 프로그램`과의 전쟁 선포라는 링크와 함께 와우나 롤처럼 앵벌이 아닌 게임을 만들라는 조언을 붙여놨다. 와우나 롤처럼?! 문득 든 생각이 와우나 롤 해보시긴 하셨나요, 라는 질문을 팍 던지고 싶었다. #…]]></description><link>https://jiniya.net/wp/archives/15002</link><guid isPermaLink="false">https://jiniya.net/wp/archives/15002</guid><pubDate>Fri, 19 Jun 2015 23:59:59 GMT</pubDate><content:encoded>&lt;p&gt;SNS에 모 분이 &lt;a href=&quot;http://www.dt.co.kr/contents.html?article_no=2015061502100831102001&quot;&gt;게임업계 `불법 프로그램`과의 전쟁 선포&lt;/a&gt;라는 링크와 함께 와우나 롤처럼 앵벌이 아닌 게임을 만들라는 조언을 붙여놨다. 와우나 롤처럼?! 문득 든 생각이 와우나 롤 해보시긴 하셨나요, 라는 질문을 팍 던지고 싶었다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;요즘 와우는 몰라도 예전 와우의 경우는 정말 오토 돌리기 좋은 게임이었다. 난 것도 모르고 매번 레이드 갈 때 마다 낚시를 손수 꼬박 꼬박 했는데 오토를 돌리고 나서는 신세계를 경험했다. 자고 나니 가방에 물고기가 넘쳐났기 때문이다. 이래서 오토, 오토 하는구나 싶었다. 그간의 그 상대적 박탈감이란 ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;블리자드도 이를 모르진 않는다. &lt;a href=&quot;http://www.pcinvasion.com/blizzard-win-legal-case-against-world-of-warcraft-bot-company&quot;&gt;그래서 봇 제작사에 소송을 걸기도 한다.&lt;/a&gt; 하지만 이런 경우는 널리 널리 퍼진 봇인데다 영리성을 추구하는 경우만 해당하는 것이고, 사용자들끼리 만들어서 공유하는 것까지 근절하기는 상당히 힘든 실정이다. 직접 개발한 warden이란 보안 솔루션도 탑재하고 있지만, 성능은 물음표(?) 정도로…&lt;/p&gt;
&lt;p&gt;롤은 전략/액션 게임이니 덜할 것 같지만 더하다. 원래 사용자끼리 승패를 가르는 게임에 핵이 더한 법이다. 왜냐하면 승부에 집착하게 되기 때문이다. “롤 핵”으로만 검색해도 절찬리 성업중인 다양한 불법 프로그램들이 나온다. 절망적인 사실은 롤은 스킨/캐릭을 팔아서 돈을 버는 구존데, 그걸 봉인 해제시키는 무료 툴도 존재한다. 물론 유료로 사는 핵들은 기능이 훨씬 강력하다. 거의 반자동 게임이 가능할 지경인 수준… 롤 커뮤니티에서도 관련된 불만은 수도 없이 제기됐고, 라이엇도 이를 모르진 않는 것 같다. 어떻게 대응을 하는지는 지켜볼 문제지만 말이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;워크래프트2 모뎀 플레이 시절엔 디스컨넥트에게, 디아블로1을 즐기던 때에는 트레이너에게, 스타크래프트가 유행하던 시기엔 맵핵에게 고통 받았습니다. 월드 오브 워크래프트에 빠져 있던 시기에는 오토봇에게 상대적 박탈감을 느낄 수 밖에는 없었습니다. 블리자드 키드를 자처할 만큼 게임에 푹 빠져 살았지만 온라인 게임 속에는 항상 해킹이 공존했습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;무턱대고 일단 까고 보고 외산 게임이라고 괜찮을 거 같다는 생각은 좀 버리는 게 좋지 않을까라는 생각이다. 이런것도 일종의 사대주의가 아닌가라는 생각까지 들 지경이다. &lt;a href=&quot;http://www.wellbia.com&quot;&gt;회사 홈페이지에&lt;/a&gt; 나와 있는 그 블리자드 키드가 나인데, 진짜 블리자드 게임만 줄창나게 했지만 “불법 프로그램”이 없었던 시점은 단 한 차례도 없었다. 이 세상에 존재하는 온라인 게임치고 불법 프로그램으로부터 자유로운 게임은 없다는 생각이다. 만약 있다면 그 누구도 불법 프로그램을 제작할 만큼의 값어치를 못 느끼는 게임일 가능성이 높지, 보안이나 게임성이 우수해서라고 보기는 힘든 것 같다. 범죄와 마약이 없는 국가를 찾기가 힘든 것과 같은 이치 아닐까나?!&lt;/p&gt;
&lt;p&gt;덧) 게임 내 불법 프로그램 근절에 관심이 많으신가요? 그럼 &lt;a href=&quot;http://www.jiniya.net/wp/archives/6174&quot;&gt;이 글도&lt;/a&gt; 함께 읽어보시길 감히 추천드립니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 물리적인 한계들…]]></title><description><![CDATA[초등학교 때 였다. 요즘은 PC방에 거의 자취를 감춰 버렸지만 그 당시만 해도 아케이드 게임을 들여놓은 오락실이 동네마다 엄청 많이 있었다. 10…]]></description><link>https://jiniya.net/wp/archives/7585</link><guid isPermaLink="false">https://jiniya.net/wp/archives/7585</guid><pubDate>Fri, 19 Jun 2015 23:59:58 GMT</pubDate><content:encoded>&lt;p&gt;초등학교 때 였다. 요즘은 PC방에 거의 자취를 감춰 버렸지만 그 당시만 해도 아케이드 게임을 들여놓은 오락실이 동네마다 엄청 많이 있었다. 100원 짜리 동전 한두개를 가지고 오락실을 가면서 난 항상 고민에 빠지곤 했다. 그 부족한 자원을 가지고 오락실에서 가장 오래 시간을 때울 수 있는 방법을 찾아야 했기 때문이었다. 인기 있는 게임을 하는 것은 재미는 있었지만 위험 부담이 너무 컸다. 중학생이나 고등학생 형들이 연결하기 일쑤였고, 나의 황금같은 100원은 순식간에 하늘 나라로 증발해 버리기 때문이었다. 그래서 구석 한켠에 아무도 하지 않는 오래된 RPG 게임을 하면서 시간을 죽이기도 했다. 나름 최적화된 투자였다.&lt;/p&gt;
&lt;p&gt;세월이 흘렀고, 세상은 많이 변했다. 그때는 G.O.D 가사에 나오는 것처럼 대부분의 집들에서 자장면이 외식 메뉴였지만 요즘은 웬만한 가정에서는 집밥 보다도 못한 메뉴로 전락해 버렸다. 거리에 차도 늘었고, 고급 레스토랑도 늘었고, GDP도 눈에 띄게 늘었다. 그런데 아이러니 하게도 모든게 풍족해 보이지만 여전히 우리는 늘 리소스 부족에 시달린다. 컴퓨터도 그렇다. 난 486 컴퓨터에서 C 프로그램을 짤 때에도, 펜티엄에서 짤 때에도, 듀얼코어에서 짤 때에도, 항상 리소스는 부족했다. 게임보안 제품을 만들면서는 더 심해졌다. 게임이란 것이 원체 헤비 프로그램이기 때문에 동시에 돌아갈려면 CPU 점유율 0.01%에도 쩨쩨하게 굴어야 하고, 메모리를 아끼기 위해서 고속 서칭 알고리즘을 포기해야 하기도 한다. 그래도 이런 것들은 비교적 귀여운 축에 속하는 고민이었다는 것을 난 최근에야 깨달았다. 물리적인 한계가 있다는 사실을 속속 깨달았기 때문이다.&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;최근에 GIT 저장소를 UTF-8로 업그레이드 하는 작업을 단행했다. 이전 버전의 GIT의 경우에는 UTF-8을 지원하지 않아서 일부 한글 파일들이 제대로 저장소에 업로드가 되지 않는 문제가 있었다. UTF-8로 된 저장소로 변경하고 나서는 그런 일이 없었다. 업그레이드 작업은 무척이나 간단한 명령어 몇 개로 가능했지만 안타깝게도 이 작업은 애꿏은 나의 하루를 모두 소비해 버렸다. 문제는 이랬다. 우리는 4-5년 전에 구매한 델 서버를 소스 저장소로 사용하고 있었다. 뭐 델 서버라고 하는데 뭔가 엄청난 건 아니고 그냥 좀 더 견고하게 만들어진 그런 하드웨어일 뿐이다. 성능이 특별히 뛰어나거나 하지는 않다. 그간 이 서버는 단 한 차례도 문제를 일으킨 적이 없어서 잘 사용하고 있었다. 그런데 저장소를 업그레이드 하고 나서는 이상하게 저장소를 클론하는데 지나치게 오랜 시간이 걸렸다. 도대체 문제가 무엇인지 알 수 없었다. 당연히 내가 바꾼 거라곤 GIT 저장소 뿐이니 그 부분을 의심할 수 밖에는 없었다.&lt;/p&gt;
&lt;p&gt;하지만 문제는 서버에 있었다. 우리가 구매한 델 서버는 4년이란 시간을 감안하더라도 놀랍게도 고작, 고작 1기가 바이트의 메모리가 달려 있었다. 그런데 더 놀라운 사실이 있다. 난 뭐 1기가 바이트라고 한들 GIT 저장소를 운영하는데는 충분한 메모리라고 생각했던 것이다. 그런데 그건 터무니 없는 나의 생각이었다. GIT 클론 명령은 오브젝트를 압축하는 작업을 하는데 그 작업 과정에서 엄청나게 많은 메모리를 요구했다. 문제의 그 저장소를 클론하려면 1기가에 육박하는 메모리가 필요했다. 만약 재수없게 동시에 두 사람이 클론하는 경우에는 시스템은 메모리 부족으로 그 어떤 서비스도 동작하지 않는 엄청난 사태가 발생했다.&lt;/p&gt;
&lt;p&gt;그래 메모리 그 까이꺼 얼마한다고 늘리면 되는 것 아닌가, 라는 생각에 델 서버를 뜯었다. 하지만 현실은 그리 녹록치가 않았다. 뭔가 호환도 되지 않는 이상한 메모리가 하나 달려 있었기 때문이다. 다른 메모리를 끼우면 동작하지 않았다. 뜯어본 델 서버는 더 가관이었다. 보드부터 시작해서 당췌 확장 가능한거라곤 아무것도 없었다. 말 그대로 재앙이었다. 그냥 조립 피씨를 한 대 구매해서 옮겨야 겠다는 생각을 했다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;XIGNCODE3는 별도 옵션 없이 로그 서버를 무상으로 제공한다. 고로 고객님들께서는 적용하는 그 순간부터 발생하는 모든 로그와 통계 정보를 실시간으로 볼 수 있는 아름다운 신세계를 경험할 수 있다. 그런데 후발 주자로써 제품의 차별성을 두기 위해서 시작한 이 정책이 생각보다 골치아픈 존재가 되었다. 왜냐하면 고객에겐 공짜로 제공되지만 우리는 공짜로 사용할 수 있는 것이 아니기 때문이다.&lt;/p&gt;
&lt;p&gt;우리가 사용하는 서버는 IDC에 10Mbps에 물려있는데, 사실 이제껏 한번도 트래픽에 대해서 생각을 해본 적이 없었다. 그것도 이유인 즉슨 몇십만되는 동접 게임도 큰 문제 없이 로그를 받았기 때문이다. 그래서 와 웹서버는 짱짱맨 이러면서 트래픽은 기억의 저편으로 날려 보냈다. 그런데 그게 아니었다. 지난 주에 대규모 게임을 런칭하면서 웹 서버가 다운되는 어처구니 없는 상황을 경험했기 때문이다. 10Mbps에서 우리 웹 서버는 이 지경이었다. 남부순환로로 출퇴근을 해 보았다면 이래서는 안 된다는 걸 일찍 알았어야 할 일이다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 621px; margin-bottom: 16px;&apos; data-url=&apos;./traffic2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/183f59c6a556ee74327f46133815ea11/41b39/traffic2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 36.84210526315789%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAIAAACHqfpvAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABMUlEQVR42mWO2W6DMBBF+f/fSaIAbmgJmw0ijSDeMIQtwWBeSL6ghvat1tHRHd3RyMY8z1JKpeZJqT/Pc98/7vXva5qmvdfNuBW60vxuvt9voyyryyUdn+307KZhZc1Dp+Rjlg8l+9VDv7ayk1U90ErJrq6KZVkMffuaxjg0SWSthNb/gLdMoZ2bh2y3J/4xh87yehlClGkC8bpnkwhsbCHcjACBGluP2LMz+3hzrdvpmCFH9q1BGYf+mUUWTwCLAUM2RbY2SwDXY2Ax36JnE+8PGuqaPLLxbp+7p2mS+ts1DKIIOLHjXr0ggzBLUI7g95eHPj59cIKOGwEXoSBOgiTVhHHsI88fh9YYpSzKElOOc0owpxomKC0oLigpqBC0FKQUtBCEC8y49o1xUd+nSf0AFIZbitfD0WMAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;traffic2&apos; title=&apos;&apos; src=&apos;/static/183f59c6a556ee74327f46133815ea11/41b39/traffic2.png&apos; srcset=&apos;/static/183f59c6a556ee74327f46133815ea11/08678/traffic2.png 190w,
/static/183f59c6a556ee74327f46133815ea11/2edd7/traffic2.png 380w,
/static/183f59c6a556ee74327f46133815ea11/41b39/traffic2.png 621w&apos; sizes=&apos;(max-width: 621px) 100vw, 621px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;인간적으로 10Mbps 라인에 이게 무슨 짓이냐고 가비아에서 따질만도 하다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;일단 10Mbps라는 말은 10메가 비트를 일초에 전송한다는 말이다. 그러니 8로 나누면 초당 꼴랑 1.25메가 바이트를 전송할 수 있다는 결론에 도달한다. 60을 곱하면 분당 75메가 바이트를 전송할 수 있다. 우리 로그가 서버가 요구하던 용량은 게임에 따라 다르지만 헤비 게임을 기준으로 기존에 210메가 바이트 정도였던 거 같다. 그런데 75메가를 전송할 수 있는 라인에 그 정도는 버벅대면서 그럭저럭 돌아갔던 것이다. 이번에 추가된 게임은 트래픽 기준으로 분당 340MB메가 바이트를 필요로 했다. 그 지경이 되니 웹서버가 정지했다. 많은 고민을 했지만 피같은 돈을 들여 더 대역폭이 높은 라인을 사용하는 것 외에는 딱히 방법이 없었다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;퇴근하러 나갔다가 배란다에서 커피를 마시는데, 새로 들어온 분석팀 직원이 담배를 피우러 와서는 묻는다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;너님: 서버 메모리 좀 올려주시면 안되요?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;나님: 왜요?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;너님: 계속 메모리 폴트 나요 ㅠㅜ~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;나님: 2번 서버 아직도 그래요?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;너님: 아뇨. 거의 전부 다 그래요.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;나님: 헉. 그래도 메모리 추가는 안 되요. 서버 한 대당 메모리 1기가 추가하면 월에 만원 추가되거든요.&lt;/p&gt;
&lt;p&gt;나님: 스크립트 새로 고쳐 놓을께요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;-- 2012. 07. 03.&lt;/p&gt;
&lt;p&gt;지금도 가난하지만 정말 가난했던 시절 이야기다. 델 서버는 조립식 서버로 교체됐고, 올초에는 저장소를 github으로 변경했다. 가비아는 모두 클라우드 서비스로 옮겼고 더 이상의 회선 문제는 없다. 물론 트래픽 비용이 발생한다는 점은 추가됐다. 로그 서버 인스턴스도 겁 없이 하이엔드를 사용하기도 한다. 월 만원 때문에 파이썬 코드 최적화 시킨답시고 메모리 해제를 강제로 하는 방법을 찾지 않아도 되니 개발자 입장에서 많이 편해졌다. 물리적 한계에 봉착해 보면 돈이 있으면 많이 편하다. 그러니 일단 많이 벌고 볼 일인듯 ㅋㅋ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[리뷰] 불편한 경제학]]></title><description><![CDATA[통상적으로 또 역사적으로 모든 이들이 같은 거래에 동의할 때 투자자들은 우려할 필요가 있다. – 오펜하이머펀드 수석 전략가 p16…]]></description><link>https://jiniya.net/wp/archives/2963</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2963</guid><pubDate>Thu, 18 Jun 2015 23:59:57 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;통상적으로 또 역사적으로 모든 이들이 같은 거래에 동의할 때 투자자들은 우려할 필요가 있다. – 오펜하이머펀드 수석 전략가 p167&lt;br&gt;
&lt;br&gt;
친구가 부자가 되는 모습을 옆에서 지켜보는 것만큼 사람들의 안락과 판단력을 혼란스럽게 만드는 것은 없습니다. 차라리 친구 말고 다른 사람이 부자가 되는 것이 속 편합니다. – p227&lt;br&gt;
&lt;br&gt;
과거를 공부하지 않는 사람들은 똑같은 오류를 되풀이하고, 과거를 공부하는 사람들은 오류에 빠지는 다른 길을 찾아낸다 – 찰스 울프 p291&lt;br&gt;
&lt;br&gt;
세계 경제 차원에서 보면 환율의 자동조절기능을 통해서 어느 한 나라가 지속적으로 너무 많은 무역흑자를 독식하는 일이 방지되는 것입니다. – p441&lt;br&gt;
&lt;br&gt;
국가의 진정한 부는 치러낸 고통의 크기에 비례한다. – p457&lt;br&gt;
&lt;br&gt;
공황에서 살아남기 위해서는 다른 자산이 아니라 유일한 부인 화폐를 보유해야 합니다. – p586&lt;br&gt;
&lt;br&gt;
“부채의 상환은 (실질) 부채잔액의 증가를 따라잡지 못하며, 부채를 갚을수록 더 많은 (실질) 부채가 쌓인다”고 했던 무서운 부채의 역설이 현실로 나타나고 있는 것입니다. – p582&lt;br&gt;
&lt;br&gt;
– 불편한 경제학, 세일러&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[[cpp] PE 파일에서 매니페스트 추출하기]]></title><description><![CDATA[PE 파일의 매니페스트에는 많은 정보가 담겨 있다. 주요하게는 해당 실행 파일이 어떤 CRT…]]></description><link>https://jiniya.net/wp/archives/14975</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14975</guid><pubDate>Thu, 18 Jun 2015 23:59:56 GMT</pubDate><content:encoded>&lt;p&gt;PE 파일의 매니페스트에는 많은 정보가 담겨 있다. 주요하게는 해당 실행 파일이 어떤 CRT와 바인딩이 되는 것인지, 또 해당 실행 파일을 실행하기 위해서 필요한 권한은 무엇인지 등의 정보가 담겨 있다. 그 외에도 실행 파일을 실행하는데 각종 필요한 정보가 계속 추가되고 있다. 매니페스트 파일을 지원하지 않는 컴파일러를 사용하던 시절에는 아래와 같은 매니페스트 xml 파일을 직접 작성해서 실행 파일의 리소스로 포함시켜줘야 했지만 요즈음 Visual Studio는 매니페스트 파일 생성을 도와 주고 있기 때문에 프로젝트 설정에서 각종 세부 사항을 설정하면 된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;xml&quot;&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token prolog&quot;&gt;&amp;lt;?xml version=&apos;1.0&apos; encoding=&apos;UTF-8&apos; standalone=&apos;yes&apos;?&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;assembly&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;urn:schemas-microsoft-com:asm.v1&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;manifestVersion&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;1.0&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;trustInfo&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;urn:schemas-microsoft-com:asm.v3&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;security&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;requestedPrivileges&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;requestedExecutionLevel&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;asInvoker&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;uiAccess&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;false&lt;span class=&quot;token punctuation&quot;&gt;&apos;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;requestedPrivileges&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;security&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;trustInfo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;assembly&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;보안 프로그램을 만드는 경우에는 종종 이러한 매니페스트 파일의 내용의 추출이 필요할 때가 있다. PE 파일에서 직접 매니페스트 XML을 추출하기 위해서는 리소스 섹션을 참고하면 된다. 매니페스트 XML 파일의 PE 파일에 RT_MANIFEST 타입의 1번 리소스로 추가되기 때문이다. 로드된 모듈의 경우에는 FindResource 함수를 사용해서 손쉽게 해당 항목을 찾을 수 있지만 로드되지 않은 모듈의 경우에는 이 작업이 쉽지 않다. 이 경우에는 직접 PE 파일에서 리소스 섹션을 뒤져서 항목을 찾아야 한다. 아래 FindResourceDirectoryEntryWithId 함수는 rd 리소스 블록에 포함된 블록 중에 ID가 넘어온 id 파라미터와 일치하는 블록 정보를 찾아서 반환하는 역할을 한다. 해당 함수를 사용해서 루트 블록에서 RT_MANIFEST를 찾고, 그 다음 해당 블록의 1번 리소스를 찾으면 매니페스트 정보를 추출할 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;PIMAGE_RESOURCE_DIRECTORY_ENTRY
&lt;span class=&quot;token function&quot;&gt;FindResourceDirectoryEntryWithId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID root&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PIMAGE_RESOURCE_DIRECTORY rd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; USHORT id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	PIMAGE_RESOURCE_DIRECTORY_ENTRY entry&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	entry &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PIMAGE_RESOURCE_DIRECTORY_ENTRY&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	ULONG cnt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; rd&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;NumberOfNamedEntries &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; rd&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;NumberOfIdEntries&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; cnt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;entry&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;NameIsString&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; entry&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
				&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;entry&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;아래 GetManifestStringFromBuffer 함수는 PE 파일을 읽어들인 버퍼에서 매니페스트 문자열을 추출하는 방법을 보여주고 있다. 리소스 섹션을 찾은 다음 해당 섹션에서 RT_MANIFEST 블록을 찾고, 다시 1번 ID 블록을 찾은 다음 정보를 복사한다. 실행 파일에서 매니페스트 문자열을 추출하는 전체 프로젝트 소스 코드는 &lt;a href=&quot;/codewiz/assets/files/2015/dump_manifest.7z&quot;&gt;여기에서&lt;/a&gt; 다운로드 받을 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;BOOL
&lt;span class=&quot;token function&quot;&gt;GetManifestStringFromBuffer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPCVOID abuffer
								&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SIZE_T buffer_size
								&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPSTR manifest
								&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SIZE_T manifest_size
								&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PSIZE_T required_size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ULONG sec_cnt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	PIMAGE_SECTION_HEADER sec &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	PIMAGE_DATA_DIRECTORY dd &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	PUCHAR buffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PUCHAR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; abuffer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	PIMAGE_NT_HEADERS32 nt32 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetNTHeaders32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; buffer_size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nt32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		sec_cnt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; nt32&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;FileHeader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;NumberOfSections&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		sec &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetSectionHeaderFromNT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nt32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		dd &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;nt32&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;OptionalHeader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DataDirectory&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;IMAGE_DIRECTORY_ENTRY_RESOURCE&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		PIMAGE_NT_HEADERS64 nt64 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetNTHeaders64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; buffer_size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nt64&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			sec_cnt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; nt64&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;FileHeader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;NumberOfSections&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			sec &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetSectionHeaderFromNT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nt64&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			dd &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;nt64&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;OptionalHeader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DataDirectory&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;IMAGE_DIRECTORY_ENTRY_RESOURCE&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;sec &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;dd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	PVOID rptr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dd&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;VirtualAddress&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; sec_cnt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		PVOID sptr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sec&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;VirtualAddress&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		PVOID eptr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sptr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sec&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Misc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;VirtualSize&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rptr &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; sptr &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; rptr &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; eptr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			PIMAGE_RESOURCE_DIRECTORY root&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			
			ULONG diff &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetOffset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sptr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rptr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			root &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PIMAGE_RESOURCE_DIRECTORY&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;sec&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PointerToRawData &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; diff&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

			&lt;span class=&quot;token comment&quot;&gt;// RT_MANIFEST 리소스 블록을 찾는다.&lt;/span&gt;

			PIMAGE_RESOURCE_DIRECTORY_ENTRY entry&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			ULONG_PTR man_id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG_PTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; RT_MANIFEST&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			entry &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;FindResourceDirectoryEntryWithId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;root&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; root&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; man_id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;entry&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
				&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

			&lt;span class=&quot;token comment&quot;&gt;// RT_MANIFEST 리소스 블록 아래 ID가 1인 리소스를 찾는다.&lt;/span&gt;

			PIMAGE_RESOURCE_DIRECTORY rd&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			rd &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PIMAGE_RESOURCE_DIRECTORY&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;root&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; entry&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;OffsetToDirectory&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			entry &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;FindResourceDirectoryEntryWithId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;root&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;entry&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
				&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

			rd &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PIMAGE_RESOURCE_DIRECTORY&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;root&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; entry&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;OffsetToDirectory&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			entry &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PIMAGE_RESOURCE_DIRECTORY_ENTRY&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

			PIMAGE_RESOURCE_DATA_ENTRY data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PIMAGE_RESOURCE_DATA_ENTRY&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;root&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; entry&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;OffsetToData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

			PVOID pdata&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			pdata &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;root&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;OffsetToData &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; sec&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;VirtualAddress &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; diff&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

			&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;required_size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
				&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;required_size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;Size &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

			&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;manifest_size &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; data&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;Size &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;token function&quot;&gt;SetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ERROR_INSUFFICIENT_BUFFER&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
				&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

			&lt;span class=&quot;token function&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;manifest&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pdata&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;Size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			manifest&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;data&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;Size&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token char&quot;&gt;&apos;\0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[리뷰] 돈, 뜨겁게 사랑하고 차갑게 다루어라]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/1189</link><guid isPermaLink="false">https://jiniya.net/wp/archives/1189</guid><pubDate>Thu, 18 Jun 2015 23:59:55 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;나는 이제 수단을 갖게 되었으므로 편안한 삶을 즐기고자 했다. 그러나 나는 내 기쁨을 마음껏 누릴 수가 없었다. 나의 철학적 현실주의와 뛰어난 증권 감각 덕택으로 나는 갑부가 되긴 하였으나 그 대신 다른 많은 것을 잃어버렸다. 내 소원은 성취되었지만 내 눈앞에 펼쳐진 세상은 너무도 슬펐다. 내가 좋아했던 친구들은 대부분 파멸했다. 그들은 공황을 거치면서 돈과 지위를 잃어버렸으며 앞으로 어떻게 살아가야 할지도 막막했다. 그와 반대로 나는 내가 꿈꿔 왔던 호화스러운 것을 모두 가질 수 있었다. 멋진 호텔, 레스토랑, 자동차, 이 모든 것을 누릴 수 있을 정도로 내 지갑은 항상 두둑했다. 그러나 그것을 같이 즐길 사람이 없었다. 화기애애한 분위기는 식었고, 즐거운 웃음이 사라진 그 자리에는 고통과 음침한 분위기만이 자리했다. 나는 정말 외톨이가 되었다. 어디든 살 수 있는 것 천지였지만 난 살 마음이 생기지 않았다. 친구들이 단 한 잔의 커피로 만족해야만 할 때 나는 샴페인과 귀한 상어 알을 먹을 수 있다는 사실이 내게 행복을 주지 않음을 그제야 알았다. 내 상황은 그 전보다 훨씬 나빠졌다. p227&lt;br&gt;
&lt;br&gt;
…&lt;br&gt;
&lt;br&gt;
이 전략은 오늘날에도 젊은 머니매니저들에게 매우 인기 있는 방법으로, 그들은 이것을 일컬어 포트폴리오 보험이라고 칭한다. 참 말도 안 되는 소리다. 왜냐하면 이 보험은 마치 화재로부터 집을 보호하기 위해 집을 판다는 식이기 때문이다. 나는 경험많은 사람들조차 어떻게 그럴 수 있는지 이해할 수 없다. p179&lt;br&gt;
&lt;br&gt;
…&lt;br&gt;
&lt;br&gt;
아주 열정적인 투자자였으나 런던 공황 때 재산을 몽땅 잃어버린 아이작 뉴턴 경은 이러한 분위기에 대해 다음과 같이 말한 바 있다.&lt;br&gt;
&lt;br&gt;
“천체 운동은 센티미터와 초 단위로 측량할 수 있으나, 정신 나간 군중이 시세를 어떻게 끌고 갈지는 정말 알 수 없다.” p172&lt;br&gt;
&lt;br&gt;
…&lt;br&gt;
&lt;br&gt;
주가지수 선물거래를 위한 증거금 비율이 아주 낮았기 때문에 1987년 이 시장은 고삐 풀린 망아지처럼 뛰어다녔다. 시카고에서 하루에 거래된 S&amp;#x26;P 500 지수 선물 계약이 뉴욕 증시에서 거래된 주식의 가치보다 많은 적도 있었다. 선물시장이 주도권을 쥐게 됨에 따라, 개가 꼬리를 흔드는 것이 아니라 꼬리가 개를 흔드는 상황이 연출된 것이다. p176&lt;br&gt;
&lt;br&gt;
…&lt;br&gt;
&lt;br&gt;
주식 투자자들은 성공하면 자기가 잘났기 때문이라고 하고, 실패하면 남의 탓으로 돌리기를 좋아한다. 가해자가 누구인지 바로 결정되었다. 프로그램 매매를 주도하던 컴퓨터에게 모든 죄가 돌아갔다. 불쌍한 컴퓨터가 가해자가 되어 버렸다. 만약 사람들이 신선하지 못한 생선을 포크와 나이프로 먹어 복통이 일어나면 그것을 포크와 나이프 탓으로 돌릴 것인가? 잘못된 것은 신선하지 못한 생선이듯, 이 문제는 사실 증권시장의 골든보이들이었다. p180&lt;br&gt;
&lt;br&gt;
– 돈, 뜨겁게 사랑하고 차갑게 다루어라, 앙드레 코스톨라니&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[[cpp] 작업 영역 정확하게 구하는 방법]]></title><description><![CDATA[일반적으로 작업 영역을 구할때는 아래와 같은 코드를 많이 사용합니다. SystemParametersInfo의 SPI_GETWORKAREA…]]></description><link>https://jiniya.net/wp/archives/3470</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3470</guid><pubDate>Thu, 18 Jun 2015 23:59:54 GMT</pubDate><content:encoded>&lt;p&gt;일반적으로 작업 영역을 구할때는 아래와 같은 코드를 많이 사용합니다. SystemParametersInfo의 SPI_GETWORKAREA를 사용하여 작업 표시줄을 제외한 작업영역을 구하는 방법입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;RECT rc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token function&quot;&gt;SystemParametersInfo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SPI_GETWORKAREA&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;rc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위 방법에는 한가지 단점이 있습니다. 작업표시줄의 자동 숨김 옵션을 활성화하면 전체 화면을 작업 영역으로 구하는 것이죠. 자동 숨김으로 하더라도 작업 표시줄이 완전히 사라지는 것이 아니라 미세하게 두께를 차지하기 때문에 약간의 높이가 있습니다. 때로는 이 미세한 영역도 정교하게 처리해 주고 싶을 때가 있습니다. 그럴 땐 SPI_GETWORKAREA를 사용할 수 없습니다.&lt;/p&gt;
&lt;p&gt;GetWorkArea는 자동 숨김 옵션을 활성화한 경우에도 항상 정확하게 작업 표시줄 영역을 구해주는 함수입니다. lprc로 RECT 구조체의 포인터를 넘겨주면 절대적인 작업 영역을 구해서 넘겨줍니다. 별로 중요하다거나 어려운 부분은 없습니다. 단지 한가지 알아두면 유용한 것은, 작업 표시줄이 어떤 위치에 바인딩 되어 있는지를 구하기 위해서는 SHAppBarMessage API를 사용한다는 점 입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GetWorkArea 함수 코드&lt;/strong&gt;
&lt;a href=&quot;/codewiz/assets/files/2015/getworkarea.cpp&quot;&gt;소스 코드 다운로드&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetWorkArea&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPRECT lprc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
    SIZE    szScreen&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
    HWND    hShell &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;FindWindowW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;Shell_TrayWnd&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
    
    szScreen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetSystemMetrics&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SM_CXSCREEN&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
    szScreen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetSystemMetrics&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SM_CYSCREEN&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
    &lt;span class=&quot;token function&quot;&gt;SetRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lprc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; szScreen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; szScreen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cy&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
    
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;hShell&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    RECT        rcTaskbar&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
    SIZE        szTaskbar&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;      
    APPBARDATA  AppBarData&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
    POINT       pt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
    POINT       ptMouse&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
        
    &lt;span class=&quot;token function&quot;&gt;GetWindowRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hShell&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;rcTaskbar&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
    szTaskbar&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; rcTaskbar&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;right &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; rcTaskbar&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;left&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
    szTaskbar&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; rcTaskbar&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bottom &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; rcTaskbar&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;top&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
        
    AppBarData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cbSize &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt; AppBarData&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
    &lt;span class=&quot;token function&quot;&gt;SHAppBarMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ABM_GETTASKBARPOS&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;AppBarData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
        
    &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;AppBarData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;uEdge&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; ABE_TOP&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; 
        lprc&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;top &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; szTaskbar&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cy&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
        &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
            
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; ABE_BOTTOM&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; 
        lprc&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;bottom &lt;span class=&quot;token operator&quot;&gt;-=&lt;/span&gt; szTaskbar&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cy&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;            
        &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
            
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; ABE_LEFT&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; 
        lprc&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;left &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; szTaskbar&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cx&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;          
        &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
            
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; ABE_RIGHT&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; 
        lprc&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;right &lt;span class=&quot;token operator&quot;&gt;-=&lt;/span&gt; szTaskbar&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cx&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
        &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;아래와 같은 테스트 코드로 두 가지 방법을 비교해 보면 작업 표시줄의 항상 숨김 옵션을 끈 경우에는 결과 값이 동일하지만 해당 옵션을 활성화한 경우에는 GetWorkArea가 구한 영역이 조금 더 작다는 것을 보실 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	RECT rc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
	&lt;span class=&quot;token function&quot;&gt;SystemParametersInfo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SPI_GETWORKAREA&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;rc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
	&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%d %d %d %d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;left&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;top&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;right&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bottom&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;GetWorkArea&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;rc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%d %d %d %d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;left&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;top&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;right&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bottom&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[cpp] 동적 연결 라이브러리 동작 원리]]></title><description><![CDATA[항공기 사고의 74%는 이륙후 3분간, 착륙전 8분간 동안 발생한다고 한다. 이를 두고 ‘마의 11분’이란 표현을 쓰기도 한다. 이는 크리티컬한 작업에 있어서 시작과 끝이 얼마나 중요하고 위험한지를 나타내는 부분이라고 볼 수 있다. 윈도우 DLL…]]></description><link>https://jiniya.net/wp/archives/10447</link><guid isPermaLink="false">https://jiniya.net/wp/archives/10447</guid><pubDate>Thu, 18 Jun 2015 23:59:53 GMT</pubDate><content:encoded>&lt;p&gt;항공기 사고의 74%는 이륙후 3분간, 착륙전 8분간 동안 발생한다고 한다. 이를 두고 ‘마의 11분’이란 표현을 쓰기도 한다. 이는 크리티컬한 작업에 있어서 시작과 끝이 얼마나 중요하고 위험한지를 나타내는 부분이라고 볼 수 있다. 윈도우 DLL을 사용할 때에도 대부분의 오류가 항공기 사고와 유사하게 DLL을 메모리에 적재하는 시점이나 해제하는 시점에 발생한다. 이는 윈도우가 DLL 목록을 관리하는 방식의 특수성에 기인한다. 이번 시간에는 이런 특수성에 대해서 살펴보고 이륙이나 착륙 과정에서의 사고를 피하기 위해서는 어떤 부분에 신경 써야 하는지 알아본다.&lt;/p&gt;
&lt;p&gt;로더 락(Loader Lock)
윈도우는 로드된 DLL을 PEB(Process Environment Block)의 Ldr 필드를 통해서 관리한다. Ldr 필드는 &amp;#x3C;리스트 1&gt;에 나와 있는 _PEB_LDR_DATA32 구조체를 가리킨다. _PEB_LDR_DATA32 구조체에는 현재 로더의 동작 상태를 나타내는 플래그와 로드된 DLL의 목록을 저장하고 있는 3개의 리스트(InLoadOrderModuleList, InMemoryOrderModuleList, InInitializationOrderModuleList)로 구성되어 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 1 _PEB_LDR_DATA32 구조체&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_PEB_LDR_DATA32&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ULONG Length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    BOOLEAN Initialized&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    PVOID32 SsHandle&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    LIST_ENTRY32 InLoadOrderModuleList&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    LIST_ENTRY32 InMemoryOrderModuleList&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    LIST_ENTRY32 InInitializationOrderModuleList&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    PVOID32 EntryInProgress&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    BOOLEAN ShutdownInProgress&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    PVOID32 ShutdownThreadId&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; PEB_LDR_DATA32&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PPEB_LDR_DATA32&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;LoadLibrary와 같은 DLL을 로드하는 함수나 로더 내부적으로 DLL을 로딩하는 경우에 로더는 해당 DLL을 로딩하고 _PEB_LDR_DATA32의 리스트에 해당 DLL의 정보를 추가한다. 마찬가지로 DLL이 메모리에서 언로드되는 경우에는 리스트에서 요청한 DLL을 제거한다. GetModuleHandle과 같이 특정 DLL을 찾는 경우에는 모듈 리스트를 순회하면서 들어온 정보와 매치되는 DLL이 있는지를 찾는다.&lt;/p&gt;
&lt;p&gt;이와 같이 DLL의 관리에는 _PEB_LDR_DATA32라는 프로세스 내부의 유일한 구조체가 사용되며, 해당 구조체의 정보는 다양한 윈도우 API에 의해서 수시로 변경된다. 이 말은 해당 구조체에 대한 접근은 직렬화될 필요가 있다는 것을 의미한다. 구조체에 대한 접근이 동기화 되지 않는다면 다중 스레드에서 구조체의 내용을 변경할 경우에 구조체 내용물이 오염되는 현상이 발생할 수 있기 때문이다. 윈도우에서는 _PEB_LDR_DATA32 구조체에 대한 접근을 직렬화 시키기 위해서 로더 락이라는 것을 사용한다. 로더 락은 PEB 내부에 존재하며 크리티컬 섹션으로 구현되어 있다. 따라서 _PEB_LDR_DATA32를 사용하는 모든 API들은 로더 락을 획득한 다음 작업을 한다고 생각하면 된다.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;리스트 2&gt;와 &amp;#x3C;리스트 3&gt;에는 이러한 로더 락의 특징을 보여주는 예제를 담고 있다. 두 개의 스레드를 생성해서 각각의 스레드가 a.dll과 b.dll을 로드한다. 각각의 DLL은 &amp;#x3C;리스트 3&gt;에 나와 있는 것과 같이 DLL이 초기화 되는 부분에서 자신의 이름을 출력한다. 만약 DLL이 로드되는 것이 직렬화 되지 않는다면 메시지 박스 두 개가 동시에 화면에 출력될 것이다. 하지만 DLL이 로드되는 작업은 직렬화가 이루어지기 때문에 절대로 두 개의 메시지 박스가 동시에 화면에 나타나는 법은 없다. 항상 하나의 메시지 박스를 닫아서 작업을 완료해야 다음 DLL의 메시지 박스가 출력된다. LoadLibrary 부분을 MessageBoxW 함수로 바꿔가면서 예제를 실행해보면 그 차이를 보다 쉽게 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 2 실행 파일 소스&lt;/strong&gt;
&lt;a href=&quot;http://www.jiniya.net/codewiz/assets/files/2015/loaderlock1.cpp&quot;&gt;소스 코드 다운로드&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;windows.h&quot;&lt;/span&gt;&lt;/span&gt;

ULONG
CALLBACK
&lt;span class=&quot;token function&quot;&gt;ThreadProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID param&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    LPCWSTR name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPCWSTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; param&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;LoadLibraryW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_tmain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; argc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _TCHAR&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; argv&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;LoadLibraryW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;user32.dll&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    HANDLE threads&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    threads&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ThreadProc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;a.dll&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    threads&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ThreadProc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;b.dll&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;WaitForMultipleObjects&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ARRAYSIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;threads&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; threads&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; INFINITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 3 DLL 소스&lt;/strong&gt;
&lt;a href=&quot;http://www.jiniya.net/codewiz/assets/files/2015/loaderlock2.cpp&quot;&gt;소스 코드 다운로드&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;windows.h&quot;&lt;/span&gt;&lt;/span&gt;

BOOL APIENTRY &lt;span class=&quot;token function&quot;&gt;DllMain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; HMODULE m&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DWORD reason&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPVOID reserved&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reason&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; DLL_PROCESS_ATTACH&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;MessageBoxW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;a.dll&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;a.dll&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MB_OK&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;DllMain에서 주의할 점
앞서 프로세스 내부의 DLL 정보를 관리하기 위해서 _PEB_LDR_DATA32라는 구조체를 사용한다는 것과 해당 구조체에 대한 접근을 로더 락을 통해서 직렬화 시킨다는 것을 배웠다. 이 단순한 사실이 DllMain을 작성하는 데에는 상당한 제약 사항을 불러온다. DllMain은 로더 락을 획득한 상태에서 호출되기 때문에 사소한 함수 호출도 데드락이나 크래시로 이어질 수 있다. &amp;#x3C;표 1&gt;에는 이러한 관점에서 DllMain에서 피해야 할 작업들의 목록이 나와 있다. 해당 작업들은 특수한 가정이 적용되는 상황이 아니라면 가급적 사용하지 않는 것이 좋다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DllMain에서 피해야 할 작업들&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LoadLibrary, LoadLibraryEx 호출&lt;br&gt;
해당 함수들은 의존성 루프를 생성할 수 있고 의존성 루프는 데드락이나 크래시를 유발할 수 있다.&lt;/li&gt;
&lt;li&gt;다른 스레드와 동기화&lt;br&gt;
데드락을 유발한다.&lt;/li&gt;
&lt;li&gt;로더 락을 획득하려는 코드가 가지고 있는 동기화 오브젝트를 획득하려는 시도&lt;br&gt;
데드락을 유발한다.&lt;/li&gt;
&lt;li&gt;CoInitializeEx를 사용한 COM 스레드 초기화&lt;br&gt;
특정 조건이 충족될 경우 CoInitializeEx는 LoadLibraryEx를 호출한다.&lt;/li&gt;
&lt;li&gt;레지스트리 관련 함수들&lt;br&gt;
이 함수들은 advapi32.dll에 구현되어 있다. advapi32.dll이 초기화 되지 않았다면 크래시가 발생할 수 있다.&lt;/li&gt;
&lt;li&gt;CreateProcess 호출&lt;br&gt;
프로세스 생성은 다른 DLL을 로드할 수 있다.&lt;/li&gt;
&lt;li&gt;ExitThread 호출&lt;br&gt;
DLL_PROCESS_DETACH 과정 중에 스레드를 종료하면 로더 락을 다시 획득하도록 만들 수 있다.&lt;/li&gt;
&lt;li&gt;네임드 파이프나 네임드 오브젝트 생성&lt;br&gt;
윈도우 2000에서 네임드 오브젝트 생성은 터미널 서비스 DLL에서 구현되어 있다. 해당 DLL이 초기화 되어 있지 않다면 크래시가 발생할 수 있다.&lt;/li&gt;
&lt;li&gt;CRT에 포함된 메모리 관리 함수 사용&lt;br&gt;
DLL 버전의 CRT를 사용한다면 해당 DLL이 초기화되어 있지 않을 수 있다.&lt;/li&gt;
&lt;li&gt;user32.dll이나 gdi32.dll에 포함된 함수 사용&lt;br&gt;
일부 함수들은 다른 DLL을 로드할 수 있고, 이 때문에 크래시가 발생할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;그럼 좀 더 세부적으로 왜 이런 금기 사항들이 생겼는지에 대해서 알아보도록 하자. 첫 번째 금기 사항은 LoadLibrary의 호출이다. LoadLibrary의 호출은 새로운 DLL을 로딩하는 일이기 때문에 당연히 로더 락을 획득하는 시도가 발생할 수 있다는 것을 알 수 있다. 하지만 앞서 로더 락은 크리티컬 섹션으로 구현되어 있다고 했다. 윈도우에서 크리티컬 섹션은 재귀적으로 획득하는 것이 가능하도록 설정돼 있기 때문에 현재 스레드가 로더 락을 획득한 상태에서 LoadLibrary를 호출하는 것은 일견 문제가 없어 보이기도 한다. 실제로 DllMain에서 LoadLibrary를 사용해보면 큰 문제 없이 정상 동작하는 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;이렇게 잘 동작하는 LoadLibrary를 왜 굳이 호출하지 않도록 권고하는 것일까? 이유는 해당 호출을 인정할 경우에 특수한 상황에서 발생하는 문제들을 잠재적으로 같이 허용하는 셈이 되기 때문이다. 대표적인 예가 의존성 루프를 생성하는 것을 들 수 있다. 예를 들면 이런 상황이다. P라는 프로그램이 A.DLL을 로드한다. A.DLL은 DllMain에서 B.DLL을 로드한다. B.DLL은 DllMain에서 A.DLL을 로드한 다음 A.DLL의 Func라는 함수를 사용한다. 이때 이 Func라는 함수는 A.DLL이 초기화가 다 완료되지 않은 상태에서 호출되기 때문에 문제가 발생할 수 있다. &amp;#x3C;리스트 4&gt;에는 이 경우에 대한 소스 코드가 나와 있다. 해당 예제를 수행해 보면 &amp;#x3C;화면 1&gt;에 나타난 것과 같이 Func 실행 부분에서 msg 값이 초기화가 완료되지 않아서 NULL 값이 출력되는 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;이 예제의 경우에는 의존성 루프가 2단계이고 모든 DLL을 우리가 만들었기 때문에 원인을 쉽게 찾을 수 있다. 하지만 이런 의존성이 여러 곳에서 긴 단계에 걸쳐서 발생하는 경우에는 찾기도 힘들뿐더러 예측하지 못했던 동작들이 발생할 수 있다. 따라서 가급적 DllMain에서는 LoadLibrary 호출을 피하는 것이 좋다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 4 의존성 루프로 인한 오류 발생 예제&lt;/strong&gt;
&lt;a href=&quot;http://www.jiniya.net/codewiz/assets/files/2015/loaderlock3.cpp&quot;&gt;소스 코드 다운로드&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// P 소스 코드&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;windows.h&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;LoadLibraryW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;a.dll&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// A.DLL 소스 코드&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;windows.h&quot;&lt;/span&gt;&lt;/span&gt;

LPCWSTR msg&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

BOOL APIENTRY &lt;span class=&quot;token function&quot;&gt;DllMain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HMODULE m&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DWORD reason&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPVOID reserved&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reason&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; DLL_PROCESS_ATTACH&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a.dll DLL_PROCESS_ATTACH\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			HMODULE m &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;LoadLibraryW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;b.dll&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			msg &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;Init Complete&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a.dll DLL_PROCESS_ATTACH 완료\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;C&quot;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__declspec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dllexport&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;MSG =&gt; %ws\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;


&lt;span class=&quot;token comment&quot;&gt;// B.DLL 소스 코드&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;windows.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;FuncT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

BOOL APIENTRY &lt;span class=&quot;token function&quot;&gt;DllMain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HMODULE m&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DWORD reason&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPVOID reserved&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reason&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; DLL_PROCESS_ATTACH&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;b.dll DLL_PROCESS_ATTACH\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

			HMODULE m &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;LoadLibraryW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;a.dll&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			FuncT func &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;FuncT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetProcAddress&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;m&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Func&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;token function&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		
			&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;b.dll DLL_PROCESS_ATTACH 완료\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;화면 1 P 실행 화면&lt;/strong&gt;
두 번째 시나리오인 다른 스레드와 동기화를 생각해보자. DllMain에서 T라는 스레드를 종료 시키기 위해서 T의 종료 이벤트를 시그널 하고 WaitForSingleObject로 T를 대기한다고 가정해보자. 이 경우에 T는 종료 이벤트가 시그널 되었기 때문에 스레드 종료를 위해서 ExitThread가 호출될 것이다. ExitThread가 호출되면 DLL_THREAD_DETACH 이벤트를 호출하기 위해서 일부 DLL에 대해서는 DllMain이 호출되어야 한다. 이는 바로 로더 락 획득을 의미한다. 그런데 a.dll의 DllMain에서 로더 락을 획득한 상태에서 T가 종료되길 대기하고 있기 때문에 T의 ExitThread는 로더 락을 획득할 수가 없다. 따라서 데드락에 빠지게 된다. &amp;#x3C;리스트 5&gt;에는 이러한 시나리오를 통해서 데드락에 빠지는 예제가 나와 있다. 해당 DLL을 로딩하는 프로그램은 자동으로 데드락에 빠진다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 5 스레드 동기화로 인한 데드락 발생 예제&lt;/strong&gt;
&lt;a href=&quot;http://www.jiniya.net/codewiz/assets/files/2015/deadlock.cpp&quot;&gt;소스 코드 다운로드&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;windows.h&quot;&lt;/span&gt;&lt;/span&gt;
HANDLE exit_event&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

ULONG
CALLBACK
&lt;span class=&quot;token function&quot;&gt;ThreadProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;WaitForSingleObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;exit_event&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; INFINITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

BOOL APIENTRY &lt;span class=&quot;token function&quot;&gt;DllMain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; HMODULE m&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DWORD reaspm&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPVOID reserved&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reason&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; DLL_PROCESS_ATTACH&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            exit_event &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            HANDLE thread &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ThreadProc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;SetEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;exit_event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;WaitForSingleObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; INFINITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;간단하게 두 가지 경우에 발생하는 문제만 살펴보았지만 다른 경우의 문제점들도 동일하게 모두 로더 락을 획득한 상태라는 특수성 때문에 발생하는 문제들이다. 숙련된 윈도우 프로그래머의 경우에도 이러한 제약 사항들에 대해서 단지 정상 동작한다는 이유로 크게 신경을 쓰지 않기도 한다. 하지만 이는 바람직한 자세가 아니다. 언제든지 해당 코드들은 문제를 발생시킬 수 있기 때문이다. 특수한 가정이 덧붙여지는 상황이 아니라면 해당 코드들을 DllMain에서 사용하는 일은 반드시 피하도록 해야 한다.&lt;/p&gt;
&lt;p&gt;초기화 지연 전략
DllMain에서 피해야할 많은 작업들에 대해서 배웠다. 그렇다면 만약 DLL의 초기화에 반드시 피해야 할 작업이 있다면 어떻게 해야 할까? 그럴 때는 DllMain에서 초기화를 시키는 것이 아닌 초기화를 지연시키는 방법을 사용해야 한다. 일반적으로 가장 좋은 방법은 &amp;#x3C;리스트 6&gt;에 나와 있는 것과 같이 DLL 초기화, 클린업 함수를 익스포트 시키는 방법이다. DLL을 사용하는 프로그래머가 DLL 로딩 후에 해당 함수를 명시적으로 호출해서 초기화와 클린업을 수행하도록 만드는 것이다. 하지만 후킹 DLL과 같은 경우에는 이러한 방법을 사용하기가 까다로운 경우가 많다. 그런 경우에는 DllMain에서 초기화 코드를 담고 있는 스레드를 생성해서 나중에 초기화가 수행되도록 만드는 것이 좋다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 6 초기화/종료 함수를 사용한 초기화 지연&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;__delcspec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dllexport&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; HRESULT &lt;span class=&quot;token function&quot;&gt;InitDLL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 실제 DLL 초기화 작업&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;__declspec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dllexport&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CleanupDLL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 실제 DLL 클린업 작업&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;DLL_PROCESS_DETACH에 관한 오해
DLL_PROCESS_DETACH는 DLL이 메모리에서 해제되는 시점, 그러니까 FreeLibrary가 호출되서 해당 DLL의 레퍼런스 카운트가 0이 되는 시점과 프로세스가 종료되는 시점에 호출된다. 이러한 특성 때문에 상당히 많은 윈도우 프로그래머가 DLL_PROCESS_DETACH에 대해서 도시전설 같은 믿음을 가지고 있다. 하나는 TerminateProcess로 종료되는 경우에는 DLL_PROCESS_DETACH 이벤트가 발생한다는 것이고, 다른 하나는 DLL_PROCESS_DETACH가 프로세스 종료 처리에 적합한 위치라고 생각한다는 점이다. 하지만 이는 둘 다 심각하게 잘못된 믿음이다.&lt;/p&gt;
&lt;p&gt;프로세스 종료를 만들어내는 두 가지 API, ExitProcess와 TerminateProcess의 구현을 살펴보면 &amp;#x3C;리스트 7&gt;에 나타난 것과 같다. 코드에 나타난 것처럼 두 함수 모두 궁극적으로는 NtTerminateProcess를 호출해서 작업을 완료한다. 둘의 차이라면 ‘shutdown process’의 진행 여부에 있다. 이 ‘shutdown process’의 진행 과정의 일환으로 호출되는 것이 DLL_PROCESS_DETACH다. 따라서 TerminateProcess로 종료될 때에는 당연히 DLL_PROCESS_DETACH 이벤트가 발생하지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 7 ExitProcess와 TerminateProcess의 구현&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;ExitProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  
    &lt;span class=&quot;token function&quot;&gt;NtTerminateProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ExitCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
    &lt;span class=&quot;token comment&quot;&gt;// shutdown process  &lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;NtTerminateProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetCurrentProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ExitCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  
&lt;span class=&quot;token function&quot;&gt;TerminateProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  
    &lt;span class=&quot;token function&quot;&gt;NtTerminateProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Process&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ExitCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;우리가 ExitProcess의 구현에서 눈치채야 할 다른 중요한 시사점은 바로 NtTerminateProcess를 호출한 다음 ‘shutdown process’를 진행한다는 점입니다. 여기에는 굉장히 중요한 점이 내포되어 있다. 바로 우리 DLL이 FreeLibrary가 아닌 프로세스 종료 때문에 DLL_PROCESS_DETACH가 호출된다면, 그 시점에는 그 어떠한 스레드도 살아 있지 않다는 점이다. NtTerminateProcess(NULL, ExitCode)를 거치는 순간 해당 프로세스의 모든 스레드는 강제로 터미네이트(Terminate)되기 때문이다.&lt;/p&gt;
&lt;p&gt;결론을 다시 정리해보면 이렇다. DLL_PROCESS_DETACH는 TerminateProcess로 종료되는 경우에는 이벤트가 발생하지 않으며, 모든 스레드가 강제로 종료된 다음에 호출될 수 있기 때문에 종료 작업을 하는 위치로는 적절하지 않다는 점이다.&lt;/p&gt;
&lt;p&gt;DllMain에서의 예외
DLL_PROCESS_ATTACH 이벤트에서 DllMain이 FALSE를 리턴한다면 윈도우는 DLL_PROCESS_DETACH 이벤트를 사용해서 DllMain을 다시 호출한 다음 해당 DLL을 메모리에서 제거한다. 반면에 DLL_PROCESS_ATTACH 수행 과정 중에 DllMain에서 예외가 발생한다면 운영체제는 DLL_PROCESS_DETACH 이벤트 통보 없이 해당 DLL을 즉시 메모리에서 제거한다.&lt;/p&gt;
&lt;p&gt;윈도우는 DllMain의 실패 처리와 관련해서 기본적으로 위와 같은 입장을 가지고 있다. 이 부분이 표면적으로는 FALSE를 리턴하면 DLL_PROCESS_DETACH가 호출되고, 예외가 발생하면 메모리에서 바로 제거된다는 내용을 담고 있는 것처럼 보여지지만 사실상 이 내용은 DllMain에서 절대로 예외를 발생시켜서는 안 된다는 이야기를 담고 있다. 그 이유는 CRT 때문이다.&lt;/p&gt;
&lt;p&gt;CRT는 멀티스레드 환경을 지원하기 위해서 FLS(Fiber Local Storage)라는 것을 사용한다. CRT 초기화 루틴에서 FlsAlloc(_freefls)를 호출해서 FLS 공간을 할당한다. 물론 이렇게 할당된 공간은 DLL_PROCESS_DETACH 이벤트에서 CRT가 직접 제거한다. 코드로 살펴보면 &amp;#x3C;리스트 8&gt;에 나타난 것과 같은 구조가 된다. 실제 DLL의 시작은 CrtDllMain이라는 CRT 코드에서 시작되고 해당 코드에서 각종 초기화를 한 다음 우리가 작성한 OurDllMain을 호출해 주는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 8 DllMain 호출 구조&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;BOOL CALLBACK &lt;span class=&quot;token function&quot;&gt;CrtDllMain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HINSTANCE instance&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ULONG reason&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PVOID reserved&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reason &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; DLL_PROCESS_ATTACH&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  
        flsindex &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;FlsAlloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_freefls&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;OurDllMain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;instance&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reason&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reserved&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;  
    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reason &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; DLL_PROCESS_DETACH&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  
        BOOL r &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;OurDllMain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;instance&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reason&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reserved&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
        &lt;span class=&quot;token function&quot;&gt;FlsFree&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;flsindex&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; r&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;  
  
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그런데 이 구조에서 OurDllMain에서 예외가 발생한다면 CRT가 할당한 FLS 공간이 문제가 된다. 왜냐하면 우리가 만든 OurDllMain에서 예외가 발생하면 CRT에서는 FlsAlloc을 사용해서 FLS 공간을 할당했지만 DLL_PROCESS_DETACH가 호출되지 않아서 그 공간을 회수할 기회를 가지지 못하기 때문이다.&lt;/p&gt;
&lt;p&gt;“몇 바이트 메모리 누수가 일어나는 것이 큰 문제일까?”라고 생각할 수 있다. 하지만 이 문제는 단순히 FLS 공간에 대한 메모리 누수만 일어나는 것으로 마무리되는 문제가 아니다. 윈도우 운영체제는 FLS에 등록된 것들을 프로세스 종료 시점에 모두 다시 회수하려고 시도한다. 이는 FlsAlloc에 지정된 콜백 함수를 호출해서 이루어진다. &amp;#x3C;리스트 8&gt;의 코드에서는 _freefls 함수가 그것이다. 즉, 우리가 예외를 발생시켜 DLL이 메모리에서 즉시 제거되고 나면 엉뚱하게 프로세스 종료 시점에 운영체제가 사라진 메모리 번지를 가리키는 _freefls를 호출하려고 하다가 크래시가 발생할 수 있다.&lt;/p&gt;
&lt;p&gt;DllMain에서는 절대로 예외를 발생시켜서는 안 된다. 왜냐하면 그 예외가 앞서 설명한 것과 같이 CRT의 코드에 영향을 미칠 수 있기 때문이다. &amp;#x3C;리스트 9&gt;에 나타난 것과 같이 DllMain에서 수행하는 작업 과정에서 발생할 수 있는 모든 예외를 봉쇄하고 예외가 발생한 경우에는 그냥 FALSE를 리턴하는 것이 현명하다. 그러면 적어도 다른 프로그램에 민폐는 안 끼칠 수 있다. 그렇지 않다면 민폐를 끼치고 엉뚱한 지점에서 크래시가 발생하는 문제가 생길 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 9 예외 처리기를 통해서 DllMain에서 발생하는 예외를 차단하는 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// /Eha 옵션으로 컴파일해야 모든 예외를 잡을 수 있다.&lt;/span&gt;
BOOL APIENTRY &lt;span class=&quot;token function&quot;&gt;DllMain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; HMODULE m&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DWORD reaspm&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPVOID reserved&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// .. DllMain에서 처리해야 할 작업들&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;lpreserved의 용도
끝으로 DllMain의 마지막 파라미터인 lpreserved에 대해서 알아보자. DllMain의 세 번째 인자는 void 포인터 타입의 lpreserved다. 흔히 그냥 추후 사용을 위해서 예약돼 있다고 막연하게 생각할 수 있는데 이 값은 윈도우 내부적으로 사용되는 값이다. 그리고 그 의미는 다음과 같다.&lt;/p&gt;
&lt;p&gt;DLL_PROCESS_ATTACH 시점에는 지금 로드되는 DLL이 LoadLibrary와 같은 함수를 사용해서 동적으로 로딩된다면 NULL을, 그렇지 않고 임포트 테이블을 사용해서 정적으로 로딩된다면 NULL이 아닌 값을 가진다.&lt;/p&gt;
&lt;p&gt;DLL_PROCESS_DETACH 시점에는 FreeLibrary 호출로 인해서 메모리에서 제거되는 경우에는 NULL을, 그렇지 않고 프로세스 종료로 인해서 DLL이 제거되는 경우에는 NULL이 아닌 값을 가진다.&lt;/p&gt;
&lt;p&gt;이런 파라미터는 DLL의 로딩을 최적화하는 용도로 사용된다. &amp;#x3C;리스트 10&gt;의 코드는 CRT의 DLL_PROCESS_DETACH 코드의 일부를 발췌한 것이다. 이 코드를 살펴보면 lpreserved 값을 조사해서 NULL일 때만 클린업 코드를 호출하는 것을 볼 수 있다. 이유는 NULL이 아닌 경우에는 프로세스가 종료되는 시점이고 우리가 일일이 리소스를 파괴하지 않아도 운영체제가 알아서 모든 리소스를 제거할 것이기 때문이다. 해당 클린업 호출을 하지 않음으로써 보다 빠르게 DllMain이 완료될 수 있도록 만들어주는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 10 CRT의 DLL 클린업 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifndef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;_DEBUG  &lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; lpreserved &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;/* _DEBUG */&lt;/span&gt;  &lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;/* 
         * The process is NOT terminating so we must clean up... 
         */&lt;/span&gt;  
        &lt;span class=&quot;token comment&quot;&gt;/* Shut down lowio */&lt;/span&gt;  
        &lt;span class=&quot;token function&quot;&gt;_ioterm&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
  
        &lt;span class=&quot;token function&quot;&gt;_mtterm&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
  
        &lt;span class=&quot;token comment&quot;&gt;/* This should be the last thing the C run-time does */&lt;/span&gt;  
        &lt;span class=&quot;token function&quot;&gt;_heap_term&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;/* heap is now invalid! */&lt;/span&gt;  
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifndef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;_DEBUG  &lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;  
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;/* _DEBUG */&lt;/span&gt;  &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[리뷰] 위대한 기업에 투자하라]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/1191</link><guid isPermaLink="false">https://jiniya.net/wp/archives/1191</guid><pubDate>Thu, 18 Jun 2015 23:59:52 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;중세 시대는 서구 세계 대부분이 생존에 필요한 물자조차 부족했고, 인간의 삶이 무척 고달팠던 시절이었다. 그 무렵 고급 두뇌의 상당 부분이 쓸데없는 문제에 몰두했던 것도 중요한 이유였다. 당시 이 세상에 천사의 숫자가 얼마나 되는지 따위의 논쟁을 하느라 허비했던 노력의 절반만이라도 굶주림과 질병, 궁핍과 싸우는 데 돌려졌더라면 어떤 일이 벌어졌을지 한번 상상해보라. 오늘날 주식 투자와 관련된 일을 하고 있는 고급 인력들이 향후 경기 동향을 예측하기 위해 바치고 있는 노력의 단 얼마만이라도 보다 생산적인 목적에 사용한다면 정말로 놀라운 결과를 가져올 수 있을 것이다.&lt;br&gt;
&lt;br&gt;
위대한 기업에 투자하라, 필립 피셔&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;맞는 말이다. 생산자는 없고 죄다 빨대 꽂으려는 놈들만 있으니…&lt;/p&gt;
&lt;p&gt;맘같아선 진짜 광합성을 배우던지 해야지 ㅋ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[정보] 빌게이츠의 인생 충고 11가지]]></title><description><![CDATA[RULE 1 Life is not fair – get used to it. 인생이란 원래 공평하지 못하다. 그런 현실에 대하여 불평할 생각하지 말고 받아들여라. 
RULE 2 The world won’t care about your self…]]></description><link>https://jiniya.net/wp/archives/10284</link><guid isPermaLink="false">https://jiniya.net/wp/archives/10284</guid><pubDate>Thu, 18 Jun 2015 23:59:51 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;RULE 1&lt;/strong&gt;&lt;br&gt;
Life is not fair – get used to it.&lt;br&gt;
인생이란 원래 공평하지 못하다. 그런 현실에 대하여 불평할 생각하지 말고 받아들여라.&lt;br&gt;
&lt;br&gt;
&lt;strong&gt;RULE 2&lt;/strong&gt;&lt;br&gt;
The world won’t care about your self-esteem. The world will expect you to accomplish something BEFORE you feel good about yourself.&lt;br&gt;
세상은 네 자신이 어떻게 생각하든 상관하지 않는다. 세상이 너희들한테 기대하는 것은 네가 스스로 만족하다고 느끼기 전에 무엇인가를 성취해서 보여줄 것을 기다리고 있다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;RULE 3&lt;/strong&gt;&lt;br&gt;
You will NOT make 40 thousand dollars a year right out of high school. You won’t be a vice president with car phone, until you earn both.&lt;br&gt;
대학교육을 받지 않는 상태에서 연봉이 4만 달러가 될 것이라고는 상상도하지 말라.&lt;br&gt;
&lt;br&gt;
&lt;strong&gt;RULE 4&lt;/strong&gt;&lt;br&gt;
If you think your teacher is tough, wait till you get a boss. He doesn’t have tenure.&lt;br&gt;
학교선생님이 까다롭다고 생각되거든 사회 나와서 직장 상사의 진짜 까다로운 맛을 한번 느껴봐라.&lt;br&gt;
&lt;br&gt;
&lt;strong&gt;RULE 5&lt;/strong&gt;&lt;br&gt;
Flipping burgers is not beneath your dignity. Your grandparents had a different word for burger flipping they called it Opportunity.&lt;br&gt;
햄버거 가게에서 일하는 것을 수치스럽게 생각하지 마라. 너희 할아버지는 그 일을 기회라고 생각하였다.&lt;br&gt;
&lt;br&gt;
&lt;strong&gt;RULE 6&lt;/strong&gt;&lt;br&gt;
If you mess up,it’s not your parents’ fault, so don’t whine about your mistakes, learn from them.&lt;br&gt;
네 인생을 네가 망치고 있으면서 부모 탓을 하지 마라. 불평만 일삼을 것이 아니라 잘못한 것에서 교훈을 얻어라.&lt;br&gt;
&lt;br&gt;
&lt;strong&gt;RULE 7&lt;/strong&gt;&lt;br&gt;
Before you were born, your parents weren’t as boring as they are now. They got that way from paying your bills, cleaning your clothes and listening to you talk about how cool you are. So before you save the rain forest from the parasites of your parent’s generation, try delousing the closet in your own room.&lt;br&gt;
당신이 태어나기 전에는 부모님의 인생도 괜찮았다. 그들의 인생이 재미없게 된 건 당신의 재미있는 인생을 뒷바라지해야 했기 때문이다. 부모님 세대가 열대우림을 망친다고 분노하기 전에 자기 방의 옷장 안이나 제대로 정리할 일이다.&lt;br&gt;
&lt;br&gt;
&lt;strong&gt;RULE 8&lt;/strong&gt;&lt;br&gt;
Your school may have done away with winners and losers, but life has not. In some schools they have abolished failing grades and they’ll give you as many times as you want to get the right answer. This doesn’t bear the slightest resemblance to ANYTHING in real life.&lt;br&gt;
학교는 승자나 패자를 뚜렷이 가리지 않을 지 모른다. 어떤 학교에서는 낙제제도를 아예 없애고 쉽게 가르치고 있다는 것을 잘 안다. 그러나 사회 현실은 이와 다르다는 것을 명심하라.&lt;br&gt;
&lt;br&gt;
&lt;strong&gt;RULE 9&lt;/strong&gt;&lt;br&gt;
Life is not divided into semesters. You don’t get summers off and very few employers are interested in helping you find yourself. Do that on your own time.&lt;br&gt;
인생은 학기처럼 구분되어 있지도 않고 여름 방학이란 것은 아예 있지도 않다. 네가 스스로 알아서 하지 않으면 직장에서는 가르쳐주지 않는다.&lt;br&gt;
&lt;br&gt;
&lt;strong&gt;RULE 10&lt;/strong&gt;&lt;br&gt;
Television is NOT real life. In real life people actually have to leave the coffee shop and go to jobs.&lt;br&gt;
TV는 현실이 아니다. 현실에서는 커피를 마셨으면 일을 시작하는 것이 옳다.&lt;br&gt;
&lt;br&gt;
&lt;strong&gt;RULE 11&lt;/strong&gt;&lt;br&gt;
Be nice to nerds. Chances are you’ll end up working for one.&lt;br&gt;
공부 밖에 할줄 모르는 “바보” 한테 잘 보여라. 사회 나온 다음에는 아마 그 “바보” 밑에서 일하게 될지 모른다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;--&lt;/p&gt;
&lt;p&gt;빌게이츠가 하지 않았는데 한 걸로 유명해진 것 같은 충고…&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[정보] 세이노칼럼: 장사꾼보다는 사업가가 되라]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/13043</link><guid isPermaLink="false">https://jiniya.net/wp/archives/13043</guid><pubDate>Thu, 18 Jun 2015 23:59:50 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;새벽마다 아파트단지에서 세차를 대행해준다는 독자가 나에게 “어떻게 하면 수입을 더 늘릴 수 있느냐”는 질문을 한 적이 있다. 사람들은 세차 차량의 수를 늘리는데만 관심을 갖는다. 그러나 일의 대가를 육체가 움직이는 시간 만큼만 비례하도록 만들게 되면 평생 가난을 못 벗어난다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;내 답변은 “세차만 하면 안된다”는 것이다. 세차 차량의 숫자를 늘리는 것은 두번째 문제이다. 나라면 우선 “저에게 일을 주셔서 감사합니다. 정성껏 세차했지만 혹시라도 불만이 있으시면 전화해 주십시오”라고 적힌 명함을 돌린다. 새벽에 세차를 하고 낮에는 세차방법과 차량정비에 대해 공부할 것이다. 몇개월 후 “경비실에 키를 맡기시면 냉각수와 세척액 오일 체크는 무료로 해 드립니다”라는 선전지를 돌린다. 다시 몇개월 후 냉각수와 세척액 오일교환 서비스를 실시하고 좋은 제품을 싼 가격에 판다. 가짜나 유사품이 많은 세상이므로 반드시 어느 회사 제품을 사용했는지를 고객에게 눈으로 확인시킨다. 타이어의 공기압도 확인하여 준다. 고객별로 모든 내용을 기록하는 것은 물론이다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;겨울철에는 “염화칼슘이 차를 부식시킨다고 합니다. 제가 알아보니 차량 세척 비용은 얼마라고 합니다만 세차장까지 일부러 시간을 내셔서 다녀오셔야 합니다. 선생님의 귀중한 시간을 아껴드리고자 출근하시기 전 혹은 퇴근하신 뒤에 제가 세차장에 차를 맡기고 찾아오는 서비스를 해 드립니다. 다만 세차비에 얼마를 더 주시면 됩니다”라는 내용의 선전지를 뿌린다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;물론 인근 세차장과 협의해 가격 할인을 받아 놓는다. 또 “밧데리가 방전되어 당황해 하시는 분들을 위하여 제가 밧데리 한 개를 준비했습니다. 동네 정비업체에 전화를 걸어 밧데리를 갖고 오라고 하실 때의 절반 가격에 빌려드립니다”라는 선전지도 배포한다. 무료로 1회 광택 서비스를 해주고 “계속 원하시면 얼마입니다”라고 알린다. 눈이 오면 출근전 앞창 유리를 닦아주기도 한다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;나의 목표는 고객들의 신뢰를 받고 고객이 조그마한 불편이라도 느끼는 것을 눈치 빠른 머슴처럼 대신하여 주되 대가는 받겠다는 것이다. 이점은 중요한 사실이므로 꼭 기억하라. 고객이 많아지면 사람을 고용하고 철저히 감독한다. 그리고 다른 아파트 단지를 찾아 나선다. 신청하는 사람이 많아 감당 못할 서비스 부분은 해당 가격을 인상시키고 주머니가 얇은 고객은 떨어내 고객의 수를 조정한다. 욕심이 앞서 감당 못할 수의 고객을 받아들이는 짓은 절대 하지 않는다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;여기서 독자들은 내가 1년 후를 생각하며 구조체를 만드는 과정에 주목해야 한다. 오늘 수입이 많았다고 좋아하는 사람은 장사꾼이고 오늘은 손해가 났어도 1년후를 생각하며 고객에게 한 약속과 신뢰를 지키는 사람은 사업가이다. 물론 나는 사업가이다. 장사꾼은 작은 돈은 벌 수 있어도 큰 돈은 못 번다. 무슨 일을 하든지 장사꾼이 되지 말고 사업가 정신을 가져야 한다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;– 세이노&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[[일상] 일요일의 단상…]]></title><description><![CDATA[매번 그냥 늘어지게 쉬고 싶다는 말을 입버릇처럼 달고 다녔다. 그래서 오늘은 그냥 늘어지게 쉬었다. 얼마만인지 ㅋㅋ~ #…]]></description><link>https://jiniya.net/wp/archives/3518</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3518</guid><pubDate>Thu, 18 Jun 2015 23:59:49 GMT</pubDate><content:encoded>&lt;p&gt;매번 그냥 늘어지게 쉬고 싶다는 말을 입버릇처럼 달고 다녔다. 그래서 오늘은 그냥 늘어지게 쉬었다. 얼마만인지 ㅋㅋ~&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;어제는 정말 기분이 꿀꿀한 날이었다. 하루 종일 기분이 좋다가 막판에 아주 꿀꿀해진 그런 날. 기분 좋지 않은 반전이 있었던 날. 어쨌던 정말 현진건의 “운수 좋은 날” 같은 그런 느낌의 하루였다. 지나고보니 그런 생각이 들었다. 결국은 내 탓이다. 기분이 좋은 것도 내 탓이고, 기분이 나쁜 것도 내 탓이고 말이다.&lt;/p&gt;
&lt;p&gt;주식을 하면서 배운 한 가지 사실은 높은 수익을 얻는 것보다는 손실을 보지 않는 것이 훨씬 크다는 점이다. 일종의 방어적 프로그래밍과 같은 그런 원리다. 실컷 신나게 수익을 올려도 한번 실수를 하면 물거품 되는 것은 시간 문제다. 그런데 그 물거품 된 것을 복구하기 위해서는 곱절의 노력이 필요한 셈이다. 어쨌든 어제 내가 느낀 점은 좋은 선택을 고심하기 보다는 나쁜 선택을 하지 않도록 주의해야 겠다는 거? ㅎㅎ~&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;꿀꿀한 기분에 푹 자고 났더니 오후다. 일어나기가 싫어서 침대맡에 머리를 파묻고는 한참을 더 잤다. 그래도 침대에서 기어나오기 싫어서 엊저녁에 보다만 책을 집어 들었다. 에쿠니 가오리의 “냉정과 열정 사이”. 한참된 책인데 내가 산 건 아니고, 아마 우리 누나가 산 책인듯 싶다. 집에 있길래 읽어 보려고 집어왔다. 에쿠니 가오리를 제법 좋아한다고 생각하면서도 이 책은 읽어보질 못했었다.&lt;/p&gt;
&lt;p&gt;소설은 제법 낭만적이었다. “사람이 있을 곳이란, 누군가의 가슴속밖에 없는 것이란다.”&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;나에게 자기애의 가장 극한 표현은 요리다. 뭔가 집밥을 해먹고 나면 나 자신에게 그래도 쪼금은 덜 미안해진다. 한동안 요리하는 거에 취미가 들려서 한창 해먹다가 요즘은 좀 뜸했다. 바쁘기도 했고. 어쨌든 오늘은 근사한 집밥을 해먹고 싶어서 간만에 밥을 했다. 된장을 끓이고 갈치를 굽고, … 결국 뭐 다 엄마표 협찬 제품이지만 다 늘어놓고 보니 간만에 제법 진수성찬이다. 실컷 먹고는 잽싸게 치웠다.&lt;/p&gt;
&lt;p&gt;입가심용 아이스크림이 다 떨어져 버린 것을 한탄하다가 오래된 꿈틀이와 짱셔요를 발견했다. 잽싸게 먹었다. 꿈틀이는 괜찮았는데 짱셔요는 하나도 안셨다. 오래되서 그런지 애가 상태가 좀 메롱이 된 듯한 느낌. ㅎㅎ~&lt;/p&gt;
&lt;p&gt;— 2010. 11. 14.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 가르쳐라. 그리하면 배울 것이다.]]></title><description><![CDATA[Q: 만약 회사에서 신입이 들어 왔는데, 저에게 그 신입의 기술을 올려 주라는…(한마디로 하루…]]></description><link>https://jiniya.net/wp/archives/4791</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4791</guid><pubDate>Thu, 18 Jun 2015 23:59:48 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt;&lt;br&gt;
만약 회사에서 신입이 들어 왔는데, 저에게 그 신입의 기술을 올려 주라는…(한마디로 하루 1 시간씩 과외 비스무리) 임무를 준다면…그걸 해야 할까요?…말아야 할까요?… 제가 꼭 그일을 해야 하는지요…회사에서 그 일을 할줄 아는 사람이 저 밖에 없는데… 회사 입장에서는 후일을 대비한 것 같고요…저는 제 나름대로 회사에서 제 장점이 있으니 유리한 입장인데…&lt;br&gt;
&lt;br&gt;
&lt;strong&gt;A:&lt;/strong&gt;&lt;br&gt;
저도 처음 회사를 다닐 때 사수분이 그런 마인드를 가지고 계셔서 아주 고생했던 기억이 나는군요. 저한테 가르쳐주고 나면 자신은 뭐 먹고 사냐고 그런 말씀을 하셨더랬죠. 그래서 늘 컴파일러나 소스를 줄 때 계속 파일 하나를 빼고 주던지 하는 식으로 해서 아주 골탕을 먹었습니다. ㅎㅎㅎ^^ 물론 지금은 사이 좋게 지냅니다~&lt;br&gt;
&lt;br&gt;
사람의 머리에서 머리로 전달될 수 있는 기술 몇 가지를 가르쳐 줬다고 자신의 밥줄을 걱정해야 할 정도라면 많이 반성해야 한다고 봅니다. 저도 프로그래머로 몇 해 동안 일했지만, 제가 가진 경쟁력은 제가 알고 있는 win32 api개수도, 제가 만들어 논 라이브러리 코드도, 제가 알고 있는 윈도우 시스템 지식도 아니라고 봅니다. 제가 신입 사원에 비해 가지는 가장 큰 경쟁력은 경험이겠죠. 몇 해 동안 일한 경험.&lt;br&gt;
&lt;br&gt;
만약 회사에서 그러한 경험과 노하우를 전부 무시하고 기술이 전수되었다고 퇴사를 권고한다면 그런 회사는 오래 다닐 필요가 없다고 봅니다.&lt;br&gt;
&lt;br&gt;
물론 저도 오래 일한 것은 아니지만 일하면서 느낀 점은 기술이라는 것은 정말 별것 아니라는 점이었습니다. 기술보다는 사람을 얻는 것이 훨씬 더 값어치 있는 일이라 생각되네요. 지금 밑에 들어온 신입 사원에게 성심 성의껏 가르쳐 주세요. 혹시 나중에 그 분한테 도움을 청할 일이 생길지도 모르니까요~&lt;br&gt;
&lt;br&gt;
끝으로 덧붙여 기술이라는 것은 자신의 머릿속에 묶어둬 봤자 아무 쓸모 없습니다. 그것을 활용하고 알리고 할 때 효용이 생기는 것이죠~ 만약 모두가 자신의 머릿속에 가둬 놓았다면, 아마 지금도 동굴 속에서 추위에 떨면서 살고 있었겠죠~~~&lt;br&gt;
&lt;br&gt;
&lt;a href=&quot;http://groups.google.com/group/microsoft.public.kr.vc.qna/browse_thread/thread/e58e4cf0d44a9c96&quot;&gt;http://groups.google.com/group/microsoft.public.kr.vc.qna/browse_thread/thread/e58e4cf0d44a9c96&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;http://stephenslighthouse.com/wp-content/uploads/2010/02/learning_pyramid.jpg&quot; alt=&quot;&quot; title=&quot;learning_pyramid&quot;&gt;&lt;/p&gt;
&lt;center&gt;**가르치는 행위는 가장 좋은 학습 방법이다.**&lt;/center&gt;</content:encoded></item><item><title><![CDATA[[정보] 놀라운 비디오 세상]]></title><description><![CDATA[93년인가 94년엔가? 리눅스를 처음 접했을 때 가장 답답한 마음은 제대로 된 튜토리얼이 없다는 것이었습니다. 책대로 그대로 했는데도 되는 것은 정말 하나도 없었습니다. 처음 X-window…]]></description><link>https://jiniya.net/wp/archives/4242</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4242</guid><pubDate>Wed, 17 Jun 2015 23:59:47 GMT</pubDate><content:encoded>&lt;p&gt;93년인가 94년엔가? 리눅스를 처음 접했을 때 가장 답답한 마음은 제대로 된 튜토리얼이 없다는 것이었습니다. 책대로 그대로 했는데도 되는 것은 정말 하나도 없었습니다. 처음 X-window 화면을 봤을 때는 감동이었죠. 이후에도 저는 리눅스 환경에서 여러 가지 일을 다양한 문서를 따라하면서 해 봤지만 늘 뭔가 잘 안되었죠. 아마 제가 글을 제대로 이해하는 능력이 부족하거나 저의 시스템이 특이해서 그랬다고 생각하지만, 아마도 다른 사람이 제대로 하는 것을 한 번이라도 TV에서 봤다면 저의 시행착오는 극적으로 줄지 않았을까란 생각을 해봅니다. 물론 요즘이라고 이런 일들이 벌어지지 않는 것은 아닙니다. 아주 문서화가 잘되어 있고, 그대로 따라해도 안되는 경우는 많습니다. 이런 것들이 텍스트의 한계라고 봅니다. 아무리 친절한 캡쳐 화면도 전부를 다 보여줄수는 없죠. 그런 점에서 비디오는 정말 큰 장점을 가지고 있습니다. 또한 인프라의 발전으로 그런 것들이 점점 다가오고 있습니다. 더욱 놀라운 사실은 프로그래밍 분야에도 성큼 다가왔다는 겁니다. 물론 주옥같은 웹캐스트야 오래전부터 있었지만 이렇게 HOWTO 같은 시리즈의 비디오가 잘 정리된 페이지는 첨 본 거 같네요. 역시 MS ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://msdn2.microsoft.com/en-us/visualc/bb496952.aspx&quot;&gt;http://msdn2.microsoft.com/en-us/visualc/bb496952.aspx&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] ARP 테이블 열거하기]]></title><description><![CDATA[프로그램 내에서 ARP 테이블을 뒤져야 할 때가 있다. ARP란 주소 해석 프로토콜로 IP의 실제 MAC 어드레스를 구하기 위해서 사용되는 프로토콜이다. 반대로 RARP라는 것도 있다. ARP…]]></description><link>https://jiniya.net/wp/archives/10188</link><guid isPermaLink="false">https://jiniya.net/wp/archives/10188</guid><pubDate>Wed, 17 Jun 2015 23:59:46 GMT</pubDate><content:encoded>&lt;p&gt;프로그램 내에서 ARP 테이블을 뒤져야 할 때가 있다. ARP란 주소 해석 프로토콜로 IP의 실제 MAC 어드레스를 구하기 위해서 사용되는 프로토콜이다. 반대로 RARP라는 것도 있다. ARP는 네트워크의 아주 하부에 존재하는 레이어로 굉장히 중요한 역할을 한다. 실제로 네트워크 레이어를 구축할때에도 아마도 제일 먼저 만들어야 하는 부분이다.&lt;/p&gt;
&lt;p&gt;매번 ARP를 요청하는 것은 시스템으로 봐서는 굉장히 멍청한 짓이다. 왜냐하면 IP에 해당하는 MAC 어드레스가 매번 바뀌지는 않기 때문이다. 그래서 시스템은 ARP 요청 정보를 일정 시간동안 캐시에 저장해 놓고 캐시에 저장된 요청이 오면 캐시에 있는 정보를 그대로 보내준다. ARP 캐시를 부려면 커맨드 창에서 arp -a를 입력하면 된다. 이 목록을 구하는 함수를 만들어 보도록 하자~&lt;/p&gt;
&lt;p&gt;아래는 ARP 테이블을 열거하는 함수를 보여준다. 첫번째 인자로 열거 콜백 함수를 두번째 인자로 콜백함수에 포함될 사용자 정의 파라미터를 넣어주면 된다. 그러면 함수는 ARP 테이블의 한 행마다 fCallback함수를 호출해 준다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ARP 테이블 열거 함수&lt;/strong&gt;
&lt;a href=&quot;/codewiz/assets/files/2015/enumarptbl.cpp&quot;&gt;소스 코드 다운로드&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BOOL&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;CALLBACK &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;CBENUMARPTBL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MIB_IPNETROW &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PVOID &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

NPDUTILAPI
BOOL WINAPI &lt;span class=&quot;token function&quot;&gt;EnumArpTbl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;CBENUMARPTBL fCallBack&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PVOID pUserData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    DWORD       cbBuffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;        &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pBuffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    DWORD       result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    MIB_IPNETTABLE  &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pTable&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    DWORD       i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    MIB_IPNETROW    &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;row&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetIpNetTable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MIB_IPNETTABLE &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; pBuffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;cbBuffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; ERROR_INSUFFICIENT_BUFFER&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; pBuffer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        pBuffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;cbBuffer&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        result  &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetIpNetTable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MIB_IPNETTABLE &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;pBuffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;cbBuffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;result &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; NO_ERROR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;       
    
    pTable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MIB_IPNETTABLE &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;pBuffer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; pTable&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;dwNumEntries&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        row &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pTable&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;table&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fCallBack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;row&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pUserData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; pBuffer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;CBENUMARPTBL 함수의 첫번째 인자로 넘어오는 MIB_IPNETROW는 다음과 같이 정의된 구조체다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_MIB_IPNETROW&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;// 어댑터의 인덱스 번호 &lt;/span&gt;
  DWORD dwIndex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

  &lt;span class=&quot;token comment&quot;&gt;// 물리 주소의 길이. 통상적으로 6이 된다. 왜냐하면 mac 주소는 6바이트이기 때문이다. &lt;/span&gt;
  DWORD dwPhysAddrLen&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 물리 주소. 보통은 mac 주소가 된다. &lt;/span&gt;
  BYTE bPhysAddr&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;MAXLEN_PHYSADDR&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// ip 주소 &lt;/span&gt;
  DWORD dwAddr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;// 다음과 같은 값을 가질 수 있다. (4 Static,3 Dynamic,2 Invalid,1 Other) &lt;/span&gt;
  DWORD dwType&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; MIB_IPNETROW&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PMIB_IPNETROW&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[cpp] 윈도우8 관리자 권한으로 프로그램 실행 시키기]]></title><description><![CDATA[윈도우8에 많은 것들이 변경됐습니다. 그 중에 하나가 UAC 정책입니다. 예전에 UAC를 끄면 UAC가 없는 것과 동일했는데 윈도우…]]></description><link>https://jiniya.net/wp/archives/9876</link><guid isPermaLink="false">https://jiniya.net/wp/archives/9876</guid><pubDate>Wed, 17 Jun 2015 23:59:45 GMT</pubDate><content:encoded>&lt;p&gt;윈도우8에 많은 것들이 변경됐습니다. 그 중에 하나가 UAC 정책입니다. 예전에 UAC를 끄면 UAC가 없는 것과 동일했는데 윈도우8 그게 변경됐습니다. 아예 없는 것이 아니라 관리자 권한 요구가 매니페스트에 포함된 프로그램에게는 사라지는 것과 동일한데 그렇지 않은 프로그램의 경우 UAC를 꺼도 그 프로그램은 일반 권한으로 실행됩니다. 프로그래밍이나 테스트 작업을 하는 사람에게는 조금 불편합니다. 완전히 꺼버리는 방법도 있는데 보안상 그닥 권해 드리고 싶지 않습니다. 관리자 권한으로 자주 사용하는 프로그램의 등록 정보에서 아래 항목을 체크하면 그 프로그램만 관리자 권한으로 실행할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 377px; margin-bottom: 16px;&apos; data-url=&apos;./윈도우8_관리자_권한으로_프로그램_실행_시키기.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ef4845278a64bf11b8b75dadc53bf763/fdd90/%EC%9C%88%EB%8F%84%EC%9A%B08_%EA%B4%80%EB%A6%AC%EC%9E%90_%EA%B6%8C%ED%95%9C%EC%9C%BC%EB%A1%9C_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8_%EC%8B%A4%ED%96%89_%EC%8B%9C%ED%82%A4%EA%B8%B0.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 136.8421052631579%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAbCAIAAADzvTiPAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAEFElEQVR42o1UW2/jVBDu30ThrWKF+ANI/A3YCxLSsg88ELrs9gbdLmm3zeZiO4nj3OM4TZz4fju+Hju2EzNxYNtCkBiNP00m/s4Zf2fmHHz5svPk1eiwGH/xMz78CRVejAsv2MKz8Wff9QvP2c+/5wALT0eFZ8PCsxG8cFiMvvpROnny9fNvfjj4tmSct7RfSOM1Zb6mjKOaXKwIRzWpWFkWq2KxKhzVlV/r0htSeUtpxy10TDvHLfuqpT59Jx+cNdX5qM20mroqa9JyMhrIkiDwsw7dmE+5fofud9ph4CWrYIX9JPLj0A88J1vZF2394LxtRYEtiLJumJpmWBYClyRF1w1BEFXNgKQsyUtBUjVtsRSXgmjZXpalJ5R6cNG1PUvv9cfdXp9ud7jJlOl0CYIcjthWi2kz3cFgiBAyTctzXYRs0zQDHGZZdtoAcgf5QVBvj+ke2+wMKyRD0AOS7hGtbr3V6455D6+yx7bebPG0uSVbPg5bQ54ZzhpdttYa0IM7gpkQzJjqcsOZ6kYbvFpHyXo/GUfxnZnI7oZH6RxteCsdyPFIiSdaMlZWrIw7i2CuR3vIvzFWliXcdNrr9Vl2suDnkqxu31hv1rnl8SNLUkhucnIbyKkkydyEm895jpuMR6yiqIsF3+8PuOlssVjcTe+i6B87rz+REzgbCR5ZFkURtLVtG+DvYItgaZruJacIOYZhmKah63oQBPhf5nkekDe5pVv2PXkN5MDH8AesucPd520e2L5v3goWc9wU1PL9IMotDMOdVJt99mDnXG0LIcPQNehGAzrU0jUdlkiSZFfFviZ5INhyKfL8nOd5QRBsx/F833EckOp/kS0EFDAXHqhiG7mu57mQXa1W/02GsteRIikwPpZhWqZpQ92GAcNlW6amKA6ysR/EcM6gQu7rbasm92oHq8QJAtvHluch3zdztKF4jF2MVWQDPt55p3YHZURVfXtqvy+hi0v8oZwRVFojwNd1MnciqVTjciW6KW/99mPw/iqj6qdt4+C8oWWV2zHNtAly0KTnY9YQJVOSALXlUl0sdUFcB3iN8QaHWw+jBC6Dj7fbeT6nVFjGdTwT+tF2VF0XZQVGX9MNWVUlRZFVDcp86EmcZPXKaUOBsu2sVlHfHNsXl0Hpyv/jaod5cB1e3yTlyurD7b3flPFlKSOrZ20zVzsJCaZZJ+sUSZFko1arNZs03aJJgoSj/zQPe+b5jDazGHs+dGSEcQj3U444ilbbAH6HUZwkcZxAAA55SGRpdALf/K5jZhHyXRS4CHso9G0X6aYms8OeKgnIUHVZGHTbwx5jabILTQzZxXyDzd/h6n1VMXs8ojjUnP7lJGtUB8o1zVf6cn2kQVxqzkqNWW2oUhMTsNyTenPrZVn7E6xrrSB2CigpAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;   8                      md 0&apos; title=&apos;&apos; src=&apos;/static/ef4845278a64bf11b8b75dadc53bf763/fdd90/%EC%9C%88%EB%8F%84%EC%9A%B08_%EA%B4%80%EB%A6%AC%EC%9E%90_%EA%B6%8C%ED%95%9C%EC%9C%BC%EB%A1%9C_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8_%EC%8B%A4%ED%96%89_%EC%8B%9C%ED%82%A4%EA%B8%B0.md_0.png&apos; srcset=&apos;/static/ef4845278a64bf11b8b75dadc53bf763/08678/%EC%9C%88%EB%8F%84%EC%9A%B08_%EA%B4%80%EB%A6%AC%EC%9E%90_%EA%B6%8C%ED%95%9C%EC%9C%BC%EB%A1%9C_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8_%EC%8B%A4%ED%96%89_%EC%8B%9C%ED%82%A4%EA%B8%B0.md_0.png 190w,
/static/ef4845278a64bf11b8b75dadc53bf763/fdd90/%EC%9C%88%EB%8F%84%EC%9A%B08_%EA%B4%80%EB%A6%AC%EC%9E%90_%EA%B6%8C%ED%95%9C%EC%9C%BC%EB%A1%9C_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8_%EC%8B%A4%ED%96%89_%EC%8B%9C%ED%82%A4%EA%B8%B0.md_0.png 377w&apos; sizes=&apos;(max-width: 377px) 100vw, 377px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;종종 반대로 실행된 프로그램 입장에서 현재 실행된 프로세스가 관리자 권한으로 실행됐는지 아니면 일반 권한으로 실행됐는지를 체크할 필요가 있는 경우가 있는데요. 이때는 아래 코드에 나와 있는 것과 같이 프로세스 토큰을 사용해서 관리자 권한인지를 조회해 보면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;관리자 권한 체크 코드&lt;/strong&gt;
&lt;a href=&quot;/codewiz/assets/files/2015/is_admin.cpp&quot;&gt;소스 코드 다운로드&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;shared_ptr&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; vsptr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

BOOL
&lt;span class=&quot;token function&quot;&gt;IsProcessUserAdmin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE process&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; BOOL &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;is_admin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	HANDLE token&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;OpenProcessToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TOKEN_QUERY&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;token&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	vsptr &lt;span class=&quot;token function&quot;&gt;token_closer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;token&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;CloseHandle&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	ULONG gsize &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetTokenInformation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;token&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TokenGroups&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; gsize&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gsize&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; ERROR_INSUFFICIENT_BUFFER&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;vector&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;UCHAR&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; gbuffer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	gbuffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;gsize&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	PTOKEN_GROUPS ginfo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PTOKEN_GROUPS&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gbuffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetTokenInformation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;token&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TokenGroups&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ginfo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; gsize&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gsize&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	PSID admin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	SID_IDENTIFIER_AUTHORITY auth &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; SECURITY_NT_AUTHORITY&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AllocateAndInitializeSid&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;auth
									&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;
									&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SECURITY_BUILTIN_DOMAIN_RID
									&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DOMAIN_ALIAS_RID_ADMINS
									&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
									&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;admin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	vsptr &lt;span class=&quot;token function&quot;&gt;sid_closer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;admin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;FreeSid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; ginfo&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;GroupCount&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;EqualSid&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;admin&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ginfo&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;Groups&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Sid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;is_admin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;is_admin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	BOOL is_admin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;IsProcessUserAdmin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetCurrentProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;is_admin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%s\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; is_admin &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;admin&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;not admin&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[소고] 강력한 언어란? …]]></title><description><![CDATA[Rica…]]></description><link>https://jiniya.net/wp/archives/977</link><guid isPermaLink="false">https://jiniya.net/wp/archives/977</guid><pubDate>Wed, 17 Jun 2015 23:59:44 GMT</pubDate><content:encoded>&lt;p&gt;Rica님 블로그를 구경하다가 알게 된 페이지입니다. 학생들이 쓴 에세이를 모아둔 페이지인데 재미있는 글들이 많이 있네요. 처음에 읽은 글이 제법 재밌어서 금방 다 읽겠지, 라는 생각으로 덤볐는데 한번에 다 읽기가 생각보다 좀 빡쎄군요. ㅋㅋ~ 다음에도 읽을 요량으로 링크를 저장해 놓습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://ropas.snu.ac.kr/~ta/4190.310/essays/&quot;&gt;http://ropas.snu.ac.kr/~ta/4190.310/essays/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2009년 2번째 에세이 부분을 전부 읽었는데요. &amp;#x3C;해커와 화가&gt;의 저자 폴 그레이엄 아저씨가 쓴 글들을 바탕으로 에세이를 적어오는 것이 과제였다고 추측됩니다. 주로 좋은 프로그래밍 언어란 무엇인가에 대한 것들을 논하고 있죠. 폴 그레이엄 아저씨의 글들을 읽어 보신 분들은 아시겠지만 그레이엄 아저씨는 Lisp 애호가 입니다. 그가 창업한 Viaweb도 Lisp를 사용해서 성공할 수 있었다고 &amp;#x3C;해커와 화가&gt;에 나와 있죠.&lt;/p&gt;
&lt;p&gt;제가 2009년 2번째 에세이를 전부 읽고 느낀 점은 딱 두가지 였습니다. 1) 국내 최고 학부답게 학생들이 글을 잘 쓴다, 2) 원문에 대한 딴지를 거는 글은 거의 없다는 겁니다. 결론은 대부분 함수형 언어의 칭찬으로 끝이 납니다. 근데 읽고나니 뭔가 좀 쎄한 느낌이 드네요.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 인과관계]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/1055</link><guid isPermaLink="false">https://jiniya.net/wp/archives/1055</guid><pubDate>Wed, 17 Jun 2015 23:59:43 GMT</pubDate><content:encoded>&lt;p&gt;언젠가 워크샵 술자리에서 이사님께서 해주신 우스개 소리 중에 이런 이야기가 있었습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;한 과학자가 파리를 가지고 실험을 하고 있었습니다. 한 날은 파리의 청력을 실험하기 위해서 파리를 앉혀 두고는 옆에서 손뼉을 쳤다고 합니다. 그러자 파리가 그 소리에 놀래서 달아났습니다. 과학자는 이어서 파리의 날개를 떼고는 다시 파리 옆에서 손뼉을 쳐서 소리를 냈습니다. 그러자 이 번에는 파리가 날아서 도망을 가지 못하고 그 자리에 그대로 있었습니다. 이를 본 과학자는 그 날 노트에 이렇게 적었다고 합니다. “파리의 귀는 날개에 달려 있다.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이 이야기를 들은 사람들은 멍청한 과학자를 생각하지만 실상은 우리는 멍청하지 않다고 생각하지만 저런 실수를 곧잘합니다. 많은 사람들이 우울증에 걸린 사람들이 알콜 중독에 걸리기도 쉽다고 생각합니다. 하지만 연구 결과에 의하면 사람들이 우울증에 걸려서 알콜 중독에 걸리기 보다는 알콜 중독에 걸려서 우울증에 걸린다고 합니다. 또 우리는 기분이 좋아서 웃는다고 생각하지만, 반대로 웃으면 기분이 좋아지기도 한답니다.&lt;/p&gt;
&lt;p&gt;애매한 문제도 많이 있습니다. 생각의 속도가 빨라서 책을 빨리 읽는 건지, 아니면 책을 빨리 읽다 보면 생각의 속도가 빨라지는건지. 인식이 개선되면(중요한 일을 하고 있다고 판단되면) 처우가 개선되는 것인지(연봉이 올라가는 것인지) 아니면 처우가 개선되면 인식이 개선되는 것인지 같은 것들 말이죠. 찾아보면 더 있을 수도 있겠죠. 여튼 인과관계를 정확하게 판단하는 일은 생각처럼 쉬운 일은 아닌 것 같습니다. 많은 경우에 우리는 농담에 등장한 과학자처럼 행동하고 있는지도 모르겠습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[2011년 5월 7일…]]></title><description><![CDATA[#…]]></description><link>https://jiniya.net/wp/archives/4150</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4150</guid><pubDate>Wed, 17 Jun 2015 23:59:42 GMT</pubDate><content:encoded>&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;집에서 사용하는 마우스가 또 고장이 났다. 증상은 똑같다. 왼쪽 마우스 버튼. 그냥 클릭을 해도 더블 클릭으로 인식되는 경우가 종종 발생한다. 별로 불편할 것 같지 않은 이 고장은 사람을 좀 미치게 만든다. 결국 늘 그랬던 것처럼 지금은 오른쪽, 왼쪽 버튼을 바꿔서 쓰고 있다. 매번 이런 고장이 발생하는 걸 보니 내가 마우스 쓰는 패턴이 이상하다는 생각도 좀 든다. 예전에는 집에 굴러 다니는 것들이 MS 마우스였는데, 지금은 어디 하나 마땅하게 대체해서 사용할 마우스도 없다. A/S를 보내야 하나 심하게 고민하고 있다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;집에 사용하던 모니터가 고장나서 얼마전에 27인치 모니터를 새로 질렀다. 신세경이다. 24인치와 27인치의 차이란 ㅋㅋ~ 한 3년 사용한 것 같은데 무상 A/S가 안될것 같아서 그냥 바꿨다. 원래 사용하던 것도 만족스럽게 사용했는데 이번 것이 더 좋은 것 같다. 단지 강화 유리 처리가 돼서 집에서 사용하면 좀 반들거린다는 단점이 있지만.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;4월 이었나 회사 사람이 mp3 파일을 줬다. 그런데 그 중에 몇개가 소리통에서 플레이 되지 않는 문제가 있었다. 특히 이소라의 바람이 분다가 플레이가 제대로 되지 않는게 안타까웠다. 알송은 참 잘도 플레이를 하는데 말이다. 그래서 몇 일 전부터 이 문제를 고쳐야 겠다고 생각하고는 작년에 덮어둔 소스 코드를 꺼내서 보게 되었다. 그리고 고쳐서 릴리즈를 하였다.&lt;/p&gt;
&lt;p&gt;언젠가 회사 직원이 그런거 뭐하러 만드냐고 물어본 적이 있었다. 그 친구는 여행 다니고, 술 마시는 걸 좋아하는데 여행은 왜 가고, 술은 왜 마시냐는 질문을 해주고 싶었다. 세상 일이 모두 어떤 목적이 있어서 하는건 아닌데 말이다. 재미삼아 만들어 보는 거지 ㅋㅋㅋ~&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;난 제법 책 읽는 것도 좋아하고 글을 쓰는 것도 좋아하는데 요즘은 도통 글 쓰는 일을 하고 싶지가 않다. 왜 그런지를 곰곰히 생각해 봤는데 작년 말부터 올초까지 너무 재미없는 글쓰기를 회사에서 너무 많이 해버린 탓인것 같다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 윈도우 종료시키기]]></title><description><![CDATA[프로그램을 작성하다 보면 종종 윈도우 시스템을 종료 시켜야 하는 상황이 발생합니다. Windows 9x의 경우에는 단순히 ExitWindowsEx API를 호출함으로써 윈도우를 종료 할 수 있으나, NT 계열에서는 그게 되지 않습니다. 그 이유는 NT…]]></description><link>https://jiniya.net/wp/archives/4072</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4072</guid><pubDate>Wed, 17 Jun 2015 23:59:41 GMT</pubDate><content:encoded>&lt;p&gt;프로그램을 작성하다 보면 종종 윈도우 시스템을 종료 시켜야 하는 상황이 발생합니다. Windows 9x의 경우에는 단순히 ExitWindowsEx API를 호출함으로써 윈도우를 종료 할 수 있으나, NT 계열에서는 그게 되지 않습니다. 그 이유는 NT 계열에서 도입된 권한 체계 때문입니다. 시스템을 종료시키는 API를 사용하려면 Shutdown 권한을 가지고 있어야 합니다. 아래 코드는 NT 계열에서 Shutdown 권한 획득후 윈도우를 종료 시키는 방법을 보여주고 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ExitWindowsExHelper 함수&lt;/strong&gt;
&lt;a href=&quot;/codewiz/assets/files/2015/exitwindowsexhelper.cpp&quot;&gt;소스 코드 다운로드&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ExitWindowsExHelper&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
    HANDLE hToken&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
    TOKEN_PRIVILEGES tkp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

    &lt;span class=&quot;token comment&quot;&gt;// Get a token for this process. &lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;OpenProcessToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetCurrentProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                         &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;TOKEN_ADJUST_PRIVILEGES &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; TOKEN_QUERY&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;hToken&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 


    &lt;span class=&quot;token comment&quot;&gt;// Get the LUID for the shutdown privilege. &lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;LookupPrivilegeValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SE_SHUTDOWN_NAME&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;tkp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Privileges&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Luid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

    tkp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PrivilegeCount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// one privilege to set &lt;/span&gt;
    tkp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Privileges&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Attributes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; SE_PRIVILEGE_ENABLED&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

    &lt;span class=&quot;token comment&quot;&gt;// Get the shutdown privilege for this process. &lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;AdjustTokenPrivileges&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hToken&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;tkp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PTOKEN_PRIVILEGES&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

    &lt;span class=&quot;token comment&quot;&gt;// Cannot test the return value of AdjustTokenPrivileges. &lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; ERROR_SUCCESS&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

    &lt;span class=&quot;token function&quot;&gt;ExitWindowsEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EWX_POWEROFF&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[올빼미형 인간]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/4540</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4540</guid><pubDate>Wed, 17 Jun 2015 23:59:40 GMT</pubDate><content:encoded>&lt;p&gt;고백하건데 나는 올빼미형 인간이다. 난 이제껏 내가 그냥 태어날 때 부터 올빼미형 인간이었다고 생각했다. 그런데 내가 올빼미형 인간이 된 것은 다름 아닌 진화에 의한 것이 아닐까란 생각이 들었다. 내가 올빼미가 된 사연은 다름아닌 컴퓨터 때문이다. 난 14살 때 처음으로 내 컴퓨터를 가지게 됐다. 그때 내가 컴퓨터를 할 수 있는 시간은 학교를 마치고 집으로 돌아온 다음 밖에 없었다. 그렇게 학창 시절을 보내고는 대학을 들어갔다. 이제는 더 올빼미가 될 수 밖에 없다. 일단 낮 시간은 여자 친구도 만나야 하고 엄마가 청소도 하고 시끄럽다. 집중이 되지 않으니 일을 할 수가 없다. 자연스럽게 내가 컴퓨터를 할 수 있는 시간은 고스란히 새벽 시간 밖에는 없다. 여친느님도 엄마도 잠드는 바로 그 시간, 황금 시간. ㅋㅋ~ 자연스럽게 나는 새벽에 일을 할 수 밖에 없었다. 이렇게 10년이 넘는 시간을 일을 했다. 이제는 어쩔 수 없이 올빼미가 될 수 밖에 없는 것이다.&lt;/p&gt;
&lt;p&gt;회사를 와도 사정은 다르지 않다. 회사의 낮 시간은 사실 진득하게 코딩을 할 수 있는 시간이 아니다. 특히 보안 업체의 하루는 전쟁터와 같다. 여기저기 해킹툴이 나오고 업데이트 요청이 있고, 사용자 로그가 접수되고, 업데이트가 있고, … 한마디로 헬이다. 무한 인터럽트는 자연스런 현상이다. 그나마 우리 회사는 연구실이 분리되어 있어서 소란스럽지는 않은데 그래도 안에 사람이 많이 있다보니 자연스럽게 집중하기는 힘들다.&lt;/p&gt;
&lt;p&gt;각종 소음들. 한번은 기계식 키보드를 개발자가 샀길래 집에 가서 쓰라고 돌려보낸 적이 있다. 또각 또각 하는 소리에 당췌 코딩을 할 수 없었기 때문이다. 물론 나도 내가 쓸 때에는 기계식 키보드를 사용하는 걸 좋아한다. 그 손맛과 함께 그 소리마저 뭔가 경쾌하게 들리는 법이다. 요즘은 핸드폰을 두고 가는 개발자들이 있어서 전쟁 중이다. 자리에 두고 갔을 때 전화가 오면 다른 사람들이 피곤하니 좀 들고 다니라고 해도 당췌 들고 다니질 않는다. 물론 다 그런건 아니고 말 안듣는 한 명이 있다. 물론 난 상황이 좀 나은 편인데 회사를 시작했기 때문에 이러한 결정을 내가 컨트롤할 수 있기 때문이다. 즉, 내가 대장이다. 그렇게 모든 변수들을 통제해도 사실 낮 시간은 코딩을 진득하게 하거나 디버깅을 하기에는 소란스럽다. 시끄럽고, 인터럽트가 많이 걸리기 때문이다. 자연스럽게 회사에서도 나는 새벽에 일을 할 수 밖에 없다. 0시에서 7시. 내가 가장 많은 코드를 작성한 시간이고, 가장 많은 버그를 잡은 시간이다.&lt;/p&gt;
&lt;p&gt;한번은 이런 일이 있었다. 레거시 코드가 도저히 관리가 되지 않아서 전체를 새롭게 작성한 일이 있었다. 세명이 한 일주일 작업했는데 도저히 진도가 나가지 않았다. 코드가 크지는 않았다. 다해서 3만 라인이 조금 안되는 컴포넌트였다. 그렇게 진도가 나가지 않았다. 그렇게 지지부진 하다 일주일이 지나고 안되겠다 싶어서 작성하던 코드를 다 버리고 밤에 혼자서 작업을 새로 했다. 그러자 이틀만에 동작하는 결과물을 얻을 수 있었다. 물론 밤시간 이틀을 말한다. 그때 느꼈다. 아. 내가 이래서 올빼미가 됐구나.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] 황당 옵션 이야기…]]></title><description><![CDATA[XIGNCODE3에는 현재 대략 16…]]></description><link>https://jiniya.net/wp/archives/11194</link><guid isPermaLink="false">https://jiniya.net/wp/archives/11194</guid><pubDate>Wed, 17 Jun 2015 23:59:39 GMT</pubDate><content:encoded>&lt;p&gt;XIGNCODE3에는 현재 대략 160개의 옵션이 있다.&lt;/p&gt;
&lt;p&gt;초기에 황당했던 경우가 있었는데 한 업체에서 스플래시를 꺼달라는 요청에 스플래시는 끄는 옵션을 만들었는데 스플래시를 보여주는 옵션이 있었던 것이다. 이 옵션이 황당한 이유는 끄는 옵션을 오프로 켜는 옵션도 오프로 하는 경우에는 옵션이 충돌하는 일이 발생하기 때문이다. 물론 이 또한 릴리즈를 담당하는 직원의 질문으로 알게 되었다. 그 이후로 옵션은 긍정 성향의 옵션만 만들겠다고 다짐했는데 여전히 우후죽순이다.&lt;/p&gt;
&lt;p&gt;어제 내일부터 CBT를 시작하는 업체에서 새로운 기능이 필요하다면 이런 저런 옵션을 만들어 달라는 이야기를 했다. 그래서 해당 옵션을 만들어 주고는 코드 정리를 하는데 예전에 그것과 똑같은 옵션을 이미 만들어 놓은 것이 보이는 게 아닌가? 사실 이제 나도 어떤 옵션이 정확하게 어떤 범위에 영향을 미치는지 예측하기가 힘들때도 있다. 핡~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] GetProcAddress를 편리하게 사용하는 방법]]></title><description><![CDATA[윈도우의 경우 9x와 NT 계열의 함수 세트가 틀린 경우가 있다. 9x에만 존재하는 함수가 있는가 하면, NT에만 존재하는 함수도 있다. 이러한 경우 한 프로그램이 두가지 환경에서 모두 동작해야 하는 경우에 주로 LoadLibrary…]]></description><link>https://jiniya.net/wp/archives/11204</link><guid isPermaLink="false">https://jiniya.net/wp/archives/11204</guid><pubDate>Wed, 17 Jun 2015 23:59:38 GMT</pubDate><content:encoded>&lt;p&gt;윈도우의 경우 9x와 NT 계열의 함수 세트가 틀린 경우가 있다. 9x에만 존재하는 함수가 있는가 하면, NT에만 존재하는 함수도 있다. 이러한 경우 한 프로그램이 두가지 환경에서 모두 동작해야 하는 경우에 주로 LoadLibrary를 사용해서 해당 함수들을 동적으로 불서서 사용한다. 물론 그 외에도 동적으로 불러쓰는 경우는 매우 많다.&lt;/p&gt;
&lt;p&gt;이렇게 LoadLibrary를 통해서 함수를 불러 쓸 때 가장 불편한 점은 함수 포인터를 반환받는 과정이다. 함수 하나하나 마다 모두 GetProcAddress로 함수 포인터를 받아야 하기 때문이다. 이러한 과정을 좀 더 간소화 시킬 수 없을까? 여기에 대한 답이 &lt;a href=&quot;http://www.codeproject.com%EC%97%90&quot;&gt;www.codeproject.com에&lt;/a&gt; 나와있다. 바로 가변 인자를 사용한 방법이다. 아래 함수는 실제 원문에 있던 함수를 약간 수정한 버전이다. 출구를 하나로 통일하고, 함수 로드에 실패한 경우에는 항상 DLL을 언로드 하도록 변경했다. 실제 원문은 &lt;a href=&quot;http://www.codeproject.com/dll/dllease.asp&quot;&gt;http://www.codeproject.com/dll/dllease.asp&lt;/a&gt; 에서 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GetProcAddresses&lt;/strong&gt;
&lt;a href=&quot;/codewiz/assets/files/2015/getprocaddresses.cpp&quot;&gt;소스 코드 다운로드&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;BOOL &lt;span class=&quot;token function&quot;&gt;GetProcAddresses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; HINSTANCE &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;hLibrary&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCSTR lpszLibrary&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; INT nCount&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    BOOL bRet &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    va_list va&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;va_start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; va&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; nCount &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;hLibrary &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;LoadLibrary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; lpszLibrary &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
        &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        FARPROC &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; lpfProcFunction &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        LPSTR lpszFuncName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        INT nIdxCount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; nIdxCount &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; nCount &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            lpfProcFunction &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;va_arg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; va&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FARPROC&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            lpszFuncName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;va_arg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; va&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPSTR &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;lpfProcFunction &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 
                &lt;span class=&quot;token function&quot;&gt;GetProcAddress&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;hLibrary&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
                lpszFuncName &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                lpfProcFunction &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                bRet &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            nIdxCount&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        bRet &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;va_end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; va &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bRet &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; FALSE &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;hLibrary &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;FreeLibrary&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;hLibrary&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; bRet&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;사용하는 방법은 무척이나 간단하다. 첫번째 인자로 리턴받을 DLL인스턴스 핸들을, 두번째 인자로 DLL 파일명을, 세번째 인자로 로드할 함수 갯수를, 그 다음부터는 함수 포인터의 포인터와, 함수명을 교대로 적어주면 된다. 말로하니 매우 복잡한데, 실제 사용예를 보면 금방 알 수 있다. 아래는 kernel32.dll에서 CreateFileW와 CloseHandle 함수를 로드하는 방법을 보여준다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HINSTANCE hinst&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;GetProcAddresses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;hinst&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;kernel32.dll&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
                 &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;fnCreateFileW&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CreateFileW&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
                 &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;fnCloseHandle&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CloseHandle&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[기억1]]></title><description><![CDATA[이제는 흐릿해진 기억인데 아마도 초등학교 3-…]]></description><link>https://jiniya.net/wp/archives/8711</link><guid isPermaLink="false">https://jiniya.net/wp/archives/8711</guid><pubDate>Wed, 17 Jun 2015 23:59:37 GMT</pubDate><content:encoded>&lt;p&gt;이제는 흐릿해진 기억인데 아마도 초등학교 3-4학년 정도 였던 것 같다. 그 해 여름 난 우리 동네에 있는 갈비집 형들과 놀았던 기억이 있다. 신기한 사실은 난 그 형들을 그 전에도 알았고, 그 후에도 알았지만 그 해 여름 말고는 친하게 놀았던 기억이 거의 없다. 근데 무슨 이유였는지 그 해 여름에는 퍽이나 붙어 다니면서 자주 놀았다.&lt;/p&gt;
&lt;p&gt;갈비집 아저씨는 자식이 세 명 있었다. 아들, 아들, 딸이었는지 아들, 딸, 아들이었는지 잘 기억이 나질 않는데 아무튼 아들이 둘이었고 딸이 하나였다. 셋 다 나보다는 나이가 많았다. 그 당시 우리 동네에는 두만이라는 전설적인 깡패가 있었다. 내가 한글을 배우던 무렵부터 동네 녀석들한테 듣게 된 전설인데 사실 초등학교를 졸업할 때까지 그 전설의 깡패를 실제로 마주한 적은 없었다. 그런데 소문에는 그 전설의 깡패를 대적할 수 있는 유일한 사람이 갈비집 큰 형이라는 이야기가 있었다.&lt;/p&gt;
&lt;p&gt;갈비집은 제법 컸다. 큰 마당이 있었고 그 속에 건물이 대략 세 개 정도 있었다. 주인 아저씨는 장사가 잘되서 나중에는 호텔 뒷편 건물에 분점을 내기도 했었다. 그 해 여름을 나는 매일같이 그 형들과 갈비집 마당에서 의미없는 장난을 하고 놀았다. 우리가 가장 많이 한 장난은 개미를 잡아서 싸움을 붙이는 것이었다. 마당에는 큰 개미들이 정말 많았다. 우리는 그 중에 두 마리를 잡은 다음 더드미를 뜯어서 싸움을 붙였다. 왜 그런 장난을 했는지는 모르겠지만 우리는 그게 재밌다고 생각했다. 사실 난 그 때나 지금이나 왜 더드미를 뜯으면 개미들이 싸우는지 모른다. 그런데 형들이 그렇게 싸움을 붙였고, 그러면 실제로 개미들은 싸우는 것처럼 보였다.&lt;/p&gt;
&lt;p&gt;무던 덥던 날이었다. 약간은 꿉꿉하기도 했다. 난 어김없이 갈비집으로 갔고 형들과 의미없는 장난질을 치고 있었다. 그러다 그 큰 형이 오늘은 진짜 재미있는 걸 보여주겠다며 따라오라고 했다. 거미가 싸우는걸 구경시켜 준다고 했다. 우리는 그 마당의 구석진 곳으로 이동했고 거기엔 실제로 거미가 있었다. 거미집을 아름답게 쳐놓고 있었다. 형은 그 평화로운 거미집에 개미를 넣었다. 그리고 난 티비가 아닌 현실 세계에서 거미가 어떻게 먹이를 잡는지 구경할 수 있었다. 거미집에 떨어진 개미는 아무런 저항도 하질 못했다. 시종일관 열세였다. 내가 받았던 가장 큰 충격은 거미가 그 개미를 실을 풀어서 칭칭 감는 장면이었다. 배가 불러서 나중에 먹으려고 그러는지는 알 수 없었지만 진짜 와우에나 나오는 것처럼 거미는 흰 실을 풀어서 개미를 칭칭 감았다. 거의 다 감길 무렵 그 형은 안되겠다며 성냥에 불을 붙여서 거미집에 던졌다. 지금도 생생하게 기억날만큼 굉장히 쇼킹한 장면이었다. 그 사건을 끝으로 아마도 난 그 갈비집에 더는 놀러가질 않았던 것 같다.&lt;/p&gt;
&lt;p&gt;내가 그 형제의 소식을 마지막으로 들은 건 고등학생 때였다. 부모님께서 우연찮게 그 갈비집 이야기를 했는데, 얼마 전에 작은 아들이 오토바이를 타다가 교통 사고로 죽었다는 이야기였다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[예비군 퇴소 풍경~]]></title><description><![CDATA[월요일부터 수요일까지 예비군 동미참 훈련을 받고 있습니다. 처음엔 와…]]></description><link>https://jiniya.net/wp/archives/10041</link><guid isPermaLink="false">https://jiniya.net/wp/archives/10041</guid><pubDate>Wed, 17 Jun 2015 23:59:36 GMT</pubDate><content:encoded>&lt;p&gt;월요일부터 수요일까지 예비군 동미참 훈련을 받고 있습니다. 처음엔 와 3일씩이나 이걸 어케 받으라고 하는 기분으로 갔는데 첫 째날, 둘 째날 갔다 오니 생각보다 할만하네요. 예비군 훈련장 경치가 너무 좋아서 사실 좀 놀랬습니다. 맨날 사무실에 틀어박혀서 바깥 세상에 단풍이 드는지, 하늘이 저렇게 높은지 보지도 못하고 지냈는데 거기 가서 실컷 보고, 멍때리고 하니 그것도 나름 좋네요. 뭐니뭐니해도 최고는 도시락먹고 벤치에 드러누워 자는 오침인 것 같습니다. 양지바른 곳에 자리잡고 누워 자니 그것만한 신선 놀음이 없더군요. ㅋ 평소 일상에 치여 놓치고 있던 많은 것들에 대해서 생각해볼 수도 있는 좋은 기횐 거 같습니다.&lt;/p&gt;
&lt;p&gt;저는 3년찬데, 2년을 학교에서 받았습니다. 그래서 사실 동미참 훈련은 처음 받는 거나 다름 없죠. 훈련장에서 훈련 마치고 나올 때 부러운 사람이 많더군요. 신분증받고 걸어 나가면서는 집 가까운 사람들이 부럽습니다. 주차장 즈음을 지날 때에는 차를 가지고 온 사람들이 부럽더군요. 그리고 정문을 나서면 애인이 데리러 온 사람이 젤 부럽습니다. 예비군 훈련 마쳤다고 데리러 오는 사람들도 있더군요. 차 가지고 데리러 온 사람들은 그나마 이해가 되는데 어제는 날씨도 추훈데 아리따운 아가씨께서 초미니 스커트를 곱게 차려입으시고는 누군가를 기다리고 있더군요. 좀 황당했습니다. 사실은 부러운 ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;— 2007.10.30&lt;/p&gt;</content:encoded></item><item><title><![CDATA[김태희 얼굴 사수하기]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/2999</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2999</guid><pubDate>Wed, 17 Jun 2015 23:59:35 GMT</pubDate><content:encoded>&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./CAP201008161239.jpg&apos; data-alt=&apos;CAP201008161239&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 480px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/543f17ac203626be9438caf30b3f7f43/a3e66/CAP201008161239.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 166.8421052631579%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAhABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAMEAv/EABcBAQEBAQAAAAAAAAAAAAAAAAABAgP/2gAMAwEAAhADEAAAAY86MMUbxTvimem0XGawdg//xAAeEAACAQMFAAAAAAAAAAAAAAABAgADEiIEEBQxMv/aAAgBAQABBQJVVglkYLK1KxBiOMZqDmEDbVgxiJaI3tep/8QAFxEAAwEAAAAAAAAAAAAAAAAAARARIP/aAAgBAwEBPwFCTH//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AV//xAAhEAABAwMEAwAAAAAAAAAAAAABABEhAhASIjFBUQMgof/aAAgBAQAGPwLUfqL7d5IYolePTJ7sQeaVTkxFO1oYE8upMev/xAAgEAACAQMEAwAAAAAAAAAAAAABEQAhMUEQUXGBobHw/9oACAEBAAE/IeqiKxt4OQEM9RyoiN4zFQSqJgRjnSDehU8wYqpg4DSHlsJYIjYxqRdwAYxPrqe6ZPM//9oADAMBAAIAAwAAABC0Bo50L//EABgRAAIDAAAAAAAAAAAAAAAAABAxARFB/9oACAEDAQE/EKEmMYP/xAAXEQADAQAAAAAAAAAAAAAAAAAAAREg/9oACAECAQE/EKUadx//xAAgEAEAAgICAgMBAAAAAAAAAAABABEhMUGRUXGhscHh/9oACAEBAAE/EOcBayBiqv29Qtg4IBODl+w6biilG3+dyjQddFq4Htj1kngFFIorbnM1SQFLixxotIHYOdkKo13mFW2Vj5LLZrWB/IgkkGL4gA1mDKRWE1+z7TZ7fRD5E//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;CAP201008161239&apos; title=&apos;&apos; src=&apos;/static/543f17ac203626be9438caf30b3f7f43/a3e66/CAP201008161239.jpg&apos; srcset=&apos;/static/543f17ac203626be9438caf30b3f7f43/8ccab/CAP201008161239.jpg 190w,
/static/543f17ac203626be9438caf30b3f7f43/ea4c8/CAP201008161239.jpg 380w,
/static/543f17ac203626be9438caf30b3f7f43/a3e66/CAP201008161239.jpg 480w&apos; sizes=&apos;(max-width: 480px) 100vw, 480px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;CAP201008161239&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt; &lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./CAP201008161237.jpg&apos; data-alt=&apos;&amp;quot;CAP201008161237&amp;quot;&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 480px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/49c7db0b252f27e0ba379b92fc1c7649/a3e66/CAP201008161237.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 166.8421052631579%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAhABQDASIAAhEBAxEB/8QAGQABAAMBAQAAAAAAAAAAAAAAAAIDBQQB/8QAFwEBAQEBAAAAAAAAAAAAAAAAAAECA//aAAwDAQACEAMQAAAB8o28OW1vkzZwsz07Rcc1wTB//8QAHxAAAgIBBAMAAAAAAAAAAAAAAQIAAxIEEBETIjEy/9oACAEBAAEFAuo8Lwx6Wl74VZkVTUHzCBtrgxiJiI32vqf/xAAXEQEAAwAAAAAAAAAAAAAAAAARARAg/9oACAEDAQE/ASoDH//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BX//EACAQAAEEAQQDAAAAAAAAAAAAAAEAAhEhEDEyQWEDEiD/2gAIAQEABj8Cti2uaDp2ticel4hFzOCDy1N9oIbpioBPMqzXz//EACEQAAICAgAHAQAAAAAAAAAAAAABESExQRBRYXGBkbHw/9oACAEBAAE/IXFkcZvQqWguhQrsRuMDFeFH0XBOaVi9iyKzSROh9HITBEHJJ21mRJa0frwfY2+5/9oADAMBAAIAAwAAABDQFo50L//EABkRAAIDAQAAAAAAAAAAAAAAAAABEBExQf/aAAgBAwEBPxBWKG02OR//xAAXEQADAQAAAAAAAAAAAAAAAAAAAREg/9oACAECAQE/EKUadx//xAAgEAEAAgIBBQEBAAAAAAAAAAABABEhMUFRcZGhsWHB/9oACAEBAAE/EBisC9m+iFqWS1Fbgz0lYXAyt78y0WKp+uD2zlZyurKs75mHJqapIULixxotIHYKdkKo15zMW2Vj5LLZrWB/kQSSDF6QAazBlIrCa+59TZ3fCHsT/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;&amp;quot;CAP201008161237&amp;quot;&apos; title=&apos;&apos; src=&apos;/static/49c7db0b252f27e0ba379b92fc1c7649/a3e66/CAP201008161237.jpg&apos; srcset=&apos;/static/49c7db0b252f27e0ba379b92fc1c7649/8ccab/CAP201008161237.jpg 190w,
/static/49c7db0b252f27e0ba379b92fc1c7649/ea4c8/CAP201008161237.jpg 380w,
/static/49c7db0b252f27e0ba379b92fc1c7649/a3e66/CAP201008161237.jpg 480w&apos; sizes=&apos;(max-width: 480px) 100vw, 480px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;&quot;CAP201008161237&quot;&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;맛폰을 처음 샀을 때 이러고 놀았다. 지금은 그 어떤 설정도 변경하지 않지만 말이다. 그때는 의욕에 넘쳐서 루팅하고 패치하고 그랬던 것 같은데. 그때나 지금이나 여전히 느린건 마찬가지… 제발 내가 사용하는 모든 걸 제외하고 그 어떤 것도 백그라운드로 돌지 않았으면 좋겠다. 내가 산 하드웨언데 왜 그게 기본적으로 안될까낭? 잡스가 관리자 권한에 대한 설정을 애시당초 제대로 설계하지 않았다에 진짜 백만표 던지고 싶다. 내가 산 하드웨어 내가 관리자가 아니면 누가 관리자란 말인가? 팀쿡인가? 아님 이재용인가? ㅠㅜ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[py] 파이썬 문자열 0 채우기…]]></title><description><![CDATA[시작 회사 웹 시스템 소스 코드를 보다가 다른 사람이 다음과 같이 코드를 작성해 놓은 것을 보았다. 뭔가 께림칙한 이 느낌. 일단 삭제. 내 생각 다음과 같이 고쳤다. zfill 그런데 이미 있었다.]]></description><link>https://jiniya.net/wp/archives/4190</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4190</guid><pubDate>Wed, 17 Jun 2015 23:59:34 GMT</pubDate><content:encoded>&lt;h3&gt;시작&lt;/h3&gt;
&lt;p&gt;회사 웹 시스템 소스 코드를 보다가 다른 사람이 다음과 같이 코드를 작성해 놓은 것을 보았다.&lt;br&gt;
뭔가 께림칙한 이 느낌. 일단 삭제.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;py&quot;&gt;&lt;pre class=&quot;language-py&quot;&gt;&lt;code class=&quot;language-py&quot;&gt;s &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;1234&apos;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    s &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;0&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; s&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;내 생각&lt;/h3&gt;
&lt;p&gt;다음과 같이 고쳤다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;py&quot;&gt;&lt;pre class=&quot;language-py&quot;&gt;&lt;code class=&quot;language-py&quot;&gt;s &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;%07d&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;zfill&lt;/h3&gt;
&lt;p&gt;그런데 이미 있었다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;py&quot;&gt;&lt;pre class=&quot;language-py&quot;&gt;&lt;code class=&quot;language-py&quot;&gt;s &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zfill&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[블랙 기업]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/13950</link><guid isPermaLink="false">https://jiniya.net/wp/archives/13950</guid><pubDate>Wed, 17 Jun 2015 23:59:33 GMT</pubDate><content:encoded>&lt;p&gt;얼마 전 들은 직원들의 불만 사항 중에 하나가 “고객 복지도 중요하지만 노동자 복지도 중요하다고 생각한다”는 것이었다. 그러면서 떠오른 동영상 하나. 그리곤 드는 생각. 열심히 한다고 했지만 잘하진 않았던 것 같다. 우린 아니겠지, 라고 생각하지만 그 어떤 기업도 이 잣대로부터 자유로울 수도 없다는 생각도 들었다. 퐁티의 말처럼 신체를 가지고 있는 한 폭력은 숙명인 것처럼 기업을 하는 한 착취도 숙명이 아닌가라는 생각이 들었다. 구조가 그렇고, 시스템이 그렇다. 그냥 뭔가 이상한것 같다는 생각이 계속 든다.&lt;/p&gt;
&lt;div class=&quot;video-container&quot;&gt;
    &lt;video controls&gt;
        &lt;source src=&quot;http://ebsvod.ebs.co.kr/ebsvod/cul/2014/bp0papb0000000009/1m/20140701_130500_m10.mp4&quot; type=&quot;video/mp4&quot;&gt;
        Your browser does not support the video tag.
    &lt;/video&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;우리는 순진무구함과 폭력을 선택하는 것이 아니다.&lt;/p&gt;
&lt;p&gt;폭력의 종류를 선택하는 것이다.&lt;/p&gt;
&lt;p&gt;우리가 신체를 가지고 있는 한 폭력은 숙명이다.&lt;/p&gt;
&lt;p&gt;– 휴머니즘과 폭력, 메를리 퐁티&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;한창 와우를 할 때 였다. 그당시 너무 심취해서는 거의 와우에 빠져 살다시피 했었다. 그러던 어느날 어려운 던전 보스를 잡고 우리는 뭉쳤다. 모임에 나가 보니 대다수가 대학생이었고, 내가 두 번째로 나이가 많았다. 새파란 대학생들이 그런다. 형 그래도 우리는 게임 폐인은 아니잖아요. 그 당시 나는 밥 먹을 시간도 없어서 짜장면을 먹으며 게임을 했었고, 그 친구들은 나보다 더 많은 시간을 접속해 있는 아이들었다. 그만큼 우리는 자신과 관련된 것들에 대해서는 정당한 평가를 하지 못하는 것 같다. 그 대학생 공대장을 비웃을 일이 아니었다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[오해]]></title><description><![CDATA[199…]]></description><link>https://jiniya.net/wp/archives/12771</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12771</guid><pubDate>Wed, 17 Jun 2015 23:59:32 GMT</pubDate><content:encoded>&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./오해.md_0.jpg&apos; data-alt=&apos;출처: 위키피디아&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 360px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/62eb3949e93d8730600326fc0bcaa105/543cd/%EC%98%A4%ED%95%B4.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 63.68421052631579%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIEAf/EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAFconmlGE//xAAaEAADAAMBAAAAAAAAAAAAAAAAAQIDEyEE/9oACAEBAAEFAtUorzwaZE+Vj66P/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGxAAAgEFAAAAAAAAAAAAAAAAAAEQAhExQWH/2gAIAQEABj8CXTJuLupx/8QAGRABAQEAAwAAAAAAAAAAAAAAAQARIUGB/9oACAEBAAE/IdGRRYyOxBHCppukfZBv/9oADAMBAAIAAwAAABDYz//EABURAQEAAAAAAAAAAAAAAAAAAAAh/9oACAEDAQE/EEf/xAAVEQEBAAAAAAAAAAAAAAAAAAAAIf/aAAgBAgEBPxCq/8QAGhABAAMBAQEAAAAAAAAAAAAAAQARMSFBgf/aAAgBAQABPxACqChQCtezmbNHPkrBR6RgRSAzd2You6jEer25/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;출처: 위키피디아&apos; title=&apos;&apos; src=&apos;/static/62eb3949e93d8730600326fc0bcaa105/543cd/%EC%98%A4%ED%95%B4.md_0.jpg&apos; srcset=&apos;/static/62eb3949e93d8730600326fc0bcaa105/8ccab/%EC%98%A4%ED%95%B4.md_0.jpg 190w,
/static/62eb3949e93d8730600326fc0bcaa105/543cd/%EC%98%A4%ED%95%B4.md_0.jpg 360w&apos; sizes=&apos;(max-width: 360px) 100vw, 360px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;출처: 위키피디아&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;1993년 뉴욕 타임즈에 한 장의 사진이 게재됐다. 수단의 한 아이가 죽어가고 있고, 그 옆에는 독수리가 그 아이가 죽기만을 기다리고 있는 사진. 독수리는 죽은 고기만 먹기 때문에 아이가 죽기를 기다리고 있었던 것이다. 이 사진이 게재된 뉴욕 타임즈에는 항의 전화가 빗발쳤다. 도대체 이 사진을 찍은 사진 작가는 뭐하는 놈이냐? 저 상황이 사진이나 찍고 있을 때냐? 아이를 구하는게 먼저 아니냐? 누구나 사진을 보고 느낄 법한 항의들. 그만큼 사진은 많은 이들에게 충격적이었다. 이듬해 사진을 찍은 사진 작가 케빈 카터는 그 공로를 인정받아 퓰리처상을 수상했고, 그 후 얼마뒤 자살했다. 물론 사람들의 비난 때문인지 아닌지는 모르겠지만 말이다…&lt;/p&gt;
&lt;p&gt;진실은 이렇다. 케빈은 수단 내전의 참상을 알리기 위한 사진을 촬영하기 위해서 수단에 있었다. 한날 그는 보호소를 떠난 좀 먼곳의 실제 상황을 알기 위해 떠나서는 위 장면을 목격했다. 잽싸게 사진을 찍고는 독수리를 쫓아냈다. 하지만 아이는 구하지 못했다. 전염병이 많아서 구호 활동을 하러 온 사람들과 현지인의 직접적인 신체 접촉은 차단되어 있었기 때문이다. 뉴욕 타임즈는 그가 찍은 사진을 잘 알아봤고 수단 내전의 참상을 알리기 위해서 신문에 게재했다. 사람들은 뉴욕 타임즈의 의도대로 엄청난 감정의 폭풍을 경험하고 내전의 참상을 알게 됨과 동시에 사진에 대한 온갖 비난들을 쏟아냈다. 그런 상황을 지켜본 퓰리처 재단은 퓰리처 상을 수여했다. 그리고 얼마뒤 사진 작가 케빈은 자살했다.&lt;/p&gt;
&lt;p&gt;그 사진을 찍은 작가, 게재한 뉴욕 타임즈, 분노한 사람들, 상을 수여한 퓰리처 재단…&lt;/p&gt;
&lt;p&gt;사실 누구도 잘못하지 않았다. 하지만 사진 작가는 자살을 했다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;오해 – 법정&lt;/p&gt;
&lt;p&gt;‘나는 당신을 죽도록 사랑합니다’라는 말의 정체는&lt;/p&gt;
&lt;p&gt;‘나는 당신을 죽도록 오해합니다’일지도 모른다.&lt;/p&gt;
&lt;p&gt;누가 나를 추켜세운다고 해서&lt;/p&gt;
&lt;p&gt;우쭐댈 것도 없고,&lt;/p&gt;
&lt;p&gt;헐뜯는다고 해서 화를 낼 일도 못 된다.&lt;/p&gt;
&lt;p&gt;그건 모두가 한쪽만을 보고 성급하게 판단한&lt;/p&gt;
&lt;p&gt;오해이기 때문이다.&lt;/p&gt;
&lt;p&gt;오해란 이해 이전의 상태가 아닌가.&lt;/p&gt;
&lt;p&gt;문제는 내가 지금 어떻게 살고 있는가에 달린 것이다.&lt;/p&gt;
&lt;p&gt;실상은 말 밖에 있는 것이고&lt;/p&gt;
&lt;p&gt;진리는 누가 뭐라 하든 흔들리지 않는다.&lt;/p&gt;
&lt;p&gt;온전한 이해는 그 어떤 관념에서가 아니라&lt;/p&gt;
&lt;p&gt;지혜의 눈을 통해서만 가능하다.&lt;/p&gt;
&lt;p&gt;그 이전에는 모두가 오해일 뿐이다.&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[의사와 환자]]></title><description><![CDATA[Breaking AV Software…]]></description><link>https://jiniya.net/wp/archives/12965</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12965</guid><pubDate>Wed, 17 Jun 2015 23:59:31 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 520px; margin-bottom: 16px;&apos; data-url=&apos;./dp.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5642ad9b69de58a3af34cba1232491db/407f2/dp.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 74.21052631578947%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAA7DAAAOwwHHb6hkAAADdUlEQVR42mMImHQ/ad6jhDmP4uc8Spj7KG72QyAjaubD2DmPUuY/jgYyZj8CkklzH4MEZz1MW/A4bjZIgf+k+wwWdWfCJlyKmHg5buqV+KlXUmZeTZ5xNaT/UtSkSwnTLidOA4pfjpxwMXnGlchJIMHUmVeTpl8L7rtkUn2KoW39/aY198DoQf3q+w2r7zeueQBkN6191LLhafumZ83rnrSsf9K49lHzukdNax83rH4IVNy89j5QI8OBqx8OXPuw/+qnPScuHDt76vTFCxu27VizadvOA7sXLp0/ceqkLVvXrtuw8vCJg6fPHjl9csexsxcOXP984Op7oEaGQ1ffH7r67uDVjweO7r96ce+pY1sOH1i7Z/faY0fW5mf4Whkq5Ce51BSF7N859dy+6ae2tZ44uuXg9a9ALUCNDOfvfTh/7/35+5+PnTowZ1Z3TEx4RnpcbXXR6tWz+jrzI4Pso0PsCtP8J5X6bZ6QcGJr55mTO84/+Hr+7nugRoZbTz7dfPzh9rPvR45sjIu0FxDgERHk5uRg8vOxWDK3sroyMczL0tdc3dNMI8pUZEmN6+ljm28/+3Hr8QegRob7zz/fffrx2bvfk6dO8fJyVlSQFhcTlpIU1VSX93E393Y3tzIz0dXSsjAzsVEXjbUU7Omoe/7x/92nH4AaQZrvPP306u2XpAknJYJblBTEZWUl1FSktLUULUw0vF0Mw/3sbEzN9ZXkgrQk/HWFi8qK33z5f+cJTPPdZ59fvfqUseOb4ZL75vZ2QgJcUrLSSooy8jKiyjJyphqGVupKMSYy/UGqZa6iMfGJb76iaX75MWHlba19P0yC42SkZNLjw6I9Df1M1KwUNe10NV315Tx0xOKtJcocuLuqsp6hOfv1+5/RhY2iy89rePjLScvZmmo1pTrURpvneGvF2ymkuyo5aApbKIlG67DObcl+iqL5yQegSwL8QxgsPVQN9WUk+Pn5Of3cDSJ8jPwsZKzV+V10+QylWDVE2LW4GMrSYl6B/PwepPneM2Bof3r0+sfaTTu7u/sXLVm2cvXqeQsWLly8ZNmKFdNmzp0+e96EqbP6J03r65/c0ty8dv3mx29+ASMIqJHhyeuvQPT41ZdXH3+///H/9ed/rz7+ff3pL5Dx5vPfd1/+A9H7b//fff3/9ss/IPnyw2+gYoguAG06EBzXQ2dwAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;dp&apos; title=&apos;&apos; src=&apos;/static/5642ad9b69de58a3af34cba1232491db/407f2/dp.png&apos; srcset=&apos;/static/5642ad9b69de58a3af34cba1232491db/08678/dp.png 190w,
/static/5642ad9b69de58a3af34cba1232491db/2edd7/dp.png 380w,
/static/5642ad9b69de58a3af34cba1232491db/407f2/dp.png 520w&apos; sizes=&apos;(max-width: 520px) 100vw, 520px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;Breaking AV Software&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;회사 생활을 하다보면 참 재미난 일이 많이 있는데 그 중에 젤 황당한 일이 의사와 환자가 뒤바뀌는 경우다. 보통은 의사가 환자를 진단하고, 환자는 의사의 처방전을 받아 들이기 마련이다. 그런데 주객이 전도되서는 의사가 환자에게 처방전을 물어보고, 환자가 의사에게 처방을 지시하는 경우들이 종종 있다. 황당하게도 말이다. 그리고 말미엔 꼭 탈이 난다. 내가 의사인지 환자인지, 내가 처방전을 쓰는 입장인지 받아야 하는 입장인지를 잘 판단하는 게 회사 생활의 기본인 것 같은데도 어려운것 같기도 하고 그렇다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[세상의 모든 문제가 그렇게 틀리면서 배우기 때문이란다]]></title><description><![CDATA[우진아, 1…]]></description><link>https://jiniya.net/wp/archives/4085</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4085</guid><pubDate>Wed, 17 Jun 2015 23:59:30 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/SUfTEc82yQs?si=-zh7Ne19OC8nqivY&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;우진아,&lt;/p&gt;
&lt;p&gt;12번 수학문제를 틀리는 것을 두려워하지 마라&lt;/p&gt;
&lt;p&gt;몇 번의 시험&lt;/p&gt;
&lt;p&gt;몇 번의 만남&lt;/p&gt;
&lt;p&gt;그리고 몇 번의 헤어짐&lt;/p&gt;
&lt;p&gt;몇 번이 될지 모르는 입사 면접&lt;/p&gt;
&lt;p&gt;너는 앞으로도 수많은 문제들을 만나고&lt;/p&gt;
&lt;p&gt;결정해야 될지도 모른단다&lt;/p&gt;
&lt;p&gt;수학은 틀려야 한다&lt;/p&gt;
&lt;p&gt;그것도 용감하게 틀려야 한다&lt;/p&gt;
&lt;p&gt;세상의 모든 문제가&lt;/p&gt;
&lt;p&gt;그렇게 틀리면서 배우기 때문이란다&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[숫타니파타]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/13519</link><guid isPermaLink="false">https://jiniya.net/wp/archives/13519</guid><pubDate>Wed, 17 Jun 2015 23:59:29 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;집착 없이 세상을 걸어가고&lt;/p&gt;
&lt;p&gt;아무것도 가진 것 없이&lt;/p&gt;
&lt;p&gt;자기를 다스릴 줄 아는 사람&lt;/p&gt;
&lt;p&gt;모든 속박을 끊고&lt;/p&gt;
&lt;p&gt;괴로움과 욕망이 없는 사람&lt;/p&gt;
&lt;p&gt;미움과 잡념과 번뇌를 벗어 던지고&lt;/p&gt;
&lt;p&gt;맑게 살아가는 사람&lt;/p&gt;
&lt;p&gt;거짓도 없고 자만심도 없고&lt;/p&gt;
&lt;p&gt;어떤 것을 내것이라 집착하지도 않는 사람&lt;/p&gt;
&lt;p&gt;이미 강을 건너 물살에 휩쓸리지 않는 사람&lt;/p&gt;
&lt;p&gt;이 세상이나 저 세상이나 어떤 세상에 있어서도&lt;/p&gt;
&lt;p&gt;삶과 죽음에 집착이 없는 사람&lt;/p&gt;
&lt;p&gt;모든 욕망을 버리고 집 없이 다니며&lt;/p&gt;
&lt;p&gt;다섯 가지 감각을 안정시켜&lt;/p&gt;
&lt;p&gt;달이 월식에서 벗어나듯이 붙들리지 않는 사람&lt;/p&gt;
&lt;p&gt;모든 의심을 넘어선 사람&lt;/p&gt;
&lt;p&gt;자기를 의지처로 하여 세상을 다니고&lt;/p&gt;
&lt;p&gt;모든 일로부터 벗어난 사람&lt;/p&gt;
&lt;p&gt;이것이 마지막 생이고 더 이상 태어남이 없는 사람&lt;/p&gt;
&lt;p&gt;고요한 마음을 즐기고&lt;/p&gt;
&lt;p&gt;생각이 깊고&lt;/p&gt;
&lt;p&gt;언제 어디서나 깨어 있는 사람&lt;/p&gt;
&lt;p&gt;– 숫타니파타 490-503&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[여유에 관한 발칙한 생각]]></title><description><![CDATA[#…]]></description><link>https://jiniya.net/wp/archives/13503</link><guid isPermaLink="false">https://jiniya.net/wp/archives/13503</guid><pubDate>Wed, 17 Jun 2015 23:59:28 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/ajCYQL8ouqw?si=NzhLl_5WjPWkowtG&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; **Let it be** &lt;/div&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;회사 직원과 둘이 점심을 먹으면서 이런 저런 이야기를 했다. 그 친구 왈 요즘은 너무 여유가 없다는 이야기를 했다. 그도 그럴것이 인원은 한정돼 있고 사이트는 계속 늘어나니 예전엔 조금씩 있던 여유가 지금은 한톨도 없다는 이야기를 한다. 그러면서 뭔가 새로운 일을 하고 싶어도 여유가 없으니 당장 코앞에 벌어진 일만 할 수 밖에 없다는 푸념을 했다. 조곤 조곤 하는 이야기를 듣고 있노라니 많이 공감이 갔다. 단지 시키는 입장에서는 왜 이것도 안되고 저것도 안되냐고 닥달하기 쉽지만 직접 일을 하는 입장에는 사소한 거 하나를 처리하는 데에도 시간이 걸리는 게 일이 아닌가라는 생각을 왜 못했나 싶었다. 난 메모리 액세스 속도를 기대했는데 사실 I/O는 SSD도 아닌 하드디스크도 아닌 플로피디스크였던 것이다. 섹터 찾는데도 시간이 걸리는 물리적인 한계가 있었던 것이다.&lt;/p&gt;
&lt;p&gt;여유가 많이 없어졌군. 이런 생각을 하면서 회사로 복귀했다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;저녁 무렵. 집 근처에 사는 후배 녀석을 만났다. 집 앞 콤마라는 커피숍에 앉아서는 이런 저런 이야기를 하는데 녀석도 비슷한 이야기를 한다. 의료 정보쪽 회사에서 프로그래머로 일하고 있는데 일이 쉽지가 않은 것이다. 사실은 회사 정책을 탐탁치 않아 하는 분위기 였다. 그 회사는 규모도 크고 매출도 제법 되는 회산데 회사에서 후배가 하는 프로젝트에 돈을 쓰기 보다는 다른 신사업에 돈을 쏟아 붓는다는 것이었다. 현재 그 회사의 캐시카우는 후배가 하는 프로젝트임에도 말이다.&lt;/p&gt;
&lt;p&gt;그래서 난 그런 말을 했다. 경영자가 미래 사업 방향을 그 신사업으로 정했다면 그건 어느 정도 납득이 되는 이야긴거 같다고. 그래서 진짜 네가 힘든게 뭐냐고 물었더니 회사 직원과 똑같은 이야기를 한다. 여유가 없다는 것이다. 이건 뽑아 먹어도 적당히 뽑아 먹어야 하는데 정말 토나오는 상황이라는게 그 친구의 말. 예를들면 이런 식이었다. 그 친구가 일주일에 통상적으로 처리해야 하는 레드마인 이슈가 10개라면 의욕도 있고 회사에서 어느 정도 인정도 받고 있어서 15개 정도를 처리하겠다고 열심히 하는데 그 중간 중간에 하나도 아니고 시도 때도 없이 인터럽트와 추가 이슈가 들어온다는 이야기였다.&lt;/p&gt;
&lt;p&gt;듣고 있는데 참 남 일 같지 않다는 생각이 들었다. 특히나 점심 때 그런 이야기를 들었으니 ㅠㅜ~ 회사 생활이라는게 참 쉽지 않구나라는 생각. 녀석은 들어가면서 그랬다. 남의 돈 버는게 어디 쉽나요…&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;지난번 블로그에 &lt;a href=&quot;http://www.jiniya.net/wp/archives/13045&quot;&gt;코드의 색깔을 찾아서&lt;/a&gt;라는 글에 문제를 냈었다. 몇 분이 답을 보내주었는데 모르는 분이 한 분 포함돼 있었다. 관심가져 주신게 고맙기도 하고 어떤 분인지 만나 보고 싶기도 해서 연락을 해서는 만났다. 만나서 통성명을 하고 인사를 하는데 큰 형님이셨다. 그러면서 이런 저런 좋은 이야기를 많이 했었다. 게임 업계에 있다가 지금은 제조 쪽에서 프로그래밍을 하고 계시다고 했다. 재밌는 문제 푸는 걸 좋아해서 한번 해봤다는 이야기를 했다.&lt;/p&gt;
&lt;p&gt;그 이야기 중간에 이런 이야기가 있었다. 그래도 연구소장 정도 되니까 블로그에 코드 색깔 스크립트나 짜서 올리고 하는 여유가 있는 것 같다고. 직원들 입장에서는 그런 걸 할 시간이 없지 않겠냐는 이야기. 형의 그 이야기를 나도 반박하지는 않았다. 내가 봐도 우리 회사 직원들은 바빠서 그런 일을 할만한 시간이 없다고 생각됐기 때문이었다. 그래서 내가 생각해도 회사 직원 입장에서는 바빠서 아마 그럴 시간은 없는게 맞는것 같다는 이야기를 했다.&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;비오는 오후 사무실에 의자에 앉아서 창밖에 내리는 비를 물끄러미 바라보며 커피를 한 잔 하고 있는데 갑자기 그런 생각이 들었다. 이 여유란 것도 어떻게 보면 빈익빈 부익부가 심할 수도 있겠다라는 생각. 나는 사실 여유가 많은 편이다. 커피를 한 잔 하고 싶으면 쉴 수도 있고, 코드 쓰다가 머리 아프면 잠시 나갔다 올 수 도 있고, 집에서 일하고 싶으면 집에서 일한다. 그러니 어쩌면 직원 입장인 친구들보다는 새로운 것들이나 문제점을 찾기가 훨씬 더 쉬운 위치에 있는지도 모른다. 그리고 그런 일들이 쌓이면서 내가 훨씬 더 여유를 많이 가질 수 있는 위치에 있게 되고 말이다. 결국 선순환과 악순환인 두 개의 피드백 루프가 있다면 어쩌다보니 난 재수가 좋아서 선순환의 피드백 루프에 들었던게 아닌가라는 생각이 들었다.&lt;/p&gt;
&lt;p&gt;지금 당장 문제를 해결할 시간도 없는데 go, rust, f# 같은 언어를 주목할 필요가 있다는 이야기는 그 친구들에게는 어쩌면 밥이 없으면 빵을 먹으라는 말처럼 들리지 않았을까? 내리는 빗방울만큼 생각도 많아지는 오후…&lt;/p&gt;</content:encoded></item><item><title><![CDATA[40대 개발자는 뭐 먹고 사나요?]]></title><description><![CDATA[김종득님이 얘기 하시는 것처럼 제가 대학교 다닐 때에 선배들이 30살 되면 프로그램 못짠다고 이런 얘기를 하셨고요. 근데 보니까 그 얘기 하시던 선배들은 프로그램 못짜던 선배였어요. 제가 30살 되니까 4…]]></description><link>https://jiniya.net/wp/archives/14748</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14748</guid><pubDate>Wed, 17 Jun 2015 23:59:27 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;김종득님이 얘기 하시는 것처럼 제가 대학교 다닐 때에 선배들이 30살 되면 프로그램 못짠다고 이런 얘기를 하셨고요. 근데 보니까 그 얘기 하시던 선배들은 프로그램 못짜던 선배였어요. 제가 30살 되니까 40살 되면 프로그램 못짠다고 이런 얘기를 많이 하시는데 근데 그 얘기 하시는 분들이 또 프로그램 못 짜던 분들이 그런 얘기 하셨던 것 같구요.&lt;/p&gt;
&lt;p&gt;– 송재경&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;30대 중반까지 코딩하는 입장에서 전적으로 틀린 말은 아니라고 생각한다. 그런데 반전은 한살 한살 먹으면서 느끼는게 점점 더 똑똑해지기 보다는 멍청해지기가 쉽다는 점이다. 예전보다 똑똑함이나 총명함을 유지하기가 정말 쉽지 않은 것 같다. 20대 때 프로그램 좀 짠다고 했던 사람이 30까지 그 실력을 유지하거나 발전시키기가 생각만큼 녹록치 않다는 말이다. 그러니 그 나이 또래 때 그럭저럭 한다고 생각해도 나이들면 쉽게 쉽게 추락하고 도태돼 버리는 게 아닐까라는 생각. 물론 신입만큼 하기야 쉽겠지만 말이다. 해외에는 나이든 엔지니어가 많다고 해도 &lt;a href=&quot;http://www.jiniya.net/wp/archives/8185&quot;&gt;그래프를 보면 쭉쭉 줄어들기는&lt;/a&gt; 마찬가진거 같다. 그나마 인력 풀이 크니깐 살아남는 사람이 상대적으로 많은 게 아닐까라는 생각이 많이 든다.&lt;/p&gt;
&lt;p&gt;대체로 출연자들이 대박 욕 먹은 동영상이긴 하지만 찬찬히 한 번 들어볼 필요는 있는 내용이 아닐까 싶다. 욕해도 그게 현실이기도 하고…&lt;/p&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/9bKP3rEzW4s?si=Yy6BdVQ1CgSlgR7N&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/vgl1SO8aOPs?si=FdTHnNtlu0PNd2lD&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/U6YpaL1kWZw?si=oTcfYZ6Hg_w5wpKI&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;</content:encoded></item><item><title><![CDATA[애플, 맥, OS X, iOS 관련 내용들…]]></title><description><![CDATA[#0 기본적으로 윈도우와 HOME/END 키 동작 방식이 다름 HOME/END 키 동작 방식 변경 방법 http://mwholt.blogspot.kr/2012/09/fix-home-and-end-keys-on-mac-os-x.html #…]]></description><link>https://jiniya.net/wp/archives/13524</link><guid isPermaLink="false">https://jiniya.net/wp/archives/13524</guid><pubDate>Wed, 17 Jun 2015 23:59:26 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;기본적으로 윈도우와 HOME/END 키 동작 방식이 다름&lt;/p&gt;
&lt;p&gt;HOME/END 키 동작 방식 변경 방법&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://mwholt.blogspot.kr/2012/09/fix-home-and-end-keys-on-mac-os-x.html&quot;&gt;http://mwholt.blogspot.kr/2012/09/fix-home-and-end-keys-on-mac-os-x.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;컨트롤 대신 대부분 단축키가 윈도키에 조합됨&lt;/p&gt;
&lt;p&gt;ctrl + c =&gt; win + c&lt;/p&gt;
&lt;p&gt;ctrl + tab =&gt; win + tab&lt;/p&gt;
&lt;p&gt;ctrl + p =&gt; win + p&lt;/p&gt;
&lt;p&gt;ctrl + z =&gt; win + z&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;다윈 커널 소스&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://opensource.apple.com/source/xnu/xnu-2422.90.20/&quot;&gt;http://opensource.apple.com/source/xnu/xnu-2422.90.20/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;top 소스 코드&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://opensource.apple.com/source/top/top-89.1.2/&quot;&gt;http://opensource.apple.com/source/top/top-89.1.2/&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 우공이산의 지혜]]></title><description><![CDATA[나에게 20살은 자유를 의미했다. 경제 활동을 시작하면서 난 부모님에게서 독릴할 수 있었고, 모든 결정을 내 멋대로 할 수 있었다. 대학도 그랬다. 난…]]></description><link>https://jiniya.net/wp/archives/8560</link><guid isPermaLink="false">https://jiniya.net/wp/archives/8560</guid><pubDate>Wed, 17 Jun 2015 23:59:25 GMT</pubDate><content:encoded>&lt;p&gt;나에게 20살은 자유를 의미했다. 경제 활동을 시작하면서 난 부모님에게서 독릴할 수 있었고, 모든 결정을 내 멋대로 할 수 있었다. 대학도 그랬다. 난 1년 동안 거의 학교에 가지 않았다. 물론 학교는 갔었지만 수업을 듣지 않았다. 사실 내 수업보다 여자친구 수업을 더 많이 들었었다. 당연히 나의 성적표는 대부분 F로 채워졌다. F가 아닌 과목은 거의 대부분 내 앞에 있었던 신명진이란 여자 아이가 출석을 부를 때 내 이름을 자기 이름으로 잘못 들어서 대출한 과목이었다. 학사경고였다. 시쳇말로 쓰리고면 제적이었기에 두번째 학사경고를 받았을 때 귀댁의 자녀가 위기에 처했다는 전화가 집으로 왔다. 내가 받았다면 난 제적을 당했을지도 모른다. 다행이 엄마가 받았고 집에는 난리가 났다. 그 등살에 난 2학년 부터는 수업을 조금씩 듣기 시작했다.&lt;/p&gt;
&lt;p&gt;그렇게 참가한 기초 전자 전기 실험에서 그 형을 처음 만났다. 당시 난 병특을 준비하고 있었고, 그 형은 병특을 마치고 학교를 복학한 상태여서 우리는 금방 친해졌다. 가끔 술도 한잔 하면서 이야기를 많이 했었는데 영어를 잘했으면 좋겠다는 이야기를 하는 나에게 형은 병특을 시작하면 영어 단어를 하루에 하나씩 외우라는 판에 박힌 조언을 해줬다. 진짜 정말 너무 어처구니가 없어서 형한테 욕을 할 뻔 했다. ㅋ~ 난 당현하게 형은 영어를 못할 거라는 생각을 가지고 있었다.&lt;/p&gt;
&lt;p&gt;우리는 더 많은 실험을 했고, 더 많이 친해졌고, 더 많은 사실을 알 수 있었다. 그러다 약간 놀랄만한 사건이 하나 있었다. 한날은 형이 실험을 하러 오면서 뭘 보고 있기에 뭐냐고 하니깐 아이트리플이라고 했다. 난 IEEE를 그렇게 읽는다는 걸 그때 처음 알았다. 그리고 학교에서 무료로 볼 수 있는 잡지를 직접 구독하는 사람이 우리과에 있다는 사실에 두 번 놀랬다. 형은 나에게 싸게 구독할 수 있는 요령을 알려주었지만 난 받아들이지 않았다. 그리고 얼마되지 않아서 더 놀라운 사실을 접했다. 나에게 하루에 영어 단어를 하나씩 외우라고 조언했던 그 형이 학교 신문에 났기 때문이었다. 그것도 무려 ACM 대학생 논문 경진대회 대상을 수상했다는 명목으로 말이다.&lt;/p&gt;
&lt;p&gt;난 놀래서 형한테 왜 그런 이야기를 안했냐니 대단한게 아니라서 말을 안했다는 허무한 대답을 들었다. 그러면서 어떻게 그런 대회에서 상을 탔냐고 도대체 어떤 논문이었냐고 어떻게 그런 생각을 해내게 됐냐고 꼬치꼬치 캐물었다. 형은 답했다. 그냥 앉아있다 이렇게 하면 더 좋지 않을까라는 생각에 써서 냈다고. 학비가 없어서 좀 더 간절했다는 더 어처구니 없는 대답. 멘붕~&lt;/p&gt;
&lt;p&gt;난 병특을 시작했다. 영어를 잘하고 싶다는 생각은 있었지만 형의 조언은 상콤하게 씹었다. 사실 생활하는데 영어가 그닥 필요하지 않았기 때문이다. 그때나 지금이나 난 영어 라이팅을 배우고 싶은데 쉽지가 않다. 그러면서 그냥 형은 원래 타고날 때부터 머리가 좋았겠지, 엄마 뱃속에서 영어를 배웠다고 생각했다.&lt;/p&gt;
&lt;p&gt;국방부 시계는 간다고 나의 병특도 어느새 끝이났다. 사실 돌아보니 너무 금방 끝이 났다. 난 영어 단어를 하나도 외우지 않았다. 형은 졸업을 했고 카이스트에 석사로 갔다. 학교 앞에서 한 번 만날 일이 있었다. 난 복학하면서 잔뜩 유학 거품이 들어 있었던터라 GRE를 준비한답시고는 겉멋에 찌들어 살고 있었다. 그날도 그랬다. 난 워드 스마트를 보면서 이런 단어를 내 평생에 한 번은 쓸까라면서 멘붕에 빠져있는데 형이 들어왔다. 옆에 책을 한 권 끼고 있었는데 날 좌절하게 만들기에 충분했다. 내가 중딩인지 고딩인지 그때 보던 능률 보카를 끼고 온 것이다. 당시 형은 GRE를 준비하는 게 아니라 실제로 GRE를 치던 시점이라 너무 어처구니가 없었다. 그리곤 형이 단어를 하나씩 외우라고 한 조언이 빈 말이 아님을 알 수 있었다. 능률 보카에 형광펜을 칠하면서 보고 있었기 때문이다.&lt;/p&gt;
&lt;p&gt;복학 이펙트는 오래가지 않았다. 한 학기 반짝하고는 난 또 그냥 그런 학교 생활을 했다. 난 학점을 메꾸지도 못했고, 유학을 가지도 못했다. GRE는 한 번 쳐보지도 못했다. 그만큼 빨리 포기했다. 반대로 형은 GRE에서 상당한 수준의 점수를 받았고, MIT로 유학을 떠났다.&lt;/p&gt;
&lt;p&gt;이런 이야기를 하면 많이들 그 형은 원래 천재였고, 1학년부터 착실히 공부를 했으며, 그래서 그런 엄청난 결과를 얻었을 거라는 이야기를 한다. 하지만 웃긴 사실은 그 형도 학사경고를 받았으며, 1학년 때에 술을 많이 마시고는 모텔을 간적이 있었다고 했다. 모텔에 가서도 술판이 한창 벌어졌는데 같이 술을 마시던 선배가 너무 술을 마니 마셔서 수영을 하자는 제안에 모텔 바닥에서 수영을 한적이 있었다고 했다. 차마 무엇과 함께 수영했는지는 상상에 맡기겠다.&lt;/p&gt;
&lt;p&gt;너무나 많은 시간이 지났다. 난 여전히 우공이산의 지혜를 머리로만 이해한다. 회사에 2년만에 신입 개발자가 첫 출근을 했다. 난 제프리 리처의 Windows via C/C++을 건내며 앞으로 한달간 이 책만 씹어먹어도 위대한 시스템 프로그래머가 될 수 있다는 이야기를 해 주었다. 이 똑같은 이야기를 난 몇 차례 했었는데 그 어떤 신입 개발자도 그 책을 씹어먹진 않았다. 너무 시시하다는 반응이 대부분이었다. 참 안타까운 일이 아닐 수 없다. 난 이 바닥에서 10년을 일했고, 그래도 나름 못한다기 보다는 잘한다는 평을 받으면서 일했다. 개인적으로도 경쟁력은 있다고 생각해 왔었다. 그런데도 난 여전히 100번도 더 읽었던 Windows via C/C++에서 힌트를 얻고 제프리 리처가 1999년도에 쓴 글을 읽으면서 감탄한다. 촌스럽다고 느끼지만 현실은 그렇다.&lt;/p&gt;
&lt;p&gt;형을 마지막으로 본게 9년전 카이스트였던 것 같다. 그때 우리는 10년 후를 이야기 했었다. 같이 간 형은 입사한 대기업 부사장이 되겠다고 했고, 난 벤처기업을 차리겠다는 이야기를, 그리고 형은 미국에 가서 자리를 잡겠다는 이야기를 했다. &lt;a href=&quot;http://www.jiniya.net/wp/archives/13369&quot;&gt;내년 초여름이면 꼭 10년이 된다.&lt;/a&gt; ㅎㅎ~ 같이 갔던 형은 여전히 그 대기업에 다니지만 부사장이 되기에는 아직 힘들어 보이고, 나는 그때 말한 것처럼 성공하진 못했지만 벤처를 시작하긴 했다. 형은 MIT 연구소로 스카웃되서 갔고, 여전히 MIT에 있다. 형의 안부가 궁금해지는 새벽녘이다. 그 옛날 400원짜리 캔커피 뽑아서는 전소 앞에 쪼롬히 앉아서 조교 씹던게 엊그제 같은데 시간이 이리도 빨리 흘렀다. 하루는 더디 흘러도, 10년은 훌쩍 가버리는 게 세월이 아닌가 싶다.&lt;/p&gt;
&lt;p&gt;쉬워 보이는 것도 꾸준히 하는 일은 우리가 생각하는 것보다 훨씬 더 효과적인 방법인지도 모른다. 왜냐하면 거의 모든 사람들이 빠른 길을 찾는다는 명분 아래 정작 아무 것도 하지 않고 시간을 보내기 때문이다. 마치 병특 때의 나처럼 말이다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[재미난 게 없어요…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/4902</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4902</guid><pubDate>Wed, 17 Jun 2015 23:59:24 GMT</pubDate><content:encoded>&lt;p&gt;나이 들어 친구든 지인이든 주변에서 제일 많이 듣게 되는 말 중에 하나가 “재미난 게 없어요”라는 말인 것 같다. 근데 그런 말 하는 사람들 대부분이 실상은 아무 것도 하지 않으면서 저절로 재미있어 지기를 바란다는 점이다. 그런 사람들에게 꼭 보여주고 싶은 테드 영상. 내가 느끼는 기분을 더 잘 표현한 &lt;a href=&quot;http://wangmul.egloos.com/3317027&quot;&gt;왕멀님의 블로그 글&lt;/a&gt;…&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] 화…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/14712</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14712</guid><pubDate>Tue, 16 Jun 2015 23:59:23 GMT</pubDate><content:encoded>&lt;p&gt;회사를 경영하는 형이 일 처리를 제대로 하지 못한 팀장에게 화를 냈다며 자책하는 이야기를 했다. 그러면서 뭐가 정답인지도 잘 모르겠다는 이야기도 덧붙인다. 세상에 뭐 그리 딱 떨어지는 정답이 있기야 하겠는가만은… 잘못된건 잘못됐다고 지적할 수 있어야 발전이 있지 않을까라는 생각이 들었다. 나는 완벽하지 않더라도 말이다…&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./화.md_0.png&apos; data-alt=&apos;생존한다는 건 장난이나 놀이가 아니다. 생각보다 훨씬 복잡하고 어렵고 힘든 일이다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 515px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/fdf487eada1106d459f6e18d2648251a/70021/%ED%99%94.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 25.263157894736842%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAIAAADKYVtkAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAA1ElEQVR42h1P27KDIAz0/z+wc+ppBcRyEaiAIreXriZMsuzObJKB8+XxN75e0ziO74k+x3+ptTLWuK+2Tmpz5tJ7zzm31q7ar5pLwXdQWi8fQQjVemWcE8reE+GcU8oInRljUmkhpFRq5gt4gImweeZC6cGsq5BiohR2KSUfYgih1Ap8nhkPDbC1DlwymPOAlo6Y0mCMJYwppf3m4e+DR1hjN+9jjBhprNtuyTq37xGT3RdEsNbday+ffT96a/CudxRkq+1mCta4ri0A19klQwRVa/0BSPoW+b81OnQAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;생존한다는 건 장난이나 놀이가 아니다. 생각보다 훨씬 복잡하고 어렵고 힘든 일이다.&apos; title=&apos;&apos; src=&apos;/static/fdf487eada1106d459f6e18d2648251a/70021/%ED%99%94.md_0.png&apos; srcset=&apos;/static/fdf487eada1106d459f6e18d2648251a/08678/%ED%99%94.md_0.png 190w,
/static/fdf487eada1106d459f6e18d2648251a/2edd7/%ED%99%94.md_0.png 380w,
/static/fdf487eada1106d459f6e18d2648251a/70021/%ED%99%94.md_0.png 515w&apos; sizes=&apos;(max-width: 515px) 100vw, 515px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;생존한다는 건 장난이나 놀이가 아니다. 생각보다 훨씬 복잡하고 어렵고 힘든 일이다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./화.md_1.jpg&apos; data-alt=&apos;일단 성공하면 다 용서되는 불편한 진실…&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/aede35c023e8d2d701cb2dae89385a8d/953fe/%ED%99%94.md_1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAUCBAP/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAH01F6ScriJ0hgH/8QAGxAAAgMBAQEAAAAAAAAAAAAAAQMAAgQREzL/2gAIAQEAAQUCUtZUzwUL8NxpaKr0kxehQpKfHOz/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/AR//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/AR//xAAhEAABBAEDBQAAAAAAAAAAAAABAAIRIQMQEjEiI0Fhcf/aAAgBAQAGPwJk4QaQ34OfScWippAB5pd3r++FDmWNOJ0//8QAHRABAQACAgMBAAAAAAAAAAAAAREAITFBEFFhcf/aAAgBAQABPyFSQTuG8rSOkGakGonBhJQIEMSNB05HC8F9/fEFIqm8lP7n/9oADAMBAAIAAwAAABCnxz7/xAAVEQEBAAAAAAAAAAAAAAAAAAARIP/aAAgBAwEBPxBj/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPxAf/8QAHRABAAIDAQADAAAAAAAAAAAAARExACFBYRBxkf/aAAgBAQABPxBihTPVF3gnIESpTycShYaEjoj6w+/AagoyU0lgGkcAury/2AR/Y78HkEqmhk9wcsgIA4Tn/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;일단 성공하면 다 용서되는 불편한 진실…&apos; title=&apos;&apos; src=&apos;/static/aede35c023e8d2d701cb2dae89385a8d/953fe/%ED%99%94.md_1.jpg&apos; srcset=&apos;/static/aede35c023e8d2d701cb2dae89385a8d/8ccab/%ED%99%94.md_1.jpg 190w,
/static/aede35c023e8d2d701cb2dae89385a8d/ea4c8/%ED%99%94.md_1.jpg 380w,
/static/aede35c023e8d2d701cb2dae89385a8d/953fe/%ED%99%94.md_1.jpg 500w&apos; sizes=&apos;(max-width: 500px) 100vw, 500px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;일단 성공하면 다 용서되는 불편한 진실…&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[리뷰] 회사원]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/10791</link><guid isPermaLink="false">https://jiniya.net/wp/archives/10791</guid><pubDate>Tue, 16 Jun 2015 23:59:22 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 678px; margin-bottom: 16px;&apos; data-url=&apos;./회사원.md_0.jpg&apos; data-height=&apos;640&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/dd6fa8b6c5b9d5dd0d56788c37951200/b98e4/%ED%9A%8C%EC%82%AC%EC%9B%90.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 142.6315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAdABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAMBAgUE/8QAFgEBAQEAAAAAAAAAAAAAAAAAAQAC/9oADAMBAAIQAxAAAAHKvECw5yGWRpZc8eav/8QAHBABAQACAgMAAAAAAAAAAAAAAgEAIQMREiNC/9oACAEBAAEFAoKkh0tYUjlXrm5Js8cWUUX6l8OHrP/EABURAQEAAAAAAAAAAAAAAAAAABAB/9oACAEDAQE/ASH/xAAVEQEBAAAAAAAAAAAAAAAAAAAQAf/aAAgBAgEBPwEp/8QAHBAAAQQDAQAAAAAAAAAAAAAAAAECETEQEiFB/9oACAEBAAY/AkgvDopbL7OHbLBCLJq68c9LP//EABsQAQADAQEBAQAAAAAAAAAAAAEAESExYXGh/9oACAEBAAE/IQjPs2m3D5MHI+Ilm7a/kSDdQdEPPZ3yrMjzARtotzl9GsE6qf/aAAwDAQACAAMAAAAQQ/Pw/8QAFhEBAQEAAAAAAAAAAAAAAAAAEBEh/9oACAEDAQE/EMhB/8QAFxEAAwEAAAAAAAAAAAAAAAAAARARIf/aAAgBAgEBPxDagNwr/8QAHxABAAMAAgEFAAAAAAAAAAAAAQARITFBgVFhccHw/9oACAEBAAE/ECJsNWaIj1AIPZFpr4gAKOc1LMLAtonZUBy4LuvUfcDHFx5mYUvj4RxTqB+dxSOKgzSYHPaEmR7XdgNgvbs//9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;    md 0&apos; title=&apos;&apos; src=&apos;/static/dd6fa8b6c5b9d5dd0d56788c37951200/b98e4/%ED%9A%8C%EC%82%AC%EC%9B%90.md_0.jpg&apos; srcset=&apos;/static/dd6fa8b6c5b9d5dd0d56788c37951200/8ccab/%ED%9A%8C%EC%82%AC%EC%9B%90.md_0.jpg 190w,
/static/dd6fa8b6c5b9d5dd0d56788c37951200/ea4c8/%ED%9A%8C%EC%82%AC%EC%9B%90.md_0.jpg 380w,
/static/dd6fa8b6c5b9d5dd0d56788c37951200/b98e4/%ED%9A%8C%EC%82%AC%EC%9B%90.md_0.jpg 678w&apos; sizes=&apos;(max-width: 678px) 100vw, 678px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;넌 일이 좋냐?&lt;/p&gt;
&lt;p&gt;오늘 진짜 이상하시네. 아까도 사고 내고.&lt;/p&gt;
&lt;p&gt;과장님은 싫으세요?&lt;/p&gt;
&lt;p&gt;나야 그냥 하는 거고. 오래했으니까.&lt;/p&gt;
&lt;p&gt;일인데요. 뭐. 좋고 싫고가 어딨어요?&lt;/p&gt;
&lt;p&gt;저 고등학교도 짤렸잖아요. 어디가서 이만큼 벌어요?&lt;/p&gt;
&lt;p&gt;불만 없어요, 저는. 위에 말이나 잘해줘요. 월급 좀 제대로 받게.&lt;/p&gt;
&lt;p&gt;부족해? 지금 받는 거?&lt;/p&gt;
&lt;p&gt;네. 불안정 하자나요. 언제 짤릴지도 모르고.&lt;/p&gt;
&lt;p&gt;야, 너 이제 스무 살이야.&lt;/p&gt;
&lt;p&gt;네.&lt;/p&gt;
&lt;p&gt;넌 뭐 되고 싶은 거 없냐고?&lt;/p&gt;
&lt;p&gt;부자요. 떼부자.&lt;/p&gt;
&lt;p&gt;한 5년 바짝 벌어가지고 미국으로 뜰라구요.&lt;/p&gt;
&lt;p&gt;마이애미, LA 이런데 가서 백인 여자들 두세 명씩 끼고…&lt;/p&gt;
&lt;p&gt;과장님은 어땠는데요? 과장님 스무 살 때요?&lt;/p&gt;
&lt;p&gt;나?&lt;/p&gt;
&lt;p&gt;가수 되고 싶었지.&lt;/p&gt;
&lt;p&gt;왜 안 하셨는데요?&lt;/p&gt;
&lt;p&gt;안 하긴. 못한거지.&lt;/p&gt;
&lt;p&gt;가수 별거 없어요. 인기 떨어지면 안 한 것만 못하지.&lt;/p&gt;
&lt;p&gt;꼭 해본 것처럼 말한다.&lt;/p&gt;
&lt;p&gt;아는 사람이 했어요. 가수.&lt;/p&gt;
&lt;p&gt;그래. 누군데?&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[[cpp] 실수 랜덤 값 생성하기, 2001]]></title><description><![CDATA[C 표준 랜덤함수는 정수의 랜덤값만 생성합니다. 일반적으로 실수 랜덤값은 아래와 같은 나눗셈을 통해서 취득할수 있습니다. 아래 코드는 low에서 high…]]></description><link>https://jiniya.net/wp/archives/4972</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4972</guid><pubDate>Tue, 16 Jun 2015 23:59:21 GMT</pubDate><content:encoded>&lt;p&gt;C 표준 랜덤함수는 정수의 랜덤값만 생성합니다. 일반적으로 실수 랜덤값은 아래와 같은 나눗셈을 통해서 취득할수 있습니다. 아래 코드는 low에서 high사이의 실수 랜덤값을 생성하는 함수입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;drand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt; low&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt; high&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
    &lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt; d&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

    d &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; RAND_MAX&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;low &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; d &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;high &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; low&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;참고로 한가지 더 적으면 터보씨에 있는 랜더마이즈(randomize)함수는 아래와 같은 매크로를 통해 동일하게 정의할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name function&quot;&gt;randomize&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;srand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;실수 랜덤 값은 도대체 뭐에 쓸려고 생성한걸까? 사고 실험인가?&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 10진수를 16진수로 변환하는 함수, 2002]]></title><description><![CDATA[직 로더를 만들면서 제작한 함수 중에 하나입니당. 테이블을 사용하면 깔끔하게 된다는 점이 돋보이는 소스 입니당. 그럼 다들 한번 찬찬히 뜯어 보세염. — 13년 지나서 보니 그다지 돋보이진 않는 것 같은데…]]></description><link>https://jiniya.net/wp/archives/4965</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4965</guid><pubDate>Tue, 16 Jun 2015 23:59:20 GMT</pubDate><content:encoded>&lt;p&gt;직 로더를 만들면서 제작한 함수 중에 하나입니당. 테이블을 사용하면 깔끔하게 된다는 점이 돋보이는 소스 입니당. 그럼 다들 한번 찬찬히 뜯어 보세염.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;dec2hex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; d&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;h&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
   &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; buf&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;1&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;2&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;3&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;4&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;5&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;6&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;7&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;8&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;9&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;A&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;B&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;C&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;D&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;E&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;F&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
      buf&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;d &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;d &lt;span class=&quot;token operator&quot;&gt;/=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   buf&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token char&quot;&gt;&apos;\0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   &lt;span class=&quot;token function&quot;&gt;ReverseStr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;h&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; buf&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;13년 지나서 보니 그다지 돋보이진 않는 것 같은데…&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] freeaddrinfo 사용 시 주의해야 할 점]]></title><description><![CDATA[http://msdn.microsoft.com/en-us/library/ms737931(VS.85).aspx The freeaddrinfo function was added to the Ws2_32.dll on Windows XP and later…]]></description><link>https://jiniya.net/wp/archives/4668</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4668</guid><pubDate>Tue, 16 Jun 2015 23:59:19 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/ms737931(VS.85).aspx&quot;&gt;http://msdn.microsoft.com/en-us/library/ms737931(VS.85).aspx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The freeaddrinfo function was added to the Ws2_32.dll on Windows XP and later. To execute an application using this function on earlier versions of Windows (Windows 2000, Windows NT, and Windows Me/98/95), then you must include the Ws2tcpip.h file and also include the Wspiapi.h file.&lt;/p&gt;
&lt;p&gt;간단번역: freeaddrinfo는 Windows XP 이후에 추가 했으니, 그전 운영체제에서 사용하려면 ws2tcpip.h는 물론 wspiapi.h를 포함시키렴.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 다시보는 assert, 2002]]></title><description><![CDATA[다들 C언어를 처음 배울때 ASSERT…]]></description><link>https://jiniya.net/wp/archives/5014</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5014</guid><pubDate>Tue, 16 Jun 2015 23:59:18 GMT</pubDate><content:encoded>&lt;p&gt;다들 C언어를 처음 배울때 ASSERT라는 매크로를 배우게 된다.별로 의미없이 지나치게 되는 매크로의 하나인데, 사실 알고보면 저것 만큼 디버깅 시간을 줄여주는 매크로는 없다는 생각이 요즘 든다. 버그의 대부분의 근거는 함수 파라미터의 실수나 리턴값의 오류에 기인한다고 할 수 있다. 그런 버그를 원천 봉쇄할 수 있는 방법이 바로 위의 ASSERT 매크로를 사용하는 것이다. 예를 들어 아래 함수를 보도록 하자.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;next_char&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;str&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;str &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위 함수의 입력값으로는 NULL포인터가 절대로 들어가서는 안된다. 그런 에러를 원천 봉쇄 할 수 있는 방법이 바로 아래와 같은 방법이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;next_char&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;str&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
  &lt;span class=&quot;token function&quot;&gt;ASSERT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;str &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;str &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이제 만약 위의 코드에 NULL값이 입력값으로 들어오면 함수는 동작하지 않고 프로그램은 오류메세지를 출력하면서 종료될 것이다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 입력 버퍼에 관한 진상, 2001]]></title><description><![CDATA[그동안 잘못 알고 있었던 상식중에 입력버퍼에 관한 내용이 있어서 올려봅니다. 제 홈페이지를 통해서도 잘못 전파된 내용이 많을 것 같다는 생각이 드네염. 보통 scanf를 통해서 입력을 받을때 엔터 한번에 쭈루룩 다음 scanf…]]></description><link>https://jiniya.net/wp/archives/4940</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4940</guid><pubDate>Tue, 16 Jun 2015 23:59:17 GMT</pubDate><content:encoded>&lt;p&gt;그동안 잘못 알고 있었던 상식중에 입력버퍼에 관한 내용이 있어서 올려봅니다. 제 홈페이지를 통해서도 잘못 전파된 내용이 많을 것 같다는 생각이 드네염. 보통 scanf를 통해서 입력을 받을때 엔터 한번에 쭈루룩 다음 scanf함수까지 넘어가는 것을 본 적이 있을 겁니다. 그런 것들을 보면 보통 scanf하기전에 입력 버퍼를 비우기 위해서 fflush함수를 사용하라고 하는데, 이 fflush라는 놈이 표준안에 정의를 보면 표준 출력에 대해서만 정의되어 있고, 표준 입력에 대해서는 아무런 동작을 하지 않는다는 것입니다. 따라서 fflush(stdin)하는 것은 undefined behavior, 즉 정의되지 않은행동. 따라서 사용하지 말아야 할 행동입니다.&lt;/p&gt;
&lt;p&gt;그러면 scanf가 쭈루룩 넘어가는 진상은 과연 어디에 있는가? 입력 버퍼를 비우는 방법은 없는 것인가? 하는 두가지 의문이 드실 겁니다. 일단 첫번째 문제에 대해서 한번 살펴보도록하죠^&lt;/p&gt;
&lt;p&gt;scanf는 특성상 개행문자를 입력받지 않는다고 합니다. 따라서 \n을 입력버퍼에 그대로 남겨두게 되고, 다음 번 scanf가 그놈때문에 자동으로 넘어가는 현상이 생기게 되는 것입니다. 따라서 scanf다음에 getchar()등으로 개행문자를 소비해주는 입력함수를 넣어주면 그런 문제를 막을 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;scanf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;getchar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그럼 두번째 질문인 입력버퍼에 대해서 알아보도록 하죠. 일반적으로 키보드의 입력 버퍼를 비우는 행동은 표준함수로 제공되지 않습니다. 따라서 그런 행동들은 운영체제나 컴파일러 제조사에 따라 다르다는 이야기입니다. 일반적으로 dos시절에는 아래 함수를 사용해서 입력 버퍼를 비울 수 있었습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;kbhit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;getch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그리고 gcc를 사용하는 경우에는 stdio.h에 정의된 flushall함수를 사용해서 입력 버퍼를 비울 수 있습니다.&lt;/p&gt;
&lt;p&gt;일반적으로 scanf의 경우 입력받은 값이 잘못된 경우 이전 상태로 복원시키는 방법을 전혀 제공하지 않습니다. 따라서 보통의 경우 입력은 문자열로 fgets등을 통해서 입력받은후 sscanf내지는 자신이 직접 제작한 입력함수를 통해서 파싱해 내는 것이 일반적입니다.&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;참 내가 썼지만 깜찍했네 ㅋㅋㅋ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 윈도우8 취약점 완화 관련 API]]></title><description><![CDATA[윈도우 8하면 보통 현란하게 바뀐 시작 화면을 떠올린다. 인터넷을 접한 사람들은 시작 버튼이 없어졌다는 사실 또한 떠올릴 것이다. 그만큼 윈도우 8의 UI 변화는 많은 사람들에게 충격적이었다. 그 UI…]]></description><link>https://jiniya.net/wp/archives/10414</link><guid isPermaLink="false">https://jiniya.net/wp/archives/10414</guid><pubDate>Tue, 16 Jun 2015 23:59:16 GMT</pubDate><content:encoded>&lt;p&gt;윈도우 8하면 보통 현란하게 바뀐 시작 화면을 떠올린다. 인터넷을 접한 사람들은 시작 버튼이 없어졌다는 사실 또한 떠올릴 것이다. 그만큼 윈도우 8의 UI 변화는 많은 사람들에게 충격적이었다. 그 UI 변화를 두고 호불호가 많이 나뉘기도 한다. 하지만 윈도우 8의 모든 변화가 단지 표면적으로 드러나는 앱 월드와 데스크톱 월드의 통합 내지는 UI 표현의 변화, 또는 사라진 시작 버튼에만 있는 것은 아니다. 우리에게 직접 나타나지 않는 내부에도 상당히 많은 변화가 있었다. 이런 내부의 경우 굉장히 혁신적인 변화임에도 관심을 가지고 살펴보지 않으면 잘 알기 힘든 부분이라 크게 평가되고 있지 못한 점이 안타깝다.&lt;/p&gt;
&lt;p&gt;윈도우 8은 내부에도 엄청난 변화가 있었다. 하지만 윈도우 8을 만든 개발자들은 비스타에서 충분히 많은 교훈을 얻었기 때문에 그 엄청난 변화를 우리가 직접 느낄 수 있도록 만들지는 않았다. 즉, 내부 구조의 변화도 겉으로 드러나는 표면적인 부분의 변화는 극히 제한적이라는 의미다. 하지만 상당히 많은 부분이 개선되었고 또 기존 것들과 충돌을 일으키지 않는 범위 내에서 실험적인 다양한 기능들이 추가되었다. 그런 변화 중에서도 보안과 관련되어 있으면서도 데스크톱 응용 프로그래머들이 알아두면 도움이 될 만한 UAC 정책 변화와 새롭게 추가된 프로세스 보안 정책에 대해서 살펴보도록 하자.&lt;/p&gt;
&lt;p&gt;사용자 계정 컨트롤(UAC) 정책 변경
사용자 계정 컨트롤은 윈도우 비스타부터 도입된 개념으로 프로그램이 관리자 권한이 필요한 작업을 수행할 때에 사용자에게 그 행위를 보고함으로써 위험한 작업이 은밀하게 발생하는 것을 방지하는 것을 의미한다. 원래 권한 개념이 크게 부각되지 않은 윈도우에서 그나마 택할 수 있는 정책이었지만 권한을 줬다가 다시 가져오는 작업은 그리 수월하지 않았다. UAC는 비스타를 가로막는 가장 강한 허들이 되었고, 그로 인해서 시장에서 비스타는 실패한 운영체제로 낙인 찍히게 되었다. 윈도우 7은 그런 교훈을 바탕으로 UAC를 좀 더 다듬어서 사용자를 덜 귀찮게 만들어서 내놓는 형태로 사용자와 타협했다.&lt;/p&gt;
&lt;p&gt;하지만 사실상 타협했다는 표현은 좀 어폐가 있다. 그도 그런 것이 거의 대부분의 윈도우 7 사용자는 UAC가 기본적으로 켜져 있음에도 굳이 옵션을 조정해서 UAC를 끈 상태로 운영체제를 사용하기 때문이다. 그래서 윈도우 8에서는 UAC 기능을 끄는 것과 관련해서 아주 미세하게 설정을 조율했다.&lt;/p&gt;
&lt;p&gt;기존의 윈도우 비스타와 윈도우 7에서는 사용자 계정 컨트롤을 가장 낮은 단계로 설정하는 경우에는 UAC가 없는 것과 동일하게 되었다. 즉, 가장 낮은 단계는 UAC를 끄는 것과 같은 맥락이었다. 하지만 윈도우 8부터는 더 이상 그런 상식이 통용되지 않는다.&lt;/p&gt;
&lt;p&gt;윈도우 8에서 사용자 계정 컨트롤을 가장 낮은 선택할 경우에 경고창은 출력되자 않지만 프로그램의 권한 컨트롤은 여전히 적용된다. 이 말이 무슨 의미냐 하면 기존의 윈도우의 경우 UAC가 가장 낮은 단계인 경우에는 오른쪽 버튼을 눌러서 관리자 권한으로 실행 메뉴를 전혀 사용할 필요가 없었다. 왜냐하면 매니페스트에 상관 없이 UAC가 꺼지면 모든 프로그램이 자동으로 관리자 권한으로 실행되었기 때문이다. 하지만 윈도우 8부터는 UAC가 가장 낮은 단계로 설정하더라도 여전히 관리자 권한으로 실행 메뉴를 사용해야 한다.&lt;/p&gt;
&lt;p&gt;이를 직접 확인해 보기 위해서는 UAC를 가장 낮은 단계로 설정한 다음 실행 메뉴를 통해서 명령창을 실행하고 관리자 권한을 필요로 하는 명령어를 입력해보면 알 수 있다. &amp;#x3C;화면 1&gt;나타난 것과 같이 권한이 없어서 명령어가 실패하는 것을 볼 수 있다. 이런 문제 때문에 윈도우 8의 탐색기에는 &amp;#x3C;화면 2&gt;에 나타난 것과 같이 관리자 권한으로 명령창을 실행하는 메뉴가 추가돼 있다. 이 메뉴를 통해서 관리자 권한으로 실행된 명령창에서 동일한 명령어를 입력하면 정상적으로 수행되는 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./윈도우8_취약점_완화_관련_API.md_0.png&apos; data-alt=&apos;화면 1 UAC가 꺼진 상태에서 관리자 권한이 필요한 작업을 수행하면 실패한다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 677px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/8fe5a18944df70c347b26f3deb087c8a/3c503/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 65.26315789473685%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAABQklEQVR42mNImnI6adbNpDn3kufeTZpzJ2nO3YRZN+MmnYmdeDq8+1hEz/HwnmMRvSfiZlyPn3kTiBJm3IiYeau+cv6UxsUMhi6R4iJCsnLysnJy4hIS8goKYuLi0tIy0jKyvGAgLCTMzsHBwMjIyMQEREzMzAxMzOwcnLXT1jGYuEUK8XMBtQkLCQkKCvDx8kqIi4mKCAsK8IsIC7GysjAxA/UxMsAAhM3GzNA2fTWDlW+iqBA/0B4RERFBQUF+fn4hISEBAQE+Pj4gm4uLiwEVQDSzszD2zNvEoG7px87CwMsHAqysrAyEAFxz99yNDHKGriAhJma4HATA1eHTLG/oBuQwMbNgVUqazUNFs7yhO9jPrMBEQAxiAlnDxMHK3D13E/k2983fyGAUWCyhYSmr7yyj50gkktZ1UDR0qpuzFwBfHVQmVoY0bwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;화면 1 UAC가 꺼진 상태에서 관리자 권한이 필요한 작업을 수행하면 실패한다.&apos; title=&apos;&apos; src=&apos;/static/8fe5a18944df70c347b26f3deb087c8a/3c503/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_0.png&apos; srcset=&apos;/static/8fe5a18944df70c347b26f3deb087c8a/08678/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_0.png 190w,
/static/8fe5a18944df70c347b26f3deb087c8a/2edd7/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_0.png 380w,
/static/8fe5a18944df70c347b26f3deb087c8a/3c503/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_0.png 677w&apos; sizes=&apos;(max-width: 677px) 100vw, 677px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;화면 1 UAC가 꺼진 상태에서 관리자 권한이 필요한 작업을 수행하면 실패한다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./윈도우8_취약점_완화_관련_API.md_1.png&apos; data-alt=&apos;화면 2 탐색기에는 관리자 권한으로 명령창을 실행하는 메뉴가 생겼다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/89bcb0b446658d84dc93451ae02ee0b4/efd7b/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 53.68421052631579%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB20lEQVR42nWRS2tTQRTH52P6JWJpshFcuBHcCm4quGsasGKSdaWUVtT4CIglaUwba9qb5ia59877PZPruQmCKA6/OcwM53/mPNC9F7NG6+JBd7XblfUO23mtnvf7Ly+6j45mu23d6Iqdw7zWTGqteb0t6h3ZaItaRz3e6z992EL3m8PDd5dSKsykUJYre3P7M89TTGmGKaaCS8VEBRfKOK+MBVuW8XQs0cfRQjJSEI4J1dYJ4/b3D6bTREA4jKWU683y3gshlFJGqxBCWbrBDUNP9l5NrsbaBkwYxC64f/+lt8oziFVgXBR4lWVZgbWx2hhKmdZ6XcKKHwYpan8jC8wJYTmmWUE2qUXYxjrAOl/hA5yhNMaYgFwqcdkbpuhsfCVpjgnX2viNk3M+xHWI0QMhBiCu4V0IySgFuxWfTzk66M3ni1xXbahUldgH0PzJVkwZz/OMUrrRlsNEo+an9C4n8befdeF/YmgJrX4W258HiULn12MlllwFZbx2ATontYPzX1RThJo5hynEbdq3Ck2WBvoeo11H42WWzb7Pri/xMlF0JckSEHgB12KZSJzSVcLzu2hFWdrRjKPmZ34yFm9/hLOJOx6pN0Oxgf/L0QCsAHs8lJ2v9NkJ/gXeCVh2schbEwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;화면 2 탐색기에는 관리자 권한으로 명령창을 실행하는 메뉴가 생겼다.&apos; title=&apos;&apos; src=&apos;/static/89bcb0b446658d84dc93451ae02ee0b4/efd7b/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_1.png&apos; srcset=&apos;/static/89bcb0b446658d84dc93451ae02ee0b4/08678/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_1.png 190w,
/static/89bcb0b446658d84dc93451ae02ee0b4/2edd7/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_1.png 380w,
/static/89bcb0b446658d84dc93451ae02ee0b4/efd7b/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_1.png 760w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;화면 2 탐색기에는 관리자 권한으로 명령창을 실행하는 메뉴가 생겼다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;UAC를 끄더라도 권한 컨트롤이 여전히 수행된다는 것은 프로그램을 그냥 실행시켰을 때 매니페스트에 관리자 권한을 요구하는 표시가 되어 있다면 경고창 없이 그 프로그램을 관리자 권한으로 실행시켜 주지만 그렇지 않은 경우에는 UAC가 가장 낮은 단계로 설정돼 있더라도 일반 권한으로 해당 프로그램을 실행시킨다는 것을 의미한다.&lt;/p&gt;
&lt;p&gt;UAC 설정은 HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System 경로에 있는 일부 키 값을 통해서 조정된다. 윈도우 8에서는 UAC에서 가장 낮은 단계를 선택하더라도 &amp;#x3C;화면 3&gt;에 나타난 것과 같이 EnableLUA 값이 0이 아닌 1로 설정돼 있는 것을 볼 수 있다. &amp;#x3C;표 1&gt;에는 사용자 계정 컨트롤 설정 값에 따른 UAC 관련 레지스트리 값의 변화가 나와 있다. 표를 살펴보면 다른 부분은 모두 같지만 가장 낮은 단계를 선택한 경우에는 EnableLUA 값이 달라진 것을 볼 수 있다. 이 값을 윈도우 7과 똑같이 조작하면 UAC가 완전히 꺼지도록 만들 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./윈도우8_취약점_완화_관련_API.md_2.png&apos; data-alt=&apos;화면 3 UAC 설정 관련 레지스트리 키&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/593a056b2924b229380cdcc0fe0ad2c1/8a72f/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 41.578947368421055%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAAsTAAALEwEAmpwYAAABlUlEQVR42kWPWWvbQBRG/e/7B2pIk/SpT6VQ+lIolNiliRVD21iWHGubkTTWrllkrdZojZQW+nDh4zsc7r2LN19PyxVerunbFVmu2c0mf/9Y3myK65/J1V3wbh1e359vhfJ2LvOZCsWVUH78pn368GOhuWl3ycoizxlChmhDmDIyDm3fcYrDLKHj2NdlXmTn15DladI19ZS3ZrIA0WUcuqYdqtwz9T8QoiiK27YbhgHZnq4BjCmjzIRmVVV1Xaua5ofROI4bCb3KY9c0bdtULFZty05YMrFh6CHCNrQQNIIgUo7HKIw55+JePDneLMvOP5k3bddxEkjIsvt+GGe7N6zo8735IJ8SQlRVJZhyXkvyIYzwxJ8AWYBwPps3fX1hHpKAAQkmWZY3DVcM/8uDJRycM6XH5yOOySSL0t7zw0mWUPr/Z155rinaplWk57+bPR97tjUNiUJkAobjS5mbQKeUTHxv0sVq7ynQkQ1P1q3fsrpT0AG4z9CXdOeXDLY7bbtThSflcadOjWy4mh0Dl6GAfhf9FzCCq3Wof330AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;화면 3 UAC 설정 관련 레지스트리 키&apos; title=&apos;&apos; src=&apos;/static/593a056b2924b229380cdcc0fe0ad2c1/efd7b/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_2.png&apos; srcset=&apos;/static/593a056b2924b229380cdcc0fe0ad2c1/08678/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_2.png 190w,
/static/593a056b2924b229380cdcc0fe0ad2c1/2edd7/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_2.png 380w,
/static/593a056b2924b229380cdcc0fe0ad2c1/efd7b/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_2.png 760w,
/static/593a056b2924b229380cdcc0fe0ad2c1/8a72f/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_2.png 780w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;화면 3 UAC 설정 관련 레지스트리 키&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;표 1 UAC 설정에 따른 레지스트리 키 값&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;설정&lt;/td&gt;
&lt;td&gt;윈도우 7&lt;/td&gt;
&lt;td&gt;윈도우 8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;항상 알림&lt;/td&gt;
&lt;td&gt;ConsentPromptBehaviorAdmin: 2&lt;br&gt;PromptOnSecureDesktop: 1&lt;br&gt;EnableLUA: 1&lt;/td&gt;
&lt;td&gt;ConsentPromptBehaviorAdmin: 2&lt;br&gt;PromptOnSecureDesktop: 1&lt;br&gt;EnableLUA: 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;설정 변경 시에만 알림&lt;/td&gt;
&lt;td&gt;ConsentPromptBehaviorAdmin: 5&lt;br&gt;PromptOnSecureDesktop: 1&lt;br&gt;EnableLUA: 1&lt;/td&gt;
&lt;td&gt;ConsentPromptBehaviorAdmin: 5&lt;br&gt;PromptOnSecureDesktop: 1&lt;br&gt;EnableLUA: 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;설정 변경 시에 알림&lt;br&gt;화면 흐리게 하지 않음&lt;/td&gt;
&lt;td&gt;ConsentPromptBehaviorAdmin: 5&lt;br&gt;PromptOnSecureDesktop: 0&lt;br&gt;EnableLUA: 1&lt;/td&gt;
&lt;td&gt;ConsentPromptBehaviorAdmin: 5&lt;br&gt;PromptOnSecureDesktop: 0&lt;br&gt;EnableLUA: 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;알리지 않음&lt;/td&gt;
&lt;td&gt;ConsentPromptBehaviorAdmin: 0&lt;br&gt;PromptOnSecureDesktop: 0&lt;br&gt;EnableLUA: 0&lt;/td&gt;
&lt;td&gt;ConsentPromptBehaviorAdmin: 0&lt;br&gt;PromptOnSecureDesktop: 0&lt;br&gt;EnableLUA: 1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;이 사소한 변화를 통해서 시작 버튼도 없애버린 마이크로소프트가 우리에게 얼마나 UAC를 강요하고 싶어하는지를 엿볼 수 있다고 생각한다. 보안을 생각했을 때 이런 변화가 결코 나쁜 변화는 아니다. 하지만 관리자 권한 매니페스트가 없는 프로그램을 자주 관리자 권한으로 실행해야 하는 사용자에게는 분명 예전보다는 불편해진 점이기도 하다. 이 때에는 프로그램의 호환성 속성을 사용하면 도움이 된다. &amp;#x3C;화면 4&gt;에 나타난 것과 같이 호환성 설정 부분에서 항상 관리자 권한으로 실행하도록 만들어주는 옵션을 선택하면 해당 프로그램은 매니페스트에 관리자 권한 요구 속성이 없어도 관리자 권한으로 실행시켜 준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./윈도우8_취약점_완화_관련_API.md_3.png&apos; data-alt=&apos;화면 4 항상 관리자 권한으로 실행하도록 설정&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 377px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/c2dff0bf6dc5b7c42ecd2cfc6fdc16cc/fdd90/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 136.8421052631579%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAbCAIAAADzvTiPAAAACXBIWXMAAAsTAAALEwEAmpwYAAADrklEQVR42o1UW3PbVBDO32Tctwwdhj/ADH8DmpYZZkofeMCkQNIW2oeUh45jW7Yly5ZvshxLtqwjHV2O7ndLrGQISXGAnaP1eqXvnN39ds/JZ89Hj1/MT5vppz+Ep9+TxrNF4xnfOFt88vWk8ZR/9I0AuvFk3jibNc7m8MFpM/78O+Xy8RdPv/z25Ksr4w2Nf6SMlz3zZc84b6NmSz5vK83Wtnm9a17L5x31p47yM6X+0sMXNLlgnAvafk9rT96hk9cDTZwPWXqgawgr2+V8ihRZltYjpi+uhMmImYyGUeBlSZCEfhb7aeQHnlMm9tuhfvJmaMWBLe+QbpgYG5ZFYCmKquuGLO80bIATKWgrKxrGm+1uK+8s2yvL/LKnnbwd256lc5PFmJsww5GwXLGjcbdLzeY8TbNDdjydzgghpml5rkuIbZpmEEZlWb7qA3hE/CDoDBcMxw9GsxbFdpkpxXBdetyhufFC8sKkvC/7otKvBhXY8sOInknsbN0f8216ykxvuuyyyy56Y2G21ty4CJN9nO2Pg8M4vTEz5BYSyUVSSFY+RelcTZc4W6gJj8LRJhD1+Aj4V9Yqy0xYrThuwvPLjSQqSKu+2Bf7Wmr7nmQ5OIsaPARwrihIWAqiKAnCcjHnVVXbbKTJZCqs1pvN5mZ1E8cfnby/BWfAjQIPQrvdDmpr2zaov4xKg+R5fhScE+IYhmGahq7rQRCE/xDP8wBc1JJX6L/BewAHfggvYM+DPqRX3JFjOVcFSwVhBdXy/SCuJYqiQ6mKY3Ln5LraFiGGoWPoRgM61NKxDltkWXaI4liT3CnYdruTJFGSJFmWbcfxfN9xHCjV/wJbBCAgLjwQRWW5rue54E2S5GFwnbOqYbMKmByIgchrfgjGGPaBaqdp+tDJuR+GBzIty6xHx6p4tqt4IATYAvRt/T6iKjeJ43m+53pJXAd5P1NI/F+oynhegNmF0ZWkDUwshA0KGgbOhN6pGd8fo6o+2XH9KlSLaKq2UxTIH2MdIQQ9i5D6Xzzbju/7SZpUctDwm6YHqh+YKlyDs6jLDjpUp0f1KKrfbrcHA4ahGapLAfW383Bknl8zJoA9HzoyDsMI7qdah3GcVAb8j2IIAIIAAxb4wVHm8SXcYe9GZhkT3yWBS0KPRL7tEt3EiJ9xmiITQ9ORPB0PZxxrYeRCE4N3Ixah+RtcvS9aJieRnkAGqz8XxRvXU/V3RmpNUGeOwb4arK/66/ZM6y1N0B84hROt5x/wHyKYwG0NK7BAAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;화면 4 항상 관리자 권한으로 실행하도록 설정&apos; title=&apos;&apos; src=&apos;/static/c2dff0bf6dc5b7c42ecd2cfc6fdc16cc/fdd90/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_3.png&apos; srcset=&apos;/static/c2dff0bf6dc5b7c42ecd2cfc6fdc16cc/08678/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_3.png 190w,
/static/c2dff0bf6dc5b7c42ecd2cfc6fdc16cc/fdd90/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_3.png 377w&apos; sizes=&apos;(max-width: 377px) 100vw, 377px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;화면 4 항상 관리자 권한으로 실행하도록 설정&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;우리가 만드는 프로그램도 사용자가 알아서 저렇게 설정해 주기를 원할 수 있지만 사용자 친화적인 프로그램이라면 이러한 설정을 메뉴를 통해서 옵션으로 제공하는 것도 나쁘지 않다. 프로그램으로 해당 옵션을 조정하는 방법은 간단한 레지스트리 조작으로 할 수 있다. 호환성 플래그를 설정하는 레지스트리 키는 아래 경로를 살펴보면 된다. 해당 경로를 이동하면 &amp;#x3C;화면 5&gt;에 나타난 것과 같이 호환성이 설정된 프로그램의 목록이 나타난다. 키 값은 해당 프로그램의 경로가 되고, 데이터는 설정된 값을 나타낸다. 관리자 권한으로 실행을 하기 위해서는 RUNASADMIN이라는 문자열을 추가해 주면 된다.&lt;/p&gt;
&lt;p&gt;HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers&lt;/p&gt;
&lt;p&gt;HKLM\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;윈도우8_취약점_완화_관련_API.md_4.png&apos; data-alt=&apos;화면 5 항상 관리자 권한으로 실행 기능이 켜진 프로그램의 AppCompatFlags 레지스트리 값&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 649px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/37c542521605041ccac85203f5f57941/1bcec/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 35.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAIAAACHqfpvAAAACXBIWXMAAAsTAAALEwEAmpwYAAABd0lEQVR42iWNS0/bQBSF/Xu7bAoItv0HXaNW4rlALU0JSViwAUJAJIiHzWQc2/Ejtic2juOxPZ4ZJzHjIn26+s6Rjq705WiycRpv/k2+ncaN33PhW0283co3TvyvR5PGsbn5J9xpZYLts7S+zaTRxLs/2j+/70lXT2Cia1DVURD4aKYbluvNCsbTnAgyASlwmi9wmmb5PE4IZWle0OWqb2DpSXeSQHFsJ46igpCZ59oqCAO0KtmS05LTZcnzPDMNg1E6dRzkI0JIVVWv1kJSprQknmMOgQI1zUCuC17BQNZfoPUoa0NZk6H5HoTaWCso1dUxHEHGy3psY0lxOcsMdfRgTxHj3A+if8/JwZAcDrODQfbrPm0pOWcMzUKxWSTY81D4Hovxi4WlZxPzzB5DYFtWFAbzebSu1lWNOJ+yqj4bEde1r+pefE6k/Uv1ogfOruX2jdLuvZ3fKJ1b0OmBbn8k5OIOCrpC/sduH5xfK53+aAD9k1vrAzLIam9Iww/OAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;화면 5 항상 관리자 권한으로 실행 기능이 켜진 프로그램의 AppCompatFlags 레지스트리 값&apos; title=&apos;&apos; src=&apos;/static/37c542521605041ccac85203f5f57941/1bcec/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_4.png&apos; srcset=&apos;/static/37c542521605041ccac85203f5f57941/08678/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_4.png 190w,
/static/37c542521605041ccac85203f5f57941/2edd7/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_4.png 380w,
/static/37c542521605041ccac85203f5f57941/1bcec/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_4.png 649w&apos; sizes=&apos;(max-width: 649px) 100vw, 649px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;화면 5 항상 관리자 권한으로 실행 기능이 켜진 프로그램의 AppCompatFlags 레지스트리 값&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;취약점 완화 방안
예전에 스타크래프트란 게임을 한창 즐기던 시절 게임 잡지에 “스타크래프트 상에서 최고의 수비는 상대를 공격하는 것”이란 기사가 실린 것을 본 적이 있다. 그 당시만 해도 우주방어테란만 고집했던 터라 내심 그 기사를 좀 무시했었다. 하지만 이후 임요환 선수가 등장하면서 모든 것이 달라졌다. 고질적으로 공격이 느리던 테란의 단점을 드랍쉽으로 커버하면서 정말 최고의 수비는 방어가 아닌 공격에서 나온다는 것을 온몸으로 보여줬기 때문이었다. 시시한 게임 이야기라고 생각하면 오산이다. 이 전략은 게임 속뿐만 아니라 현실 세계에서도 얼마든지 통용되는 전략이기 때문이다.&lt;/p&gt;
&lt;p&gt;모든 프로그래머들은 버그가 없는 프로그램, 보안 취약성이 없는 프로그램을 만들고 싶어한다. 하지만 안타깝게도 현대 프로그램은 그 규모와 복잡도가 너무나 커져 버려서 사실상 그런 프로그램을 만든다는 것은 거의 불가능에 가까워졌다고 할 수 있다. 매일같이 보고되는 수많은 취약점, 제로데이 공격들이 그 근거라고 할 수 있겠다. 이러한 이슈가 발생할 때 마다 프로그래머는 빠르게 관련 문제를 수정하지만 수정한 것을 배포할 때쯤엔 또 다른 버그와 취약점이 기다리고 있다. 이미 속도에서 경쟁이 안 되는 상태가 돼 버린 것이다.&lt;/p&gt;
&lt;p&gt;그래서 임요환 선수같이 똑똑한 프로그래머들이 조금 다른 생각을 하기 시작했다. “왜 우리만 항상 이렇게 당해야 하지? 우리도 똑같이 해커를 공격할 방법은 없는 것일까?”라는 생각에서 출발한 전략이 바로 취약점 완화 방안이다. 이 방법의 전략은 단순하다. 어차피 늘 상 있는 버그, 취약점은 인정하겠다는 것이다. 하지만 그런 것들을 알고 있는 해커라고 하더라도 그걸 공격하는 코드를 만드는 것은 어렵도록 만들겠다는 취지다. 그래서 모든 취약점 완화 방안은 근본적인 대책은 아니다. 하지만 이런 사소한 것들이 여러 개 모이면 공격자 입장에서는 다양한 환경에서 항상 정상적으로 동작하는 코드를 만드는 일이 예전보다 훨씬 어려워지기 때문에 공격의 속도가 늦어지고 악성 코드를 만드는 데에 더 많은 비용이 투입되도록 만드는 장점이 있다.&lt;/p&gt;
&lt;p&gt;시스템 프로그래머가 아니라면 이러한 방법이 있었다는 것을 모르는 경우가 많지만 사실 윈도우가 취약점 완화 기능을 만들기 시작한지는 제법 오래됐다. 많이 알려진 기능으로는 2002년에 처음 소개된 VIsual C++의 /GS 기능이 있다. 이 기능을 사용하면 스택 오버플로 공격을 통해서 임의의 코드를 실행하는 것을 억제할 수 있다. 2003년에는 SafeSEH라는 기능이 개발됐다. 이미지에 기록된 예외처리 핸들러만 실행하도록 운영체제에서 제한한 것이다. 2004년에는 데이터 실행 방지(DEP) 개념이 소개됐다. 이 기능은 프로그램 내의 스택과 힙과 같은 영역에서 코드가 실행될 수 있는 것을 제한한 기능이다. 윈도우 비스타가 출시되던 2006년에는 주소 공간 배치를 랜덤화 하는 ASLR이라는 기술이 소개됐다. 이 기술은 /DYNAMICBASE 플래그가 지정된 DLL의 로드 주소를 랜덤하게 결정하는 기술이다. 이 기술과 함께 윈도우 핵심 DLL들은 모두 이 플래그를 사용하도록 변경됐기 때문에 윈도우 비스타 이후에는 주소가 하드 코딩된 형태로 시스템을 공격하는 코드는 더 이상 동작하지 않게 되었다. 윈도우 8에는 이런 기존의 취약점 완화 기능들을 보다 향상시키는 한편 새로운 취약점 완화 기능들이 대거 추가했다. 새롭게 추가된 기능에 대해서 하나씩 살펴보도록 하자.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON&lt;/strong&gt;&lt;br&gt;
이 정책이 적용된 프로세스는 로드되는 모든 DLL에 대해서 강제로 주소 공간 배치 랜덤화(ASLR) 기능을 적용한다. /DYNAMICBASE가 지정되지 않은 구형 DLL 또한 강제로 랜덤한 주소에 로드하도록 만든다는 의미다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS&lt;/strong&gt;&lt;br&gt;
이 정책은 앞서 설명한 강제로 ASLR을 적용하는 것에 더불어 재배치 정보가 없어서 랜덤한 주소에 로드할 수 없는 모듈의 경우에는 DLL의 로드를 실패 처리한다. 이 정책이 지정된 프로세스에는 재배치 정보가 포함되지 않은 DLL은 아예 로드 자체가 불가능해진다는 의미다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON&lt;/strong&gt;&lt;br&gt;
이 정책이 지정되면 힙이 손상되는 경우에는 자동으로 해당 힙을 파괴한다. 힙 오버플로나 힙의 메타 정보를 사용한 공격이 발생하는 과정에서 공격자 코드의 결함으로 힙의 정보가 손상되는 경우에는 해당 힙을 바로 파괴해 버리도록 만든다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON&lt;/strong&gt;&lt;br&gt;
스택을 포함한 bottom-up 할당기가 적용되는 메모리 할당에 ASLR을 적용한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON&lt;/strong&gt;&lt;br&gt;
bottom-up 할당기의 할당 범위를 1테라 바이트 주소 공간까지 확장한다. 네이티브 64비트 프로그램에만 적용된다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON&lt;/strong&gt;&lt;br&gt;
잘못된 핸들을 사용하는 경우에 즉시 예외가 발생한다. 이 플래그가 설정되지 않은 프로세스에서는 실패 값이 반환된다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON&lt;/strong&gt;&lt;br&gt;
win32 서브시스템과 관련된 코드는 유저 모드와 커널 모드에 모두 코드가 존재하면서 상호 정보를 교환하기 때문에 윈도우 구조상 가장 취약한 부분이라고 할 수 있다. 이 정책이 적용된 프로세스는 win32 서브시스템과 관련된 API 호출이 원천적으로 봉쇄된다. 이 말은 쉽게 말하면 user32.dll에 있는 API를 호출할 수 없도록 만드는 옵션이라고 생각하면 된다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON&lt;/strong&gt;&lt;br&gt;
높은 수준의 보안성을 유지해야 하는 프로그램에 있어서 AppInit이나 윈도우 훅과 같은 알려진 시스템 루트를 통한 침투는 굉장히 취약한 부분이다. 이러한 기능은 일반적인 프로그램에서도 많이 사용하기 때문에 악의적인 목적의 공격인지를 판단하는 것이 더욱 어렵다. 이 정책이 적용된 프로세스는 이러한 알려진 시스템 루트를 통해서 DLL이 로딩되는 것을 원천적으로 차단된다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;프로세스 취약점 완화 정책 설정&lt;/h3&gt;
&lt;p&gt;윈도우 8에서 추가된 다양한 취약점 완화 정책들을 살펴보았다. 그렇다면 도대체 이 정책들은 어떻게 설정할 수 있는 것일까? 윈도우 8에서는 그런 목적을 위해서 2개의 함수가 추가됐다. 취약점 완화 정책을 설정하기 위해서 SetProcessMitigationPolicy, 취약점 완화 정책을 조회하기 위해서 GetProcessMitigationPolicy 함수가 추가됐다. 각 함수의 원형은 &amp;#x3C;리스트 1&gt;에 나와 있는 것과 같다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 1 SetProcessMitigationPolicy/GetProcessMitigationPolicy 함수 원형&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;BOOL WINAPI &lt;span class=&quot;token function&quot;&gt;SetProcessMitigationPolicy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
PROCESS_MITIGATION_POLICY MitigationPolicy
&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PVOID lpBuffer
&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SIZE_T dwLength
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

BOOL WINAPI &lt;span class=&quot;token function&quot;&gt;GetProcessMitigationPolicy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    HANDLE hProcess
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PROCESS_MITIGATION_POLICY MitigationPolicy
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PVOID lpBuffer
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SIZE_T dwLength
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;함수 사용방법은 간단하다. SetProcessMitigationPolicy의 경우 현재 프로세스에 대해서만 적용되며, GetProcessMitigationPolicy 함수의 경우에는 첫 번째 인자로 넘어간 프로세스의 정책을 구한다. MitigationPolicy에는 &amp;#x3C;표 2&gt;에 나타난 것과 같은 상수 각을 사용할 수 있다. buffer에는 MitigationPolicy에 지정한 상수에 맞는 구조체의 포인터를, dwLength에는 해당 구조체의 크기를 넘겨주면 된다.&lt;/p&gt;
&lt;p&gt;표 2 MitigationPolicy 값&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;MitigationPolicy 값&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ProcessDEPPolicy&lt;/td&gt;
&lt;td&gt;데이터 실행 방지(DEP) 정책을 설정한다.&lt;br&gt;buffer에는 PROCESS_MITIGATION_DEP_POLICY 구조체 포인터를 전달한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ProcessASLRPolicy&lt;/td&gt;
&lt;td&gt;주소 공간 배치 랜덤화 정책을 설정한다.&lt;br&gt;buffer에는 PROCESS_MITIGATION_ASLR_POLICY 구조체 포인터를 전달한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ProcessStrictHandleCheckPolicy&lt;/td&gt;
&lt;td&gt;엄격한 핸들 체크 정책을 설정한다.&lt;br&gt;buffer에는 PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY 구조체 포인터를 전달한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ProcessSystemCallDisablePolicy&lt;/td&gt;
&lt;td&gt;시스템 호출 금지 정책을 설정한다.&lt;br&gt;buffer에는 PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY 구조체 포인터를 전달한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ProcessExtensionPointDisablePolicy&lt;/td&gt;
&lt;td&gt;프로세스 확장 포인트 금지 정책을 설정한다.&lt;br&gt;buffer에는 PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY 구조체 포인터를 전달한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;#x3C;리스트 2&gt;에는 ProcessStrictHandleCheckPolicy 정책을 구하고 설정하는 예제가 나와 있다. 프로그램을 살펴보면 첫 번째 VirtualAllocEx는 ProcessStrictHandleCheckPolicy 정책이 설정되기 전에 호출되었기 때문에 일반적인 호출과 같이 함수 실패로 처리된다. 하지만 두 번째 VirtualAllocEx의 경우에는 해당 정책이 설정된 다음에 잘못된 핸들을 사용해서 호출하고 있기 때문에 예외가 발생해서 프로그램이 크래시 되도록 만든다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 2 PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON 테스트&lt;/strong&gt;
&lt;a href=&quot;/codewiz/assets/files/2015/mitigation1.cpp&quot;&gt;소스 코드 다운로드&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;_WIN32_WINNT&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;0x0602&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Windows.h&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    HANDLE process &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x4444&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;VirtualAllocEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4096&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MEM_COMMIT &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; MEM_RESERVE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PAGE_READWRITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;First VirtualAllocEx Call\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY splc1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetProcessMitigationPolicy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetCurrentProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                                    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ProcessStrictHandleCheckPolicy
                                    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;splc1
                                    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;splc1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;DisallowWin32kSystemCalls: %d\n&quot;&lt;/span&gt;
                 &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; splc1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;RaiseExceptionOnInvalidHandleReference&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY splc2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    splc2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;RaiseExceptionOnInvalidHandleReference &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    splc2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;HandleExceptionsPermanentlyEnabled &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SetProcessMitigationPolicy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ProcessStrictHandleCheckPolicy
                                     &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;splc2
                                     &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;splc2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;SetProcessMitigationPolicy fail %d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY splc3&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetProcessMitigationPolicy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetCurrentProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                                    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ProcessStrictHandleCheckPolicy
                                    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;splc3
                                    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;splc3&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;DisallowWin32kSystemCalls: %d\n&quot;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; splc3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;RaiseExceptionOnInvalidHandleReference&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;VirtualAllocEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4096&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MEM_COMMIT &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; MEM_RESERVE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PAGE_READWRITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Second VirtualAllocEx Call\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&amp;#x3C;리스트 2&gt;의 예를 살펴보면 프로그램이 정책을 설정하기 전에는 여전히 해당 정책으로 금지하려는 동작이 수행 가능한 것을 알 수 있다. 이를 보면 당연히 공격자 입장에서 정책이 설정되기 직전에 공격을 한다면 타이밍 공격이 가능하다는 것을 알 수 있다. 더불어 앞서 살펴보았던 정책 중에 ASLR과 같은 것들은 주소 공간의 변화에 대한 것들이라 프로그램이 실행된 이후에 설정하는 것은 아무 의미가 없다. 왜냐하면 이미 프로그램이 실행됐다는 것은 프로그램 실행에 필요한 DLL이 거의 다 로드됐다는 의미이기 때문이다. 따라서 사실상 이런 정책은 앞서 소개한 API를 통해서 설정하는 것 보다는 프로세스 생성시에 지정하는 것이 가장 큰 효과를 가질 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;리스트 3&gt;에는 프로세스 생성 시에 정책을 설정하는 것을 보여주고 있다. 실행하면 PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON 정책을 설정한 다음 파라미터를 추가해서 자기 자신을 다시 실행한다. 다시 실행되면 if문의 코드는 수행되지 않고 뒤쪽의 현재 정책을 출력하고 user32.dll을 로드하는 코드가 수행된다. 이 경우에는 시작 시점에 이미 win32k 시스템 호출 금지 정책이 적용됐기 때문에 user32.dll의 로드가 실패해서 모듈 주소가 0으로 출력되는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 3 PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON 정책 테스트&lt;/strong&gt;
&lt;a href=&quot;/codewiz/assets/files/2015/mitigation2.cpp&quot;&gt;소스 코드 다운로드&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_tmain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; argc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _TCHAR&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; argv&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;argc &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        STARTUPINFOEXW si &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        PROCESS_INFORMATION pi&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        WCHAR cmd&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;MAX_PATH&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token function&quot;&gt;StringCbPrintfW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cmd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cmd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;\&quot;%s\&quot; dummy_args&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; argv&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        UCHAR buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4096&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        LPPROC_THREAD_ATTRIBUTE_LIST attr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPPROC_THREAD_ATTRIBUTE_LIST&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        SIZE_T size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;InitializeProcThreadAttributeList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; ERROR_INSUFFICIENT_BUFFER&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        attr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPPROC_THREAD_ATTRIBUTE_LIST&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; UCHAR&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;InitializeProcThreadAttributeList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        ULONG policy 
        &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;UpdateProcThreadAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attr
                                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
                                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY
                                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;policy
                                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;policy&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;
                                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;DeleteProcThreadAttributeList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        si&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StartupInfo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cb &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;si&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        si&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lpAttributeList &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; attr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CreateProcessW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;
                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cmd
                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;
                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;
                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FALSE
                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; EXTENDED_STARTUPINFO_PRESENT
                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;
                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;
                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;si&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StartupInfo
                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;pi&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;DeleteProcThreadAttributeList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token function&quot;&gt;WaitForSingleObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hProcess&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; INFINITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;DeleteProcThreadAttributeList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;attr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY plc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetProcessMitigationPolicy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetCurrentProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                                    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ProcessSystemCallDisablePolicy
                                    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;plc
                                    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;plc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;DisallowWin32kSystemCalls: %d\n&quot;&lt;/span&gt;
                    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; plc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;DisallowWin32kSystemCalls&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;user32.dll =&gt; %p\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;LoadLibraryW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;user32.dll&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;getchar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&amp;#x3C;리스트 3&gt;의 코드에 MessageBoxW와 같은 win32 서브시스템을 사용하는 함수를 정적으로 호출하는 코드를 추가한 다음 프로그램을 다시 실행하면 &amp;#x3C;화면 6&gt;에 나타난 것과 같이 정상적으로 응용 프로그램을 시작할 수 없다는 메시지가 출력되고 프로그램이 실행되지 않는다. 이는 해당 함수가 정적으로 바인딩 됐기 때문에 운영체제 로더가 user32.dll을 로드해야 하는데 그 또한 정상적으로 수행할 수 없기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./윈도우8_취약점_완화_관련_API.md_5.png&apos; data-alt=&apos;화면 6 응용 프로그램 시작 실패 메시지&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 490px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/aded2bbc8fb82f47219d11a87b3eea17/ce5c5/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_5.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 35.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAIAAACHqfpvAAAACXBIWXMAAAsTAAALEwEAmpwYAAABR0lEQVR42oXLzUrDQBAH8LyntnqoeQGfwCcQPEi19CTYKqIgXhSqqMWWIrYU0ybNVz/SJJtNSPqRZnebZN024MWDw4/hP8MMx1/N+OqCr8wOqnOmcOnnS9puUcqX9L3yeOe0lyuKLOfO1cL2hq8E+zfk5Oi6fHjM3XVW8pwKfipBOvDowE1FEPcsImSmkWAiFtim76QZAaQKiG8/A64NaPTVnL7UDDCRpK6qieORapojyxp7LoDQhtCyLcOa6OZEg44JgOE4JqW0pYdc26Fus67Xnk3PVYe6Nhqy7vk+IgRvsYAwRpvC2SbCZPOshVxDWVKa4jiJE1ZpnKSsr9cJwusMJpmYYeMK4VVEaEzqUsA1ZZ+iIJz70TL4hcLZXyRa+K5tjJS+0IWG8tCQuYu63RCd12/nTfjHew/WOlP2c/8hP7WUs0f1B8VLa/dkvwf0AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;화면 6 응용 프로그램 시작 실패 메시지&apos; title=&apos;&apos; src=&apos;/static/aded2bbc8fb82f47219d11a87b3eea17/ce5c5/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_5.png&apos; srcset=&apos;/static/aded2bbc8fb82f47219d11a87b3eea17/08678/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_5.png 190w,
/static/aded2bbc8fb82f47219d11a87b3eea17/2edd7/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_5.png 380w,
/static/aded2bbc8fb82f47219d11a87b3eea17/ce5c5/%EC%9C%88%EB%8F%84%EC%9A%B08_%EC%B7%A8%EC%95%BD%EC%A0%90_%EC%99%84%ED%99%94_%EA%B4%80%EB%A0%A8_API.md_5.png 490w&apos; sizes=&apos;(max-width: 490px) 100vw, 490px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;화면 6 응용 프로그램 시작 실패 메시지&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 윈도우 찾기]]></title><description><![CDATA[FindWindow 함수는 탑레벨 윈도우 중에서 원하는 윈도우를 찾는 기능을 한다. 탑레벨 윈도우란 desktop 윈도우를 부모로 갖는 윈도우를 말한다. 첫 번째 인자에는 찾고자 하는 윈도우의 클래스 이름을 넣어주면 된다. NULL…]]></description><link>https://jiniya.net/wp/archives/4363</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4363</guid><pubDate>Tue, 16 Jun 2015 23:59:15 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HWND &lt;span class=&quot;token function&quot;&gt;FindWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPCTSTR lpClassName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCTSTR lpWindowName&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;FindWindow 함수는 탑레벨 윈도우 중에서 원하는 윈도우를 찾는 기능을 한다. 탑레벨 윈도우란 desktop 윈도우를 부모로 갖는 윈도우를 말한다. 첫 번째 인자에는 찾고자 하는 윈도우의 클래스 이름을 넣어주면 된다. NULL을 지정할 경우에는 윈도우를 찾을 때 클래스 이름은 무시하고 찾는다. 두 번째 인자로 찾고자 하는 윈도우의 윈도우 이름을 넣어준다. 첫 번째 인자와 마찬가지로 NULL을 넣을 경우 이 항목은 무시된다. 윈도우의 핸들이 리턴 된다. 윈도우가 없다면 NULL이 리턴 된다. FindWindow(“#32770″, “TEST”)와 같이 사용할 경우 클래스 이름이 #32770이고 캡션이 TEST인 윈도우를 찾는다. FindWindow(“#32770″, NULL)과 같이 사용할 경우엔 캡션에 관계없이 클래스 이름이 #32770인 윈도우를 찾는다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HWND &lt;span class=&quot;token function&quot;&gt;FindWindowEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HWND hwndParent
                  &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HWND hwndChildAfter
                  &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCTSTR lpszClass
                  &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCTSTR lpszWindow&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;FindWindowEx는 특정 윈도우의 자식 윈도우 중에서 원하는 윈도우를 찾아준다. 첫 번째 인자로 찾고자 하는 윈도우의 부모 핸들을 넣어준다. 만약 NULL을 넣게 되면 FindWindow와 마찬가지로 Top 윈도우를 찾는다. 두 번째 인자로 검색 시작이 될 자식 윈도우를 넣어준다. 일반적으로 윈도우는 많은 자식 윈도우를 가지고 있다. 그 중에서 특정 자식 윈도우 다음부터 검사하고 싶은 경우 이 인자를 사용하면 된다. NULL을 지정할 경우 처음부터 검사한다. 세 번째, 네 번째 인자는 FindWindow의 인자와 같은 의미를 가진다. 리턴 값도 FindWindow와 동일하다. 아래 코드는 위에서 찾은 다이알로그의 자식 중에 확인 버튼을 찾는 것을 보여준다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HWND hwnd &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;FindWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;32770&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;TEST&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
HWND button &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;FindWindowEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hwnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;BUTTON&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;확인&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위의 두 함수 외에도 직접적으로 윈도우를 찾는 함수는 아니지만 도움이 되는 함수가 있다. GetNextWindow와 GetWindow가 그것이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HWND &lt;span class=&quot;token function&quot;&gt;GetNextWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HWND hWnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; UINT wCmd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;GetNextWindow는 z-order 상에서 다음에 있는 윈도우나 이전에 있는 윈도우를 찾는 기능을 한다. 첫 번째 인자로 검색 대상이 될 윈도우를 넣어주면 된다. 두 번째 인자는 GW_HWNDNEXT나 GW_HWNDPREV중에 하나를 넣으면 된다. GW_HWNDNEXT를 넣을 경우 z-order 상에서 다음에 존재하는 윈도우를 리턴 하고, GW_HWNDPREV를 넣을 경우 z-order 상에서 이전에 존재하는 윈도우를 리턴 한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HWND &lt;span class=&quot;token function&quot;&gt;GetWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HWND hWnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; UINT uCmd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;GetWindow는 대상 윈도우로부터 특정한 관계에 있는 윈도우를 찾는 기능을 한다. GetNextWindow의 일반화된 버전이라고 생각할 수 있다. 첫 번째 인자로는 대상이 되는 윈도우를 넣으면 된다. 두 번째 인자로는 다음 목록에 있는 것 중에 하나를 넣어주면 된다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;GW_CHILD&lt;br&gt;
대상 윈도우의 자식 중에서 z-order가 가장 위에 있는 윈도우를 리턴 한다. 만약 대상 윈도우의 자식이 없다면 NULL을 리턴 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;GW_ENABLEDPOPUP&lt;br&gt;
Windows 2000/XP이상에 적용되는 값이다. 대상 윈도우 다음윈도우 중에서 팝업 윈도우를 찾아서 리턴 한다. 팝업 윈도우가 없는 경우엔 NULL을 리턴 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;GW_HWNDFIRST&lt;br&gt;
같은 계층의 윈도우 중에서 가장 높은 z-order를 가지는 윈도우를 리턴 한다. 만약 대상 윈도우가 Top 레벨 윈도우라면 Top 레벨 윈도우 중에서 가장 높은 z-order를 가지는 윈도우를 리턴 한다. 만약 대상 윈도우가 자식 윈도우라면 형제 윈도우 중에서 가장 높은 z-order를 가지는 윈도우를 리턴 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;GW_HWNDLAST&lt;br&gt;
같은 계층의 윈도우 중에서 가장 낮은 z-order를 가지는 윈도우를 리턴 한다. 만약 대상 윈도우가 Top 레벨 윈도우라면 Top 레벨 윈도우 중에서 가장 낮은 z-order를 가지는 윈도우를 리턴 한다. 만약 대상 윈도우가 자식 윈도우라면 형제 윈도우 중에서 가장 낮은 z-order를 가지는 윈도우를 리턴 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;GW_HWNDNEXT&lt;br&gt;
대상 윈도우의 다음 z-order를 가지는 윈도우를 리턴 한다. GetNextWindow의 두 번째 인자에 사용되는 의미와 동일하다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;GW_HWNDPREV&lt;br&gt;
대상 윈도우의 이전 z-order를 가지는 윈도우를 리턴 한다. GetNextWindow의 두 번째 인자에 사용되는 의미와 동일하다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;GW_OWNER&lt;br&gt;
대상 윈도우의 소유자 윈도우를 리턴 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HWND &lt;span class=&quot;token function&quot;&gt;GetDesktopWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;VOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Desktop 윈도우를 구하는 함수다. 모든 Top 레벨 윈도우는 이 윈도우의 자식이다. 또한 Spy++에서 가장 위에 표시되는 윈도우 이기도 하다. 인자는 없고 리턴 값이 Desktop 윈도우 핸들이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HWND &lt;span class=&quot;token function&quot;&gt;GetShellWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;VOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Shell 윈도우를 구하는 함수다. Shell 윈도우는 작업 표시줄 윈도우를 말한다. 인자는 없고 리턴 값은 Shell 윈도우 핸들이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HWND &lt;span class=&quot;token function&quot;&gt;GetForegroundWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;VOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Foreground 윈도우 핸들을 구하는 함수다. Foreground 윈도우란 사용자와 상호 작용을 하고 있는 윈도우를 말한다. Windows가 멀티태스킹 시스템 이지만 사용자와 상호 작용을 하는 윈도우는 하나밖에 없다. 인자는 없고 리턴 값이 foreground 윈도우 핸들이다. Foreground 윈도우가 없는 경우 NULL을 리턴 한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HWND &lt;span class=&quot;token function&quot;&gt;GetParent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HWND hWnd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;부모 윈도우를 구해주는 함수다. 인자로 대상 윈도우 핸들을 넣어주면 부모 윈도우 핸들을 리턴 한다. 만약 대상 윈도우가 top 레벨 윈도우 이거나 함수 수행에 실패한 경우 NULL을 리턴 한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HWND &lt;span class=&quot;token function&quot;&gt;GetTopWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HWND hWnd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;첫 번째 자식 윈도우(자식 윈도우 중에서 z-order가 가장 높은 것)를 구하는 함수다. 인자로 윈도우 핸들을 넣어주면 첫 번째 자식 윈도우를 리턴 한다. 자식이 없거나 동작이 실패한 경우 NULL을 리턴 한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HWND &lt;span class=&quot;token function&quot;&gt;GetAncestor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HWND hwnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; UINT gaFlags&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;조상 윈도우를 구하는 함수다. 첫 번째 인자로 윈도우 핸들을, 두 번째 인자로 다음 목록에 있는 값 중에 하나를 넣어주면 된다. 리턴 값은 첫 번째 인자로 전달된 윈도우에 대한 조상 윈도우 핸들이다. 전달된 윈도우가 탑 레벨 윈도우일 경우 NULL이 리턴 된다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GA_PARENT&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;부모 윈도우를 리턴 한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GA_ROOT&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;최 상단 부모 윈도우를 리턴 한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GA_ROOTOWNER&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;최 상단 부모 윈도우를 소유한 윈도우를 리턴 한다.&lt;/p&gt;
&lt;p&gt;끝으로 앞서 배운 함수를 통해서 특정 윈도우의 하위에 존재하는 모든 윈도우를 열거하는 방법을 알아보자. GetWindow 함수와 재귀 호출 함수를 사용하면 손쉽게 구현할 수 있다. 아래 이렇게 구현해 본 ScrabWindow 함수가 있으니 참고해 보도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;모든 자식 윈도우를 수집하는 ScrabWindow 함수&lt;/strong&gt;
&lt;a href=&quot;/codewiz/assets/files/2015/scrabwindow.cpp&quot;&gt;소스 코드 다운로드&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BOOL&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;CALLBACK &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;ScrabWindowCallback&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HWND hwnd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

BOOL
&lt;span class=&quot;token function&quot;&gt;ScrabWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HWND hwnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ScrabWindowCallback cb&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cb&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hwnd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	HWND c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hwnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; GW_CHILD&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; GW_HWNDNEXT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ScrabWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cb&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

BOOL
CALLBACK
&lt;span class=&quot;token function&quot;&gt;PrintWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HWND hwnd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%08x\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; hwnd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;ScrabWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetDesktopWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PrintWindow&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[cpp] 초간단 암호화, 2001]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/4975</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4975</guid><pubDate>Tue, 16 Jun 2015 23:59:14 GMT</pubDate><content:encoded>&lt;p&gt;자신의 데이터에 어떤 기준으로 락을 걸고 싶을때가 있습니다. 하지만 막상 금방 코드를 작성하려면 방법이 잘 떠오르지 않는것이 이런 암호와 관련된 것들이죠. 몇가지 간단한 방법들을 여기서 소개해 드리도록 하겠습니다. 실질적으로 높은 수준의 보안을 유지할 수는 없는 방법들입니다. 간단하고 이해하기 쉬우며 암호의 원리를 알아보도록 하죠.&lt;/p&gt;
&lt;p&gt;암호는 기본적으로 상대방과 나와의 약속입니다. “내가 이렇게 원래 데이터를 바꿀테니 너는 이러이러케해서 원본데이터를 봐라”라고 하는 것들이 암호의 핵심입니다. 그런데 요즘 비번같은 암호의 경우는 비복원 방식을 사용하는 경우가 대부분입니다. 비복원이라는 말은 데이터가 암호와만 되고 역으로 추출해 내기는 힘들다는 이야기 입니다. 즉 abc가 zdsalkfj223으로 바뀌었을때, 이 바뀐 zds…이 abc로 돌아올 수는 없다는 이야기입니다. 반대로 복원 가능한 암호는 암호화 된 데이터로부터 원본 데이터를 그대로 복원해 낼 수 있습니다.&lt;/p&gt;
&lt;p&gt;가장 간단한 암호와 기법으로는 고전적인 방식의 시저 암호가 있습니다. 즉 데이터를 상대방과 약속을 하고 일정한 수를 가감하거나 가산하는 방식을 말합니다. a=&gt;b가 되면, c=&gt;d가 되는 식입니다.. 코드의 구현은 아주 간단하겠죠.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;SEED&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Encrypt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
       &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;data &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; SEED&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; 

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Decrypt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
       &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;data &lt;span class=&quot;token operator&quot;&gt;-=&lt;/span&gt; SEED&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;다음으로는 더욱 간단한 방법으로 암호라고 하기는 힘들지만 데이터를 반전시키는 방법을 사용할 수 있습니다. 이런 경우의 암호는 주로 텍스트 파일 등을 에디터로 봐서는 보기 힘들게 하는 정도의 보안 수준에 사용하면 좋겠죠. 암호화와 복원이 한 함수로 이루어 집니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;EncDecrypt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
       &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;끝으로는 사용자가 지정한 패스워드에 기반한 암호 알고리즘입니다. 소스 설명은 생략하도록 하겠습니다. 간단해서 보시면 금방 아! 하실수 있을것 같네염. 위 홤수와 마찬가지로 암호화와 복원이 한 함수로 이루어 지며, pwd에는 비번을 입력해 주시면 됩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;EncDecrypt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pwd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
   &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   &lt;span class=&quot;token comment&quot;&gt;// 아래 맵은 256개의 문자로 초기화 시켜 주시면 됩니다... &lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; map&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;acvkjasewr23478cxvlkjdflk2349ds8fxcv,masfkjer234&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pwd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
   &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
       map&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; pwd&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; map&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; 

   &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
      &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;data &lt;span class=&quot;token operator&quot;&gt;^=&lt;/span&gt; map&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;
&lt;p&gt;일반적으로 실질적인 보안을 생각한다면 위와 같이 직접 만든 암호화 알고리즘을 사용하는 것은 좋지 않습니다. 수학적으로 검증된 기존 알고리즘을 사용하는 것이 안전합니다. 하지만 기존 암호화 알고리즘을 공부하고 또 그것을 코드로 직접 구현하는 일이 그리 쉽진 않지요. 그럴때에는 기존에 만들어둔 라이브러리를 사용하면 손쉽게 암호화, 복호화를 하실 수 있습니다. 아래는 윈도우에 포함된 암호화 API를 사용해서 RC4 알고리즘을 이용해서 암, 복호화를 수행하는 코드를 보여주고 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;RC4 암호화 함수&lt;/strong&gt;
&lt;a href=&quot;/codewiz/assets/files/2015/rc4.cpp&quot;&gt;소스 코드 다운로드&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;//////////////////////////////////////////////////////////////////////////&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! RC4를 사용한 암호화 함수&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \param pbKey 는 암호화 하는데 사용되는 키 버퍼&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \param dwKeySize 는 암호화 하는데 사용되는 키 버퍼의 크기&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \param pbPlaintText 는 암호화 하는데 사용되는 원문&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \param pbCipherText 는 암호화 된 문장이 저장될 버퍼(원문의 크기 이상이어야 함)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \param dwHowMuch 는 암호화 하는데 사용되는 원문의 크기&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \return GetLastError의 반환값, 성공한 경우 0 리턴&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \remark 모든 버퍼는 문자열이 아닌 바이트 스트림으로 간주해야 함.&lt;/span&gt;

DWORD &lt;span class=&quot;token function&quot;&gt;Encrypt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;UCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pbKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
              DWORD dwKeySize&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
              UCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pbPlaintext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
              UCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pbCipherText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
              DWORD dwHowMuch&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    HCRYPTPROV  hProv &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    HCRYPTKEY   hKey &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    HCRYPTHASH  hHash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    DWORD       dwBuff &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; dwHowMuch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    BOOL        dwRet &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token function&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pbCipherText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pbPlaintext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dwHowMuch&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CryptAcquireContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;hProv&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
                                &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
                                &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
                                PROV_RSA_FULL&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
                                CRYPT_VERIFYCONTEXT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CryptCreateHash&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hProv&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; CALG_MD5&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;hHash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CryptHashData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hHash&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pbKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dwKeySize&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CryptDeriveKey&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hProv&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; CALG_RC4&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; hHash&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; CRYPT_EXPORTABLE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;hKey&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CryptEncrypt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pbCipherText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;dwBuff&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dwHowMuch&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; DWORD dwLastError&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        dwRet &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; dwLastError&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hKey&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;CryptDestroyKey&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hKey&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hHash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;CryptDestroyHash&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hHash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hProv&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;CryptReleaseContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hProv&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; dwRet&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;RC4 복호화 함수&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;//////////////////////////////////////////////////////////////////////////&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! RC4를 사용한 복호화 함수&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \param pbKey 는 암호화 하는데 사용되는 키 버퍼&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \param dwKeySize 는 암호화 하는데 사용되는 키 버퍼의 크기&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \param pbCipherText 는 암호화된 버퍼&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \param pbPlaintText 는 암호가 해독된 원문(암호화된 버퍼 크기 이상이어야 함)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \param dwHowMuch 는 암호화된 버퍼 크기&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \return GetLastError의 반환값, 성공한 경우 0 리턴&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \remark 모든 버퍼는 문자열이 아닌 바이트 스트림으로 간주해야 함.&lt;/span&gt;

DWORD &lt;span class=&quot;token function&quot;&gt;Decrypt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;UCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pbKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
              DWORD dwKeySize&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
              UCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pbCipherText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
              UCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pbPlaintext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
              DWORD dwHowMuch&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    HCRYPTPROV  hProv &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    HCRYPTKEY   hKey &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    HCRYPTHASH  hHash &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    DWORD       dwBuff &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; dwHowMuch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    DWORD       dwRet &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token function&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pbPlaintext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pbCipherText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dwHowMuch&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CryptAcquireContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;hProv&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
                               &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
                               &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
                               PROV_RSA_FULL&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; 
                               CRYPT_VERIFYCONTEXT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CryptCreateHash&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hProv&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; CALG_MD5&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;hHash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CryptHashData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hHash&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pbKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dwKeySize&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CryptDeriveKey&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hProv&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; CALG_RC4&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; hHash&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; CRYPT_EXPORTABLE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;hKey&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CryptDecrypt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pbPlaintext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;dwBuff&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; DWORD dwLastError&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        dwRet &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; dwLastError&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hKey&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;CryptDestroyKey&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hKey&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hHash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;CryptDestroyHash&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hHash&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hProv&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;CryptReleaseContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hProv&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; dwRet&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;RC4를 이용한 암, 복호화 테스트 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;//////////////////////////////////////////////////////////////////////////&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! 바이트 버퍼를 헥사값으로 출력하는 함수&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \param pbText 는 출력될 바이트 버퍼&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \param dwLength 는 출력될 바이트 버퍼 크기&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \return 은 없음&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//! \remark 이 함수는 출력을 완료한 후 개행함&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;PrintByte&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;UCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pbText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DWORD dwLength&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    DWORD   i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    CHAR    &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;szHexaMap &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;0123456789ABCDEF&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; dwLength&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;putchar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;szHexaMap&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;pbText&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x0f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;putchar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;szHexaMap&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;pbText&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;putchar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos; &apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;token function&quot;&gt;putchar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;\n&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; argc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; argv&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    UCHAR   szPlainText&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello World!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    UCHAR   szChipherText&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;MAX_PATH&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    UCHAR   szDecryptText&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;MAX_PATH&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    UCHAR   szKey&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;pohang&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    DWORD   dwBuffSize &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt; szPlainText&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    DWORD   dwKeySize &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt; szKey&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;PrintByte&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;szPlainText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dwBuffSize&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Encrypt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;szKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dwKeySize&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; szPlainText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; szChipherText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dwBuffSize&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;PrintByte&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;szChipherText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dwBuffSize&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Decrypt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;szKey&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dwKeySize&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; szChipherText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; szDecryptText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dwBuffSize&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;PrintByte&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;szDecryptText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dwBuffSize&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[소고] 극과 극은 통한다: 위대한 기업과 블랙 회사는 어쩌면 같은 건지도…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/14592</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14592</guid><pubDate>Fri, 22 May 2015 23:59:13 GMT</pubDate><content:encoded>&lt;p&gt;작년인지 제작년인지 알리바바가 미국 증시에 상장을 했다. 시총은 아마존을 제꼈고, 알리바바 회장인 마윈은 세계에서 손꼽히는 거부가 되었다. 걸출한 성공을 거둔 잭 마, 자본주의 사회답게 거대한 부를 축적한 그를 동경하는 눈들이 많다. 매스컴에서는 그에 관한 다큐를 제작해서 방영하기도 했다. 얼마전 페북에서는 그의 명함을 받았다고 자랑스럽게 공개하는 사람도 있었다. 그 명함 한 장이 무엇이라고… 여튼 이쯤하면 기업가치고는 스타덤에 올랐다고 할 수 있겠다.&lt;/p&gt;
&lt;p&gt;그런 그의 위대함을 조금이나 배우고자 그에 관한 다큐를 꼼꼼히 살폈다. 그러다 다소 놀라운 장면을 목격하게 되었는데 다름아닌 아래 동영상이었다. 아래 영상은 알리바바 초창기인 1999년에 마윈이 직원들에게 이야기하는 것을 녹화한 화면이다. 첫째는 뭐 나름 비전 제시라고 할 수 있겠다. 하지만 두 번째 부분에서는 정말 뿜찌 않을 수 없었다. 어떻게 저런 이야기를 얼굴 표정 하나 변하지 않고 저리도 진지하게 이야기 할 수 있을까?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;second, we need to learn the hard working spirit of Sillicon Valley. If we go to work at 8am and go home at 5pm, this is not a high tech company and Alibaba will never be successful. If we have that kind of 8am-to-5pm spirit, then we should just go and do something else.&lt;br&gt;
&lt;br&gt;
둘째, 우리는 실리콘 밸리의 워크홀릭 정신을 배울 필요가 있습니다. 만약 우리가 8시에 출근해서 5시에 퇴근한다면, 그건 높은 기술력을 가진 회사라 할 수 없습니다. 그리고 알리바바는 결코 성공하지 못할 겁니다. 만약 우리가 8시 출근, 5시 퇴근 따위의 정신을 가지고 있다면 그만두고 다른 일을 하는 것이 옳을 겁니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;위대한 기업과 블랙 회사, 사기꾼과 위대한 기업가는 같은 건지도 모른다. 진실과 거짓의 차이는 누가 더 뻔뻔하냐와 덜 뻔뻔하냐 정도의 차이밖에, 위대한 기업가와 사기꾼은 성공했냐 실패했냐 정도의 차이밖에는 없는게 아닐까라는 위험한 생각이 머릿속을 뱅뱅 헤집고 다닌다. 정말 요지경속이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./극과_극은_통한다_위대한_기업과_블랙_회사는_어쩌면_같은_건지도.md_0.jpg&apos; data-alt=&apos;실리콘밸리도 도찐개찐, 마윈 회장이 잘 배운 건지도 ㅋㅋ~&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/2ce7867184b5557024ad6d07ce6b6805/953fe/%EA%B7%B9%EA%B3%BC_%EA%B7%B9%EC%9D%80_%ED%86%B5%ED%95%9C%EB%8B%A4_%EC%9C%84%EB%8C%80%ED%95%9C_%EA%B8%B0%EC%97%85%EA%B3%BC_%EB%B8%94%EB%9E%99_%ED%9A%8C%EC%82%AC%EB%8A%94_%EC%96%B4%EC%A9%8C%EB%A9%B4_%EA%B0%99%EC%9D%80_%EA%B1%B4%EC%A7%80%EB%8F%84.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGQABAAIDAAAAAAAAAAAAAAAAAAIEAwUG/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAGdjlbJJXJj2Ioan//EABoQAAMBAQEBAAAAAAAAAAAAAAECAwATBBH/2gAIAQEAAQUCkk+QnHesAXySLgr8OixAqo6f/8QAFREBAQAAAAAAAAAAAAAAAAAAEAH/2gAIAQMBAT8BIf/EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EAB8QAAIBAwUBAAAAAAAAAAAAAAABEQIDEBIhMTJikf/aAAgBAQAGPwKiaLfB0s/R6UkvOJIeNhn/xAAcEAEAAwACAwAAAAAAAAAAAAABABEhMVEQQWH/2gAIAQEAAT8hWyVOrPYkD6IZw4l/COyh0dx3wTwfFVxS6Wz/2gAMAwEAAgADAAAAEDf3/wD/xAAYEQEAAwEAAAAAAAAAAAAAAAABABARIf/aAAgBAwEBPxAF4TYsa//EABcRAQEBAQAAAAAAAAAAAAAAAAABETH/2gAIAQIBAT8QZUXr/8QAIBABAAIBAwUBAAAAAAAAAAAAAQARMSFBURCBkbHB0f/aAAgBAQABPxB00CMVrW9Mx2y5R6qHWtCXixCoFlckVzGEtXzvBWUUjt0YKEXXibpgQf2f/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;실리콘밸리도 도찐개찐, 마윈 회장이 잘 배운 건지도 ㅋㅋ~&apos; title=&apos;&apos; src=&apos;/static/2ce7867184b5557024ad6d07ce6b6805/953fe/%EA%B7%B9%EA%B3%BC_%EA%B7%B9%EC%9D%80_%ED%86%B5%ED%95%9C%EB%8B%A4_%EC%9C%84%EB%8C%80%ED%95%9C_%EA%B8%B0%EC%97%85%EA%B3%BC_%EB%B8%94%EB%9E%99_%ED%9A%8C%EC%82%AC%EB%8A%94_%EC%96%B4%EC%A9%8C%EB%A9%B4_%EA%B0%99%EC%9D%80_%EA%B1%B4%EC%A7%80%EB%8F%84.md_0.jpg&apos; srcset=&apos;/static/2ce7867184b5557024ad6d07ce6b6805/8ccab/%EA%B7%B9%EA%B3%BC_%EA%B7%B9%EC%9D%80_%ED%86%B5%ED%95%9C%EB%8B%A4_%EC%9C%84%EB%8C%80%ED%95%9C_%EA%B8%B0%EC%97%85%EA%B3%BC_%EB%B8%94%EB%9E%99_%ED%9A%8C%EC%82%AC%EB%8A%94_%EC%96%B4%EC%A9%8C%EB%A9%B4_%EA%B0%99%EC%9D%80_%EA%B1%B4%EC%A7%80%EB%8F%84.md_0.jpg 190w,
/static/2ce7867184b5557024ad6d07ce6b6805/ea4c8/%EA%B7%B9%EA%B3%BC_%EA%B7%B9%EC%9D%80_%ED%86%B5%ED%95%9C%EB%8B%A4_%EC%9C%84%EB%8C%80%ED%95%9C_%EA%B8%B0%EC%97%85%EA%B3%BC_%EB%B8%94%EB%9E%99_%ED%9A%8C%EC%82%AC%EB%8A%94_%EC%96%B4%EC%A9%8C%EB%A9%B4_%EA%B0%99%EC%9D%80_%EA%B1%B4%EC%A7%80%EB%8F%84.md_0.jpg 380w,
/static/2ce7867184b5557024ad6d07ce6b6805/953fe/%EA%B7%B9%EA%B3%BC_%EA%B7%B9%EC%9D%80_%ED%86%B5%ED%95%9C%EB%8B%A4_%EC%9C%84%EB%8C%80%ED%95%9C_%EA%B8%B0%EC%97%85%EA%B3%BC_%EB%B8%94%EB%9E%99_%ED%9A%8C%EC%82%AC%EB%8A%94_%EC%96%B4%EC%A9%8C%EB%A9%B4_%EA%B0%99%EC%9D%80_%EA%B1%B4%EC%A7%80%EB%8F%84.md_0.jpg 500w&apos; sizes=&apos;(max-width: 500px) 100vw, 500px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;실리콘밸리도 도찐개찐, 마윈 회장이 잘 배운 건지도 ㅋㅋ~&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 윈도우 10 버전 구하기]]></title><description><![CDATA[윈도우 XP 시점인가를 기점으로 VerifyVersionInfo라는 함수가 생겼다. 등록 정보에서 호환성 모드를 설정한 경우에 GetVersion/GetVerionEx…]]></description><link>https://jiniya.net/wp/archives/14774</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14774</guid><pubDate>Thu, 23 Apr 2015 23:59:12 GMT</pubDate><content:encoded>&lt;p&gt;윈도우 XP 시점인가를 기점으로 VerifyVersionInfo라는 함수가 생겼다. 등록 정보에서 &lt;a href=&quot;http://jiniya.net/tt/25&quot;&gt;호환성 모드를&lt;/a&gt; 설정한 경우에 GetVersion/GetVerionEx 함수가 페이크 값을 리턴하면서 원본 값을 구하기 위해서 생긴 함수였다. 근데 이게 윈도우 10 되면서 또 무용지물이 되었다.&lt;/p&gt;
&lt;p&gt;윈도우 10부터 매니페스트에 윈도우 10을 타겟으로 컴파일되지 않은 바이너리는 GetVersion/GetVersionEx/VerifyVersionInfo 모두 페이크 값을 전달하도록 변경됐기 때문이다. 이뭐병 ㅠㅜ~&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Applications not manifested for Windows 8.1 or Windows 10 Technical Preview will return the Windows 8 OS version value (6.2). Once an application is manifested for a given operating system version, GetVersionEx will always return the version that the application is manifested for in future releases. To manifest your applications for Windows 8.1 or Windows 10 Technical Preview, refer to Targeting your application for Windows.&lt;/p&gt;
&lt;p&gt;– &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx&quot;&gt;https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451(v=vs.85).aspx&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;원본 값을 구하고 싶은 경우에는 &lt;a href=&quot;https://github.com/DarthTon/Blackbone/blob/master/contrib/VersionHelpers.h&quot;&gt;VersionHelpers.h&lt;/a&gt;에 포함된 IsWindows10OrGreater 함수를 사용하면 된다. 결국은 RtlGetVersion 이라는 함수를 사용해서 버전을 구하는 꼼수를 보여주고 있다. 이 무슨 병신같은 시츄에이션인지 ㅠㅜ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[시스템] 슬랙 윈도 네이티브 애플리케이션 폰트 변경하기]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/14752</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14752</guid><pubDate>Thu, 26 Mar 2015 23:59:11 GMT</pubDate><content:encoded>&lt;p&gt;그간 윈도 환경에서 슬랙은 네이티브 앱이 없고 크롬 확장으로 사용해야 해서 다소 불편함이 있었습니다. 그런 불편함을 알았는지 드디어 슬랙에서 윈도 네이티브 프로그램을 &lt;a href=&quot;https://wellbia.slack.com/apps&quot;&gt;절찬리 배포하기&lt;/a&gt; 시작했습니다. 반가운 마음에 깔아보았는데 시작부터 이건 비주얼에 큰 실망을 안겨주는 군요 ㅠㅜ~ 안타깝게도 폰트 설정을 찾아보았으나 쉽게 찾을 수가 없었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./슬랙_윈도_네이티브_애플리케이션_폰트_변경하기.md_0.png&apos; data-alt=&apos;폰트 이건 아니잖아~&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 576px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/e90f94b184e83a6b06caddb27ce4b2be/694da/%EC%8A%AC%EB%9E%99_%EC%9C%88%EB%8F%84_%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C_%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98_%ED%8F%B0%ED%8A%B8_%EB%B3%80%EA%B2%BD%ED%95%98%EA%B8%B0.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 66.84210526315789%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABmElEQVR42pWRzWrCQBSF85Au9AHEjYgIoi5c+AyCWxFcuap02y6EgnSh4EJKrbXmrzEzJjPJZDL5qabXBKQtCvYskjvn3m84yZWeH++eHu5lfbd+3xKHU0+I8MsPYiZiLmLXD7mIjsfkoiRTXcvrF+oFFmEA76lHHC8tuEW5zQTwxyu0lL0I8xXkIMq3iL7plrZ3ZER9EV5ksrvgKR1TWYRuZE1R9a2qbRRNVrXX9censcN4bxiGqmoIIYxOMhF2HIdSSgiRsjuCIADHtgl44Huet8eYcw5Dtm1no4y5tm1R5v2KDXAcxz8j7UxztVqZpnkt8wU4azDGFEWBAgJblvU/2HXdxWKxXC673W6lUpnP52AeDoebYIxxu91utVrNZrNQKAwGg5tgUBRF/X6/0Wh0Op1arZbL5er1+mw2O/MX4CiKM17X9VKpVC6Xq9VqsVjM5/NwnEwm0IKBQ6q/cBCEsC3YDSxmPB73er3hcDgajaCeTqfw52BbsD/f9yHaXziMTgIe2kIIKMJUqR35qcCE1vkDkyT5Bs+kzRsAgIbuAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;폰트 이건 아니잖아~&apos; title=&apos;&apos; src=&apos;/static/e90f94b184e83a6b06caddb27ce4b2be/694da/%EC%8A%AC%EB%9E%99_%EC%9C%88%EB%8F%84_%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C_%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98_%ED%8F%B0%ED%8A%B8_%EB%B3%80%EA%B2%BD%ED%95%98%EA%B8%B0.md_0.png&apos; srcset=&apos;/static/e90f94b184e83a6b06caddb27ce4b2be/08678/%EC%8A%AC%EB%9E%99_%EC%9C%88%EB%8F%84_%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C_%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98_%ED%8F%B0%ED%8A%B8_%EB%B3%80%EA%B2%BD%ED%95%98%EA%B8%B0.md_0.png 190w,
/static/e90f94b184e83a6b06caddb27ce4b2be/2edd7/%EC%8A%AC%EB%9E%99_%EC%9C%88%EB%8F%84_%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C_%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98_%ED%8F%B0%ED%8A%B8_%EB%B3%80%EA%B2%BD%ED%95%98%EA%B8%B0.md_0.png 380w,
/static/e90f94b184e83a6b06caddb27ce4b2be/694da/%EC%8A%AC%EB%9E%99_%EC%9C%88%EB%8F%84_%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C_%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98_%ED%8F%B0%ED%8A%B8_%EB%B3%80%EA%B2%BD%ED%95%98%EA%B8%B0.md_0.png 576w&apos; sizes=&apos;(max-width: 576px) 100vw, 576px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;폰트 이건 아니잖아~&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;혹시나 방법이 있나 싶어서 구글신에게 물어보았더니 친절한 &lt;a href=&quot;http://blog.hinaloe.net/2015/03/24/change-font-of-slack-for-windows/&quot;&gt;일본 블로그에서&lt;/a&gt; 해결 방법을 찾을 수 있었습니다. 아래 방법대로 하면 폰트를 변경하실 수 있습니다.&lt;/p&gt;
&lt;p&gt;node-js깔고 아래 명령어를 치면 app.extract 디렉터리에 소스 코드가 풀립니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;npm install -g asar
cd %LOCALAPPDATA%/slack/app-1.0.0/resources
asar e app.asar app.extract&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;압축 풀린 디렉터리에 가서 “/src/ssb/app.js” 파일을 열어 보면 아래와 같은 부분이 있습니다. ko-KR이 아니라 ja-JP로 되어 있습니다. 그 부분을 아래와 같이 고쳐주면 됩니다. MS PGothic 찾아서 죄다 앞에다 원하는 폰트를 적어주면 됩니다. 저는 Malgun Gothic으로 설정했습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;layouts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ko-KR&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Figure out what the default font family for messages currently is&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; fontFamily &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cssom&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fontFamily&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&apos;Lato&apos;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Lato&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                       &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Lato,&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Lato, Malgun Gothic, MS PGothic,&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;수정 다 했으면 &quot;asar p app.extract app.asar&quot; 명령어를 입력해서 파일을 다시 패키징해주면 됩니다. 그리고 슬랙을 껐다 키면 아름답고 미려한 폰트를 구경하실 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./슬랙_윈도_네이티브_애플리케이션_폰트_변경하기.md_1.png&apos; data-alt=&apos;바로 이거죠~&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 578px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/1d87f7602d6628e614e3eb56298afa2c/8c7b4/%EC%8A%AC%EB%9E%99_%EC%9C%88%EB%8F%84_%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C_%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98_%ED%8F%B0%ED%8A%B8_%EB%B3%80%EA%B2%BD%ED%95%98%EA%B8%B0.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 67.89473684210526%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAIAAACgpqunAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABzElEQVR42o1TO4/iMBDmX1KAqKCgQAhEQ0VBgWj4BUh0Jzp0HRI6CkpaKHaB1cp5OySbF3bsPG+c3LLc7Z7uvsTSeMbffM7MpIJenl3X0VSVMR7HcZZleZ6L9R+o/Pj+zbB8ScWm7ZvO7c2jbsAsj1xdarwR3SaUxZBNIC+e0izJsGjILde/OgG82tU1LM90AscnURQVjL8rw/ICcpYxMuxX1XpC+CSZz0g3LIeFIaWUkFsQBIVBwEFu4BBgjAkybAxdU2RJlSVNVTA2FBmZpqECFEWWZQkhXddME4Pt+YHIKRKFFfgAHgmEBSAf55FlWb7vc85ZyIooF96IE0qTNP24NpAhWG7KSoDe5XJBCEGuu/N+IEvT7DO5PARq5/MZDIzxZrORJEmE0l+VToH5kOsL5e12u1wuZ7NZrVYbj8eP+o99+kLZ87zJZNLtdkejUaPR6Pf7p9Pp3+QS8/l8MBgAczgcVqvVVqs1nU5h8u7MP8lQRwhDCmgmyDabzV6v1+l06vV6u91eLBZwc6gFnEmS5BMZWsIYzAC053A4rFar9Xq92+32+/3xeNQ0zbZt+JxiSML0t1bleVwAlCFF+W8k7yid/B3FwH4o/wR66gVag1uZuwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;바로 이거죠~&apos; title=&apos;&apos; src=&apos;/static/1d87f7602d6628e614e3eb56298afa2c/8c7b4/%EC%8A%AC%EB%9E%99_%EC%9C%88%EB%8F%84_%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C_%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98_%ED%8F%B0%ED%8A%B8_%EB%B3%80%EA%B2%BD%ED%95%98%EA%B8%B0.md_1.png&apos; srcset=&apos;/static/1d87f7602d6628e614e3eb56298afa2c/08678/%EC%8A%AC%EB%9E%99_%EC%9C%88%EB%8F%84_%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C_%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98_%ED%8F%B0%ED%8A%B8_%EB%B3%80%EA%B2%BD%ED%95%98%EA%B8%B0.md_1.png 190w,
/static/1d87f7602d6628e614e3eb56298afa2c/2edd7/%EC%8A%AC%EB%9E%99_%EC%9C%88%EB%8F%84_%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C_%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98_%ED%8F%B0%ED%8A%B8_%EB%B3%80%EA%B2%BD%ED%95%98%EA%B8%B0.md_1.png 380w,
/static/1d87f7602d6628e614e3eb56298afa2c/8c7b4/%EC%8A%AC%EB%9E%99_%EC%9C%88%EB%8F%84_%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C_%EC%95%A0%ED%94%8C%EB%A6%AC%EC%BC%80%EC%9D%B4%EC%85%98_%ED%8F%B0%ED%8A%B8_%EB%B3%80%EA%B2%BD%ED%95%98%EA%B8%B0.md_1.png 578w&apos; sizes=&apos;(max-width: 578px) 100vw, 578px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;바로 이거죠~&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[일상] 좋은 날]]></title><description><![CDATA[#0 2014. 12. 19. FRI, 회사 창업하고 처음으로 직원들에게 인센티브가 지급됐다. 만으로 꼭 8년 하고도 3개월 정도가 된 시점. 생각보다 오래 걸렸고, 생각보다 오래 걸렸다. 26살에 처음 창업 대열에 끼어들던 나는 한…]]></description><link>https://jiniya.net/wp/archives/14481</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14481</guid><pubDate>Fri, 13 Feb 2015 23:59:10 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/9X5Kcr8hXmI?si=BnXyFyqlXv-38k6u&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;2014. 12. 19. FRI, 회사 창업하고 처음으로 직원들에게 인센티브가 지급됐다. 만으로 꼭 8년 하고도 3개월 정도가 된 시점. 생각보다 오래 걸렸고, 생각보다 오래 걸렸다. 26살에 처음 창업 대열에 끼어들던 나는 한 3년 하면 성공할 줄 알았었다. 지금 대표를 하고 있는 형은 처음 대표로 취임하던 날 2년만 해보자는 이야기를 했었다. 우리는 너무 어렸고, 너무 쉽게 생각했다. 그래서 그런지 예측은 다 빗나갔다. 3년이 지났을 땐 5년 정도 하면 성공할 줄 알았다. 5년이 지났을 땐 더 이상 날짜를 기약하지 않게 되었다. 나이도 들었고, 목표 보다는 과정을 보는 눈도 생겼기 때문이다. 어쨌든 그런 희망고문 같은 판타지가 우리를 버티게 해주었는지도 모를 일이다. 우리는 매일같이 쪽팔리지 말자, 좋은 날이 올거야, 라는 말을 주문처럼 외우면서 살았다.&lt;/p&gt;
&lt;p&gt;인센티브가 지급되던 장면은 나에겐 약간 아이러니하게 느껴졌다. 왜냐하면 그 자리에서 인센티브를 받고 기분 좋아하는 직원들이 아닌 그 자리에 있었어야 할, 하지만 있지 못하는 사람들이 떠올랐기 때문이다. 짧은 의식같은 행사가 끝났을 무렵 내 머릿속에 가장 먼저 떠오른 것은 안나 카레니나의 첫 문장이었다. 왠지 이 문장이 지금의 모든 분위기를 대변하는 것 같다는 느낌이 들어서였다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;All happy families are alike; each unhappy family is unhappy in its own way.&lt;br&gt;
&lt;br&gt;
행복한 가정은 서로 닮았지만, 불행한 가정은 모두 저마다의 이유로 불행하다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;– 안나 카레니나, 톨스토이&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;회사를 하면서 내가 기억하는 핵심 장면들이 몇 있다. 첫 번째 장면은 2007년 초, 우리가 처음 게임 보안 제품을 만들기로 한 날이었다. 모 게임사에서 펀딩을 해서 시작하게 된 사업이었는데 지금도 별볼일 없는 우리를 믿고 투자해준 그 회사가 신기할 따름이다. 나는 이 일을 우리 회사에 있어서 가장 큰 빅딜이었다고 생각하는 편이다. 지금 대표인 형이 그 계약을 성사시켰는데, 그 공로를 인정 받아(?!) 이듬해 우리 회사의 두 번째 대표가 되었다.&lt;/p&gt;
&lt;p&gt;두 번째 장면은 2008년 중순, 우리가 만든 제품으로 처음 매출을 올린 날이었다. 지금 생각해보면 참 조촐한 첫 매출이었지만 통장에 외화가 꽃혔다는 이유로 우리는 즐거워하며 회식을 했었다.&lt;/p&gt;
&lt;p&gt;세 번째 장면에 오늘을 포함시키기로 했다. 얼마가 됐든 약속한 것보다 조금이라도 더 줄 수 있다는 게 쉬운 일이기도 하고, 어려운 일이기도 하다. 그러나 어쨌든 그런 일이 처음이기도 하고 회사가 여기까지 잘 도착했다는 사실이 대견하기도 한 것 같아 포함시키기로 했다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;이상하게도 이 좋은 날 옛날 생각이 많이 떠올랐다. 제품 소개차 나간 미팅 자리에서 제품이 엣지 없다는 소리를 들었던 날도 있었고, 제품은 좋은데 검증이 안 된 것 같다며 레퍼런스를 확보하고 오라는 이야기를 들었던 날도 많았다. 회사가 망하면 어쩌냐는 소리를 들었던 수많은 자리가 있었고, 세번씩이나 똑같은 업체에 미팅을 하고는 돌아오는 차 안에 난데없이 거미가 나타난 적도 있었다. 더 어처구니없게도 우린 그걸 보며 이게 아침 거미인지 밤 거미인지 하면서 미신을 뒤적거리며 그 업체와 계약이 될지 안 될지를 점치기도 했었다. 정말 좋은 기회라고 싱글벙글하면서 나간 미팅 자리가 우리를 음해하는 세력이 꾸민 장례식 자리가 됐었던 어처구니 없는 상황도 있었다. 참 많은 일들이 있었다.&lt;/p&gt;
&lt;p&gt;향수에 젖어서는 예전 일기장을 뒤적거려 보았다. 난 특이하게도 힘들면 일기를 쓰는 습관이 있는데, 회사를 하면서는 2010년, 2011년 일기가 많다. 회사를 하고 제법 시간이 흐르기도 한데다 그 당시에는 마치 모든 일이 멈춰버린 것 같은 상황들이 많았기 때문이었다. 꿈틀거릴수록 뭔가 점점 더 나빠지는 느낌들이 나를 엄습했던 시기이기도 했다. 어쨌든 그래서 그 당시에는 제법 부지런히 일기를 썼었다. 다시 살펴보니 회사도 나도 귀엽기도 하고 깜찍하기도 하고 그렇다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;2010. 01. 27. WED&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;
그날 밤을 새며 M과 둘이서 HACK.DLL을 분석했지만 답을 찾지 못했다. 사실 분석에 있어서는 우리 둘 다 초보였다. 우리는 Themida로 패킹된 프로그램을 디버깅 하는 방법도 Yoda Crypter로 패킹된 DLL을 언팩하는 방법도 몰랐다. 닥치고 초보였던 것이다. 그러면서 사내에 이런 교육이 절실하다는 사실을 깨닫게 되었다. 게임 보안 제품을 만드는 회사에서 해킹툴 DLL을 분석할 수 있는 사람 한 명 없다니, 이 얼마나 아니러니 한 사실인가? 좀 쪽 팔리는 사실이기도 했다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2010. 01. 28. THU&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;
저녁에는 K가 첫 월급 턱이라고 밥을 샀다. 개발팀, QA팀 합해서 7명이 가서 순두부를 먹었다. 3명이었던 팀원이 갑자기 이렇게 늘어나니 관리가 통 안된다는 생각이 들었다. 물론 이제는 회식을 한 번 하기에도 부담스러운 인원이 된 것은 두말할 필요도 없다. 팀이 점점 나의 손을 떠나는 느낌이 많이 든다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;요즘은 회사의 느낌이 죽 끓이는 것 같다는 생각을 많이 한다. 마치 사인 곡선처럼 좋았다, 나빴다를 반복하는 것이다. 어쩌면 나 스스로 점점 더 자신감을 잃어가는 과정은 아닌지 모르겠다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2010. 01. 30. SAT&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;
거의 밤을 새우다 싶이 하고는 오후 2시에 퇴근을 했다. H도 밤샘 작업이 있다고 그때 마친다고 했기 때문이었다. 결국 HACK.DLL 분석 작업 마무리를 못했다. 월요일에 T에게 헬프 메일을 보내야겠다. 찜찜한 기분으로 집으로 왔다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;엉망진창인 집. 내 생활의 한 조각, 아니 전부를 보여주는듯 했다. 내 방은 엉망진창이고, 그건 내 생활 또한 엉망진창이라는 것을 나타내기 때문이다. 일주일을 돌아본다. 내가 이 방에서 한 일이라곤 쓰러져 몇 시간 잠을 자고 씻고 출근하는 것이 전부였다. 온통 양말과 수건으로 널부러진 방을 보기만 해도 머리가 아팠다. 정리가 필요했다. 이 방에도, 내 삶에도…&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2010. 02. 21. SUN&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;
느즈막히 출근을 했다. 어제 작업하던 V 모듈 마무리 작업이 있었다. CDN에서 N 코드를 다운로드 받아서 실행하는 부분을 추가할 계획이었다. 작업을 하려고 PC를 켜고 Visual Studio를 정리했다. 그러고는 늘상 하듯이 브라우저를 켜고 모니터링 사이트를 방문해 보고는 했다. 그러다 엄청난 사실을 알게 되었다. XIGNCODE로 영문 위키 페이지가 생성되어 있는 것이었다. 물론 내용은 안습이었다. 최악의 보안 프로그램이다. 막는게 하나도 없다와 같은 이야기였다. 조금 충격적이었다. 사실 많이 충격적이었다. 나중에 다시 보니 페이지는 지워지고 없었다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;최고의 보안 제품을 만들겠다는 일념으로 3년을 넘게 달려왔다. 그런데 ‘worst anti cheat’라는 수식어라니. 자존심이 좀 상하기도 하고, 좀 얼떨떨 하기도 하고 그랬다. 한동안은 코딩도 못했다. 이내 마음을 다잡았다. 아직 갈 길이 많이 남았다는 생각을 했다. 그래도 유저들이 우리 제품을 인식하고 있다는 긍정적인 신호로 받아들이기로 했다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2010. 02. 23. TUE&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;
엄청난 하루였다. 어제 수정한 V 모듈이 오늘 패치된 것이다. 패치는 정말 감동 그 자체였다. 커뮤니티에는 핵이 완전히 사라졌다고 좋아하는 글들이 올라왔고 핵의 숙주인 DG에는 빨간불이 들어왔다. N 코드는 의외로 별 문제 없이 잘 동작했다. 그런데 문제는 V 모듈에 있었다. 새롭게 추가한 DirectX 훅 체크 코드의 if문이 엉뚱하게 붙어 있었던 것이다. else if가 되어야 하는데 독립 if문으로 해버린 사소한 실수였다. 그 덕분에 게임 스트리밍 서비스를 사용하는 많은 정상 유저가 끊기는 일이 발생했다. 코드를 고치는 것은 간단했지만 실제 업데이트에 적용 되러면 얼마간 시간이 걸릴 것으로 보인다. 다시한번 실시간 업데이트의 필요성을 절감했다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;center&gt;
![](./x3beta4.png)  
**가장 힘들었던 그해 6월, 우리의 세번째 판올림 XIGNCODE3 베타 버전이 나왔다.**
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 347px; margin-bottom: 16px;&apos; data-url=&apos;./x3health.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/374165dfe39289402db882259528a27b/c8500/x3health.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 53.68421052631579%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABWElEQVR42n1RS07DMBTs2ViyYsFZWHIAWHABlpyBj7gDEpuWNh8nTk3SJv7EduzUcRqcRAVaqRlZtmW98cybN5MlZ4wVaU4xs227H9B1nTEGY1wyRglRSgrBK1mlWUYwpg6EaK1ntCAJiMEyggB1A0aylBKtExAEMIZFsXUlnrcCYRT4XhxBzkVPxnkBQZyibPO9lUyQgu2McWSt1RpCZ0opXdfaXRilTrwsmRBylJkV6Wb+uQj9ACXIn3vewt9kOcldhYhB1DS2O49ZXSmKaVmWSilGmTO5higOoyzLkiQxg4shhr6Xfb/Gtgby/5/cswsphhBzjtIUIWTtpPL+gO6Qc2ebdvlluDDWurSdqT+tE/KRctsXvX2g1cWlvb7ayUrVtaqqs8pH5GG/fw5v7l6fbh8FLn8nN0VumsbNghC6q9Uc5A8vwbvHxximeh6Ptm31gOmETsg/FlJ011ZnpjQAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;x3health&apos; title=&apos;&apos; src=&apos;/static/374165dfe39289402db882259528a27b/c8500/x3health.png&apos; srcset=&apos;/static/374165dfe39289402db882259528a27b/08678/x3health.png 190w,
/static/374165dfe39289402db882259528a27b/c8500/x3health.png 347w&apos; sizes=&apos;(max-width: 347px) 100vw, 347px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;근 2년간 700번의 새로운 엔진 빌드. 우리는 거의 매일 새로워졌다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 572px; margin-bottom: 16px;&apos; data-url=&apos;./xx3.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/25941b5ad33f9ac0308250c2642837f6/698d8/xx3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 32.10526315789474%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAA7CAAAOwgEVKEqAAAAA8ElEQVR42mWPTU8DIRCG+f9/oAcPXoyJmujNgzWe6sHEeFa7i223+0VZCwvsgPuBA1oT0yeTl2GS92Ugi5vL54drxlmel/WOCymbvWiV0toAgOkCFgFrtDF4Bwgj00EHZHFxdX92mhdlts5W602WbSldpSlNE4oNpR/LJMm3xfvbsq6ZEFIpJWVQTCcemTxYpzuYfhhDjZFDE4fT5P9DtBYOWovLgO2HsR+QcYiOEDv5P0cMiuHj7xPk9mQ2P58xvivLGquoKlyvqhnnTdN84p57IbDDz/ojyOvj08vdXMhWGfN1wLmgNh4o1rq+H47N339qUyQgE6K6AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;xx3&apos; title=&apos;&apos; src=&apos;/static/25941b5ad33f9ac0308250c2642837f6/698d8/xx3.png&apos; srcset=&apos;/static/25941b5ad33f9ac0308250c2642837f6/08678/xx3.png 190w,
/static/25941b5ad33f9ac0308250c2642837f6/2edd7/xx3.png 380w,
/static/25941b5ad33f9ac0308250c2642837f6/698d8/xx3.png 572w&apos; sizes=&apos;(max-width: 572px) 100vw, 572px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./x3rep.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/dde73cdd1630e472ec230cecfe155474/dface/x3rep.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 83.15789473684211%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAIAAABSJhvpAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACO0lEQVR42m2TiXKiQBCGff83i9lKRKMIgoICIvc1g6Am+w2zcY/aLqqrmem/++9jZmkz8J1yGRXqs8+dG4tGDp+Pxzje7vf77ab057d8/SGzLM+DMIrTPCuqumllfxVCNm0rpazrGt22bd/3X/+TmRQiCsM8z0TXjePQS3m9XvEehkEIgQFea37Rf4Evl4vjOMfjMQiC8/m83+8PhwO/SZKgPc/b7ewgCLl1XRfnx+PxGxxFEae4nk4nDH7xA4ZflmVo3/cJgQNxOfk3s2ma8STkxGmE/TDQJ/jrmruug7mY5Pu8p3kzChKyb5qGC061h66NuJZl7ZQ4m42J7boU5VmW7Tju1DApcSItBcOZzBiccFcU5cfHer3evL8vXl7m4JfL5evrD2zP8xUYhkVRVFVZVRW2HizEuSvLcrvdhmEE7Zoxtl3TtHBM0wzaCkxBVV3neZ6mKReEqKdfSgjDEKr0j55BnY5MzF16RBoFphP0kCRwTicBCXMqB2wYBslXqxWGNQnMF4uFHhi06e6oF1BrTrWmflw1GIN1eEbBU4FJRAchRuYTDI9HBg4R7jRtYGBs2yYKo0bD/FfmJAj2rssaBKtVYBj+29t+Ps89jzvIK7CxpEidHLcNTTdNmqrAse9fptkk01cWRZokbDvDKyaheF7YfXpbWp4bOjvHMavrHTwIB2FIbGhTHsxH1Q+1asxuuA567W680ye4qUs9xk7wrpRUJTNXh+AZHvNleGmSlmXRNHVd1YTU4J8HJa9dLR9xHwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;x3rep&apos; title=&apos;&apos; src=&apos;/static/dde73cdd1630e472ec230cecfe155474/dface/x3rep.png&apos; srcset=&apos;/static/dde73cdd1630e472ec230cecfe155474/08678/x3rep.png 190w,
/static/dde73cdd1630e472ec230cecfe155474/2edd7/x3rep.png 380w,
/static/dde73cdd1630e472ec230cecfe155474/dface/x3rep.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./xx8.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a65c57e968dbb325f2ec7a09e1fbb40a/dface/xx8.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 23.684210526315788%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAIAAADKYVtkAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAvklEQVR42j1Pyw6DMAzj/79uQ+wMzatpGZvUTsAuMNPDrKhN6tpJujlnFUHknOd5joAZSndXNfdkKFVzSjG6gzNjUYtxeb06ARcjo3S/CCZRxQmxiHADZMLUXEQoxDAt7t9t67jvdRio7024iS8JfnETonkIIaVEHKC8Ok6TDo9wvy1mnRIhjIiJMPI4jlBRA2wwMJpBD99rt0Zh0uf7ve07xlZPCY5Y+QPUiqOUgru2vL3VWso/39b1OI7zPH9UHg9p5K/MPQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;xx8&apos; title=&apos;&apos; src=&apos;/static/a65c57e968dbb325f2ec7a09e1fbb40a/dface/xx8.png&apos; srcset=&apos;/static/a65c57e968dbb325f2ec7a09e1fbb40a/08678/xx8.png 190w,
/static/a65c57e968dbb325f2ec7a09e1fbb40a/2edd7/xx8.png 380w,
/static/a65c57e968dbb325f2ec7a09e1fbb40a/dface/xx8.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 464px; margin-bottom: 16px;&apos; data-url=&apos;./xx91.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/9e8fbb1c60839a9ae26193ae369eca47/0359b/xx91.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 45.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABUElEQVR42o1R2W6DQAzk/3+vraIqsPe9wC6QbMKVdIhaVX3rWAJLnvGO7epyLb7Nrh2GcZqmS87per2uB5ZlPeL4vDDP8/qdHti2rTJGnc+1NVopqbVumpoQLgRnlDLOCNAQC5KUpGkoJagQimgY45XgvD7X0AguPk8nxjkBp6mbcy2EQIuP9zd6yBi8XS7TNE7DOA7DkNJQdW0rpdRKGmvxMmUUFqwzAKdMKw1PeBNdQvQGFGNgE5Kcx6qNwVnr4cxAK/F3FiMoMOCOMYYCDDBG0SZ63/e9Q83oW7lX1kUujTJeSEO5FspJbQhT1nksL6fUdx0EMQbYfv5FlfLY9qlPGKjc7uvtvszLVm5Y9X7UH79UpI8ffItLKbhWHkueyrptOMY837d9f/4DFa4aMLYL2liHaY51WB9iG8I0Dh4ZIoTU9z6Ermuxmhjj/ur+BRPw9J4cdE1EAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;xx91&apos; title=&apos;&apos; src=&apos;/static/9e8fbb1c60839a9ae26193ae369eca47/0359b/xx91.png&apos; srcset=&apos;/static/9e8fbb1c60839a9ae26193ae369eca47/08678/xx91.png 190w,
/static/9e8fbb1c60839a9ae26193ae369eca47/2edd7/xx91.png 380w,
/static/9e8fbb1c60839a9ae26193ae369eca47/0359b/xx91.png 464w&apos; sizes=&apos;(max-width: 464px) 100vw, 464px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 620px; margin-bottom: 16px;&apos; data-url=&apos;./x3s.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/992cbbd84811e49ffea562a134185d62/abf7b/x3s.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 26.31578947368421%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAIAAADKYVtkAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAA7ElEQVR42h3NYU+EMAwG4O2QjQGDjbGt2wAxknheTjxBz/jB//+3LDZPmrbJm5Kn5O4v8vdS/JzFOnPBHgRH2dHzU8EOuJbHJeM5RYLRktGKU5KsWuawPMIy+ecxjNFHsGOEBDaBm1LwfZeCG4KbByj5CcPFfx4R8M0Ytbc1WBl8E70MToKrcUApqAHaBG3wkuUZpQSdKGEZqfHz9dy9vXbrRX9czbbabe139O4+0c3ft7Cv9uvmt9VVJS+KgnMuhKhLIStGxmn53pcA0LRGa6t1r5QxxuPcKiulUq3pjFfKGtOnGJ2zEQsDVv8BDREXihIMZXwAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;x3s&apos; title=&apos;&apos; src=&apos;/static/992cbbd84811e49ffea562a134185d62/abf7b/x3s.png&apos; srcset=&apos;/static/992cbbd84811e49ffea562a134185d62/08678/x3s.png 190w,
/static/992cbbd84811e49ffea562a134185d62/2edd7/x3s.png 380w,
/static/992cbbd84811e49ffea562a134185d62/abf7b/x3s.png 620w&apos; sizes=&apos;(max-width: 620px) 100vw, 620px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;그리고 우리가 얻은 것: ‘worst anti cheat’에서 조금은 자부심을 가질 만한 평가들&lt;/strong&gt;  &lt;/center&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;세상에 &lt;a href=&quot;http://www.woowahan.com/?page_id=6104&quot;&gt;훨씬 더 좋고&lt;/a&gt; &lt;a href=&quot;http://www.jennifersoft.com/docs/jennifersoft-jobs.html&quot;&gt;훨씬 더 대단한&lt;/a&gt; 회사들이 많이 있다. 대단하지 않은 작은 성취지만 기분 좋은 마음에 몇 자 끄적여 봤다. 왜냐하면 난 용뼈를 먹고도 뛸듯이 좋아했던 사람이니까… 거기에 비하면 이건 훨씬 더 대단한 일 아닐까낭?!…&lt;/p&gt;
&lt;center&gt;
![](./wow.png)  
**이 별거도 아닌 아이템 하나 먹고 난 세상을 다 가진 줄 알았었다.**
&lt;p&gt;&lt;strong&gt;와우에 적용될 그 날을 기다리며…&lt;/strong&gt;&lt;/center&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 방어적 프로그래밍]]></title><description><![CDATA[위와 같은 코드를 줬더니 그대로 사용해서 “buffer[written] = ‘\0′;” 구문에서 written이 MAX_BODY_CONTENT보다 크면 어쩌냐는 이야기를 했다. 그랬더니 dn->ToBuffer 함수가 실패한 경우에도 written…]]></description><link>https://jiniya.net/wp/archives/14694</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14694</guid><pubDate>Thu, 12 Feb 2015 23:59:09 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HRESULT &lt;span class=&quot;token function&quot;&gt;SomeFunc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;

	SIZE_T written&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;vector&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;xch&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MAX_BODY_CONTENT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	HRESULT hr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; dn&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ToBuffer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;written&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SUCCEEDED&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; hr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;written&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token char&quot;&gt;&apos;\0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위와 같은 코드를 줬더니 그대로 사용해서 “buffer[written] = ‘\0′;” 구문에서 written이 MAX_BODY_CONTENT보다 크면 어쩌냐는 이야기를 했다. 그랬더니 dn-&gt;ToBuffer 함수가 실패한 경우에도 written에 값이 저장되냐는 둥, 소스가 더 커도 실제 크기가 written에 넘어오냐는 등의 질문을 한다.&lt;/p&gt;
&lt;p&gt;dn-&gt;ToBuffer 함수가 어찌 동작하든 간에 if문 하나만 추가하면 안전해지는 문제 아니냐는 말을 했더니 기어코 소스 코드를 찾아내서는 그렇게 반환하는 경우는 없는것 같다고 궁시렁거리는 신입 프로그래머의 패기. dn-&gt;ToBuffer 함수가 내일 동작이 바뀌어서 그런 값을 반환하면 어쩔거냐고 했더니 그제서야 if문을 추가한다.&lt;/p&gt;
&lt;p&gt;다른 함수에 불필요한 가정을 추가하지 말자. 불필요한 가정이 필요하다면 그 가정이 사실인지 반드시 확인하자 (ASSERT가 됐든 if가 됐든). 그리고 다른 함수가 정상 동작할 거라는 일말의 기대도 하지 말자.&lt;/p&gt;
&lt;p&gt;돈을 받고 갈켜줘도 시원찮을 판에 월급 주며 갈켜주는데도 엉뚱 소리를 하니 속에 천불이 ㅠㅜ~&lt;/p&gt;
&lt;p&gt;참 갑갑한 현실…&lt;/p&gt;
&lt;center&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; margin-bottom: 16px;&apos; data-url=&apos;./[플밍노트]_방어적_프로그래밍.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/abebf59db012b5e1939bae0dbfc9cfdb/953fe/%5B%ED%94%8C%EB%B0%8D%EB%85%B8%ED%8A%B8%5D_%EB%B0%A9%EC%96%B4%EC%A0%81_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 66.31578947368422%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMEBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAGtcS4rMor/xAAeEAABAwQDAAAAAAAAAAAAAAABAAIDBBESExQiMf/aAAgBAQABBQLfZSVJaea9E9pDmfF//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGhABAAIDAQAAAAAAAAAAAAAAAAExETJBYf/aAAgBAQAGPwJs4pM+Ky//xAAbEAEAAwADAQAAAAAAAAAAAAABABEhMUFhkf/aAAgBAQABPyGulAiKumZKOviFUQnNRmM8QQUn0z//2gAMAwEAAgADAAAAEMvf/8QAFREBAQAAAAAAAAAAAAAAAAAAEDH/2gAIAQMBAT8Qh//EABYRAAMAAAAAAAAAAAAAAAAAAAEQIf/aAAgBAgEBPxAVf//EABwQAQEBAAIDAQAAAAAAAAAAAAERADFhIXGBwf/aAAgBAQABPxBKcAXvDhLDFDlUp3pRJnsnjC+SEBxGfuvk/Tf/2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                 md 0&apos; title=&apos;&apos; src=&apos;/static/abebf59db012b5e1939bae0dbfc9cfdb/953fe/%5B%ED%94%8C%EB%B0%8D%EB%85%B8%ED%8A%B8%5D_%EB%B0%A9%EC%96%B4%EC%A0%81_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D.md_0.jpg&apos; srcset=&apos;/static/abebf59db012b5e1939bae0dbfc9cfdb/8ccab/%5B%ED%94%8C%EB%B0%8D%EB%85%B8%ED%8A%B8%5D_%EB%B0%A9%EC%96%B4%EC%A0%81_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D.md_0.jpg 190w,
/static/abebf59db012b5e1939bae0dbfc9cfdb/ea4c8/%5B%ED%94%8C%EB%B0%8D%EB%85%B8%ED%8A%B8%5D_%EB%B0%A9%EC%96%B4%EC%A0%81_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D.md_0.jpg 380w,
/static/abebf59db012b5e1939bae0dbfc9cfdb/953fe/%5B%ED%94%8C%EB%B0%8D%EB%85%B8%ED%8A%B8%5D_%EB%B0%A9%EC%96%B4%EC%A0%81_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D.md_0.jpg 500w&apos; sizes=&apos;(max-width: 500px) 100vw, 500px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;안개가 짙은 길을 주행할 땐 일단 서행하렴. 눈 앞에 갑자기 차가 나타날 수 있단다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;운전이나 코딩이나 방어가 중요하다는 거…&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;</content:encoded></item><item><title><![CDATA[[cpp] 함수 디자인]]></title><description><![CDATA[회사의 신입 개발자가 아래와 같은 함수를 만들었다. URL의 페이지를 긁어 오는 함수다. url에는 긁어올 웹 페이지 주소를 지정해서 함수를 호출하면 해당 웹 페이지를 긁어오는데 성공하면 check에 TRUE가 반환되고 string…]]></description><link>https://jiniya.net/wp/archives/14684</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14684</guid><pubDate>Wed, 11 Feb 2015 23:59:08 GMT</pubDate><content:encoded>&lt;p&gt;회사의 신입 개발자가 아래와 같은 함수를 만들었다. URL의 페이지를 긁어 오는 함수다. url에는 긁어올 웹 페이지 주소를 지정해서 함수를 호출하면 해당 웹 페이지를 긁어오는데 성공하면 check에 TRUE가 반환되고 string에는 페이지 내용이, 실패한 경우에는 check에 FALSE가 반환되고, string은 빈 문자열이 넘어온다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string &lt;span class=&quot;token function&quot;&gt;GetPage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; BOOL &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;check&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 디자인의 칭찬할 점은 함수의 리턴 값을 중의적인 내용으로 사용하지 않았다는 점에 있다. 리턴 문자열이 빈 문자열(“”)이면 오류라고 식별하는 것처럼 디자인해서 리턴 값에 성공/실패의 의미와 페이지 내용을 같이 담지는 않았다는 의미다.&lt;/p&gt;
&lt;p&gt;하지만 둘 중에 어떤 것을 리턴 값으로 선택하는지에 대해서는 생각이 조금 짧았다. 왜냐하면 함수 내용을 살펴보면 check는 함수의 수행 지점에 상관 없이 항상 덮어쓰기가 일어나지만 리턴 문자열은 성공한 경우에만 덮어쓰면 되기 때문이다. 이런 점을 생각했다면 check를 리턴 값으로 삼는 것이 좋았을 것이다. check를 리턴 값으로 선택하면 실패한 경우에 문자열 복사가 발생하지 않기 때문이다.&lt;/p&gt;
&lt;p&gt;일반적으로 개발자들이 많이 사용하는 함수 디자인 패턴이 있다. 그런 디자인 패턴에는 일반적으로 함수를 디자인한 사람의 생각과 그 함수를 사용하는 사람이 전제할 수 있는 내용들이 있다. 많이 사용되는 디자인을 살펴보면 다음과 같은 형태들이 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;BOOL &lt;span class=&quot;token function&quot;&gt;GetPage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; WCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;url에 const가 붙어있기 때문에 입력으로 사용되는 값임을 유추할 수 있다. buffer는 레퍼런스이기 때문에 반드시 값이 지정되어야 한다는 것을 의미한다. BOOL은 함수의 성공 여부를 리턴 한다고 기대할 수 있다. 실패한 경우에는 GetLastError같은 함수나 errno 같은 전역 변수를 사용해서 추가적인 오류 코드를 확인할 수 있도록 설계된 경우가 대부분이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HRESULT &lt;span class=&quot;token function&quot;&gt;GetPage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; WCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 경우에 바뀐건 BOOL이 HRESULT가 된 것 뿐이다. GetLastError를 사용할 필요 없이 실패 원인을 직접 반환하겠다는 의도다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HRESULT &lt;span class=&quot;token function&quot;&gt;GetPage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; WCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;buffer가 레퍼런스에서 포인터로 변경됐다. 이 값이 필요 없는 경우에는 NULL을 지정해도 된다는 것을 의미한다. 물론 이 관습을 모든 함수가 따르는 건 아니다. 대체로 그렇다는 말이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HRESULT &lt;span class=&quot;token function&quot;&gt;GetPage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; WCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SIZE_T size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;buffer가 문자열 클래스에서 문자열 포인터로 변경됐다. buffer는 size 만큼을 담을 수 있다는 것을 의미한다. 이 경우에 size가 문자 개수냐 바이트 수냐는 애매하다. 함수 설명에 어떤 내용을 의미하는지 명시할 필요가 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HRESULT &lt;span class=&quot;token function&quot;&gt;GetPage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; WCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;GetPage란 함수가 메모리를 할당해서 buffer에 반환하겠다는 의도다. 이렇게 디자인 된 함수는 통상적으로 어떤 함수를 사용해서 buffer를 해제해야 하는지를 명시하고 있는 경우가 대부분이다. buffer의 사용이 끝나면 해당 함수를 통해서 메모리 해제를 해주어야 한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;WCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetPage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; WCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;반환 값이 WCHAR *이 된 함수다. 이 함수 또한 GetPage 내부에서 메모리 할당을 하겠다는 생각이 깔려있다. 실패한 경우에는 통상적으로 NULL이 반한되고 세부적인 원인은 GetLastError등의 별도 함수를 사용해서 알 수 있도록 디자인된 경우가 대부분이다. 또한 앞선 함수와 마찬가지로 반환 값을 어떤 함수를 사용해서 해제해야 하는지를 명시하는 경우가 대부분이다. 반환값 사용이 끝나면 해당 함수를 통해서 메모리 해제를 해주어야 한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HANDLE &lt;span class=&quot;token function&quot;&gt;GetPage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; WCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;반환 값이 HANDLE이 된 함수다. 이 경우에는 핸들을 통해서 페이지 내용을 조회할 수 있는 함수와 핸들을 닫는 함수가 존재한다는 것을 의미한다. 각각 어떤 함수를 사용해야 하는지를 명시할 필요가 있다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 올바른 의사 결정과 조직 구성원의 감정, 그리고 황금알을 낳는 거위]]></title><description><![CDATA[#…]]></description><link>https://jiniya.net/wp/archives/14583</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14583</guid><pubDate>Mon, 12 Jan 2015 23:59:07 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;바야흐로 평가의 계절이 돌아왔다. 사람이 사람을 평가한다는 게 참 우습지만 조직의 자원 분배라는 측면을 고려한다면 평가는 필연적일 수밖에 없다는 생각이 들기도 한다. 모두가 평등하게 보상을 받는 사회주의 시스템의 말로를 우리는 똑똑히 보았다. 유토피아적인 퐌타지를 자극하지만 인간의 욕망을 거세한 다음 남는 것은 무기력감밖에 없었다는 사실을 우리는 모두 알고 있다. 조직도 비슷하다는 생각이 든다. 회색 빛깔 조직이 되지 않으려면 아주 단순한 사실, 조직을 위해 더 기여한 사람은 더 나은 보상을 받아야 한다, 라는 사실을 상기할 필요가 있다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/wp/archives/3803&quot;&gt;몇 해 전 여기에 관한 글을 하나 적은 기억이 난다.&lt;/a&gt; 한 3년 지났는데 지금 읽어봐도 참 공감이 간다. 그사이 내가 깨달은 한 가시 사실이 있다면 황금알을 낳는 거위의 배를 가르지 않기 위해서는 생각보다 엄청난 노력이 필요하다는 점이다. 특히나 조직이 커지면 커질수록 불가능에 가까워지는 것 같다. 지수 함수의 그것처럼 빠른 속도로 말이다. 100명, 1000명, 10000명이 되는 조직에서는 그 일이 얼마나 힘들지 상상조차 되지 않는다.&lt;/p&gt;
&lt;p&gt;최근에 나는 황금알을 낳는 거위를 보호하기 위해서 많은 노력을 했다. 다양한 사람들과 많은 이야기를 했고, 황금알을 낳는 거위가 다른 사람들이 보기에도 황금알을 낳는 거위처럼 보이도록 만들기 위한 작업들도 했다. 하지만 그런 작업들이 결코 순탄치는 않았다. 그 과정에서 더러는 유혹도 있었고, 회유도 있었고, 역설득도 있었고, 협박도 있었다. 참 이 조그만 조직 사람들을 설득하기도 쉽지 않다는 생각을 많이 했다. 나 좋자는 것도 아니고 다 잘되자는 건데 말이다. 물론 그 황금알을 낳는 거위가 없어진다고 우리가 망하진 않을 것이다. 단지 엄청나게 불편하고 느려지고 바보 같아질 뿐이겠지만 말이다.&lt;/p&gt;
&lt;p&gt;어쨌든 난 최근의 이런 경험을 통해서 한가지 사실을 깨달았다. 대부분의 조직에서 조직 구성원들이 황금알을 낳는 거위의 배를 갈라버리는 이유는 그들이 바보여서도 아니고, 그들이 정치적이어서도 아니고, 단지 배를 찢어버리는 게 그들의 삶을 더 편안하게 만들어주기 때문이란 사실이다. 마치 한약이 몸엔 좋지만 입에 쓴 것처럼 말이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;“인생은 B와 D 사이의 C다”라고 장 폴 사르트르는 말했다. B는 탄생을(Birth), D는 죽음을(Death), C는 선택을(Choice) 나타낸다. 우리 인생은 매 순간 선택의 연속이고, 그 선택의 합이 누군가의 인생이라는 말이다. 조직도 틀리지 않다. 현재 어떤 조직의 상태는 그 조직의 설립 이후 지금까지의 의사 결정의 총합이다. 그래서 올바른 의사 결정은 조직의 생존을 위해서 매우 중요하다. 특히나 작고 힘없는 조직의 경우에는 더 그렇다. 왜냐하면 여분의 버퍼가 없기 때문에 잘못된 의사 결정 한번으로 몽땅 도루묵이 돼 버릴수도 있기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;올바른 의사 결정이 조직의 생사를 결정할만큼 중요하기 때문에 조직 입장에서는 올바른 의사 결정을 내리는 것 자체가 굉장히 중요한 일이다. 따라서 올바른 의사 결정을 내리는 사람들이야 말로 조직의 관점에서는 황금알을 낳는 거위라고 부를 수 있다. 하지만 정말 아이러니하게도 조직 구성원에게는 이 황금알을 낳는 거위가 그다지 매력적으로 비춰지진 않는다. 올바른 의사 결정이 이해 당사자의 입장에서는 그다지 매력적이지 않기 때문이다.&lt;/p&gt;
&lt;p&gt;회사에서 새로운 제품을 만들자는 의사 결정을 내렸다고 생각해보자. 새로운 제품을 만들기 위해서 신규 인력을 충원한다면 이야기가 다르겠지만 기존 조직 구성원만으로 새로운 제품을 만든다면 당연히 그 제품을 추가적으로 만들어야 하는 개발팀 입장에서는 반대할 수밖에 없다. 왜냐하면, 당장 자신들의 일이 늘어나기 때문이다. 그들의 시각에서는 새로운 제품 개발이 올바른 의사 결정이라 하더라도 탐탁지 않게 생각되는 것이다.&lt;/p&gt;
&lt;p&gt;주말에 인터넷 서핑을 하다가 회사 제품이 탑재된 게임과 관련한 취약점 정보가 공유되는 것을 보게 되었다. 그런데 이미 그 취약점은 패치된 것이었다. 월요일 출근해서는 패치 담당자들에게 패치 요청을 이야기한다. 지극히 당연한 일이 벌어진 것처럼 보인다. 하지만 패치 담당자 입장에서는 일견 기분이 나쁠 수도 있다. 갑자기 추가적인 패치를 해야 하는 일이 생긴 것이기 때문이다. 특히나 이미 패치된 취약점이 반영되지 않았다는 것은 그 사이트의 업데이트가 쉽지 않을 수도 있기 때문에 더 골치아픈 일이 생긴 것이다. 그러니 취약점이 있어서 패치를 해야 한다는 누가봐도 토를 달기 힘든 의사 결정 앞에서도 기분은 썩 좋지 않다.&lt;/p&gt;
&lt;p&gt;분석팀에서 해킹툴을 분석하다 취약점을 하나 찾았다. 런 타임에 결정돼야 하는 CRC가 링크 타임에 결정되도록 알고리즘을 만들어 둔 것이다. 물론 그 해킹툴은 이미 다른 로직을 통해서 차단이 되고 있다. 그걸 개발팀 담당자에게 가서 이야기를 한다. 이건 런 타임에 계산되야 효과가 있는데 링크 타임에 결정되니 효과가 없고 그래서 이런 취약점이 생긴다. 이 경우에 개발팀 담당자에 따라서 여러 케이스가 발생할 수 있다. 이 이야기를 이해 못하는 개발팀 담당자가 있을 수 있다. 얘가 또 왜 피곤한 이야기하지, 라고 생각하고 그냥 흘려 넘긴다. 이해는 하는데 그 해킹툴이 막힌걸 아는 담당자라면 이미 막혔는데 왜 그런 소리를 하느냐고 답변하기도 한다. 그 개발자가 문제를 제기한 분석가보다 상급자라면 최악의 경우가 생길수도 있다. 니가 뭘 안다고 이래라 저래라야, 라는 이야기를 할 수도 있다. 이랬든 저랬든 결국 모든 반응은 한 가지 지점을 가리킨다. 왜 나한테 와서 추가적인 일감을 만들어놓느냐는 것이다. 그 이야기의 옳고 그름이 중요한게 아니라 말이다.&lt;/p&gt;
&lt;p&gt;이렇듯 대다수 조직에서의 올바른 결정이란 결국 누군가를 불편하게 만드는 것이다. 누군가를 불편하게 만든다는 건 불편해지는 누군가는 그 의사 결정에 좋은 감정을 가지기가 쉽지 않다는 것을 의미한다. 그러니 조직을 위해 지속적으로 올바른 의사 결정을 내리거나 제시하는 어떤 사람이 있다면 그 사람은 광역으로 질타를 받을 가능성이 농후하다. 왜냐하면 다양한 사람들을 불편하게 만들었기 때문이다. 불편한 의사 결정의 희생양이 된 사람들은 그 의사 결정의 옳고 그름을 떠나서 자신의 일이 늘어나거나 상해버린 감정을 먼저 생각하기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;서 있으면 앉고 싶고, 앉으면 눕고 싶고, 누우면 자고 싶는게 사람 심리다. 조직도 똑같다. 새로운 변화는 두렵기 마련이고, 굴러 가면 굴러 가던대로 굴러가려는 관성이 생기게 마련이다. 그게 편하기 때문이다. 사람의 본성이 그러니 올바른 의사 결정을 싫어하는 다수를 뭐라고 할 수는 없는 노릇이다. 하지만 분명한 하나는 다수가 외면하기 때문에 올바른 의견을 제시하는 사람을 기피한다면 조직 내에는 그 누구도 좋은 의견을 제시하지 않을 거라는 점이다. 다수가 불편해지더라도, 욕먹을 각오를 하고 그런 이야기를 해주는 사람을 지지하고 보호해 줄 필요가 있다. 그래야 조직도 한걸음 전진할 수 있다.&lt;/p&gt;
&lt;p&gt;처음 소스 코드 저장소를 사용하자는 말에 직원들은 자신들의 실수를 감시하려는 목적이 아니냐는 어처구니 없는 이야기를 했었다. 빌드 시스템을 만들 때에는 귀찮게 이런 걸 왜 만드냐는 이야기를 들었다. 웹 지원 시스템을 만들 때에는 이런 게 필요하냐는 이야기를 들었고, 디자인을 바꿔야 한다는 이야기를 했을 땐 니가 하라는 소리까지 들어서 직접 하기도 했었다. 레드마인을 쓰는 과정도 순탄치는 않았고, 최근에 슬랙을 사용하자는 이야기를 했었을 땐 어처구니 없게도 대화를 감시하려는 목적이 아니냐는 이야기를 듣기도 했었다. 안드로이드 버전을 만들 땐 이런 건 돈도 안되잖아요, 라는 이야기를 수도 없이 들었다. 돈을 벌고 안 벌고는 니가 판단할 문제가 아니라는 말을 수도 없이 했었다. 돌아보면 지금은 당연한 것들이지만 그 어떤 것도 쉽지 않았다. 당연한 것들이지만 받아들여지지 않은 것도 수도 없이 많다. 그래도 그나마 나는 권한이 있기에 쉬웠다.&lt;/p&gt;
&lt;p&gt;일 더하기 일은 이다. 이렇게 말하든 저렇게 말하든 일 더하기 일은 이다. 여기서 중요한 건 일 더하기 일은 이라는 사실을 말했다는 게 중요하지 그걸 이렇게 말했느냐 저렇게 말했느냐가 중요하지는 않다. 사람에 따라서는 장황하게 말하는 걸 좋아하는 사람도 있을 수 있고, 간략하게 말하는 걸 좋아하는 사람이 있을 수도 있다. 자신의 기호에 맞다 안 맞다가 중요한게 아니다. 그 이야기를 한 사람이 자신보다 직급이 높은지 낮은지가 중요한 것도 아니다. 제일 중요한 건 그 사람이 말한 컨텐츠가 옳으냐 아니냐가 중요하다. 적어도 옳다면 그 사람 말을 진지하게 들어줄 필요가 있다. 지금 당장 실행할 수 없다고 하더라도 말이다. 그래야 하는 가장 큰 이유는 그 불편함을 만드는 바로 그 사람이 당신의 배를 채워주는 부가가치를 창출하는 사람이기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#4&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;모두가 미리부터 전사하겠노라는 말은 하지만 막상 적의 칼날이 눈앞에 닿으면 목 자르는 형틀이 뒤에 있더라도 도망쳐 버려서 죽을 수 없게 됩니다. 그것은 사와 민이 죽을 수 없어서가 아니라 위에 있는 자가 할 수 없게 했기 때문입니다. 입으로는 상을 준다 하고 주지 않으며 처벌한다고 말하고는 실행하지 않아 상과 벌이 확실치 못하기 때문에 사와 민이 죽어 주지 않는 것입니다.&lt;/p&gt;
&lt;p&gt;– 한비자&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[신의 생각]]></title><description><![CDATA[우리가 생활하는 실제 세계가 이럴지도 모른다.…]]></description><link>https://jiniya.net/wp/archives/13653</link><guid isPermaLink="false">https://jiniya.net/wp/archives/13653</guid><pubDate>Thu, 20 Nov 2014 23:59:59 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; margin-bottom: 16px;&apos; data-url=&apos;./신의_생각.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ece2503092ae18eaad70165843b9d399/0eb09/%EC%8B%A0%EC%9D%98_%EC%83%9D%EA%B0%81.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAA7DAAAOwwHHb6hkAAADCElEQVR42hWSW28aRxiG97JqLtg57OxhZndnDywYsAOYgzks7AJeY3AMPhBjwK0jN02qRm4apZGipIrUq/Y39C/0R/bzzUgjzfd+8z7vq5AeR2du8FAnl75xW6DXAT3z7LuKeuqQuTRWBbSUaOnhuaQLnwxtNHXQQqKYa4mroKYJd3wi1bGAF+QmJBe+vauY6yJbBvrLCN36ZBvq22LpzRGf5XMzG5aRDmdtW9Fih009NOS4a5FdxO6L+lWerkOyCo3LCM1dsgrQqwivAu9D01iE7NTT5p7aNllDKFrD0hOJxoJ0TW2b125CbezufYnpOo8yh6Q2mUmy9PRt5H9s6ZmkbYskAnUtvesoqMLAAE0cfGSSuQur8ETId3W6CtFEoNgCXdS3yMwVbw/0scw1dfVYqIe62XEVsm+QkW2e5c2hRAnHQ4F7lvtbja3z1qagLT2S8tzIpJnj/lIlqUA1HXYYfVercwU3LdTn6tRmqYu7HKUcjwR/qPhXpeHfL7Kvi97r9PuBRkaCbSMy4KRloZFNW/zJcy7h1mXRuyo/0c5sNLDIxNY3kXext/h3d//f4/Tb5Xc9gmHnzDGmvjEPgK4+lMZQKjDD1lHp1w6eOMZ5qJ/5OOFowllq1/5Mk38W5bvDZzVMTiR94YM0EEGJgHY8RUWObbqJgCeOOeqaQEhtMHWfsmNX/n4Y/NE0zv1cnaIxKAq1b7LMA4TV25Y7iRQMBrYR2xRgGDcMdGTCiTsWuvaMxwP+ocrelTG0asTRscDguSdQKsy2Y8RSoQOXXAfaXYGMbVxnastgJ170vl3+NvA/tdjH5/zxObryc4mV65oERJsGmtgQFetCwzq2eFlir/boqST7DFyhsQ2tDD4fRX/F/H1Vf1uGhL3HOkSAhxxKgjMHPsgOIaqGSTLX/rFiTQO1rgMC6AxeSH5f1u6L9HWR/7TPfz4wHkrGD3tk4lCIFt60zCdgtMO1TJJz31pGPAvpxNFTaa4K3puatSvhdRjuqmJT0i7y+ZsqVIjGgl0EPPZ5P/gflnOb+c6WoaoAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;      md 0&apos; title=&apos;&apos; src=&apos;/static/ece2503092ae18eaad70165843b9d399/0eb09/%EC%8B%A0%EC%9D%98_%EC%83%9D%EA%B0%81.md_0.png&apos; srcset=&apos;/static/ece2503092ae18eaad70165843b9d399/08678/%EC%8B%A0%EC%9D%98_%EC%83%9D%EA%B0%81.md_0.png 190w,
/static/ece2503092ae18eaad70165843b9d399/2edd7/%EC%8B%A0%EC%9D%98_%EC%83%9D%EA%B0%81.md_0.png 380w,
/static/ece2503092ae18eaad70165843b9d399/0eb09/%EC%8B%A0%EC%9D%98_%EC%83%9D%EA%B0%81.md_0.png 500w&apos; sizes=&apos;(max-width: 500px) 100vw, 500px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;우리가 생활하는 실제 세계가 이럴지도 모른다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;6월에 상당히 재미난 과학책을 한 권 읽었습니다. “신의 생각”이란 책인데, 심심하신 분들은 한번 읽어보길 권해 드리고 싶네요. 시간 가는 줄 모르고 읽게 되는 묘한 매력이 있는 책입니다. 책의 논지는 결국 모든 출발점에는 정보가 있었고, 그 정보는 아마도 숫자였을꺼라는 뭐 그런 내용입니다. 그런 생각을 가졌던 물리학자들의 발자취를 따라가는 그런 책이지요. 책을 너무 감명 깊게 읽어서 서평을 써야지 하고 있다가 늘 그렇듯이 흐지부지 되었습니다. 그렇게 한동안 잊고 있다가 오늘 Reinhard Vz님께서 공유한 유튜브 동영상을 보는데 잊었던 그 내용들이 다시금 새록새록 머릿속에 떠올라, 내친김에 몇 자 끄적여 봅니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;결국 테그마크에 따르면 ‘실재계’는 인간의 능력으로는 도저히 이해할 수 없는 심오한 수학적 실재가 인간이 의식할 수 있는 수준으로 투사된 것에 지나지 않는다. 한마디로 그것은 허상일 뿐이다. 흡사 스크린 위에 비춰진 영화의 영상과 음악, 음향이 0 또는 1의 형태로 DVD 홈에 새겨진 심오한 현실과 극명한 차이를 보이는 것처럼 말이다. 그런 의미에서 스크린 위에 투사된 영화를 진정한 ‘현실’로 인식하는 것은 망상이라 하겠다. 스크린 위에 펼쳐지는 영화는 한낱 환영일 뿐, 진정 유일한 실체는 오로지 DVD 안에 정보로만 기록되어 있다.&lt;/p&gt;
&lt;p&gt;– 신의 생각, 이고르 보그다노프,그리슈카 보그다노프&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;물론 아직까지 완전히 증명된 것은 아니지만 오늘날 π는 소위 ‘우주－수’일 가능성이 있다고 여겨진다. 그것이 무슨 의미일까? 아주 기막힌 사실을 의미한다. 한마디로 여러분은 π 속에서 여러분이 원하는 것은 무엇이든 다 찾아낼 수 있다는 말이다! 가령 여러분의 생년월일은 물론, 여러분의 모습이 찍힌 최초의 사진, 혹은 이 순간 여러분이 손에 쥐고 있는 책(커버 사진과 같은 세세한 것을 모두 포함해서)까지도 전부! 사실상 우주－수는 모든 것, 우주에 존재했던 정말 모든 것을 품고 있다. 심지어는 미래에 존재하게 될 모든 것까지도. 그저 우리가 찾고 있는 것을 암호화해놓은 숫자열을 발견할 때까지 그저 멀리, 상상할 수 없을 만큼 멀리 나아가기만 하면 된다.&lt;/p&gt;
&lt;p&gt;하지만 미국의 수학자 그레고리 카이틴이 지적한 것처럼 바로 거기에서 모든 역설이 시작된다. “π는 무한수이지만, 동시에 기하학적으로는 직선 위의 한 점에 불과하다.” 지당한 말씀이다! π란 실제 직선 위의 두 점 3.1과 3.2 사이 그 어딘가에 찍힌 작은 점, 그 이상도 이하도 아니기 때문이다.&lt;/p&gt;
&lt;p&gt;그럼에도 다른 점과 그리 다를 것도 없는 이 ‘점’은 세계 곳곳에서 열광적인 반응을 만들어냈다. 가령 1980년대에는 ‘파이 데이’라는 기념일까지 만들어져, 매년 전세계 수학자들을 한자리에 불러 모으고 있다. 사실상 π의 탄생을 기념하겠다는 취지에서 만들어진 이 날은 π의 첫번째 세 자리 숫자(3, 1, 4)를 따서 3월 14일로 정해졌다. 흥미롭게도 이 날은 1879년 3월 14일 태어난 아인슈타인의 생일과도 겹친다.&lt;/p&gt;
&lt;p&gt;– 신의 생각, 이고르 보그다노프,그리슈카 보그다노프&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이쯤 읽고 나면 누구나 그렇듯 정말 파이에 그 모든 것이 다 들어 있을까 궁금해지기 마련이죠. 그래서 얼마나 긴 파이가 계산되었나 찾아보게 되었습니다. 아래 링크가 그런 파이 내용을 담고 있는 사이트 입니다. 그래서 그 안에서 몇몇 분들의 생년원일을 찾아봤는데 약속이나 한 것처럼 모두 그 거대한 파이 속에 있었습니다. 당연히 없는 사람들도 있겠지만 그건 어쩌면 아직 계산되지 않은건 아닐까라는 어처구니 없는 상상의 나래를 펼쳐 보기도 했습니다. 너무 심심해서 미칠 지경인 분들은 아래 사이트에서 자신의 생년월일을 한 번 찾아보는 소소한 재미를 누려 보시는 것도 좋을 것 같아요 ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://piworld.calico.jp/estart.html&quot;&gt;http://piworld.calico.jp/estart.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.eveandersson.com/pi/digits/1000000&quot;&gt;http://www.eveandersson.com/pi/digits/1000000&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 302px; margin-bottom: 16px;&apos; data-url=&apos;./신의_생각.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/731916bec83ca8ffba7eda614bcc5067/83034/%EC%8B%A0%EC%9D%98_%EC%83%9D%EA%B0%81.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 16.842105263157894%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAA3UlEQVR42mMwMzOTYQACDw8PvoSEBKPo6GhbIFvZ1dXVPDY2VriwsDAiMzPTJSMjw9be3t4iNDTUPjg42ASohSs8PNwqMjIyAKgnDCgem5eXp8NgYWEhzc/PL6CmpiYCNMQJyDczNDSUDwwMtPDz8+PV0tKSU1dXl7K1tVW0s7MzdHFxMfH29ja2srIyAbJtLC0tNVRUVERVVVWlgeLSDMnJyXogFwJpoYiIiEigoZ7+/v4Gubm5/gEBAWoMUAAUE0hKSnIGYsfExET7kJAQoPIID6CvZKFKmOrr65kAEw85wM8qb7cAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;      md 1&apos; title=&apos;&apos; src=&apos;/static/731916bec83ca8ffba7eda614bcc5067/83034/%EC%8B%A0%EC%9D%98_%EC%83%9D%EA%B0%81.md_1.png&apos; srcset=&apos;/static/731916bec83ca8ffba7eda614bcc5067/08678/%EC%8B%A0%EC%9D%98_%EC%83%9D%EA%B0%81.md_1.png 190w,
/static/731916bec83ca8ffba7eda614bcc5067/83034/%EC%8B%A0%EC%9D%98_%EC%83%9D%EA%B0%81.md_1.png 302w&apos; sizes=&apos;(max-width: 302px) 100vw, 302px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;라마누잔의 파이 공식&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;이게 인간의 머리에서 나올 수 있는 공식이란 말인가? 핡~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;파이 하면 또 빼놓을 수 없는 사람이 바로 라마누잔인데요. 꿈 속에서 신이 불러준 내용을 적었다는 그의 말이 진짠지 거짓인진 모르겠지만 정말 사람이 상상해 냈다고 하기엔 공식이 참 뷁스럽지요 ㅋㅋ~&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;사실상 몇 년 전 괴델은 불완전성 정리를 모든 우주에 적용해보는 연습을 했다. 그때 그는 우주의 의미는 우주만 가지고는 절대 알아낼 수 없다는 논리학적으로 명쾌한 결론에 도달했다. 우주 안의 의미를 발견하려면 반드시 우주 바깥의 원인이 필요했다. 한마디로 괴델은 신의 존재에 대해 자신만의 ‘증명’을 해나가는 과정에서, 요컨대 이 작업이 실은 자신이 기존 연구에서 발견한 것을 순전히 형식적인 차원에서 더욱 보강하는 것에 지나지 않는다는 사실을 깨달았다. 몇 달 뒤 그는 괴델판 ‘존재론적 증명’의 초안을 완성했다. 이 연구서에서 우리는 괴델의 논리전개 과정을 따라가다 마지막에 이런 결론에 도달하게 된다. “고로 신은 존재한다.”&lt;/p&gt;
&lt;p&gt;– 신의 생각, 이고르 보그다노프,그리슈카 보그다노프&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이런 생각을 괴델만 한 건 아닐겁니다. 논리적으로 증명한건 괴델이겠지만요 ㅋㅋ~ 중학교 땐지 고딩땐지 링이라는 소설이 유행했었는데 그때 링을 읽고는 그런 이야기를 했던 기억이 떠올랐습니다. 그때 그 친구는 우리가 살고 있는 이 세상이 어쩌면 거대한 고래 뱃속인지도 모른다고 했었던 기억이 나네요. 어쨌든 링3편의 “날 그 쪽으로 데려가줘”라는 대사는 당시엔 정말 충격과 공포 그 자체였습니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 270px; margin-bottom: 16px;&apos; data-url=&apos;./신의_생각.md_2.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/eae20ca27fe9d509fc998c41cc6fc618/bf933/%EC%8B%A0%EC%9D%98_%EC%83%9D%EA%B0%81.md_2.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 147.89473684210526%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAeABQDASIAAhEBAxEB/8QAGQAAAwADAAAAAAAAAAAAAAAAAAECAwQF/8QAFgEBAQEAAAAAAAAAAAAAAAAAAQAC/9oADAMBAAIQAxAAAAHkOsrnWASnKJAJ/8QAGRABAAMBAQAAAAAAAAAAAAAAAQAQMREh/9oACAEBAAEFApy3XcV8jf8A/8QAFREBAQAAAAAAAAAAAAAAAAAAEBH/2gAIAQMBAT8BKf/EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EABsQAAIBBQAAAAAAAAAAAAAAAAAQQQIgITGB/9oACAEBAAY/AiF0pMaUW//EABwQAQEAAgMBAQAAAAAAAAAAAAERACEQcYFBYf/aAAgBAQABPyGVgDjrdusnWDBZYNY/tkV4YOwnuLRBfzk8f//aAAwDAQACAAMAAAAQtxqN/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQAQEf/aAAgBAwEBPxAMEXb/xAAWEQEBAQAAAAAAAAAAAAAAAAABEBH/2gAIAQIBAT8QVmDP/8QAHRABAAIDAAMBAAAAAAAAAAAAAQARITFBUWGBwf/aAAgBAQABPxAWEluf2NgBNruoBtEW68SrbUPkZxMQ0tVeBQc2e5tLltuo/wBQaMf0CpRhBX2AspXHZU//2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;      md 2&apos; title=&apos;&apos; src=&apos;/static/eae20ca27fe9d509fc998c41cc6fc618/bf933/%EC%8B%A0%EC%9D%98_%EC%83%9D%EA%B0%81.md_2.jpg&apos; srcset=&apos;/static/eae20ca27fe9d509fc998c41cc6fc618/8ccab/%EC%8B%A0%EC%9D%98_%EC%83%9D%EA%B0%81.md_2.jpg 190w,
/static/eae20ca27fe9d509fc998c41cc6fc618/bf933/%EC%8B%A0%EC%9D%98_%EC%83%9D%EA%B0%81.md_2.jpg 270w&apos; sizes=&apos;(max-width: 270px) 100vw, 270px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;링3 루프: 날 그쪽으로 데려가줘&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Digital physics is grounded in one or more of the following hypotheses; listed in order of decreasing strength. The universe, or reality:&lt;/p&gt;
&lt;p&gt;is essentially informational (although not every informational ontology needs to be digital)&lt;/p&gt;
&lt;p&gt;is essentially computable (the pancomputationalist position)&lt;/p&gt;
&lt;p&gt;can be described digitally&lt;/p&gt;
&lt;p&gt;is in essence digital&lt;/p&gt;
&lt;p&gt;is itself a computer (pancomputationalism)&lt;/p&gt;
&lt;p&gt;is the output of a simulated reality exercise&lt;/p&gt;
&lt;p&gt;– &lt;a href=&quot;http://en.wikipedia.org/wiki/Digital_physics&quot;&gt;http://en.wikipedia.org/wiki/Digital_physics&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;책을 덮고나서 흥미가 생겨 위키 페이지를 살펴봤습니다. 디지털 물리학이라, 네오가 왜 갑인지 알 것 같지 않나요?! ㅋㅋㅋ~ 그리고 아래는 오늘 유튜브에서 보았다는 동영상입니다. 블랙홀의 표면에 정보가 기록된다는 부분에서 쇼름이… 핡~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;결국은 다 매트릭스?! ㅋㅋ&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] argc, argv가 필요할 때에…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/14350</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14350</guid><pubDate>Thu, 30 Oct 2014 23:59:58 GMT</pubDate><content:encoded>&lt;p&gt;우리 회사 제품 코드는 크게 커밋 정책이 두 가지로 나뉘어져 있다. 아무나 손쉽게 커밋할 수 있는 공간과 내가 리뷰를 한 다음에 머지 해주는 공간이다. 당연히 전자는 빠르고, 새로운 것들이 손쉽게 추가되는 반면 후자는 더디고 어렵게 작업된다. 프로그래머 입장에서는 후자의 경우 빠꾸(리젝) 당하는 일도 많기 때문에 얼마간 자존심이 상하는 지점이기도 하다. 하지만 난 이런 정책이 우리 제품 코드를 보다 안정적이면서 빠르게 변화할 수 있도록 만들어 준다고 생각한다.&lt;/p&gt;
&lt;p&gt;가끔, 대체로 어떤 문제가 발생했을 때, 내가 리뷰하지 않은 코드들에 대해서도 검토하는 일을 하는데 어제도 그런 일이 있었다. 그런데 생각보다 그 부분이 나에겐 다소 충격이었다. 비슷한 상황에 빠질 많은 초보 프로그래머에게 도움이 될 것 같아서 여기에 내용을 조금 옮겨 본다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;첫 번째 부분은 argc, argv였다. 윈도우 창을 띄우는 WinMain을 가진 프로그램이었는데, 프로그램 동작 과정 중에 커맨드라인 파싱 작업이 필요했던 것 같다. 그 프로그래머는 argc와 argv를 얻기 위해서 WinMain의 lpszCmdLine을 파싱하는 코드를 WinMain 내부에 작성해 두었다. 나중에 사용할 곳도 없지만 lpszCmdLine의 부족한 부분을 메우기 위해서 argv[0]는 GetModuleHandle을 사용해서 추가해주는 일도 잊지 않았다.&lt;/p&gt;
&lt;p&gt;내가 충격을 받은 점은 다음과 같은 사실이었다. 1) 그 복잡한 파싱 for 문을 왜 함수로 빼지 않았을까, 2) 그 복잡한 파싱 for 문에 왜 커맨드 라인 파싱에 대한 일체의 고려도(따옴표, 역슬래시같은) 되어 있지 않을까? 3) 왜 이렇게 단순화한 버전을 만들면서 이미 다른 사람이 만들어 둔 내용을 사용하지 않았을까?&lt;/p&gt;
&lt;p&gt;즉, 결론은 이랬다. 그 파싱 구문들은 굉장히 부적절하고 아주 많은 경우에 잘못된 파싱 결과를 가져오는 코드였다. 실제로 그 프로그램은 argv[1]만 필요로 하기 때문에 심지어는 lpszCmdLine을 직접 평가하는 작업이 더 적절했을 수도 있다. 이런 여러가지 가능성을 제쳐두고 그 프로그래머는 아주 조악한 코드를 자신이 직접 만드는 길을 선택했다.&lt;/p&gt;
&lt;p&gt;argc, argv가 필요한 윈도우 프로그램을 만든다면 &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dn727674.aspx&quot;&gt;__argc, __argv, __wargv&lt;/a&gt; 같은 좋은 지원 도구들이 있다. 직접 만들 필요가 없다. 이미 검증된 파싱 루틴을 통해서 우리가 원하든 원하지 않든 WinMain이 시작되는 지점에 이미 그 데이터는 우리가 사용할 수 있도록 모두 준비되어 있다. 그러니 그저 가져다 쓰기만 하면 된다. 바퀴를 새로 만들고 이미 다 파싱해 놓은 걸 다시 또 파싱하겠다고 호기를 부릴 필요는 없다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;내가 두번째로 충격을 받은 부분은 한 곳이 더 있었는데 아래와 같은 코드였다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__argc &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__argc &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;도대체 드 모르간의 법칙을 생각나게 하는 이 코드는 무엇일까? 이 코드를 이해하기 위해서는 얼마간 에디터의 도움이 필요했다. 마지막 괄호를 지웠다 다시 썼을 때 에디터가 그 닫기 괄호가 어디에 매핑되는지를 알려주었기 때문이었다. 에디터의 도움이 없었다면 난 다시 스페이스를 사용해서 이 조건문의 실제 의미를 일일이 파악해야 했으리라.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__argc &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; __argc &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;대체로 많은 경우에 괄호가 없도록 조건문을 구성하는 것이 훨씬 읽기 쉬운 코드를 만든다. 위 코드는 에디터의 도움이 없이도 쉽게 의미하는 바를 눈치챌 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__argc &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;의미를 고려한다면 그 조건문은 위와 같이 더 단순화 될 수도 있다. 왜냐하면 그 코드는 argv[1]에 접근 할 수 있는지를 검증하기 위한 용도로 사용되고 있었기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;같은 현상을 설명하는 두 개의 주장이 있다면, 간단한 쪽을 선택하라&lt;/p&gt;
&lt;p&gt;given two equally accurate theories, choose the one that is less complex&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://ko.wikipedia.org/wiki/%EC%98%A4%EC%BB%B4%EC%9D%98_%EB%A9%B4%EB%8F%84%EB%82%A0&quot;&gt;오컴의 면도날&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;오컴의 면도날이라는 말이 있다. 난 이 말이 프로그래밍에도 적용된다고 생각한다. 대부분의 경우에 간단한 쪽을 선택하는 편이 읽기도 좋고, 단순하며, 안정적인 좋은 코드를 만든다. 그래서 래리 월(펄의 창시자) 아저씨가 최고의 프로그래머 덕목 중 하나로 게으름을 꼽았는지도 모르겠다. 게으른 사람은 적어도 남들이 만든 걸 또 만들거나, 단순한 걸 두고 복잡한 걸 선택하지는 않을 테니 말이다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[반갑다(?!), 윈10]]></title><description><![CDATA[많은 이들의 기대를 저버리고 윈9이 아닌 윈10이 출시됐습니다. 어제 윈도 10이 발표됐습니다. 많은 사람들의 윈 9일거라는 추측을 무너뜨리고 9은 건너뛰고 10이 출시됐습니다. 왜 1…]]></description><link>https://jiniya.net/wp/archives/14318</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14318</guid><pubDate>Thu, 02 Oct 2014 23:59:57 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 610px; margin-bottom: 16px;&apos; data-url=&apos;./반갑다(!),_윈10.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f4f5107eebbfee7583cbdf7be879fb7c/5d5ad/%EB%B0%98%EA%B0%91%EB%8B%A4(!)%2C_%EC%9C%8810.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 104.21052631578948%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAVCAIAAADJt1n/AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAE2ElEQVR42k2Re1SSZxzHn8CpLW1zTtO1ss1qbantdL8sp55sq86s/iixnVq1mVEuNQUBBVRgXvBWkuDSoLQ8ZqbCC+8LL/CimIDghcvQEiqbW01FzdzZads57tVT257zeZ7/Puf7/L4/0Oac+H3a02Ppt/T295h7H4088UxNT0xOTkxOeaampmdmpp/Pn/HJ6b9nJ5Pujq+6NOq0W202G34B5pqc++uF6ye7y2F12QeG+i1P7jsfDzoeOu1PBu1TT38eGx/77dmzP2Y8c3MvTraOh1eMuJ1W67xuA/RG/WW0P/Om7mwtkipR4y/5Gppap/peoj7T1E2uV18RSvjV9fRmezk6EskfCsy3Q129gw477oNobnMgvc2XDoO0dpAunSet3fei1JuFJbrnou9YHSei1WQSODe6ImfsfMvzZdxfi9rMDwdt/bicUKMMZMJv58J+DAWBAhEpMiIVImZKCdmKXbec2y5r2SfI1LM5Pum/1Btf1vW89Mt7ViazuAdtA7h8WtwWwlb45yBeVAhkyXAWZUoBDXk/WQK/GZG69sQO7tB6hj04e5QNv4wRzXqzx8qhXrdzQU6olIblI34MGODOv3I2HExuqF1/IPmzc5vSFVEZ6pVUZ0Tuw+VU91v0B6VS86vkpOyuDQy1PwteQleAzHmZkCUFFCTsgrgjYaOOFG1K3CZOTNi5R3b2iJJyqvPLOKSq2TA8ZB8YsILdnKZPOFBQHurPeC3PJ6tWnxOOJG2dNWr+bKqQH47ZGw9rGt0GaDQxXltxU++677DZ7GAzrz04V4a37UODCBQZjhcFnxmXRY9IW54K2B7qIfnR+Pg4qCilszD53tE4dYlE04mp5HIF2MppD2LIgtgqvPBFWf99e9UFcVdijObQDuPBKPHXR3bth04moKQ96i/2avgNGKaG5QoYxAq6PuCigSyld/brtnE5SxGQcauEV1QpEF4qqTicnMErrOaViZg/XErK4HKutWCoEkYQEF+jCOdBi+mIL00OXiXLwEXoY3arpJBRX10m5LJYqcdUN0XwtYomAftGo4R/oxVqb+vuNoDYK3cii6VLc1RL6P+TM6HVjNYi8nkhryTtm+9SD+5jp5ClVT/eZmY2XK4Ttmi0GqXZYga7S6Wr8qE3qHJ8z4soMpz5mRnK0ONXdXGpmtgL6MZvNdtSsK0k/WaSPiS2YWVCjQS5pzXrlAawsSZtk0C8prArtAAJLVAtoAzlYO8y6iPSt0fSYqJYOz9lHok6c2flqcawU40rUpr5LXpbr8lgNAH/PEFg3u2AXDSACQcwkQUU7+Rii5kicAWAq0RwCwDxRwSanaYf5/bNgDIn567Rqrd06/uAH00byERD8hF8w8QFvCjtRIqKQKsOECwNqXtvsQQQRet8KeZa09Nmh8enpJ91W69HNVKZClR2DhtHPJhrAnNPaF0T2uFx1f0x0+PZ442toBz4iLyBBADhWh+KxSunh5DXBwr6yiDjY4elr8cIKFJHpc5VjA4Vqx9UYMOVHQ9qDYOCDvcxiSKYn7W88nhQ+elIUcGHvK5lnM4Art4nv4N8Qy9WmKplJrC/5t4WPraBq1zHVX8lMmwvVSZeRzYUoaQqxeZi6YHrhZ9Xqfhtln0i3ZoSXUR55/ryjrWlWDhfG87X/gOpT6o40ubMLwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;         10 md 0&apos; title=&apos;&apos; src=&apos;/static/f4f5107eebbfee7583cbdf7be879fb7c/5d5ad/%EB%B0%98%EA%B0%91%EB%8B%A4(!)%2C_%EC%9C%8810.md_0.png&apos; srcset=&apos;/static/f4f5107eebbfee7583cbdf7be879fb7c/08678/%EB%B0%98%EA%B0%91%EB%8B%A4(!)%2C_%EC%9C%8810.md_0.png 190w,
/static/f4f5107eebbfee7583cbdf7be879fb7c/2edd7/%EB%B0%98%EA%B0%91%EB%8B%A4(!)%2C_%EC%9C%8810.md_0.png 380w,
/static/f4f5107eebbfee7583cbdf7be879fb7c/5d5ad/%EB%B0%98%EA%B0%91%EB%8B%A4(!)%2C_%EC%9C%8810.md_0.png 610w&apos; sizes=&apos;(max-width: 610px) 100vw, 610px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;많은 이들의 기대를 저버리고 윈9이 아닌 윈10이 출시됐습니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;어제 윈도 10이 발표됐습니다. 많은 사람들의 윈 9일거라는 추측을 무너뜨리고 9은 건너뛰고 10이 출시됐습니다. 왜 10인가에 대한 여러가지 억측 유머가 난무한 날이기도 했지요. 티맥스 윈도우 9 때문에 10이 됐다는 설, 8.1이 실제는 9이었다는 설, 맥 운영체제 버전에 맞추기 위해서 10을 했다는 설, 기존에 9이라고 알려진 걸 너무 많이 뜯어고치다 보니 완전 새로운 운영체제가 돼서 10을 했다는 설등 온갖 설들이 난무했습니다. 물론 진실은 안드로메다에 있겠지요. 어쨌든 발표된 윈도 10은 기존의 8 시리즈에서 지적됐던 많은 문제들을 개선했고, 또 새로운 기능이 다수 추가된 아주 혁.신.적.인 운영체제라고 합니다. 흥망은 뚜껑열어봐야 알겠지만요. MS의 발표에 따르자면 그렇다는 겁니다.&lt;/p&gt;
&lt;p&gt;MS 말이 사실인지 확인하기 위해서 저도 테크니컬 프리뷰를 설치해 보았습니다. 윈도 10을 먼저 경험해 보고 싶으신 분들은 &lt;a href=&quot;http://windows.microsoft.com/en-us/windows/preview-iso&quot;&gt;여기&lt;/a&gt;에서 다운받아 설치해 보시면 되겠습니다. 일단 설치하고 가장 눈에 띄는 건 시작 버튼이 돌아온 거네요. 저에겐 크게 필요하진 않았던 부분이지만 인상적이긴 한 것 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./반갑다(!),_윈10.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/c21f574b63bc0892c53a481c368e9b33/dface/%EB%B0%98%EA%B0%91%EB%8B%A4(!)%2C_%EC%9C%8810.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 101.05263157894737%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACa0lEQVR42pWTzYrUQBDH84yCFx/Bh/AFvAviZRG8CJ714kFFcEEQdz52MpnufKfT3ekk3Z3ufE0y1syg7MoeZv8URTXkR9W/uuM8/7B79s59crV++vYWihcfQ4RDd7Pbeb7nYUYFpeJm4d0sdwuIFVqu8NYLEQrSlDooiP04X22xi6M0F4SVVVXjNPDjQCo97edx2Pf9OAzjcM6n6LoeslNwzhgthRBFYY0py9Jqm3S57NV+2jd9045tN3ZQQLaDOR733TiNUDi/F8s4TgCNwqiua900Rpu4JXpo7GCpzmUn67bmDWcNY5oKU6hODfvhDC/W61uEEOeFOkobbeM2b0ZTWYEEZg1vB6t7XdoSMChghMNJThCEQRhB1FKZtqtqdYbPnau2og0bp+HwkJySJiREaeB1TXWY2s6qRhm/yWRfz4dxPszn+Aecjn/hl5/Iq8/Zm2tz9bN/fd29/6WVNL5Ng1wm0YHTimWME37MtFBSzXc7XyP1dUm+rNj3TfFtU/zYMC1hYVlWyJxNBa9L4ElR0VpybXV7b+wIbyPk0jSUguqSGy2VMrnNVF/VXc0tl4OklsJuH/CMEN5sXIR8QvIsI6wQjbJBm+WlqQT4O+pkdJ6maZ7mu3KSOE7TVBTwRorTSxFwW+3Uj/C4jrr/+fwfnCR4B9eMovCoNCVKN4fL5PgYb91tFEXxSSTLldaXwpTSNEmyLMvBdJ5zfhz7UhhG3Xm7wA+SCNpmQRBJqS4e2w/c243nedCYEALrg7u6FGaUJXEC/WFz8Hsxxh/hGfbsbb04ScjJsxDlIzwDgBFyXRdjDM7Lsroc/gNv6mmr4U+T2AAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;         10 md 1&apos; title=&apos;&apos; src=&apos;/static/c21f574b63bc0892c53a481c368e9b33/dface/%EB%B0%98%EA%B0%91%EB%8B%A4(!)%2C_%EC%9C%8810.md_1.png&apos; srcset=&apos;/static/c21f574b63bc0892c53a481c368e9b33/08678/%EB%B0%98%EA%B0%91%EB%8B%A4(!)%2C_%EC%9C%8810.md_1.png 190w,
/static/c21f574b63bc0892c53a481c368e9b33/2edd7/%EB%B0%98%EA%B0%91%EB%8B%A4(!)%2C_%EC%9C%8810.md_1.png 380w,
/static/c21f574b63bc0892c53a481c368e9b33/dface/%EB%B0%98%EA%B0%91%EB%8B%A4(!)%2C_%EC%9C%8810.md_1.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;우리는 또 수많은 비공개 구초체를 한땀한땀 추가해야 할 뿐이고…&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;시스템 프로그래머 입장에서 새로운 운영체제 발표는 사실 그닥 달갑지는 않은 일입니다. 왜냐하면 운영체제의 비공개된 부분을 사용하기 때문에 그걸 또 죄다 조사해서 맞춰주어야 하거든요. 어려운 작업은 아닌데 단순하고 무식하며 반복적이고 타이핑 실수가 발생하면 엄청나게 골치아파지는 그런 까탈스런 부분이죠. 그래서 설레임보다는 두려움이 앞서기도 합니다. 하지만 포스의 어두운 면과 밝은 면은 항상 공존하는 것처럼 제품을 판매하는 입장에서는 좋은 일이기도 합니다. 허들이 하나 더 추가되는 것이거든요. 왜냐하면 새로 진입하려는 사람들 입장에서는 새로운 운영체제를 추가적으로 지원해야 하는 부담감이 생기게 되는 것이고, 유사 제품을 만드는 회사들에게도 발빠르게 대응하지 않으면 먼저 지원한 제품에게는 차별적인 마케팅 포인트를 내주는 셈이 되기도 하거든요. 아직도 윈 10이 지원되지 않는 보안 제품을 사용하고 계신가요? 뭐 이런거죠? ㅋㅋ~&lt;/p&gt;
&lt;p&gt;직업 프로그래머로 있었던 동안에 지원해야 했던 윈도 클라이언트 운영체제는 95, 98, 2000, XP, VISTA, 7, 8, 8.1에 이어서 아홉번째로 10인데요. 어떤 느낌의 운영체제일지 궁금하네요. 제발 내부적으로 크게 바뀌지 않았기를 미리 빌어봅니다. MS개발자느님들 저에게 자비쩜. 1년에 한번은 좀 빡쎄지 않나요(??!!)…&lt;/p&gt;</content:encoded></item><item><title><![CDATA[예제의 중요성, 복붙 프로그래밍의 위험성]]></title><description><![CDATA[ExampleSlot의 핸들릭을 가진 해킹툴 프로그램 간만에 해킹툴을 하나 살펴보고 있었습니다. 특징적인 게 메일슬롯을 사용하는데 ExampleSlot이란 이벤트 핸들릭이 있었습니다. ExampleSlot…]]></description><link>https://jiniya.net/wp/archives/14297</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14297</guid><pubDate>Mon, 15 Sep 2014 23:59:56 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 615px; margin-bottom: 16px;&apos; data-url=&apos;./예제의_중요성,_복붙_프로그래밍의_위험성.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/e3ecb55b5ef191219a83bbfc50df7699/8ab79/%EC%98%88%EC%A0%9C%EC%9D%98_%EC%A4%91%EC%9A%94%EC%84%B1%2C_%EB%B3%B5%EB%B6%99_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%98_%EC%9C%84%ED%97%98%EC%84%B1.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 94.21052631578947%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAIAAAAf7rriAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACq0lEQVR42oVTa1ObQBTN//8R2k5n/NBa66i109hqYpKqIYGwPJbHAlleIYCJFQivJHRJ1H7QtDtnLnDZM/ee+2i8O/i6d3K3d9LfP6P2T6n3Z8ODJnfU1T93tBrdDTra1vOpgw5b8OOVeHTcPvzwpcHxChRlCFUJqhAqAi+RF1lCqqJLEoKiKsuaqurkgoaw7XhBMHucx+lDZIy9huUGvu+7Djm253lFUZRlWRR5uXmQkxPkeZZlxBLfarVcrVZVtbb83w3Hu1ftwJol06g0rMl9OE/iNErS2A8TwMeilHFCnmR5scyy4gWLeDF2g4bpBGNspllWVRUejwEA7IilOY5vt6VWi6KZYEhXeb4mv9e12Z5lUWgWIbshSZukRFxTz0NIU2RZ1nX19tagKFE35rxQZdlrMiJk64lcEJc3mSAVKbJCyBoh9/uipj3w/G6yE5qmtU3bMk0AuKe0Wy14fU2xIByxO8lEM8Y4TdNaM8YsyzI0PWAB+HkptFt3zChgmNeaV8/kkHRoq9nzJgiRxsqSpm3SvhMRmnPc68hlniPTrzWHQbjVPJ1ODcMgshHGRLA5HMrG+EF4o2CLOFbwtCZb1l/NHOAAC2iOF1pteN2hwP80m6TPaU02MQa1ZmYIOO7ySmy3+yM2YEZv9vmp2q47yTaRXdclgqEIBUVRej3t5gbI8gxw/+pzEATZ85Douo5UVcNY7/fxYFBrJkOy6cUb1SaRbdvZRnZsSxQEgeNZEUqdjtLt0jx/z4Kd1R7bvm05ruuF4cwwsCyroigJkqoMae38XPnetJsXcz+I4iR6jKIorpGQvUnq2SZbVC1XWZzmSVos8jItymxri5KsYF4WKfnM18XyBYSZPkY2WcmrHjNkIcXAwQgOGHEXqGeQaxetX6fffhw3e38AZ6ECiuy6o5EAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                       md 0&apos; title=&apos;&apos; src=&apos;/static/e3ecb55b5ef191219a83bbfc50df7699/8ab79/%EC%98%88%EC%A0%9C%EC%9D%98_%EC%A4%91%EC%9A%94%EC%84%B1%2C_%EB%B3%B5%EB%B6%99_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%98_%EC%9C%84%ED%97%98%EC%84%B1.md_0.png&apos; srcset=&apos;/static/e3ecb55b5ef191219a83bbfc50df7699/08678/%EC%98%88%EC%A0%9C%EC%9D%98_%EC%A4%91%EC%9A%94%EC%84%B1%2C_%EB%B3%B5%EB%B6%99_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%98_%EC%9C%84%ED%97%98%EC%84%B1.md_0.png 190w,
/static/e3ecb55b5ef191219a83bbfc50df7699/2edd7/%EC%98%88%EC%A0%9C%EC%9D%98_%EC%A4%91%EC%9A%94%EC%84%B1%2C_%EB%B3%B5%EB%B6%99_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%98_%EC%9C%84%ED%97%98%EC%84%B1.md_0.png 380w,
/static/e3ecb55b5ef191219a83bbfc50df7699/8ab79/%EC%98%88%EC%A0%9C%EC%9D%98_%EC%A4%91%EC%9A%94%EC%84%B1%2C_%EB%B3%B5%EB%B6%99_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%98_%EC%9C%84%ED%97%98%EC%84%B1.md_0.png 615w&apos; sizes=&apos;(max-width: 615px) 100vw, 615px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;ExampleSlot의 핸들릭을 가진 해킹툴 프로그램&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;간만에 해킹툴을 하나 살펴보고 있었습니다. 특징적인 게 메일슬롯을 사용하는데 ExampleSlot이란 이벤트 핸들릭이 있었습니다. ExampleSlot이라고 네임드 이벤트 이름을 지은 것도 웃긴데, 핸들릭도 어처구니 없는 그런 해킹툴이었죠. 메일슬롯으로 아주 중요한 데이터가 오가는 것 같아서 관련 함수를 살펴보고 있었습니다. 그러다 이 모든 시츄에이션을 설명해주는 MSDN 예제를 만나게 되었습니다. 그제서야 해커가 왜 그런 ㅂㅅ같은 짓을 했는지 자연스럽게 이해가 되더군요. MSDN 예제를 그대로 복사, 붙여넣기 했는데 그 예제에 핸들릭이 있었던 것이죠. 아무 생각없이 사용하다 벌어지는 정말 웃픈 상황이었습니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 505px; margin-bottom: 16px;&apos; data-url=&apos;./예제의_중요성,_복붙_프로그래밍의_위험성.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/8aef95a0fa5b38e69c21f4eb6d307eff/eccca/%EC%98%88%EC%A0%9C%EC%9D%98_%EC%A4%91%EC%9A%94%EC%84%B1%2C_%EB%B3%B5%EB%B6%99_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%98_%EC%9C%84%ED%97%98%EC%84%B1.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 81.57894736842105%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAIAAACZeshMAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABx0lEQVR42pVT25KrIBD0/78yUTHGIPfhLtlWs9mtPJzaM4UUIk3PdI/dVmsIIeWSUwp7eO+Dc1RrJU8pJbxjDj54ooKTRBkjp9ZaF2Iex5Gvd2MNmxgbxxUhZIhRKYlNxDlpJZM1JGVQypOrdeu29vQ+3u/e2DTPk5Ri27bn36KrteDWy4WvwizLPaaIXaT0no9ox/oY7RgnOMY4z3N/vfT95TbdkGoIL/wb3J6fizdztc5xzok8alsePMb0j1QPfDtv6aAb2HwIJRcsrLXOWikEJDn3U0nCSROMIuWC/WR2zk63qe97xtgwDEpKuIJyiBysM6RndWfidpPTohdJSpKkSDsYDzQDZoBjjMHk1n6p3Zr2+mEeD8OBxOL6uFLyZSsvcCkA99d+APnu04/Iu2zWa8BmzYVdZzWPgtXv27vzjJArqNEcnK+o+Tcz6hQkZ72sduWW51p+agZT8MkYTd6XUk/Aa36n8G37p1XoaqLgrIHOOefn/wSYEfXs3gD+ldMqgtJo4GNoj06WCnmhB5USSmocxa/yVntjI775mQ2K8xpTibHGWGIoMdW0v0JUGBEj/roAJAzewSXng/y5bQ1bW2t/T/sLkIqgdyZe7yYAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                       md 1&apos; title=&apos;&apos; src=&apos;/static/8aef95a0fa5b38e69c21f4eb6d307eff/eccca/%EC%98%88%EC%A0%9C%EC%9D%98_%EC%A4%91%EC%9A%94%EC%84%B1%2C_%EB%B3%B5%EB%B6%99_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%98_%EC%9C%84%ED%97%98%EC%84%B1.md_1.png&apos; srcset=&apos;/static/8aef95a0fa5b38e69c21f4eb6d307eff/08678/%EC%98%88%EC%A0%9C%EC%9D%98_%EC%A4%91%EC%9A%94%EC%84%B1%2C_%EB%B3%B5%EB%B6%99_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%98_%EC%9C%84%ED%97%98%EC%84%B1.md_1.png 190w,
/static/8aef95a0fa5b38e69c21f4eb6d307eff/2edd7/%EC%98%88%EC%A0%9C%EC%9D%98_%EC%A4%91%EC%9A%94%EC%84%B1%2C_%EB%B3%B5%EB%B6%99_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%98_%EC%9C%84%ED%97%98%EC%84%B1.md_1.png 380w,
/static/8aef95a0fa5b38e69c21f4eb6d307eff/eccca/%EC%98%88%EC%A0%9C%EC%9D%98_%EC%A4%91%EC%9A%94%EC%84%B1%2C_%EB%B3%B5%EB%B6%99_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%98_%EC%9C%84%ED%97%98%EC%84%B1.md_1.png 505w&apos; sizes=&apos;(max-width: 505px) 100vw, 505px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;CloseHandle은 배고플 때 먹으려고 아껴두었죠.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://msdn.microsoft.com/ko-kr/library/windows/desktop/aa365785(v=vs.85).aspx&quot;&gt;핸들릭을 가진 MSDN 예제&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;언젠가 발표자료에서 보았던 이 그림이 생각나더군요. 생각 없이 코딩하는 프로그래머가 너무 많은 것 같습니다. 생각을 합시다. 머리는 폼으로 달려있는 건 아니잖아요. 물론 남 말 할 때는 아니지만 말입니다. 어쨌든 복사, 붙여넣기 할 때에는 그 코드가 어떤 코드든지, 누가 작성한 코드든지 한번 더 꼼꼼히 검토해 봐야 한다는 걸 잊지 맙시다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 520px; margin-bottom: 16px;&apos; data-url=&apos;./예제의_중요성,_복붙_프로그래밍의_위험성.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5642ad9b69de58a3af34cba1232491db/407f2/%EC%98%88%EC%A0%9C%EC%9D%98_%EC%A4%91%EC%9A%94%EC%84%B1%2C_%EB%B3%B5%EB%B6%99_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%98_%EC%9C%84%ED%97%98%EC%84%B1.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 74.21052631578947%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAA7DAAAOwwHHb6hkAAADdUlEQVR42mMImHQ/ad6jhDmP4uc8Spj7KG72QyAjaubD2DmPUuY/jgYyZj8CkklzH4MEZz1MW/A4bjZIgf+k+wwWdWfCJlyKmHg5buqV+KlXUmZeTZ5xNaT/UtSkSwnTLidOA4pfjpxwMXnGlchJIMHUmVeTpl8L7rtkUn2KoW39/aY198DoQf3q+w2r7zeueQBkN6191LLhafumZ83rnrSsf9K49lHzukdNax83rH4IVNy89j5QI8OBqx8OXPuw/+qnPScuHDt76vTFCxu27VizadvOA7sXLp0/ceqkLVvXrtuw8vCJg6fPHjl9csexsxcOXP984Op7oEaGQ1ffH7r67uDVjweO7r96ce+pY1sOH1i7Z/faY0fW5mf4Whkq5Ce51BSF7N859dy+6ae2tZ44uuXg9a9ALUCNDOfvfTh/7/35+5+PnTowZ1Z3TEx4RnpcbXXR6tWz+jrzI4Pso0PsCtP8J5X6bZ6QcGJr55mTO84/+Hr+7nugRoZbTz7dfPzh9rPvR45sjIu0FxDgERHk5uRg8vOxWDK3sroyMczL0tdc3dNMI8pUZEmN6+ljm28/+3Hr8QegRob7zz/fffrx2bvfk6dO8fJyVlSQFhcTlpIU1VSX93E393Y3tzIz0dXSsjAzsVEXjbUU7Omoe/7x/92nH4AaQZrvPP306u2XpAknJYJblBTEZWUl1FSktLUULUw0vF0Mw/3sbEzN9ZXkgrQk/HWFi8qK33z5f+cJTPPdZ59fvfqUseOb4ZL75vZ2QgJcUrLSSooy8jKiyjJyphqGVupKMSYy/UGqZa6iMfGJb76iaX75MWHlba19P0yC42SkZNLjw6I9Df1M1KwUNe10NV315Tx0xOKtJcocuLuqsp6hOfv1+5/RhY2iy89rePjLScvZmmo1pTrURpvneGvF2ymkuyo5aApbKIlG67DObcl+iqL5yQegSwL8QxgsPVQN9WUk+Pn5Of3cDSJ8jPwsZKzV+V10+QylWDVE2LW4GMrSYl6B/PwepPneM2Bof3r0+sfaTTu7u/sXLVm2cvXqeQsWLly8ZNmKFdNmzp0+e96EqbP6J03r65/c0ty8dv3mx29+ASMIqJHhyeuvQPT41ZdXH3+///H/9ed/rz7+ff3pL5Dx5vPfd1/+A9H7b//fff3/9ss/IPnyw2+gYoguAG06EBzXQ2dwAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                       md 2&apos; title=&apos;&apos; src=&apos;/static/5642ad9b69de58a3af34cba1232491db/407f2/%EC%98%88%EC%A0%9C%EC%9D%98_%EC%A4%91%EC%9A%94%EC%84%B1%2C_%EB%B3%B5%EB%B6%99_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%98_%EC%9C%84%ED%97%98%EC%84%B1.md_2.png&apos; srcset=&apos;/static/5642ad9b69de58a3af34cba1232491db/08678/%EC%98%88%EC%A0%9C%EC%9D%98_%EC%A4%91%EC%9A%94%EC%84%B1%2C_%EB%B3%B5%EB%B6%99_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%98_%EC%9C%84%ED%97%98%EC%84%B1.md_2.png 190w,
/static/5642ad9b69de58a3af34cba1232491db/2edd7/%EC%98%88%EC%A0%9C%EC%9D%98_%EC%A4%91%EC%9A%94%EC%84%B1%2C_%EB%B3%B5%EB%B6%99_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%98_%EC%9C%84%ED%97%98%EC%84%B1.md_2.png 380w,
/static/5642ad9b69de58a3af34cba1232491db/407f2/%EC%98%88%EC%A0%9C%EC%9D%98_%EC%A4%91%EC%9A%94%EC%84%B1%2C_%EB%B3%B5%EB%B6%99_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%98_%EC%9C%84%ED%97%98%EC%84%B1.md_2.png 520w&apos; sizes=&apos;(max-width: 520px) 100vw, 520px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;생각 없는 프로그래머가 너무 많아요. 머리는 폼이 아니라는거~ ㅋㅋ&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[MmIsAddressValid와 PTE]]></title><description><![CDATA[다른 메모리에 접근할 일이 많은 보안 드라이버에서 자주 사용되는 함수 중에 하나가 MmIsAddressValid 함수다. MmIsAddressValid…]]></description><link>https://jiniya.net/wp/archives/14290</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14290</guid><pubDate>Mon, 15 Sep 2014 23:59:55 GMT</pubDate><content:encoded>&lt;p&gt;다른 메모리에 접근할 일이 많은 보안 드라이버에서 자주 사용되는 함수 중에 하나가 MmIsAddressValid 함수다. MmIsAddressValid 함수는 접근하려는 메모리가 제대로 된 메모리인지 검사하는 코드다. 그런데 이 함수에서 말하는 valid의 의미는 생각보다 많이 좁다. 단순히 할당되서 접근할 수 있는 메모리를 의미하는 것이 아닌 실제로 물리 메모리에 존재하는 것들에 대해서만 valid 하다고 판단하기 때문이다. 즉, 페이지 아웃된 메모리는 접근할 수 있지만 MmIsAddressValid 함수는 FALSE를 리턴한다는 말이다.&lt;/p&gt;
&lt;p&gt;그렇다면 페이지 아웃된 메모리까지 넓혀서 접근 가능한 커널 메모리를 체크하려면 어떤 방법이 있을까? 의외로 방법이 없는 것으로 추정(?!) 된다. ProbeForRead 같은 함수를 생각해 볼 수 있는데 해당 함수는 사용자 메모리에 대한 접근 여부를 체크하는 함수다. 커널 메모리를 넣으면 그냥 예외를 발생시키도록 설계돼 있다. 그.래.서. 결국 커널 영역 메모리의 할당 여부를 체크하려면 PDE, PTE를 직접 체크하는 수 밖에는 없다. 아마도…&lt;/p&gt;
&lt;p&gt;직접 체크하는 방법을 구현하려면 PDE, PTE 따위의 구조외 윈도우에서 그것들을 어디에다 매핑시키는지 주소 공간 따위를 알아야 한다. 이게 또 처음 접해보면 다소 생소한 부분이다. 그때 참고하면 도움이 될만한 글이 있어서 소개해본다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blogs.msdn.com/b/ntdebugging/archive/2010/02/05/understanding-pte-part-1-let-s-get-physical.aspx&quot;&gt;PTE 이해하기 1편&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blogs.msdn.com/b/ntdebugging/archive/2010/04/14/understanding-pte-part2-flags-and-large-pages.aspx&quot;&gt;PTE 이해하기 2편&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blogs.msdn.com/b/ntdebugging/archive/2010/06/22/part-3-understanding-pte-non-pae-and-x64.aspx&quot;&gt;PTE 이해하기 3편&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[가상 함수 테이블 보호하기]]></title><description><![CDATA[클라이언트 코드 보안은 여러모로 복마전 같은 느낌이 강하다. CPU…]]></description><link>https://jiniya.net/wp/archives/14277</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14277</guid><pubDate>Fri, 05 Sep 2014 23:59:54 GMT</pubDate><content:encoded>&lt;p&gt;클라이언트 코드 보안은 여러모로 복마전 같은 느낌이 강하다. CPU가 최종적으로 코드를 실행 시키기 때문에 사실상 해커가 코드를 분석하는 것을 완전하게 막는 방법은 없다. 게다가 현대적인 프로그램들은 이미 그 규모가 어마어마하게 크기 때문에 어떤 지점에서 어떤 공격이 벌어질지 사실상 예측하는 것이 불가능하다고 할 수 있다. 이런 이유로 클라이언트 코드 보안 영역에서는 줄기차게 해커와 경쟁을 벌일 수 밖에 없는 구조다. 상황이 이렇다보니 사실상 코드 보안에 대한 해법 보다는 해커와의 비용 경쟁으로 귀결되는 경우가 많다. 그래서 여기엔 해법(solution) 보다는 완화 방안(mitigation method)이 주를 이룬다.&lt;/p&gt;
&lt;p&gt;최근 몇 년 사이 가장 각광받는 클라이언트 코드 공격 기술 중의 하나가 가상 함수 테이블 후킹 기법이다. 이 기법이 유행하게 된 데는 여러가지 이유가 있겠지만 가장 큰 이유는 공격 대상을 찾기가 쉽다는 것과, 한번 찾으면 쉽게 바뀌지 않는다는 점이라고 할 수 있다. 거대한 소프트웨어를 만들기 위해서는 필연적으로 레고 블록 같은 컴포넌트 기술이 발전할 수 밖에 없다. 그런 컴포넌트 기법 중에 사실상 업계 표준이 된 것은 COM이다. COM의 ABI(application binary interface)가 C++의 가상 함수 테이블의 구조로 이루어졌기에 광범위한 곳에서 C++의 가상함수 테이블과 유사한 바이너리 체계를 사용하게 되었다. 컴포넌트 인터페이스가 가지는 또 하나의 주요한 특징은 한번 정의되고 나면 바꾸기가 쉽지 않다는 점이다. 왜냐하면 여기저기 얽혀있는 경우가 많고, 심지어는 외부의 모듈들이 내부 컴포넌트를 참조하는 경우도 있기 때문이다. 이런 사실은 결국 해커 입장에서는 한번 공격하면 오랫동안 지속시킬 수 있다는 것을 의미하기 때문에 공격 비용이 낮아진다는 것과 같은 말이 된다. 해커 입장에서는 아주 빨대를 꽂기에 좋은 지점이지만 방어하는 입장에서는 한두군데가 아니기 때문에 아주 뼈아픈 지점이다.&lt;/p&gt;
&lt;p&gt;그럼 실제로 공격이 어떤 방법으로 이루어지고 그걸 또 어떤 방식으로 방어할 수 있는지 알아보도록 하자. [리스트 1] 에는 간단한 가상 함수 테이블을 후킹하는 코드가 나와 있다. ICharacter 클래스는 체력을 구하는 GetHP 함수와, 체력을 설정하는 SetHP 함수를 가지고 있다. main을 살펴보면 캐릭터를 생성하고 10씩 체력을 감소시켜 가기 때문에 코드가 정상적으로 수행됐다면 90부터 0까지 값이 출력되어야 한다. 하지만 예제에서는 GetHP 함수를 HookGetHP로 대체했기 때문에 체력이 줄어들지 않고 모두 100으로 출력된다. 이런 원리로 게임에서 무적 핵이 만들어지곤 한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 1 vftable 후킹 예제&lt;/strong&gt;
&lt;a href=&quot;/codewiz/assets/files/2015/vftablehook.cpp&quot;&gt;소스 코드 다운로드&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;windows.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ICharacter&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; WINAPI &lt;span class=&quot;token function&quot;&gt;GetHP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; WINAPI &lt;span class=&quot;token function&quot;&gt;SetHP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; hp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Romeo&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token base-clause&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ICharacter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; hp_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;Romeo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; hp_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; WINAPI &lt;span class=&quot;token function&quot;&gt;GetHP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; hp_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; WINAPI &lt;span class=&quot;token function&quot;&gt;SetHP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; hp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; hp_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; hp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; WINAPI &lt;span class=&quot;token function&quot;&gt;HookGetHP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID obj&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;HookVftable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID obj&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; vf_idx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PVOID hook_fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PVOID &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;or_fn&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ULONG_PTR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;xobj &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG_PTR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; obj&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG_PTR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;vft &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG_PTR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; xobj&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;or_fn&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;or_fn &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; vft&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;vf_idx&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	ULONG oldp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;VirtualProtect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;vft&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;vf_idx&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hook_fn&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PAGE_READWRITE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;oldp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	vft&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;vf_idx&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG_PTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; hook_fn&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;VirtualProtect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;vft&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;vf_idx&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hook_fn&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; oldp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;oldp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ICharacter &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;chr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Romeo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;HookVftable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;chr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HookGetHP&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		chr&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SetHP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;chr&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetHP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; chr&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetHP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;getchar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;앞서도 말했지만 이런 코드 공격은 게임에서만 벌어지는 것은 아니다. 인터페이스가 존재하는 모든 프로그램들이 공격 대상이 될 수 있다. 특히나 웹 브라우저 같은 프로그램은 해커에게 아주 좋은 먹잇감이 되곤 한다. Internet Explorer 10 버전부터는 이러한 가상 함수 테이블 변조를 방지하기 위해서 주요 인터페이스 코드에 VTGuard란 것이 적용되었다.&lt;/p&gt;
&lt;p&gt;VTGuard의 원리는 간단하다. 가상 함수 테이블 끝에 추가적인 필드를 붙여서 중간의 함수 메소드 값이 변경되었는지 검사하는 방식이다. [그림 1]에 나와 있는 것과 같이 테이블 끝에 vtguard에 해당하는 값을 넣어서 중간에 값이 변경되었는지 검사할 수 있다. vtguard에 VirtualMethod1, 2, 3, 4, …의 CRC 값이 담겨 있다면 앞선 가상 함수들이 호출될 때 테이블의 무결성을 검증할 수 있다. 물론 그 검증하는 코드는 모든 가상 함수의 앞쪽에 붙어 있어야 할 것이다. 물론 이 VTGuard라는 기법 자체도 가상 함수 변조를 완전히 막는 솔루션은 아니다. 왜냐하면 해커가 가상 함수의 값을 변경하고, 그에 맞춰서 vtguard의 값도 업데이트 한다면 우회할 수 있기 때문이다. 서두에 언급한 것과 같이 가상 함수 변조를 조금 더 어렵게 만드는 취약점 완화 방안이라고 생각하면 될 것 같다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 257px; margin-bottom: 16px;&apos; data-url=&apos;./가상_함수_테이블_보호하기.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f33f6b9c4ebcfc343dad793545c985a9/7101e/%EA%B0%80%EC%83%81_%ED%95%A8%EC%88%98_%ED%85%8C%EC%9D%B4%EB%B8%94_%EB%B3%B4%ED%98%B8%ED%95%98%EA%B8%B0.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 71.57894736842105%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAA7DAAAOwwHHb6hkAAADgUlEQVR42kWS21NTVxyF8wf5UocWxci0L0yrTKmQIncRofAHoBVoxxlkcKiWixkBaakwpUVuTcJFAlhMQu6ggdxvtMpNmISLaB86rXz9nfPShzVn77XPXufbax+NVqulra2Nrq77dHZ2cl+vp7u7m56eHlEvvb2ihw/p6+2hr+8Hfuzvp180ODjIT48eMTAwIOMBhoaGaG1tRZOTk0MiHsPtdrJkteDzPcdiWcRmteJ22FldWyUUChCLxUgkYjjsSyx7PdjtNjweN6FgEJfbzeHhIaOjo2i057MZM5oxTi0wYZpj3DjLyMQMY4ZZxkWG6adMzT5TNW22YJS5YWpe9sxx57t2bly/TmNjk3rK+vp6NFnnP2HBd8CcZ5sZxwYzrg3mV3aYXFrHZE0yMutjaMrHpH0Dw7MERmuCx2Y/qzvQ2NKJLv8LKq9epby8nJqaGgnUfozVv89K8i9ckSM8sTd448e4o0e4wgc4QmkcwX3c4rvEU3ybf4+1Tbh1R09JUaEEfUVtbS11dXVozkrgU19aCLeE8CVPnK8we7eELobJEmdsbpVfZ3zMODdUYpM1zmOh9qyf8G2rnstfFlB17RrXRCrhmXPZWANpniff4YkKnZAsJ96xHH+r0jiCKZyhA3VNmSvrVjmvfwsJ7KJQl68euaqqiurqajSZWdnMK4TeHaYVQvemEG5jsMTUvsYXAgw/WZNuNzHZ1lVv4vcw9vg/NLV0SYd5XLlSSWVlpRqqyTyrxaYQJt6qFB6hWJHxcuIYT+QQR2BPCPdV3xM9lI6lQ982wdfQdLuD/Et5VFRUqFJCNR+eOcf8ixRm6XBy6Q/p6hWzQjmxGJZbjTE27+eX6RdMS4dG6VTR8MwKjuR7Gpo7uJSXS1lZmSolVJORmYUt8oZoCgI7J4R2Ub+uSJkHX58Q3kP1/9d7Ivtws7mdvM8vUlpaJipVQzUZGR/hdMQJh1P4/bsEAruEZByNHhD077Dm2yIaSRMJK0oRlAr84sfjR/JD3yY39wLFxcUUFRVRUlIit3z6NMfLLvgzwUkiAutx/vavkLYtcuSyk3YuceR1si/PlNMGySj/xkLwMsm9hq/J+ewClwsLKRQpoZoPTp3C1NLMYsf3LLbfw3y3DUNHN5N3OxluusnPDQ2M3PqG3+QdY0sL9gd6rPouvD0PuCG3+unFXHQFBeh0OjX0Py0cSWssySt4AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;               md 0&apos; title=&apos;&apos; src=&apos;/static/f33f6b9c4ebcfc343dad793545c985a9/7101e/%EA%B0%80%EC%83%81_%ED%95%A8%EC%88%98_%ED%85%8C%EC%9D%B4%EB%B8%94_%EB%B3%B4%ED%98%B8%ED%95%98%EA%B8%B0.md_0.png&apos; srcset=&apos;/static/f33f6b9c4ebcfc343dad793545c985a9/08678/%EA%B0%80%EC%83%81_%ED%95%A8%EC%88%98_%ED%85%8C%EC%9D%B4%EB%B8%94_%EB%B3%B4%ED%98%B8%ED%95%98%EA%B8%B0.md_0.png 190w,
/static/f33f6b9c4ebcfc343dad793545c985a9/7101e/%EA%B0%80%EC%83%81_%ED%95%A8%EC%88%98_%ED%85%8C%EC%9D%B4%EB%B8%94_%EB%B3%B4%ED%98%B8%ED%95%98%EA%B8%B0.md_0.png 257w&apos; sizes=&apos;(max-width: 257px) 100vw, 257px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;그림 1 vtguard 구조&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;가상 함수 테이블 변조가 프로그램의 심각한 취약점이 되면서 많은 컴파일러들이 VTGuard와 유사한 메커니즘을 속속 추가하고 있다. 보안 프로그래머 입장에서는 새로운 방어 기법과 컴파일러 옵션을 이해하는 것도 중요하지만 가장 원론적인 구성 원리를 체득하기 위해서는 그 메커니즘을 직접 구현해 보는 것이 가장 좋다. [리스트 2]에는 VTGuard를 구현할 수 있는 기본적인 매크로를 추가해 두었다. 살펴보면 가상 함수 끝에 엔트리를 추가하기 위해서 DECL_VT_GUARD라는 것을, vtguard 값의 초기화를 위해서 생성자에는 INIT_VT_GUARD를, 그리고 모든 멤버 함수 앞에는 가상 함수 테이블의 무결성을 검증하기 위한 CHECK_VT_GUARD 매크로가 추가됐다. 각각의 매크로를 구현해서 [리스트 1]의 코드와 연결했을 때 프로그램이 정상적으로 실행되지 않도록 만들어 보자.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 2 VTGuard의 구현&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Romeo&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token base-clause&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ICharacter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; hp_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;Romeo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;INIT_VT_GUARD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; hp_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; WINAPI &lt;span class=&quot;token function&quot;&gt;GetHP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CHECK_VT_GUARD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; hp_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; WINAPI &lt;span class=&quot;token function&quot;&gt;SetHP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; hp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CHECK_VT_GUARD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; hp_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; hp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;DECL_VT_GUARD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;덧) 여러분의 해법을 기다리고 있답니다. 썩 잘 만들었다고 생각하신다면 codewiz at gmail dot com으로 보내주세요. &lt;a href=&quot;http://www.jiniya.net/wp/archives/12367&quot;&gt;함께 할 만한 일이 있을지도 모르잖아요&lt;/a&gt; ^^;;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[윈도우 2k: kernel32, ntdll 함수 덤프]]></title><description><![CDATA[MSDN 도움말에서 윈도우 2000이 사라진지 참 오래됐지요. 그럼에도 불구하고 여전히 윈도우 2000에서 돌아가는 프로그램을 만들어야 하는 개발자라면 과연 이 API가 윈도우 200…]]></description><link>https://jiniya.net/wp/archives/14265</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14265</guid><pubDate>Thu, 04 Sep 2014 23:59:53 GMT</pubDate><content:encoded>&lt;p&gt;MSDN 도움말에서 윈도우 2000이 사라진지 참 오래됐지요. 그럼에도 불구하고 여전히 윈도우 2000에서 돌아가는 프로그램을 만들어야 하는 개발자라면 과연 이 API가 윈도우 2000에 있는건지 없는건지 참 헷갈리는 경우가 많습니다. 그래서 써야 할까 말아야 할까? 동적 바인딩을 해야할까? 그냥 써도 될까? 궁금한거죠. 그러다 까딱 잘못하면 뭐 함수를 찾을 수 없다는 엄청난 오류에 봉착하곤 합니다. 그래서 매번 테스트 해보거나 윈도우 2000에서 dependency walker에 넣어서 보곤 했는데요. 귀찮아서 한번 덤프를 떠봤습니다. 저같은 고민을 하는 개발자라면 도움이 될지도 모르겠습니다. 윈도우 2000에 포함된 kernel32.dll과 ntdll.dll에 포함된 함수 덤프 정보입니다. 다소 스압이 있을지도 모르니 주의하시길 ㅋ~&lt;/p&gt;
&lt;p&gt;덧) 특정 DLL의 익스포트 함수 목록을 추출하는 방법이 궁금하신 분들은 &lt;a href=&quot;/codewiz/assets/files/2015/dump_eat.7z&quot;&gt;dump_eat 프로젝트 소스 코드를&lt;/a&gt; 다운로드 받아보세요.&lt;/p&gt;
&lt;h3&gt;kernel32.dll 정보&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;// kernel32.dll
   1 0001B65B AddAtomA
   2 0000DF58 AddAtomW
   3 0004639D AddConsoleAliasA
   4 00046366 AddConsoleAliasW
   5 00047187 AllocConsole
   6 000355B2 AllocateUserPhysicalPages
   7 00016C75 AreFileApisANSI
   8 00045AF4 AssignProcessToJobObject
   9 0002B9F6 BackupRead
  10 0002BC52 BackupSeek
  11 0002C5B9 BackupWrite
  12 0002ABAC BaseAttachCompleteThunk
  13 0002C7D7 Beep
  14 000423C9 BeginUpdateResourceA
  15 000421D2 BeginUpdateResourceW
  16 0003C271 BindIoCompletionCallback
  17 00044B59 BuildCommDCBA
  18 00044AE3 BuildCommDCBAndTimeoutsA
  19 00044A90 BuildCommDCBAndTimeoutsW
  20 00044B09 BuildCommDCBW
  21 000374F3 CallNamedPipeA
  22 000028B5 CallNamedPipeW
  23 000382B3 CancelDeviceWakeupRequest
  24 00030DFA CancelIo
  25 0003C4D4 CancelTimerQueueTimer
  26 0000301C CancelWaitableTimer
  27 0003C38F ChangeTimerQueueTimer
  28 0003DF83 ClearCommBreak
  29 0003DF91 ClearCommError
  30 00005C50 CloseConsoleHandle
  31 00009168 CloseHandle
  32 0001F8CB CloseProfileUserMapping
  33 00021580 CmdBatNotification
  34 0003DB27 CommConfigDialogA
  35 0003DA4B CommConfigDialogW
  36 0001076D CompareFileTime
  37 0000D3D4 CompareStringA
  38 0000E2FB CompareStringW
  39 00009A1D ConnectNamedPipe
  40 000040CC ConsoleMenuControl
  41 0002DDC9 ContinueDebugEvent
  42 00004856 ConvertDefaultLocale
  43 00020E6C ConvertThreadToFiber
  44 000146C0 CopyFileA
  45 000324D4 CopyFileExA
  46 00014736 CopyFileExW
  47 00020069 CopyFileW
  48 0004876A CreateConsoleScreenBuffer
  49 000239D8 CreateDirectoryA
  50 0002E0A8 CreateDirectoryExA
  51 0001F9FD CreateDirectoryExW
  52 0001DFF5 CreateDirectoryW
  53 00014CEA CreateEventA
  54 0001B259 CreateEventW
  55 00020D7E CreateFiber
  56 00020D96 CreateFiberEx
  57 000157E2 CreateFileA
  58 0000C8DA CreateFileMappingA
  59 000143E4 CreateFileMappingW
  60 0000C351 CreateFileW
  61 00045CFA CreateHardLinkA
  62 00045D4D CreateHardLinkW
  63 000099CD CreateIoCompletionPort
  64 0004594B CreateJobObjectA
  65 000459B0 CreateJobObjectW
  66 00016DA5 CreateMailslotA
  67 00016CAF CreateMailslotW
  68 0000A4F6 CreateMutexA
  69 0001D584 CreateMutexW
  70 00036D7A CreateNamedPipeA
  71 00022806 CreateNamedPipeW
  72 000206B1 CreatePipe
  73 0001C0A0 CreateProcessA
  74 0001BF86 CreateProcessInternalA
  75 00011BA0 CreateProcessInternalW
  76 00038628 CreateProcessInternalWSecure
  77 0000B252 CreateProcessW
  78 000133C3 CreateRemoteThread
  79 00006890 CreateSemaphoreA
  80 0001EAD5 CreateSemaphoreW
  81 0004583F CreateTapePartition
  82 000095C2 CreateThread
  83 0003C31A CreateTimerQueue
  84 0003C33B CreateTimerQueueTimer
  85 0003C50F CreateToolhelp32Snapshot
  86 00006DC4 CreateVirtualBuffer
  87 00002FE4 CreateWaitableTimerA
  88 00020B94 CreateWaitableTimerW
  89 0002DDFB DebugActiveProcess
  90 0002D9F6 DebugBreak
  91 000303DF DefineDosDeviceA
  92 000148BE DefineDosDeviceW
  93 00057090 DelayLoadFailureHook
  94 0000DFA9 DeleteAtom
  95          DeleteCriticalSection =&gt; NTDLL.RtlDeleteCriticalSection
  96 00020E22 DeleteFiber
  97 0001BEEA DeleteFileA
  98 0000D9F9 DeleteFileW
  99 0003C4B0 DeleteTimerQueue
 100 0003C41B DeleteTimerQueueEx
 101 0003C3D0 DeleteTimerQueueTimer
 102 00041972 DeleteVolumeMountPointA
 103 00041B33 DeleteVolumeMountPointW
 104 0001D626 DeviceIoControl
 105 0001C912 DisableThreadLibraryCalls
 106 00009A9D DisconnectNamedPipe
 107 0002D1D3 DnsHostnameToComputerNameA
 108 0002D13B DnsHostnameToComputerNameW
 109 00007B91 DosDateTimeToFileTime
 110 00039A1B DosPathToSessionPathA
 111 00017417 DosPathToSessionPathW
 112 00005C98 DuplicateConsoleHandle
 113 0000E960 DuplicateHandle
 114 00042746 EndUpdateResourceA
 115 000425DA EndUpdateResourceW
 116          EnterCriticalSection =&gt; NTDLL.RtlEnterCriticalSection
 117 0004ACB8 EnumCalendarInfoA
 118 0004ACD4 EnumCalendarInfoExA
 119 0004D407 EnumCalendarInfoExW
 120 0004D3EB EnumCalendarInfoW
 121 0004AD06 EnumDateFormatsA
 122 0004AD1E EnumDateFormatsExA
 123 0004D423 EnumDateFormatsExW
 124 0001814F EnumDateFormatsW
 125 0004AEB0 EnumLanguageGroupLocalesA
 126 0004D3A9 EnumLanguageGroupLocalesW
 127 0003695F EnumResourceLanguagesA
 128 00023BC7 EnumResourceLanguagesW
 129 0003673A EnumResourceNamesA
 130 00001530 EnumResourceNamesW
 131 00036545 EnumResourceTypesA
 132 00036ADD EnumResourceTypesW
 133 0004AEE0 EnumSystemCodePagesA
 134 0004D3D9 EnumSystemCodePagesW
 135 0004AE9A EnumSystemLanguageGroupsA
 136 0004D393 EnumSystemLanguageGroupsW
 137 00017BA1 EnumSystemLocalesA
 138 00018127 EnumSystemLocalesW
 139 0004ACF0 EnumTimeFormatsA
 140 00018139 EnumTimeFormatsW
 141 0004AECA EnumUILanguagesA
 142 0004D3C3 EnumUILanguagesW
 143 00045813 EraseTape
 144 0003E1AD EscapeCommFunction
 145 0000E01A ExitProcess
 146 00005F3B ExitThread
 147 000031EF ExitVDM
 148 00017208 ExpandEnvironmentStringsA
 149 0001A0EC ExpandEnvironmentStringsW
 150 0004699E ExpungeConsoleCommandHistoryA
 151 00046990 ExpungeConsoleCommandHistoryW
 152 00035E47 ExtendVirtualBuffer
 153 00039397 FatalAppExitA
 154 00039350 FatalAppExitW
 155 000393DE FatalExit
 156 0000D1B2 FileTimeToDosDateTime
 157 0000EA21 FileTimeToLocalFileTime
 158 000095E2 FileTimeToSystemTime
 159 000045A6 FillConsoleOutputAttribute
 160 0004872D FillConsoleOutputCharacterA
 161 0004874D FillConsoleOutputCharacterW
 162 00016410 FindAtomA
 163 0002EAD1 FindAtomW
 164 0000EE4B FindClose
 165 0001B2CF FindCloseChangeNotification
 166 000249A2 FindFirstChangeNotificationA
 167 0001B6AB FindFirstChangeNotificationW
 168 0001D88F FindFirstFileA
 169 00030748 FindFirstFileExA
 170 0000C96C FindFirstFileExW
 171 00007770 FindFirstFileW
 172 0004048D FindFirstVolumeA
 173 00040738 FindFirstVolumeMountPointA
 174 00040B52 FindFirstVolumeMountPointW
 175 00003F28 FindFirstVolumeW
 176 00023D67 FindNextChangeNotification
 177 00010275 FindNextFileA
 178 0000CCB3 FindNextFileW
 179 000405CC FindNextVolumeA
 180 00040C5F FindNextVolumeMountPointA
 181 00040EB5 FindNextVolumeMountPointW
 182 00021E34 FindNextVolumeW
 183 0001D38D FindResourceA
 184 00014B2C FindResourceExA
 185 0000B82D FindResourceExW
 186 0000B622 FindResourceW
 187 00004052 FindVolumeClose
 188 0001B2CF FindVolumeMountPointClose
 189 000045C3 FlushConsoleInputBuffer
 190 0001C9CC FlushFileBuffers
 191 0001132B FlushInstructionCache
 192 0000E2C6 FlushViewOfFile
 193 0004AD44 FoldStringA
 194 0001AD12 FoldStringW
 195 00016DEF FormatMessageA
 196 00006DA1 FormatMessageW
 197 0004739A FreeConsole
 198 0000A8A4 FreeEnvironmentStringsA
 199 0000A8A4 FreeEnvironmentStringsW
 200 0000DFDA FreeLibrary
 201 0000FFE9 FreeLibraryAndExitThread
 202 0000754C FreeResource
 203 000355D9 FreeUserPhysicalPages
 204 00006E63 FreeVirtualBuffer
 205 00048E8F GenerateConsoleCtrlEvent
 206 0000FE74 GetACP
 207 00023F24 GetAtomNameA
 208 0000DF68 GetAtomNameW
 209 0003EFCA GetBinaryType
 210 0003EFCA GetBinaryTypeA
 211 00020F84 GetBinaryTypeW
 212 0000B732 GetCPInfo
 213 0004AEF2 GetCPInfoExA
 214 00050CF3 GetCPInfoExW
 215 0004A4C6 GetCalendarInfoA
 216 00004EDC GetCalendarInfoW
 217 0003E2AE GetCommConfig
 218 0003E43C GetCommMask
 219 0003E4BA GetCommModemStatus
 220 0003E538 GetCommProperties
 221 0003E5E9 GetCommState
 222 0003E87C GetCommTimeouts
 223 00014B16 GetCommandLineA
 224 0001386F GetCommandLineW
 225 00031D43 GetCompressedFileSizeA
 226 00031D64 GetCompressedFileSizeW
 227 0001631F GetComputerNameA
 228 00001779 GetComputerNameExA
 229 0001C5F7 GetComputerNameExW
 230 0000F7C8 GetComputerNameW
 231 00046505 GetConsoleAliasA
 232 000468F9 GetConsoleAliasExesA
 233 0004663F GetConsoleAliasExesLengthA
 234 00046637 GetConsoleAliasExesLengthW
 235 000468E7 GetConsoleAliasExesW
 236 000464E0 GetConsoleAliasW
 237 000467B3 GetConsoleAliasesA
 238 000465D2 GetConsoleAliasesLengthA
 239 000465C4 GetConsoleAliasesLengthW
 240 0004679D GetConsoleAliasesW
 241 0000465B GetConsoleCP
 242 00049746 GetConsoleCharType
 243 00046C80 GetConsoleCommandHistoryA
 244 00046B0A GetConsoleCommandHistoryLengthA
 245 00046AFC GetConsoleCommandHistoryLengthW
 246 00046C6A GetConsoleCommandHistoryW
 247 00022291 GetConsoleCursorInfo
 248 00049911 GetConsoleCursorMode
 249 000220DB GetConsoleDisplayMode
 250 00048C35 GetConsoleFontInfo
 251 00048D5C GetConsoleFontSize
 252 000479C5 GetConsoleHardwareState
 253 00046D91 GetConsoleInputExeNameA
 254 00046E12 GetConsoleInputExeNameW
 255 00047478 GetConsoleInputWaitHandle
 256 00004710 GetConsoleKeyboardLayoutNameA
 257 000494F7 GetConsoleKeyboardLayoutNameW
 258 0000C0DA GetConsoleMode
 259 00049554 GetConsoleNlsMode
 260 0000C16D GetConsoleOutputCP
 261 0001CEAA GetConsoleScreenBufferInfo
 262 00046D2A GetConsoleTitleA
 263 0000EDB2 GetConsoleTitleW
 264 00049505 GetConsoleWindow
 265 0004AA47 GetCurrencyFormatA
 266 00053056 GetCurrencyFormatW
 267 00048DC4 GetCurrentConsoleFont
 268 00015813 GetCurrentDirectoryA
 269 0001BAC7 GetCurrentDirectoryW
 270 0001E0C8 GetCurrentProcess
 271 0000B8F4 GetCurrentProcessId
 272 00015633 GetCurrentThread
 273 000110D1 GetCurrentThreadId
 274 00017A38 GetDateFormatA
 275 00018893 GetDateFormatW
 276 0003DCE2 GetDefaultCommConfigA
 277 0003DC06 GetDefaultCommConfigW
 278 00055438 GetDefaultSortkeySize
 279 0003824E GetDevicePowerState
 280 0000ACF8 GetDiskFreeSpaceA
 281 0001AE60 GetDiskFreeSpaceExA
 282 0001AE8E GetDiskFreeSpaceExW
 283 0000AD29 GetDiskFreeSpaceW
 284 0000A6B4 GetDriveTypeA
 285 000067A7 GetDriveTypeW
 286 0001092C GetEnvironmentStrings
 287 0001092C GetEnvironmentStringsA
 288 0000733F GetEnvironmentStringsW
 289 0000614F GetEnvironmentVariableA
 290 0000BB88 GetEnvironmentVariableW
 291 0001BC2B GetExitCodeProcess
 292 0001F362 GetExitCodeThread
 293 00015134 GetFileAttributesA
 294 0003112C GetFileAttributesExA
 295 0001DCC7 GetFileAttributesExW
 296 0001B5CE GetFileAttributesW
 297 0000B0C4 GetFileInformationByHandle
 298 0001D0D4 GetFileSize
 299 0001D109 GetFileSizeEx
 300 00005E40 GetFileTime
 301 0001544F GetFileType
 302 00007A45 GetFullPathNameA
 303 00005D07 GetFullPathNameW
 304 000356C0 GetHandleInformation
 305 00048ADF GetLargestConsoleWindowSize
 306 0001278D GetLastError
 307 00055456 GetLinguistLangSize
 308 000106E0 GetLocalTime
 309 0000A132 GetLocaleInfoA
 310 00007786 GetLocaleInfoW
 311 00037D4E GetLogicalDriveStringsA
 312 000029BF GetLogicalDriveStringsW
 313 0000E4DB GetLogicalDrives
 314 00040164 GetLongPathNameA
 315 00021A72 GetLongPathNameW
 316 00035CB6 GetMailslotInfo
 317 00014C44 GetModuleFileNameA
 318 00010FB7 GetModuleFileNameW
 319 0000AB06 GetModuleHandleA
 320 00010182 GetModuleHandleW
 321 00036F92 GetNamedPipeHandleStateA
 322 00037071 GetNamedPipeHandleStateW
 323 00037290 GetNamedPipeInfo
 324 00021179 GetNextVDMCommand
 325 00011191 GetNlsSectionName
 326 0004A825 GetNumberFormatA
 327 00022C57 GetNumberFormatW
 328 000489D7 GetNumberOfConsoleFonts
 329 00048A26 GetNumberOfConsoleInputEvents
 330 00048B85 GetNumberOfConsoleMouseButtons
 331 00011562 GetOEMCP
 332 0001449E GetOverlappedResult
 333 00039573 GetPriorityClass
 334 0000ACAE GetPrivateProfileIntA
 335 00015F45 GetPrivateProfileIntW
 336 0002F005 GetPrivateProfileSectionA
 337 0002EAE1 GetPrivateProfileSectionNamesA
 338 0002EAFA GetPrivateProfileSectionNamesW
 339 00023726 GetPrivateProfileSectionW
 340 0000EC3E GetPrivateProfileStringA
 341 0000D957 GetPrivateProfileStringW
 342 0002EB13 GetPrivateProfileStructA
 343 0002EC24 GetPrivateProfileStructW
 344 0000E6A9 GetProcAddress
 345 000173D7 GetProcessAffinityMask
 346 0000AC86 GetProcessHeap
 347 00016C9C GetProcessHeaps
 348 000398B6 GetProcessIoCounters
 349 00039883 GetProcessPriorityBoost
 350 00039617 GetProcessShutdownParameters
 351 00039692 GetProcessTimes
 352 0001C933 GetProcessVersion
 353 00039705 GetProcessWorkingSetSize
 354 00011538 GetProfileIntA
 355 00016420 GetProfileIntW
 356 0002EF51 GetProfileSectionA
 357 00023710 GetProfileSectionW
 358 0000C905 GetProfileStringA
 359 0000AB2B GetProfileStringW
 360 0000FE7A GetQueuedCompletionStatus
 361 0001A1E1 GetShortPathNameA
 362 0001E1CC GetShortPathNameW
 363 000149DF GetStartupInfoA
 364 00017109 GetStartupInfoW
 365 0000AF0D GetStdHandle
 366 00017B2B GetStringTypeA
 367 000223CA GetStringTypeExA
 368 00017CB0 GetStringTypeExW
 369 00006658 GetStringTypeW
 370 00019A86 GetSystemDefaultLCID
 371 00015150 GetSystemDefaultLangID
 372 0001F14B GetSystemDefaultUILanguage
 373 0000EDED GetSystemDirectoryA
 374 0000FF1C GetSystemDirectoryW
 375 0001AAA4 GetSystemInfo
 376 000207D1 GetSystemPowerStatus
 377 000069F9 GetSystemTime
 378 0002D737 GetSystemTimeAdjustment
 379 000072E5 GetSystemTimeAsFileTime
 380 00019796 GetSystemWindowsDirectoryA
 381 000078B2 GetSystemWindowsDirectoryW
 382 000458A5 GetTapeParameters
 383 0004578F GetTapePosition
 384 00045934 GetTapeStatus
 385 000070D4 GetTempFileNameA
 386 0001D962 GetTempFileNameW
 387 00013B81 GetTempPathA
 388 00006476 GetTempPathW
 389 00003050 GetThreadContext
 390 0000C1C4 GetThreadLocale
 391 0000A545 GetThreadPriority
 392 0003BB69 GetThreadPriorityBoost
 393 0002DFF6 GetThreadSelectorEntry
 394 00020D1E GetThreadTimes
 395 00015594 GetTickCount
 396 0001796C GetTimeFormatA
 397 0001B481 GetTimeFormatW
 398 00015177 GetTimeZoneInformation
 399 000115AD GetUserDefaultLCID
 400 000115AD GetUserDefaultLangID
 401 0001E96D GetUserDefaultUILanguage
 402 0003F3F3 GetVDMCurrentDirectories
 403 0001EB3A GetVersion
 404 00013C2D GetVersionExA
 405 0000E8A7 GetVersionExW
 406 0001199F GetVolumeInformationA
 407 000109E7 GetVolumeInformationW
 408 00040ECB GetVolumeNameForVolumeMountPointA
 409 000076EC GetVolumeNameForVolumeMountPointW
 410 00041E15 GetVolumePathNameA
 411 00041F32 GetVolumePathNameW
 412 00009C00 GetWindowsDirectoryA
 413 0000B810 GetWindowsDirectoryW
 414 00035668 GetWriteWatch
 415 0000E2B6 GlobalAddAtomA
 416 0000727B GlobalAddAtomW
 417 000116B4 GlobalAlloc
 418 0003599B GlobalCompact
 419 0001596E GlobalDeleteAtom
 420 00009F88 GlobalFindAtomA
 421 0000CC0B GlobalFindAtomW
 422 000354A9 GlobalFix
 423 00015B74 GlobalFlags
 424 000132AF GlobalFree
 425 000248EE GlobalGetAtomNameA
 426 0000DF91 GlobalGetAtomNameW
 427 00014344 GlobalHandle
 428 0001E6AF GlobalLock
 429 00009D2A GlobalMemoryStatus
 430 000025DB GlobalMemoryStatusEx
 431 00007416 GlobalReAlloc
 432 00014286 GlobalSize
 433 000354E2 GlobalUnWire
 434 000354BE GlobalUnfix
 435 0000B426 GlobalUnlock
 436 000354D3 GlobalWire
 437 0003C6D1 Heap32First
 438 0003C590 Heap32ListFirst
 439 0003C63F Heap32ListNext
 440 0003C7DD Heap32Next
 441          HeapAlloc =&gt; NTDLL.RtlAllocateHeap
 442 000073F4 HeapCompact
 443 0001AE05 HeapCreate
 444 00035A18 HeapCreateTagsW
 445 00014567 HeapDestroy
 446 000359EE HeapExtend
 447          HeapFree =&gt; NTDLL.RtlFreeHeap
 448 00035B0E HeapLock
 449 00035A31 HeapQueryTagW
 450          HeapReAlloc =&gt; NTDLL.RtlReAllocateHeap
 451          HeapSize =&gt; NTDLL.RtlSizeHeap
 452 00035A4D HeapSummary
 453 00035B21 HeapUnlock
 454 00035AA1 HeapUsage
 455 0001B240 HeapValidate
 456 00035B34 HeapWalk
 457 0002EAAA InitAtomTable
 458 0001BE13 InitializeCriticalSection
 459 00015157 InitializeCriticalSectionAndSpinCount
 460 0000A96D InterlockedCompareExchange
 461 0001C23D InterlockedDecrement
 462 00008FBC InterlockedExchange
 463 00013E7C InterlockedExchangeAdd
 464 0001C22C InterlockedIncrement
 465 000488FC InvalidateConsoleDIBits
 466 000150C4 IsBadCodePtr
 467 00006AE2 IsBadHugeReadPtr
 468 0000A4E6 IsBadHugeWritePtr
 469 0000F0F7 IsBadReadPtr
 470 0001BE4B IsBadStringPtrA
 471 000159F3 IsBadStringPtrW
 472 0001A055 IsBadWritePtr
 473 0000CC8D IsDBCSLeadByte
 474 0001871B IsDBCSLeadByteEx
 475 0000191E IsDebuggerPresent
 476 000062D7 IsProcessorFeaturePresent
 477 0003828B IsSystemResumeAutomatic
 478 000060C4 IsValidCodePage
 479 0004BF19 IsValidLanguageGroup
 480 00017D7E IsValidLocale
 481 00017859 LCMapStringA
 482 00019CA1 LCMapStringW
 483          LeaveCriticalSection =&gt; NTDLL.RtlLeaveCriticalSection
 484 000105CF LoadLibraryA
 485 00010606 LoadLibraryExA
 486 0001A952 LoadLibraryExW
 487 000152C5 LoadLibraryW
 488 00038FAD LoadModule
 489 0000A63A LoadResource
 490 0001C13B LocalAlloc
 491 0003599B LocalCompact
 492 000163DF LocalFileTimeToFileTime
 493 0002A48E LocalFlags
 494 0001C1C6 LocalFree
 495 0002A594 LocalHandle
 496 000128A2 LocalLock
 497 00014F2B LocalReAlloc
 498 000359B0 LocalShrink
 499 000154D4 LocalSize
 500 000127F8 LocalUnlock
 501 0001E4E4 LockFile
 502 00030C21 LockFileEx
 503 0001154E LockResource
 504 00035600 MapUserPhysicalPages
 505 00035627 MapUserPhysicalPagesScatter
 506 00006533 MapViewOfFile
 507 0001D74A MapViewOfFileEx
 508 0003CE25 Module32First
 509 0003CD6F Module32FirstW
 510 0003CF91 Module32Next
 511 0003CEF1 Module32NextW
 512 0001ED51 MoveFileA
 513 0001274C MoveFileExA
 514 00001CDA MoveFileExW
 515 000166A0 MoveFileW
 516 00010C86 MoveFileWithProgressA
 517 00010CF0 MoveFileWithProgressW
 518 00009BBA MulDiv
 519 000078FF MultiByteToWideChar
 520 00011138 NlsConvertIntegerToString
 521 00019071 NlsGetCacheUpdateCount
 522 0004BEF8 NlsResetProcessLocale
 523 00017658 OpenConsoleW
 524 00019184 OpenDataFile
 525 00014EDA OpenEventA
 526 0001162C OpenEventW
 527 0000BF59 OpenFile
 528 0000C1D1 OpenFileMappingA
 529 0000C222 OpenFileMappingW
 530 00045A17 OpenJobObjectA
 531 00045A84 OpenJobObjectW
 532 0001AFA6 OpenMutexA
 533 0001AFF7 OpenMutexW
 534 000091B9 OpenProcess
 535 0001DB3A OpenProfileUserMapping
 536 0001F491 OpenSemaphoreA
 537 00013D96 OpenSemaphoreW
 538 0003BAC1 OpenThread
 539 0003A5F7 OpenWaitableTimerA
 540 0003A664 OpenWaitableTimerW
 541 00024539 OutputDebugStringA
 542 0002D9FC OutputDebugStringW
 543 00047D60 PeekConsoleInputA
 544 00047D7C PeekConsoleInputW
 545 0003730E PeekNamedPipe
 546 00001B4D PostQueuedCompletionStatus
 547 000457E7 PrepareTape
 548 000166F6 PrivCopyFileExW
 549 000319F6 PrivMoveFileIdentityW
 550 0003CA16 Process32First
 551 0003C960 Process32FirstW
 552 0003CB70 Process32Next
 553 0003CAD0 Process32NextW
 554 0001A355 ProcessIdToSessionId
 555 00020B6D PulseEvent
 556 0003E916 PurgeComm
 557 0001651F QueryDosDeviceA
 558 0000A2A6 QueryDosDeviceW
 559 00045B3C QueryInformationJobObject
 560 0000AA7D QueryPerformanceCounter
 561 00016F20 QueryPerformanceFrequency
 562 000301F1 QueryWin31IniFilesMappedToRegistry
 563 000030AB QueueUserAPC
 564 00020F64 QueueUserWorkItem
 565 0000A48C RaiseException
 566 000220AB ReadConsoleA
 567 0002225C ReadConsoleInputA
 568 00047DB4 ReadConsoleInputExA
 569 00047DD1 ReadConsoleInputExW
 570 00047D98 ReadConsoleInputW
 571 000044D6 ReadConsoleOutputA
 572 0004854A ReadConsoleOutputAttribute
 573 0004850C ReadConsoleOutputCharacterA
 574 0004852B ReadConsoleOutputCharacterW
 575 00048098 ReadConsoleOutputW
 576 00023603 ReadConsoleW
 577 000144DA ReadDirectoryChangesW
 578 00006582 ReadFile
 579 00030D56 ReadFileEx
 580 00030E21 ReadFileScatter
 581 00022AA8 ReadProcessMemory
 582 00049B85 RegisterConsoleIME
 583 000499D5 RegisterConsoleOS2
 584 00004116 RegisterConsoleVDM
 585 0000C6DC RegisterWaitForInputIdle
 586 00020ECB RegisterWaitForSingleObject
 587 0003C1B8 RegisterWaitForSingleObjectEx
 588 000025A2 RegisterWowBaseHandlers
 589 00003243 RegisterWowExec
 590 000117F4 ReleaseMutex
 591 0001565A ReleaseSemaphore
 592 00023D98 RemoveDirectoryA
 593 00023DB0 RemoveDirectoryW
 594 00001EE4 ReplaceFile
 595 0003492C ReplaceFileA
 596 00001EE4 ReplaceFileW
 597 00038295 RequestDeviceWakeup
 598 00038230 RequestWakeupLatency
 599 0000BF41 ResetEvent
 600 0003569A ResetWriteWatch
 601 0000BEE4 ResumeThread
 602          RtlFillMemory =&gt; NTDLL.RtlFillMemory
 603          RtlMoveMemory =&gt; NTDLL.RtlMoveMemory
 604          RtlUnwind =&gt; NTDLL.RtlUnwind
 605          RtlZeroMemory =&gt; NTDLL.RtlZeroMemory
 606 000492A5 ScrollConsoleScreenBufferA
 607 000492C2 ScrollConsoleScreenBufferW
 608 0000E540 SearchPathA
 609 00019BA4 SearchPathW
 610 00050B1F SetCPGlobal
 611 0004A5F8 SetCalendarInfoA
 612 0004CB09 SetCalendarInfoW
 613 0003E995 SetCommBreak
 614 0003E9A3 SetCommConfig
 615 0003EA34 SetCommMask
 616 0003EACA SetCommState
 617 0003EDE7 SetCommTimeouts
 618 0002D025 SetComputerNameA
 619 0002D0EB SetComputerNameExA
 620 0002CF5E SetComputerNameExW
 621 0002CA9A SetComputerNameW
 622 00048EF9 SetConsoleActiveScreenBuffer
 623 000493B4 SetConsoleCP
 624 00046C96 SetConsoleCommandHistoryMode
 625 00017814 SetConsoleCtrlHandler
 626 0004776D SetConsoleCursor
 627 00049020 SetConsoleCursorInfo
 628 000498AE SetConsoleCursorMode
 629 00048FC3 SetConsoleCursorPosition
 630 00047871 SetConsoleDisplayMode
 631 000492F5 SetConsoleFont
 632 00047A89 SetConsoleHardwareState
 633 00049352 SetConsoleIcon
 634 00046EA7 SetConsoleInputExeNameA
 635 0001E9B1 SetConsoleInputExeNameW
 636 00047B19 SetConsoleKeyShortcuts
 637 00049808 SetConsoleLocalEUDC
 638 000493A9 SetConsoleMaximumWindowSize
 639 00047BBF SetConsoleMenuClose
 640 00006076 SetConsoleMode
 641 00049699 SetConsoleNlsMode
 642 00046A60 SetConsoleNumberOfCommandsA
 643 00046A4E SetConsoleNumberOfCommandsW
 644 00049A2C SetConsoleOS2OemFormat
 645 000494AE SetConsoleOutputCP
 646 00047C16 SetConsolePalette
 647 00048F66 SetConsoleScreenBufferSize
 648 0000460B SetConsoleTextAttribute
 649 00004073 SetConsoleTitleA
 650 000243A9 SetConsoleTitleW
 651 000490E2 SetConsoleWindowInfo
 652          SetCriticalSectionSpinCount =&gt; NTDLL.RtlSetCriticalSectionSpinCount
 653 00010C18 SetCurrentDirectoryA
 654 0000FB16 SetCurrentDirectoryW
 655 0003DE9D SetDefaultCommConfigA
 656 0003DDC1 SetDefaultCommConfigW
 657 0000F2A6 SetEndOfFile
 658 00023650 SetEnvironmentVariableA
 659 00006038 SetEnvironmentVariableW
 660 0001ABA9 SetErrorMode
 661 0000B608 SetEvent
 662 00035795 SetFileApisToANSI
 663 0002040E SetFileApisToOEM
 664 0001B36A SetFileAttributesA
 665 0001B386 SetFileAttributesW
 666 0001D7CC SetFilePointer
 667 00001C2A SetFilePointerEx
 668 0001E638 SetFileTime
 669 0001154E SetHandleCount
 670 00022FBB SetHandleInformation
 671 00045C06 SetInformationJobObject
 672 00049FFE SetLastConsoleEventActive
 673 000148AB SetLastError
 674 00029F44 SetLocalTime
 675 0001F16C SetLocaleInfoA
 676 0001F1D5 SetLocaleInfoW
 677 00013914 SetMailslotInfo
 678 000382D1 SetMessageWaitingIndicator
 679 00009AD9 SetNamedPipeHandleState
 680 00020AA2 SetPriorityClass
 681 0003984F SetProcessAffinityMask
 682 0001F05E SetProcessPriorityBoost
 683 00002F71 SetProcessShutdownParameters
 684 0001DD9F SetProcessWorkingSetSize
 685 0000D089 SetStdHandle
 686 000381E3 SetSystemPowerState
 687 0000183D SetSystemTime
 688 000018EC SetSystemTimeAdjustment
 689 000458FA SetTapeParameters
 690 00045750 SetTapePosition
 691 0003A97F SetTermsrvAppInstallMode
 692 000175AB SetThreadAffinityMask
 693 0003BBEE SetThreadContext
 694 00009655 SetThreadExecutionState
 695 0003C0E9 SetThreadIdealProcessor
 696 0001CDA0 SetThreadLocale
 697 0001B593 SetThreadPriority
 698 0003BB35 SetThreadPriorityBoost
 699 0002D625 SetTimeZoneInformation
 700 0003C45B SetTimerQueueTimer
 701 0000BC57 SetUnhandledExceptionFilter
 702 0003F2C9 SetVDMCurrentDirectories
 703 00037DF1 SetVolumeLabelA
 704 00037E4E SetVolumeLabelW
 705 00041311 SetVolumeMountPointA
 706 0004163C SetVolumeMountPointW
 707 00017546 SetWaitableTimer
 708 0003E0F1 SetupComm
 709 000477CA ShowConsoleCursor
 710 0003A468 SignalObjectAndWait
 711 0001504C SizeofResource
 712 0001AC6E Sleep
 713 0001AC7C SleepEx
 714 0003BC10 SuspendThread
 715 0001F93F SwitchToFiber
 716 0003C15D SwitchToThread
 717 00009B45 SystemTimeToFileTime
 718 0002D788 SystemTimeToTzSpecificLocalTime
 719 00045B18 TerminateJobObject
 720 00038DC3 TerminateProcess
 721 00017584 TerminateThread
 722 0003A96D TermsrvAppInstallMode
 723 0003CC2A Thread32First
 724 0003CCDB Thread32Next
 725 0000D279 TlsAlloc
 726 0000EA53 TlsFree
 727 00015D42 TlsGetValue
 728 0000A8C5 TlsSetValue
 729 0003C927 Toolhelp32ReadProcessMemory
 730 0000AB4F TransactNamedPipe
 731 0003EE87 TransmitCommChar
 732 00035E98 TrimVirtualBuffer
 733          TryEnterCriticalSection =&gt; NTDLL.RtlTryEnterCriticalSection
 734 00036D3F UTRegister
 735 00036D77 UTUnRegister
 736 0003BD2B UnhandledExceptionFilter
 737 00010538 UnlockFile
 738 00010570 UnlockFileEx
 739 00006135 UnmapViewOfFile
 740 00049C2E UnregisterConsoleIME
 741 000030D0 UnregisterWait
 742 00020F32 UnregisterWaitEx
 743 00042512 UpdateResourceA
 744 00042428 UpdateResourceW
 745 0004A0CC VDMConsoleOperation
 746 0003F0D8 VDMOperationStarted
 747 00023123 ValidateLCType
 748 00015E41 ValidateLocale
 749 0004C173 VerLanguageNameA
 750 0004C129 VerLanguageNameW
 751          VerSetConditionMask =&gt; NTDLL.VerSetConditionMask
 752 00019FF4 VerifyConsoleIoHandle
 753 000027B6 VerifyVersionInfoA
 754 00007304 VerifyVersionInfoW
 755 0001175C VirtualAlloc
 756 00011776 VirtualAllocEx
 757 00035EB1 VirtualBufferExceptionHandler
 758 0001E2DC VirtualFree
 759 0001E2F3 VirtualFreeEx
 760 000025AE VirtualLock
 761 0001C0F8 VirtualProtect
 762 0001C112 VirtualProtectEx
 763 0001A14C VirtualQuery
 764 0001A163 VirtualQueryEx
 765 00016C44 VirtualUnlock
 766 0003EF06 WaitCommEvent
 767 0002DB7E WaitForDebugEvent
 768 0001ABE4 WaitForMultipleObjects
 769 0000BD39 WaitForMultipleObjectsEx
 770 00011B0C WaitForSingleObject
 771 0001C468 WaitForSingleObjectEx
 772 0003757C WaitNamedPipeA
 773 00002962 WaitNamedPipeW
 774 0000A994 WideCharToMultiByte
 775 00009C1D WinExec
 776 0001C3FE WriteConsoleA
 777 00047F26 WriteConsoleInputA
 778 00047C8C WriteConsoleInputVDMA
 779 00047CA8 WriteConsoleInputVDMW
 780 00047F42 WriteConsoleInputW
 781 0004839D WriteConsoleOutputA
 782 000486E1 WriteConsoleOutputAttribute
 783 000486A3 WriteConsoleOutputCharacterA
 784 000486C2 WriteConsoleOutputCharacterW
 785 00048380 WriteConsoleOutputW
 786 0000C0C0 WriteConsoleW
 787 0001C24E WriteFile
 788 00030DA8 WriteFileEx
 789 00030EED WriteFileGather
 790 0000198E WritePrivateProfileSectionA
 791 0002F159 WritePrivateProfileSectionW
 792 0000A869 WritePrivateProfileStringA
 793 0001CCB6 WritePrivateProfileStringW
 794 0002ED41 WritePrivateProfileStructA
 795 0002EE40 WritePrivateProfileStructW
 796 00017303 WriteProcessMemory
 797 0000197C WriteProfileSectionA
 798 0002EF67 WriteProfileSectionW
 799 00023353 WriteProfileStringA
 800 0001CCA0 WriteProfileStringW
 801 00045872 WriteTapemark
 802 00010F74 _hread
 803 0001F332 _hwrite
 804 0000A8F1 _lclose
 805 00022ACF _lcreat
 806 0000997F _llseek
 807 0001CDD5 _lopen
 808 00010F74 _lread
 809 0001F332 _lwrite
 810 0001DF5C lstrcat
 811 0001DF5C lstrcatA
 812 0000A22C lstrcatW
 813 0001D453 lstrcmp
 814 0001D453 lstrcmpA
 815 0001D141 lstrcmpW
 816 00006A6C lstrcmpi
 817 00006A6C lstrcmpiA
 818 0001A18D lstrcmpiW
 819 0001E471 lstrcpy
 820 0001E471 lstrcpyA
 821 00008FFC lstrcpyW
 822 0000FA6D lstrcpyn
 823 0000FA6D lstrcpynA
 824 0000BE4E lstrcpynW
 825 00015D89 lstrlen
 826 00015D89 lstrlenA
 827 0000D20C lstrlenW&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;ntdll.dll 정보&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;// ntdll.dll
   1 000213CD PropertyLengthAsVariant
   2 00021336 RtlConvertPropertyToVariant
   3 00021296 RtlConvertVariantToProperty
   4 0003C7B6 RtlUlongByteSwap
   5 0003C7BB RtlUlonglongByteSwap
   6 0003C7B1 RtlUshortByteSwap
   7 00012D38 CsrAllocateCaptureBuffer
   8 0000E6DA CsrAllocateMessagePointer
   9 00009778 CsrCaptureMessageBuffer
  10 0001652A CsrCaptureMessageString
  11 0001BA35 CsrCaptureTimeout
  12 0000917D CsrClientCallServer
  13 000100CA CsrClientConnectToServer
  14 0000E6C6 CsrFreeCaptureBuffer
  15 0001B96A CsrIdentifyAlertableThread
  16 00004BCC CsrNewThread
  17 0001BAA7 CsrProbeForRead
  18 0001BA5F CsrProbeForWrite
  19 0001B999 CsrSetPriorityClass
  20 0002144B DbgBreakPoint
  21 00018C08 DbgPrint
  22 00021504 DbgPrintReturnControlC
  23 0002158D DbgPrompt
  24 0001BD9F DbgSsHandleKmApiMsg
  25 0001BD59 DbgSsInitialize
  26 0001BFDC DbgUiConnectToDbg
  27 0001C1B3 DbgUiContinue
  28 0001C0CC DbgUiWaitStateChange
  29 0002144D DbgUserBreakPoint
  30 00021644 KiRaiseUserExceptionDispatcher
  31 000215CC KiUserApcDispatcher
  32 000215DC KiUserCallbackDispatcher
  33 000215F8 KiUserExceptionDispatcher
  34 00012577 LdrAccessResource
  35 00006A42 LdrAlternateResourcesEnabled
  36 00008A24 LdrDisableThreadCalloutsForDll
  37 000218E7 LdrEnumResources
  38 000216DE LdrFindEntryForAddress
  39 0001640C LdrFindResourceDirectory_U
  40 00007134 LdrFindResource_U
  41 00001278 LdrFlushAlternateResourceModules
  42 00011C8C LdrGetDllHandle
  43 00012B73 LdrGetProcedureAddress
  44 00004AF2 LdrInitializeThunk
  45 00006A6F LdrLoadAlternateResourceModule
  46 00003261 LdrLoadDll
  47 0000679D LdrProcessRelocationBlock
  48 000112C9 LdrQueryImageFileExecutionOptions
  49 0001DF85 LdrQueryProcessModuleInformation
  50 0000DD8E LdrShutdownProcess
  51 0000E42E LdrShutdownThread
  52 0000CBAE LdrUnloadAlternateResourceModule
  53 0000B5DF LdrUnloadDll
  54 0001DDF5 LdrVerifyImageMatchesChecksum
  55 000465B4 NPXEMULATORTABLE
  56 0004FF22 NlsAnsiCodePage
  57 0004F314 NlsMbCodePageTag
  58 0004F318 NlsMbOemCodePageTag
  59 0000F610 NtAcceptConnectPort
  60 00016066 NtAccessCheck
  61 00005E52 NtAccessCheckAndAuditAlarm
  62 0001650E NtAccessCheckByType
  63 0000F9C8 NtAccessCheckByTypeAndAuditAlarm
  64 0001AFDD NtAccessCheckByTypeResultList
  65 0001AFEB NtAccessCheckByTypeResultListAndAuditAlarm
  66 0001AFF9 NtAccessCheckByTypeResultListAndAuditAlarmByHandle
  67 0000E50B NtAddAtom
  68 0001B007 NtAdjustGroupsToken
  69 00008816 NtAdjustPrivilegesToken
  70 0001B015 NtAlertResumeThread
  71 0000CD6F NtAlertThread
  72 0001558D NtAllocateLocallyUniqueId
  73 0001B023 NtAllocateUserPhysicalPages
  74 0001B031 NtAllocateUuids
  75 00015459 NtAllocateVirtualMemory
  76 0001B03F NtAreMappedFilesTheSame
  77 0001B04D NtAssignProcessToJobObject
  78 0000CD99 NtCallbackReturn
  79 0001B06C NtCancelDeviceWakeupRequest
  80 0001B05E NtCancelIoFile
  81 00008C51 NtCancelTimer
  82 0000C6A4 NtClearEvent
  83 00004D93 NtClose
  84 00003679 NtCloseObjectAuditAlarm
  85 0000F61E NtCompleteConnectPort
  86 0000E57A NtConnectPort
  87 00008553 NtContinue
  88 0001B486 NtCreateChannel
  89 0001B07D NtCreateDirectoryObject
  90 00009FFD NtCreateEvent
  91 0001B08B NtCreateEventPair
  92 0000F9BA NtCreateFile
  93 00005EB6 NtCreateIoCompletion
  94 0001B099 NtCreateJobObject
  95 00007E08 NtCreateKey
  96 000024B1 NtCreateMailslotFile
  97 00007E16 NtCreateMutant
  98 0001651C NtCreateNamedPipeFile
  99 0001B0A7 NtCreatePagingFile
 100 00005EC4 NtCreatePort
 101 00003B9E NtCreateProcess
 102 0001B0B5 NtCreateProfile
 103 000135BF NtCreateSection
 104 0000B153 NtCreateSemaphore
 105 0000FA3D NtCreateSymbolicLinkObject
 106 000127AE NtCreateThread
 107 000169D5 NtCreateTimer
 108 00016BCD NtCreateToken
 109 0001B0C3 NtCreateWaitablePort
 110 00023AC7 NtCurrentTeb
 111 00009153 NtDelayExecution
 112 000037D5 NtDeleteAtom
 113 0001B0D1 NtDeleteFile
 114 000077CA NtDeleteKey
 115 000010A5 NtDeleteObjectAuditAlarm
 116 00009D81 NtDeleteValueKey
 117 000150D4 NtDeviceIoControlFile
 118 0001B0DF NtDisplayString
 119 00007724 NtDuplicateObject
 120 00015AE8 NtDuplicateToken
 121 0000C394 NtEnumerateKey
 122 00014A5A NtEnumerateValueKey
 123 0001B0ED NtExtendSection
 124 0001B0FB NtFilterToken
 125 0000EBA6 NtFindAtom
 126 0001570D NtFlushBuffersFile
 127 00014940 NtFlushInstructionCache
 128 000023B5 NtFlushKey
 129 0000A419 NtFlushVirtualMemory
 130 0001B109 NtFlushWriteBuffer
 131 0001B115 NtFreeUserPhysicalPages
 132 0000EC81 NtFreeVirtualMemory
 133 00007126 NtFsControlFile
 134 00016BDB NtGetContextThread
 135 0001B123 NtGetDevicePowerState
 136 000024BF NtGetPlugPlayEvent
 137 0001B131 NtGetTickCount
 138 0001B13D NtGetWriteWatch
 139 0001B14B NtImpersonateAnonymousToken
 140 00009D39 NtImpersonateClientOfPort
 141 00004DA1 NtImpersonateThread
 142 0001B159 NtInitializeRegistry
 143 0001B167 NtInitiatePowerAction
 144 0001B175 NtIsSystemResumeAutomatic
 145 0001B494 NtListenChannel
 146 0001B181 NtListenPort
 147 0001B18F NtLoadDriver
 148 0001B19D NtLoadKey2
 149 00016BE9 NtLoadKey
 150 0000BF81 NtLockFile
 151 000010B3 NtLockVirtualMemory
 152 000087DC NtMakeTemporaryObject
 153 0001B1AB NtMapUserPhysicalPages
 154 0001B1B9 NtMapUserPhysicalPagesScatter
 155 0000AE4F NtMapViewOfSection
 156 00006C1A NtNotifyChangeDirectoryFile
 157 00006CFA NtNotifyChangeKey
 158 00016BF7 NtNotifyChangeMultipleKeys
 159 0001B4A2 NtOpenChannel
 160 00009D8F NtOpenDirectoryObject
 161 0001149E NtOpenEvent
 162 0001B1C7 NtOpenEventPair
 163 00015337 NtOpenFile
 164 0001B1D5 NtOpenIoCompletion
 165 0001B1E3 NtOpenJobObject
 166 000061CC NtOpenKey
 167 00014AA4 NtOpenMutant
 168 00005B01 NtOpenObjectAuditAlarm
 169 000023C3 NtOpenProcess
 170 0000E717 NtOpenProcessToken
 171 00008AEC NtOpenSection
 172 0001255F NtOpenSemaphore
 173 00006151 NtOpenSymbolicLinkObject
 174 000024CD NtOpenThread
 175 00001EB3 NtOpenThreadToken
 176 0001B1F1 NtOpenTimer
 177 00001F74 NtPlugPlayControl
 178 00016C05 NtPowerInformation
 179 000165D5 NtPrivilegeCheck
 180 0001B1FF NtPrivilegeObjectAuditAlarm
 181 000010C1 NtPrivilegedServiceAuditAlarm
 182 0000BFC4 NtProtectVirtualMemory
 183 00016C13 NtPulseEvent
 184 00009FEF NtQueryAttributesFile
 185 0000E964 NtQueryDefaultLocale
 186 000051D0 NtQueryDefaultUILanguage
 187 00005510 NtQueryDirectoryFile
 188 00016C21 NtQueryDirectoryObject
 189 0001B20D NtQueryEaFile
 190 0001285D NtQueryEvent
 191 0001346B NtQueryFullAttributesFile
 192 000148F0 NtQueryInformationAtom
 193 0000F6AF NtQueryInformationFile
 194 00003BAC NtQueryInformationJobObject
 195 0001B21B NtQueryInformationPort
 196 00013351 NtQueryInformationProcess
 197 00008571 NtQueryInformationThread
 198 00005B0F NtQueryInformationToken
 199 0000455F NtQueryInstallUILanguage
 200 0001B229 NtQueryIntervalProfile
 201 0000BD4F NtQueryIoCompletion
 202 00007EBB NtQueryKey
 203 0001B237 NtQueryMultipleValueKey
 204 0001B245 NtQueryMutant
 205 000107D8 NtQueryObject
 206 0001B253 NtQueryOpenSubKeys
 207 000152DD NtQueryPerformanceCounter
 208 0001B261 NtQueryQuotaInformationFile
 209 000112BB NtQuerySection
 210 000038C7 NtQuerySecurityObject
 211 0001B26F NtQuerySemaphore
 212 00005EA8 NtQuerySymbolicLinkObject
 213 0001B27D NtQuerySystemEnvironmentValue
 214 00007D11 NtQuerySystemInformation
 215 000148E2 NtQuerySystemTime
 216 00011775 NtQueryTimer
 217 0000CBA0 NtQueryTimerResolution
 218 000062D2 NtQueryValueKey
 219 00015AA3 NtQueryVirtualMemory
 220 0000E588 NtQueryVolumeInformationFile
 221 0000366B NtQueueApcThread
 222 00014B92 NtRaiseException
 223 0001B28E NtRaiseHardError
 224 0000C552 NtReadFile
 225 0001B29C NtReadFileScatter
 226 0000F6A1 NtReadRequestData
 227 0000DEE6 NtReadVirtualMemory
 228 00004BB2 NtRegisterThreadTerminatePort
 229 00015475 NtReleaseMutant
 230 00008E81 NtReleaseSemaphore
 231 0000BEA7 NtRemoveIoCompletion
 232 0001B2AA NtReplaceKey
 233 0000E596 NtReplyPort
 234 00009161 NtReplyWaitReceivePort
 235 000039BC NtReplyWaitReceivePortEx
 236 0001B2B8 NtReplyWaitReplyPort
 237 0001B4B0 NtReplyWaitSendChannel
 238 0001B2C6 NtRequestDeviceWakeup
 239 00005290 NtRequestPort
 240 0000916F NtRequestWaitReplyPort
 241 0001B2D4 NtRequestWakeupLatency
 242 00016C2F NtResetEvent
 243 0001B2E2 NtResetWriteWatch
 244 0001B2F0 NtRestoreKey
 245 00008FB7 NtResumeThread
 246 00016C3D NtSaveKey
 247 0001B2FE NtSaveMergedKeys
 248 0000808A NtSecureConnectPort
 249 0001B4BE NtSendWaitReplyChannel
 250 0001B4CC NtSetContextChannel
 251 00016C4B NtSetContextThread
 252 0001B30C NtSetDefaultHardErrorPort
 253 0001B31A NtSetDefaultLocale
 254 0001B328 NtSetDefaultUILanguage
 255 0001B336 NtSetEaFile
 256 00008563 NtSetEvent
 257 0001B344 NtSetHighEventPair
 258 0001B352 NtSetHighWaitLowEventPair
 259 0000EE28 NtSetInformationFile
 260 0001B360 NtSetInformationJobObject
 261 0001B36E NtSetInformationKey
 262 000107E6 NtSetInformationObject
 263 00013B6D NtSetInformationProcess
 264 0000A1E0 NtSetInformationThread
 265 00016C59 NtSetInformationToken
 266 0001B37C NtSetIntervalProfile
 267 000086C0 NtSetIoCompletion
 268 00016C67 NtSetLdtEntries
 269 0001B38A NtSetLowEventPair
 270 0001B398 NtSetLowWaitHighEventPair
 271 0001B3A6 NtSetQuotaInformationFile
 272 00011F97 NtSetSecurityObject
 273 0001B3B4 NtSetSystemEnvironmentValue
 274 000010CF NtSetSystemInformation
 275 0001B3C2 NtSetSystemPowerState
 276 000010DD NtSetSystemTime
 277 0000C1DA NtSetThreadExecutionState
 278 00008C5F NtSetTimer
 279 00018958 NtSetTimerResolution
 280 0001B3D0 NtSetUuidSeed
 281 0000AA1B NtSetValueKey
 282 0001B3DE NtSetVolumeInformationFile
 283 0001B3EC NtShutdownSystem
 284 0001B3FA NtSignalAndWaitForSingleObject
 285 0001B408 NtStartProfile
 286 0001B416 NtStopProfile
 287 0001B424 NtSuspendThread
 288 0001B432 NtSystemDebugControl
 289 0001B440 NtTerminateJobObject
 290 0000DD80 NtTerminateProcess
 291 0000DFC2 NtTerminateThread
 292 00004BC0 NtTestAlert
 293 0001B44E NtUnloadDriver
 294 00016C75 NtUnloadKey
 295 00010312 NtUnlockFile
 296 000024DB NtUnlockVirtualMemory
 297 0000A3D8 NtUnmapViewOfSection
 298 00016C83 NtVdmControl
 299 00013233 NtWaitForMultipleObjects
 300 00014086 NtWaitForSingleObject
 301 0001B45C NtWaitHighEventPair
 302 0001B46A NtWaitLowEventPair
 303 000023A7 NtWriteFile
 304 0001B478 NtWriteFileGather
 305 0000816A NtWriteRequestData
 306 0000815C NtWriteVirtualMemory
 307 00012445 NtYieldExecution
 308 00023C36 PfxFindPrefix
 309 00023ACE PfxInitialize
 310 00023AE2 PfxInsertPrefix
 311 00023BBA PfxRemovePrefix
 312 0004A215 RestoreEm87Context
 313 00016E81 RtlAbortRXact
 314 0000A2E0 RtlAbsoluteToSelfRelativeSD
 315 0000C258 RtlAcquirePebLock
 316 00008098 RtlAcquireResourceExclusive
 317 00008D24 RtlAcquireResourceShared
 318 00009C9C RtlAddAccessAllowedAce
 319 000170C1 RtlAddAccessAllowedAceEx
 320 000249B3 RtlAddAccessAllowedObjectAce
 321 000014A2 RtlAddAccessDeniedAce
 322 00024938 RtlAddAccessDeniedAceEx
 323 000249F9 RtlAddAccessDeniedObjectAce
 324 000025A9 RtlAddAce
 325 000241C4 RtlAddActionToRXact
 326 00014D6D RtlAddAtomToAtomTable
 327 00016EBA RtlAddAttributeActionToRXact
 328 00024955 RtlAddAuditAccessAce
 329 00024982 RtlAddAuditAccessAceEx
 330 00024A40 RtlAddAuditAccessObjectAce
 331 000246B6 RtlAddCompoundAce
 332 0004D817 RtlAddRange
 333 000027E1 RtlAdjustPrivilege
 334 000042B0 RtlAllocateAndInitializeSid
 335 000089B1 RtlAllocateHandle
 336 0004C2AD RtlAllocateHeap
 337 000148FE RtlAnsiCharToUnicodeChar
 338 000286AD RtlAnsiStringToUnicodeSize
 339 000114AC RtlAnsiStringToUnicodeString
 340 00001739 RtlAppendAsciizToString
 341 00028C4F RtlAppendStringToString
 342 0000BEB5 RtlAppendUnicodeStringToString
 343 00011E2C RtlAppendUnicodeToString
 344 000241FE RtlApplyRXact
 345 00016FDA RtlApplyRXactNoFlush
 346 0000551E RtlAreAllAccessesGranted
 347 00025434 RtlAreAnyAccessesGranted
 348 0002948B RtlAreBitsClear
 349 00006B32 RtlAreBitsSet
 350 000298DD RtlAssert
 351 0001E7BA RtlCallbackLpcClient
 352 0002B0B6 RtlCancelTimer
 353 0002B447 RtlCaptureStackBackTrace
 354 0000E5A4 RtlCharToInteger
 355 00021448 RtlCheckForOrphanedCriticalSections
 356 0002C841 RtlCheckRegistryKey
 357 0001742C RtlClearAllBits
 358 00006AE0 RtlClearBits
 359 00010701 RtlCompactHeap
 360 0000529E RtlCompareMemory
 361 00011961 RtlCompareMemoryUlong
 362 00028B57 RtlCompareString
 363 0000AF43 RtlCompareUnicodeString
 364 0002ECEC RtlCompressBuffer
 365 000091F2 RtlConsoleMultiByteToUnicodeN
 366 00016D07 RtlConvertExclusiveToShared
 367 000169FA RtlConvertLongToLargeInteger
 368 00016CC8 RtlConvertSharedToExclusive
 369 0000A6D5 RtlConvertSidToUnicodeString
 370 0001F770 RtlConvertToAutoInheritSecurityObject
 371 0001F9A8 RtlConvertUiListToApiList
 372 0003C97E RtlConvertUlongToLargeInteger
 373 0000B5BC RtlCopyLuid
 374 00025231 RtlCopyLuidAndAttributesArray
 375 0004E0BE RtlCopyRangeList
 376 0001F333 RtlCopySecurityDescriptor
 377 00009CB8 RtlCopySid
 378 00025114 RtlCopySidAndAttributesArray
 379 00002949 RtlCopyString
 380 0000EC8F RtlCopyUnicodeString
 381 0000F857 RtlCreateAcl
 382 0001F462 RtlCreateAndSetSD
 383 0000AABF RtlCreateAtomTable
 384 000179CA RtlCreateEnvironment
 385 0004B425 RtlCreateHeap
 386 0001E5A9 RtlCreateLpcServer
 387 00003CCB RtlCreateProcessParameters
 388 0001FFBA RtlCreateQueryDebugBuffer
 389 0002C867 RtlCreateRegistryKey
 390 0000F96F RtlCreateSecurityDescriptor
 391 00011388 RtlCreateTagHeap
 392 0000FE89 RtlCreateTimer
 393 000174C0 RtlCreateTimerQueue
 394 000125AB RtlCreateUnicodeString
 395 000110F0 RtlCreateUnicodeStringFromAsciiz
 396 0002F2BC RtlCreateUserProcess
 397 0001F6FE RtlCreateUserSecurityObject
 398 0002F671 RtlCreateUserThread
 399 00022EA5 RtlCustomCPToUnicodeN
 400 0002F788 RtlCutoverTimeToSystemTime
 401 00003F82 RtlDeNormalizeProcessParams
 402 0002AEF4 RtlDebugPrintTimes
 403 0002ED40 RtlDecompressBuffer
 404 0002ED85 RtlDecompressFragment
 405 0001F78E RtlDefaultNpAcl
 406 0001886A RtlDelete
 407 00001445 RtlDeleteAce
 408 00014EB2 RtlDeleteAtomFromAtomTable
 409 00007BF9 RtlDeleteCriticalSection
 410 000188AF RtlDeleteElementGenericTable
 411 0002FC28 RtlDeleteNoSplay
 412 0004DE5D RtlDeleteOwnersRanges
 413 0004DD1C RtlDeleteRange
 414 0002C88D RtlDeleteRegistryValue
 415 000011DE RtlDeleteResource
 416 0000CD4E RtlDeleteSecurityObject
 417 0000437C RtlDeleteTimer
 418 00029CE6 RtlDeleteTimerQueue
 419 00029D7E RtlDeleteTimerQueueEx
 420 0000721E RtlDeregisterWait
 421 0000722C RtlDeregisterWaitEx
 422 00024AFA RtlDestroyAtomTable
 423 00003CAB RtlDestroyEnvironment
 424 00027AE7 RtlDestroyHandleTable
 425 0004B16C RtlDestroyHeap
 426 00003CAB RtlDestroyProcessParameters
 427 0002009B RtlDestroyQueryDebugBuffer
 428 00006BD6 RtlDetermineDosPathNameType_U
 429 000289BB RtlDnsHostNameToComputerName
 430 00003454 RtlDoesFileExists_U
 431 00011982 RtlDosPathNameToNtPathName_U
 432 0000ED36 RtlDosSearchPath_U
 433 00005480 RtlDowncaseUnicodeString
 434 0001ECF3 RtlDumpResource
 435 00024BD4 RtlEmptyAtomTable
 436 0001ED36 RtlEnableEarlyCriticalSectionEventCreation
 437 0003C84D RtlEnlargedIntegerMultiply
 438 0003C863 RtlEnlargedUnsignedDivide
 439 0003C858 RtlEnlargedUnsignedMultiply
 440 00009103 RtlEnterCriticalSection
 441 0002DA86 RtlEnumProcessHeaps
 442 0002FED7 RtlEnumerateGenericTable
 443 0002FF76 RtlEnumerateGenericTableWithoutSplaying
 444 00009AD9 RtlEqualComputerName
 445 000030E8 RtlEqualDomainName
 446 00025211 RtlEqualLuid
 447 000107F4 RtlEqualPrefixSid
 448 0000810F RtlEqualSid
 449 0000A18F RtlEqualString
 450 00015523 RtlEqualUnicodeString
 451 0002506A RtlEraseUnicodeString
 452 00009DA4 RtlExpandEnvironmentStrings_U
 453 0002D70D RtlExtendHeap
 454 0000361D RtlExtendedIntegerMultiply
 455 0001854E RtlExtendedLargeIntegerDivide
 456 0000BDA7 RtlExtendedMagicDivide
 457 0003C7C4 RtlFillMemory
 458 00018538 RtlFillMemoryUlong
 459 00008903 RtlFindClearBits
 460 0000897A RtlFindClearBitsAndSet
 461 0002962D RtlFindLastBackwardRunClear
 462 00029796 RtlFindLeastSignificantBit
 463 000293CA RtlFindLongestRunClear
 464 00006226 RtlFindMessage
 465 000296F8 RtlFindMostSignificantBit
 466 00029542 RtlFindNextForwardRunClear
 467 0004E30C RtlFindRange
 468 00028E18 RtlFindSetBits
 469 000290BF RtlFindSetBitsAndClear
 470 0000F93B RtlFirstFreeAce
 471 000161BC RtlFormatCurrentUserKeyPath
 472 00009F47 RtlFormatMessage
 473 0001329F RtlFreeAnsiString
 474 000037E3 RtlFreeHandle
 475 0004C7D3 RtlFreeHeap
 476 0000F7B4 RtlFreeOemString
 477 0004E181 RtlFreeRangeList
 478 00004332 RtlFreeSid
 479 0001329F RtlFreeUnicodeString
 480 0002F726 RtlFreeUserThreadStack
 481 00030329 RtlGUIDFromString
 482 000304D4 RtlGenerate8dot3Name
 483 000117E4 RtlGetAce
 484 0002B0F2 RtlGetCallersAddress
 485 0002ECA8 RtlGetCompressionWorkSpaceSize
 486 00005F92 RtlGetControlSecurityDescriptor
 487 0000B385 RtlGetCurrentDirectory_U
 488 00013241 RtlGetDaclSecurityDescriptor
 489 00018B4D RtlGetElementGenericTable
 490 0004E485 RtlGetFirstRange
 491 0000C127 RtlGetFullPathName_U
 492 00011712 RtlGetGroupSecurityDescriptor
 493 0001526E RtlGetLongestNtPathLength
 494 0004E4D9 RtlGetNextRange
 495 0000495C RtlGetNtGlobalFlags
 496 00008058 RtlGetNtProductType
 497 000116D9 RtlGetOwnerSecurityDescriptor
 498 00002ACA RtlGetProcessHeaps
 499 0002539B RtlGetSaclSecurityDescriptor
 500 00027AA0 RtlGetSecurityDescriptorRMControl
 501 00010F8A RtlGetUserInfoHeap
 502 00003034 RtlGetVersion
 503 00017193 RtlIdentifierAuthoritySid
 504 00012237 RtlImageDirectoryEntryToData
 505 000101F2 RtlImageNtHeader
 506 00013146 RtlImageRvaToSection
 507 00031150 RtlImageRvaToVa
 508 0001E7A7 RtlImpersonateLpcClient
 509 0000F7C9 RtlImpersonateSelf
 510 0000FFC3 RtlInitAnsiString
 511 000059D6 RtlInitCodePageTable
 512 00003B15 RtlInitNlsTables
 513 00010F30 RtlInitString
 514 0001566D RtlInitUnicodeString
 515 00003C9D RtlInitializeAtomPackage
 516 00005A97 RtlInitializeBitMap
 517 000311C0 RtlInitializeContext
 518 00015749 RtlInitializeCriticalSection
 519 000047F3 RtlInitializeCriticalSectionAndSpinCount
 520 0002FE18 RtlInitializeGenericTable
 521 0000421E RtlInitializeHandleTable
 522 00023E8C RtlInitializeRXact
 523 0004D800 RtlInitializeRangeList
 524 0000CA94 RtlInitializeResource
 525 0000E4E1 RtlInitializeSid
 526 00017AD2 RtlInsertElementGenericTable
 527 0002BC00 RtlInt64ToUnicodeString
 528 00013B7B RtlIntegerToChar
 529 00005CAB RtlIntegerToUnicodeString
 530 0004E653 RtlInvertRangeList
 531 000030C2 RtlIsDosDeviceName_U
 532 00018B3F RtlIsGenericTableEmpty
 533 00017C10 RtlIsNameLegalDOS8Dot3
 534 0004E1BC RtlIsRangeAvailable
 535 00013E34 RtlIsTextUnicode
 536 00010688 RtlIsValidHandle
 537 0001507C RtlIsValidIndexHandle
 538 0003C83A RtlLargeIntegerAdd
 539 0003C92E RtlLargeIntegerArithmeticShift
 540 000313B9 RtlLargeIntegerDivide
 541 0003C959 RtlLargeIntegerNegate
 542 0003C8E0 RtlLargeIntegerShiftLeft
 543 0003C907 RtlLargeIntegerShiftRight
 544 0003C96B RtlLargeIntegerSubtract
 545 0002B826 RtlLargeIntegerToChar
 546 00009134 RtlLeaveCriticalSection
 547 0000C68E RtlLengthRequiredSid
 548 00008FF6 RtlLengthSecurityDescriptor
 549 0000E2CB RtlLengthSid
 550 0002FA9A RtlLocalTimeToSystemTime
 551 0000C837 RtlLockHeap
 552 000026A7 RtlLookupAtomInAtomTable
 553 0002FE82 RtlLookupElementGenericTable
 554 0000A1EE RtlMakeSelfRelativeSD
 555 0000BE24 RtlMapGenericMask
 556 0004E572 RtlMergeRangeLists
 557 00001C66 RtlMoveMemory
 558 000078A1 RtlMultiByteToUnicodeN
 559 00004C66 RtlMultiByteToUnicodeSize
 560 0001F193 RtlNewInstanceSecurityObject
 561 0001F202 RtlNewSecurityGrantedAccess
 562 00001256 RtlNewSecurityObject
 563 0000FA4B RtlNewSecurityObjectEx
 564 00003A8A RtlNormalizeProcessParams
 565 0000D02E RtlNtStatusToDosError
 566 0002FF6C RtlNumberGenericTableElements
 567 000293FA RtlNumberOfClearBits
 568 00029440 RtlNumberOfSetBits
 569 000286AD RtlOemStringToUnicodeSize
 570 000052E6 RtlOemStringToUnicodeString
 571 00005361 RtlOemToUnicodeN
 572 0000313E RtlOpenCurrentUser
 573 00031526 RtlPcToFileHeader
 574 00024E99 RtlPinAtomInAtomTable
 575 00018980 RtlPrefixString
 576 0000ACE6 RtlPrefixUnicodeString
 577 0002CBC5 RtlProtectHeap
 578 00014F83 RtlQueryAtomInAtomTable
 579 0000B181 RtlQueryEnvironmentVariable_U
 580 0000253A RtlQueryInformationAcl
 581 00020363 RtlQueryProcessBackTraceInformation
 582 0002015F RtlQueryProcessDebugInformation
 583 0002055A RtlQueryProcessHeapInformation
 584 00020A3E RtlQueryProcessLockInformation
 585 0002C420 RtlQueryRegistryValues
 586 0001EF7F RtlQuerySecurityObject
 587 0002D5A2 RtlQueryTagHeap
 588 0002C939 RtlQueryTimeZoneInformation
 589 00013D6F RtlQueueWorkItem
 590 000316C8 RtlRaiseException
 591 00031780 RtlRaiseStatus
 592 00001B06 RtlRandom
 593 00012025 RtlReAllocateHeap
 594 0002FD08 RtlRealPredecessor
 595 0002FCD7 RtlRealSuccessor
 596 00007150 RtlRegisterWait
 597 0000C268 RtlReleasePebLock
 598 0000857F RtlReleaseResource
 599 00031275 RtlRemoteCall
 600 00003BBA RtlResetRtlTranslations
 601 000027A9 RtlRunDecodeUnicodeString
 602 00002741 RtlRunEncodeUnicodeString
 603 0002FA6A RtlSecondsSince1970ToTime
 604 0002FA33 RtlSecondsSince1980ToTime
 605 00024427 RtlSelfRelativeToAbsoluteSD2
 606 0000130F RtlSelfRelativeToAbsoluteSD
 607 00017453 RtlSetAllBits
 608 000252B2 RtlSetAttributesSecurityDescriptor
 609 00004EED RtlSetBits
 610 000252ED RtlSetControlSecurityDescriptor
 611 0000DD34 RtlSetCriticalSectionSpinCount
 612 00004F72 RtlSetCurrentDirectory_U
 613 0002EE40 RtlSetCurrentEnvironment
 614 00009CE4 RtlSetDaclSecurityDescriptor
 615 0000AFDB RtlSetEnvironmentVariable
 616 00002035 RtlSetGroupSecurityDescriptor
 617 0002461C RtlSetInformationAcl
 618 00029BD9 RtlSetIoCompletionCallback
 619 00001FF2 RtlSetOwnerSecurityDescriptor
 620 000028AE RtlSetSaclSecurityDescriptor
 621 00027AC3 RtlSetSecurityDescriptorRMControl
 622 0001EF3C RtlSetSecurityObject
 623 0001EF5D RtlSetSecurityObjectEx
 624 0000BC20 RtlSetThreadPoolStartFunc
 625 0002CA5A RtlSetTimeZoneInformation
 626 0002AFEB RtlSetTimer
 627 00021448 RtlSetUnicodeCallouts
 628 0002D260 RtlSetUserFlagsHeap
 629 00001EC1 RtlSetUserValueHeap
 630 0001E694 RtlShutdownLpcServer
 631 0004B906 RtlSizeHeap
 632 00018859 RtlSplay
 633 00016E35 RtlStartRXact
 634 00017BA1 RtlStringFromGUID
 635 00008154 RtlSubAuthorityCountSid
 636 000153A5 RtlSubAuthoritySid
 637 0002FCBC RtlSubtreePredecessor
 638 0002FCA1 RtlSubtreeSuccessor
 639 00004C87 RtlSystemTimeToLocalTime
 640 0000349A RtlTimeFieldsToTime
 641 0002F9AB RtlTimeToElapsedTimeFields
 642 00016629 RtlTimeToSecondsSince1970
 643 00005E60 RtlTimeToSecondsSince1980
 644 000081FE RtlTimeToTimeFields
 645 00031953 RtlTraceDatabaseAdd
 646 000317A8 RtlTraceDatabaseCreate
 647 000318BB RtlTraceDatabaseDestroy
 648 00031CE1 RtlTraceDatabaseEnumerate
 649 00031981 RtlTraceDatabaseFind
 650 00031C87 RtlTraceDatabaseLock
 651 00031C93 RtlTraceDatabaseUnlock
 652 00031913 RtlTraceDatabaseValidate
 653 0000A130 RtlTryEnterCriticalSection
 654 0002868F RtlUnicodeStringToAnsiSize
 655 0001335F RtlUnicodeStringToAnsiString
 656 000284D5 RtlUnicodeStringToCountedOemString
 657 0001246E RtlUnicodeStringToInteger
 658 0002868F RtlUnicodeStringToOemSize
 659 000031E2 RtlUnicodeStringToOemString
 660 0002308E RtlUnicodeToCustomCPN
 661 0000C6B2 RtlUnicodeToMultiByteN
 662 000102D8 RtlUnicodeToMultiByteSize
 663 00012EEA RtlUnicodeToOemN
 664 00006341 RtlUniform
 665 0000C872 RtlUnlockHeap
 666 0000EA4A RtlUnwind
 667 0000CC2C RtlUpcaseUnicodeChar
 668 0000B2AD RtlUpcaseUnicodeString
 669 000283DD RtlUpcaseUnicodeStringToAnsiString
 670 0001735D RtlUpcaseUnicodeStringToCountedOemString
 671 00003739 RtlUpcaseUnicodeStringToOemString
 672 00023235 RtlUpcaseUnicodeToCustomCPN
 673 00015788 RtlUpcaseUnicodeToMultiByteN
 674 00010320 RtlUpcaseUnicodeToOemN
 675 00002078 RtlUpdateTimer
 676 00012451 RtlUpperChar
 677 00028C07 RtlUpperString
 678 0002DB14 RtlUsageHeap
 679 0000F8A7 RtlValidAcl
 680 0002794F RtlValidRelativeSecurityDescriptor
 681 00005ED2 RtlValidSecurityDescriptor
 682 0000ED77 RtlValidSid
 683 00001C9F RtlValidateHeap
 684 0002D9C0 RtlValidateProcessHeaps
 685 00013C7F RtlVerifyVersionInfo
 686 0002B4E9 RtlWalkFrameChain
 687 0002E076 RtlWalkHeap
 688 0002C7EC RtlWriteRegistryValue
 689 0004E7E1 RtlZeroHeap
 690 0003C7F5 RtlZeroMemory
 691 00031E7F RtlpNtCreateKey
 692 00031EED RtlpNtEnumerateSubKey
 693 00031EE1 RtlpNtMakeTemporaryKey
 694 0000A05A RtlpNtOpenKey
 695 0000A077 RtlpNtQueryValueKey
 696 00031EBC RtlpNtSetValueKey
 697 000123AA RtlpUnWaitCriticalSection
 698 00012313 RtlpWaitForCriticalSection
 699 000286AD RtlxAnsiStringToUnicodeSize
 700 000286AD RtlxOemStringToUnicodeSize
 701 0002868F RtlxUnicodeStringToAnsiSize
 702 0002868F RtlxUnicodeStringToOemSize
 703 0004A1EC SaveEm87Context
 704 00013D37 VerSetConditionMask
 705 0000F610 ZwAcceptConnectPort
 706 00016066 ZwAccessCheck
 707 00005E52 ZwAccessCheckAndAuditAlarm
 708 0001650E ZwAccessCheckByType
 709 0000F9C8 ZwAccessCheckByTypeAndAuditAlarm
 710 0001AFDD ZwAccessCheckByTypeResultList
 711 0001AFEB ZwAccessCheckByTypeResultListAndAuditAlarm
 712 0001AFF9 ZwAccessCheckByTypeResultListAndAuditAlarmByHandle
 713 0000E50B ZwAddAtom
 714 0001B007 ZwAdjustGroupsToken
 715 00008816 ZwAdjustPrivilegesToken
 716 0001B015 ZwAlertResumeThread
 717 0000CD6F ZwAlertThread
 718 0001558D ZwAllocateLocallyUniqueId
 719 0001B023 ZwAllocateUserPhysicalPages
 720 0001B031 ZwAllocateUuids
 721 00015459 ZwAllocateVirtualMemory
 722 0001B03F ZwAreMappedFilesTheSame
 723 0001B04D ZwAssignProcessToJobObject
 724 0000CD99 ZwCallbackReturn
 725 0001B06C ZwCancelDeviceWakeupRequest
 726 0001B05E ZwCancelIoFile
 727 00008C51 ZwCancelTimer
 728 0000C6A4 ZwClearEvent
 729 00004D93 ZwClose
 730 00003679 ZwCloseObjectAuditAlarm
 731 0000F61E ZwCompleteConnectPort
 732 0000E57A ZwConnectPort
 733 00008553 ZwContinue
 734 0001B486 ZwCreateChannel
 735 0001B07D ZwCreateDirectoryObject
 736 00009FFD ZwCreateEvent
 737 0001B08B ZwCreateEventPair
 738 0000F9BA ZwCreateFile
 739 00005EB6 ZwCreateIoCompletion
 740 0001B099 ZwCreateJobObject
 741 00007E08 ZwCreateKey
 742 000024B1 ZwCreateMailslotFile
 743 00007E16 ZwCreateMutant
 744 0001651C ZwCreateNamedPipeFile
 745 0001B0A7 ZwCreatePagingFile
 746 00005EC4 ZwCreatePort
 747 00003B9E ZwCreateProcess
 748 0001B0B5 ZwCreateProfile
 749 000135BF ZwCreateSection
 750 0000B153 ZwCreateSemaphore
 751 0000FA3D ZwCreateSymbolicLinkObject
 752 000127AE ZwCreateThread
 753 000169D5 ZwCreateTimer
 754 00016BCD ZwCreateToken
 755 0001B0C3 ZwCreateWaitablePort
 756 00009153 ZwDelayExecution
 757 000037D5 ZwDeleteAtom
 758 0001B0D1 ZwDeleteFile
 759 000077CA ZwDeleteKey
 760 000010A5 ZwDeleteObjectAuditAlarm
 761 00009D81 ZwDeleteValueKey
 762 000150D4 ZwDeviceIoControlFile
 763 0001B0DF ZwDisplayString
 764 00007724 ZwDuplicateObject
 765 00015AE8 ZwDuplicateToken
 766 0000C394 ZwEnumerateKey
 767 00014A5A ZwEnumerateValueKey
 768 0001B0ED ZwExtendSection
 769 0001B0FB ZwFilterToken
 770 0000EBA6 ZwFindAtom
 771 0001570D ZwFlushBuffersFile
 772 00014940 ZwFlushInstructionCache
 773 000023B5 ZwFlushKey
 774 0000A419 ZwFlushVirtualMemory
 775 0001B109 ZwFlushWriteBuffer
 776 0001B115 ZwFreeUserPhysicalPages
 777 0000EC81 ZwFreeVirtualMemory
 778 00007126 ZwFsControlFile
 779 00016BDB ZwGetContextThread
 780 0001B123 ZwGetDevicePowerState
 781 000024BF ZwGetPlugPlayEvent
 782 0001B131 ZwGetTickCount
 783 0001B13D ZwGetWriteWatch
 784 0001B14B ZwImpersonateAnonymousToken
 785 00009D39 ZwImpersonateClientOfPort
 786 00004DA1 ZwImpersonateThread
 787 0001B159 ZwInitializeRegistry
 788 0001B167 ZwInitiatePowerAction
 789 0001B175 ZwIsSystemResumeAutomatic
 790 0001B494 ZwListenChannel
 791 0001B181 ZwListenPort
 792 0001B18F ZwLoadDriver
 793 0001B19D ZwLoadKey2
 794 00016BE9 ZwLoadKey
 795 0000BF81 ZwLockFile
 796 000010B3 ZwLockVirtualMemory
 797 000087DC ZwMakeTemporaryObject
 798 0001B1AB ZwMapUserPhysicalPages
 799 0001B1B9 ZwMapUserPhysicalPagesScatter
 800 0000AE4F ZwMapViewOfSection
 801 00006C1A ZwNotifyChangeDirectoryFile
 802 00006CFA ZwNotifyChangeKey
 803 00016BF7 ZwNotifyChangeMultipleKeys
 804 0001B4A2 ZwOpenChannel
 805 00009D8F ZwOpenDirectoryObject
 806 0001149E ZwOpenEvent
 807 0001B1C7 ZwOpenEventPair
 808 00015337 ZwOpenFile
 809 0001B1D5 ZwOpenIoCompletion
 810 0001B1E3 ZwOpenJobObject
 811 000061CC ZwOpenKey
 812 00014AA4 ZwOpenMutant
 813 00005B01 ZwOpenObjectAuditAlarm
 814 000023C3 ZwOpenProcess
 815 0000E717 ZwOpenProcessToken
 816 00008AEC ZwOpenSection
 817 0001255F ZwOpenSemaphore
 818 00006151 ZwOpenSymbolicLinkObject
 819 000024CD ZwOpenThread
 820 00001EB3 ZwOpenThreadToken
 821 0001B1F1 ZwOpenTimer
 822 00001F74 ZwPlugPlayControl
 823 00016C05 ZwPowerInformation
 824 000165D5 ZwPrivilegeCheck
 825 0001B1FF ZwPrivilegeObjectAuditAlarm
 826 000010C1 ZwPrivilegedServiceAuditAlarm
 827 0000BFC4 ZwProtectVirtualMemory
 828 00016C13 ZwPulseEvent
 829 00009FEF ZwQueryAttributesFile
 830 0000E964 ZwQueryDefaultLocale
 831 000051D0 ZwQueryDefaultUILanguage
 832 00005510 ZwQueryDirectoryFile
 833 00016C21 ZwQueryDirectoryObject
 834 0001B20D ZwQueryEaFile
 835 0001285D ZwQueryEvent
 836 0001346B ZwQueryFullAttributesFile
 837 000148F0 ZwQueryInformationAtom
 838 0000F6AF ZwQueryInformationFile
 839 00003BAC ZwQueryInformationJobObject
 840 0001B21B ZwQueryInformationPort
 841 00013351 ZwQueryInformationProcess
 842 00008571 ZwQueryInformationThread
 843 00005B0F ZwQueryInformationToken
 844 0000455F ZwQueryInstallUILanguage
 845 0001B229 ZwQueryIntervalProfile
 846 0000BD4F ZwQueryIoCompletion
 847 00007EBB ZwQueryKey
 848 0001B237 ZwQueryMultipleValueKey
 849 0001B245 ZwQueryMutant
 850 000107D8 ZwQueryObject
 851 0001B253 ZwQueryOpenSubKeys
 852 000152DD ZwQueryPerformanceCounter
 853 0001B261 ZwQueryQuotaInformationFile
 854 000112BB ZwQuerySection
 855 000038C7 ZwQuerySecurityObject
 856 0001B26F ZwQuerySemaphore
 857 00005EA8 ZwQuerySymbolicLinkObject
 858 0001B27D ZwQuerySystemEnvironmentValue
 859 00007D11 ZwQuerySystemInformation
 860 000148E2 ZwQuerySystemTime
 861 00011775 ZwQueryTimer
 862 0000CBA0 ZwQueryTimerResolution
 863 000062D2 ZwQueryValueKey
 864 00015AA3 ZwQueryVirtualMemory
 865 0000E588 ZwQueryVolumeInformationFile
 866 0000366B ZwQueueApcThread
 867 00014B92 ZwRaiseException
 868 0001B28E ZwRaiseHardError
 869 0000C552 ZwReadFile
 870 0001B29C ZwReadFileScatter
 871 0000F6A1 ZwReadRequestData
 872 0000DEE6 ZwReadVirtualMemory
 873 00004BB2 ZwRegisterThreadTerminatePort
 874 00015475 ZwReleaseMutant
 875 00008E81 ZwReleaseSemaphore
 876 0000BEA7 ZwRemoveIoCompletion
 877 0001B2AA ZwReplaceKey
 878 0000E596 ZwReplyPort
 879 00009161 ZwReplyWaitReceivePort
 880 000039BC ZwReplyWaitReceivePortEx
 881 0001B2B8 ZwReplyWaitReplyPort
 882 0001B4B0 ZwReplyWaitSendChannel
 883 0001B2C6 ZwRequestDeviceWakeup
 884 00005290 ZwRequestPort
 885 0000916F ZwRequestWaitReplyPort
 886 0001B2D4 ZwRequestWakeupLatency
 887 00016C2F ZwResetEvent
 888 0001B2E2 ZwResetWriteWatch
 889 0001B2F0 ZwRestoreKey
 890 00008FB7 ZwResumeThread
 891 00016C3D ZwSaveKey
 892 0001B2FE ZwSaveMergedKeys
 893 0000808A ZwSecureConnectPort
 894 0001B4BE ZwSendWaitReplyChannel
 895 0001B4CC ZwSetContextChannel
 896 00016C4B ZwSetContextThread
 897 0001B30C ZwSetDefaultHardErrorPort
 898 0001B31A ZwSetDefaultLocale
 899 0001B328 ZwSetDefaultUILanguage
 900 0001B336 ZwSetEaFile
 901 00008563 ZwSetEvent
 902 0001B344 ZwSetHighEventPair
 903 0001B352 ZwSetHighWaitLowEventPair
 904 0000EE28 ZwSetInformationFile
 905 0001B360 ZwSetInformationJobObject
 906 0001B36E ZwSetInformationKey
 907 000107E6 ZwSetInformationObject
 908 00013B6D ZwSetInformationProcess
 909 0000A1E0 ZwSetInformationThread
 910 00016C59 ZwSetInformationToken
 911 0001B37C ZwSetIntervalProfile
 912 000086C0 ZwSetIoCompletion
 913 00016C67 ZwSetLdtEntries
 914 0001B38A ZwSetLowEventPair
 915 0001B398 ZwSetLowWaitHighEventPair
 916 0001B3A6 ZwSetQuotaInformationFile
 917 00011F97 ZwSetSecurityObject
 918 0001B3B4 ZwSetSystemEnvironmentValue
 919 000010CF ZwSetSystemInformation
 920 0001B3C2 ZwSetSystemPowerState
 921 000010DD ZwSetSystemTime
 922 0000C1DA ZwSetThreadExecutionState
 923 00008C5F ZwSetTimer
 924 00018958 ZwSetTimerResolution
 925 0001B3D0 ZwSetUuidSeed
 926 0000AA1B ZwSetValueKey
 927 0001B3DE ZwSetVolumeInformationFile
 928 0001B3EC ZwShutdownSystem
 929 0001B3FA ZwSignalAndWaitForSingleObject
 930 0001B408 ZwStartProfile
 931 0001B416 ZwStopProfile
 932 0001B424 ZwSuspendThread
 933 0001B432 ZwSystemDebugControl
 934 0001B440 ZwTerminateJobObject
 935 0000DD80 ZwTerminateProcess
 936 0000DFC2 ZwTerminateThread
 937 00004BC0 ZwTestAlert
 938 0001B44E ZwUnloadDriver
 939 00016C75 ZwUnloadKey
 940 00010312 ZwUnlockFile
 941 000024DB ZwUnlockVirtualMemory
 942 0000A3D8 ZwUnmapViewOfSection
 943 00016C83 ZwVdmControl
 944 00013233 ZwWaitForMultipleObjects
 945 00014086 ZwWaitForSingleObject
 946 0001B45C ZwWaitHighEventPair
 947 0001B46A ZwWaitLowEventPair
 948 000023A7 ZwWriteFile
 949 0001B478 ZwWriteFileGather
 950 0000816A ZwWriteRequestData
 951 0000815C ZwWriteVirtualMemory
 952 00012445 ZwYieldExecution
 953 000382C5 _CIpow
 954 000467F7 __eCommonExceptions
 955 00046000 __eEmulatorInit
 956 00049A66 __eF2XM1
 957 00048335 __eFABS
 958 00046DD7 __eFADD32
 959 00046DFF __eFADD64
 960 00046E4A __eFADDPreg
 961 00046E4F __eFADDreg
 962 00046E51 __eFADDtop
 963 00048346 __eFCHS
 964 00048526 __eFCOM
 965 00048449 __eFCOM32
 966 00048472 __eFCOM64
 967 00048517 __eFCOMP
 968 00048432 __eFCOMP32
 969 0004845B __eFCOMP64
 970 000484FB __eFCOMPP
 971 000490CE __eFCOS
 972 00049F37 __eFDECSTP
 973 00047216 __eFDIV32
 974 0004722A __eFDIV64
 975 000472E3 __eFDIVPreg
 976 00047220 __eFDIVR32
 977 00047234 __eFDIVR64
 978 0004723E __eFDIVRPreg
 979 00047243 __eFDIVRreg
 980 00047245 __eFDIVRtop
 981 000472E8 __eFDIVreg
 982 000472EA __eFDIVtop
 983 00048356 __eFFREE
 984 00046D87 __eFIADD16
 985 00046DAF __eFIADD32
 986 000483F7 __eFICOM16
 987 00048420 __eFICOM32
 988 000483E0 __eFICOMP16
 989 00048409 __eFICOMP32
 990 000471EE __eFIDIV16
 991 00047202 __eFIDIV32
 992 000471F8 __eFIDIVR16
 993 0004720C __eFIDIVR32
 994 00047AF8 __eFILD16
 995 00047B09 __eFILD32
 996 00047B13 __eFILD64
 997 00046F64 __eFIMUL16
 998 00046F98 __eFIMUL32
 999 00049F54 __eFINCSTP
1000 00046000 __eFINIT
1001 000481A0 __eFIST16
1002 000480AE __eFIST32
1003 0004819B __eFISTP16
1004 000480A9 __eFISTP32
1005 00048253 __eFISTP64
1006 00046CC6 __eFISUB16
1007 00046D93 __eFISUB32
1008 00046D79 __eFISUBR16
1009 00046DA1 __eFISUBR32
1010 00048708 __eFLD1
1011 00047A79 __eFLD32
1012 00047ACF __eFLD64
1013 00047BC9 __eFLD80
1014 00049ED0 __eFLDCW
1015 0004A071 __eFLDENV
1016 00048773 __eFLDL2E
1017 00048795 __eFLDLN2
1018 000487A6 __eFLDPI
1019 00048744 __eFLDZ
1020 00046FDA __eFMUL32
1021 0004701E __eFMUL64
1022 0004706B __eFMULPreg
1023 00047070 __eFMULreg
1024 00047072 __eFMULtop
1025 00046A66 __eFPATAN
1026 00046A2A __eFPREM
1027 00046A50 __eFPREM1
1028 000491DB __eFPTAN
1029 0004738D __eFRNDINT
1030 0004A0AB __eFRSTOR
1031 00049FFE __eFSAVE
1032 00046A5F __eFSCALE
1033 00049173 __eFSIN
1034 0004A2CA __eFSQRT
1035 00047C84 __eFST
1036 00047F22 __eFST32
1037 00047D4D __eFST64
1038 00049F16 __eFSTCW
1039 00049F82 __eFSTENV
1040 00047C2A __eFSTP
1041 00047F1D __eFSTP32
1042 00047D48 __eFSTP64
1043 000482DA __eFSTP80
1044 00049F22 __eFSTSW
1045 00046DBB __eFSUB32
1046 00046DE3 __eFSUB64
1047 00046E0B __eFSUBPreg
1048 00046DC9 __eFSUBR32
1049 00046DF1 __eFSUBR64
1050 00046E26 __eFSUBRPreg
1051 00046E2B __eFSUBRreg
1052 00046E2D __eFSUBRtop
1053 00046E10 __eFSUBreg
1054 00046E12 __eFSUBtop
1055 0004869A __eFTST
1056 000484F1 __eFUCOM
1057 000484E2 __eFUCOMP
1058 00048484 __eFUCOMPP
1059 00048674 __eFXAM
1060 0004835C __eFXCH
1061 00048A03 __eFXTRACT
1062 00046A87 __eFYL2X
1063 00046A8E __eFYL2XP1
1064 0004A18D __eGetStatusWord
1065 000386DE __isascii
1066 00038730 __iscsym
1067 000386F3 __iscsymf
1068 000386EB __toascii
1069 0000C5A8 _alldiv
1070 00007A9F _allmul
1071 000160D6 _alloca_probe
1072 000387F1 _allrem
1073 000388A3 _allshl
1074 000388C2 _allshr
1075 0003891A _atoi64
1076 0000DB68 _aulldiv
1077 0000DB91 _aullrem
1078 00007D61 _aullshr
1079 000160D6 _chkstk
1080 00051028 _fltused
1081 00002CDA _ftol
1082 00038AB4 _i64toa
1083 00038BD4 _i64tow
1084 000189D2 _itoa
1085 00001B59 _itow
1086 00038A8A _ltoa
1087 00038B78 _ltow
1088 00038C05 _memccpy
1089 00038C58 _memicmp
1090 00038CF0 _snprintf
1091 00008E0E _snwprintf
1092 00038D65 _splitpath
1093 00011634 _strcmpi
1094 00011634 _stricmp
1095 00017DD3 _strlwr
1096 00004DE6 _strnicmp
1097 00002D01 _strupr
1098 00038F4F _tolower
1099 00038F6A _toupper
1100 00038B5D _ui64toa
1101 0000FE10 _ultoa
1102 00038BA6 _ultow
1103 00018D01 _vsnprintf
1104 00001FA5 _wcsicmp
1105 00038F98 _wcslwr
1106 00012DD7 _wcsnicmp
1107 00038FC2 _wcsupr
1108 00038FEC _wtoi
1109 0003900F _wtoi64
1110 00038FEC _wtol
1111 000393F2 abs
1112 00039032 atan
1113 0001673E atoi
1114 000166E3 atol
1115 000390E9 ceil
1116 000391B5 cos
1117 0003924F fabs
1118 00039304 floor
1119 0003862C isalnum
1120 0003853D isalpha
1121 000386B6 iscntrl
1122 00002C85 isdigit
1123 00038688 isgraph
1124 00038593 islower
1125 0003865A isprint
1126 00038604 ispunct
1127 00002CA3 isspace
1128 0003856B isupper
1129 000393D0 iswalpha
1130 0000C629 iswctype
1131 00007FA3 iswdigit
1132 000393E1 iswlower
1133 00018AE8 iswspace
1134 00017DF6 iswxdigit
1135 000385C9 isxdigit
1136 000393F2 labs
1137 000393FD log
1138 00001B87 mbstowcs
1139 000394E2 memchr
1140 00039583 memcmp
1141 0003962F memcpy
1142 0001109B memmove
1143 00039950 memset
1144 000382DE pow
1145 000399A8 qsort
1146 00039B6A sin
1147 00017E20 sprintf
1148 00039C16 sqrt
1149 00039CBC sscanf
1150 00039D62 strcat
1151 00005B1D strchr
1152 00039E02 strcmp
1153 00039CF6 strcpy
1154 00039E83 strcspn
1155 00039EC0 strlen
1156 00039F37 strncat
1157 00002D4E strncmp
1158 00008824 strncpy
1159 0003A084 strpbrk
1160 00017EC0 strrchr
1161 0003A0BD strspn
1162 00017EE7 strstr
1163 0003A10C strtol
1164 000180CD strtoul
1165 0000423D swprintf
1166 0003A271 tan
1167 00002D26 tolower
1168 00015A1E toupper
1169 0003A30F towlower
1170 000180E4 towupper
1171 0003A32A vsprintf
1172 000121E4 wcscat
1173 00012544 wcschr
1174 0000972D wcscmp
1175 0000C23F wcscpy
1176 0000CA53 wcscspn
1177 000152EB wcslen
1178 00006459 wcsncat
1179 0000EBD1 wcsncmp
1180 0000BCE6 wcsncpy
1181 0000DF7B wcspbrk
1182 0000F661 wcsrchr
1183 00016A11 wcsspn
1184 0000456D wcsstr
1185 00008B39 wcstol
1186 0003A446 wcstombs
1187 0001815A wcstoul&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[MFC 위성 DLL 취약점]]></title><description><![CDATA[MFC 7.0부터 위성 DLL이란게 추가된 것 같습니다. 이게 머 위성 DLL하니 말이 거창한데 리소스 DLL을 분리시켜 놓고 시스템 언어에 맞게 리소스 DLL…]]></description><link>https://jiniya.net/wp/archives/14240</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14240</guid><pubDate>Wed, 03 Sep 2014 23:59:52 GMT</pubDate><content:encoded>&lt;p&gt;MFC 7.0부터 위성 DLL이란게 추가된 것 같습니다. 이게 머 위성 DLL하니 말이 거창한데 리소스 DLL을 분리시켜 놓고 시스템 언어에 맞게 리소스 DLL을 로드하는 것을 의미하나 봅니다. 상세 기능은 &lt;a href=&quot;http://msdn.microsoft.com/en-US/library/8fkteez0.aspx&quot;&gt;여기 링크&lt;/a&gt;를 참고하시면 됩니다. 근데 안타깝게도 MFC 개발팀에서 이 기능을 만들면서 초기에 소소한 실수(?!)를 하는 바람에 취약점이 생겼나 보네요. 머 대단한 취약점은 아니고 LPK.DLL이나 USP10.DLL 같이 임의의 코드가 리소스 DLL에 감염돼 있으면 실행되는 취약점입니다. 그럼 왜 생겼는지 한 번 살펴볼까요?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;아래는 VS 2008의 위성 DLL 로드 부분 코드입니다. MFC에 포함된 appcore.cpp의 _AfxLoadLangDLL 코드의 일부입니다. 보면 리소스 DLL을 LoadLibraryEx를 통해서 로드하는데 안타깝게도 마지막 인자가 0입니다. 0이라는 말은 그냥 일반 DLL 처럼 로드하겠다는 의미죠. 리소스 DLL에 악성 코드가 감염되어 있었다면 같이 실행될 수 있다는 것을 의미합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pfnFindActCtxSectionString &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;pfnFindActCtxSectionString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// Load using the dll name only...&lt;/span&gt;
	hInstance &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;LoadLibraryEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pszFilename&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// Load using the full path...&lt;/span&gt;
	hInstance &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;LoadLibraryEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;szLangDLL&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;취약한 VS 2008 위성 DLL 로드 부분&lt;/strong&gt;
아래는 VS 2013의 appcore.cpp의 _AfxLoadLangDLL 함수 부분을 발췌한 내용입니다. 살펴보면 LoadLibraryEx를 할 때 마지막 인자에 LOAD_IMAGE_AS_DATAFILE을 넣어서 DllMain이 실행되지 않도록 하고 있습니다. 악성 코드에 감염되어 있다고 하더라도 해당 코드가 실행되지는 않는다는 것을 의미하죠.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;hInstance &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;LoadLibraryExW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;szLangDLL
           &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;
           &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; LOAD_LIBRARY_AS_IMAGE_RESOURCE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hInstance &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// if library load failed using flags only valid on Vista+, ...&lt;/span&gt;
	hInstance &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;LoadLibraryExW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;szLangDLL&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LOAD_LIBRARY_AS_DATAFILE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;안전한 VS 2013 위성 DLL 로드 부분&lt;/strong&gt;
&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이런 사실을 알게 된다면 굳이 위성 DLL 기능이 필요 없다면 기능을 사용하고 싶지 않을 수도 있는데요. 위성 DLL은 MFC DLL의 DllMain에서 아래와 같은 코드에 의해서 로드됩니다. 보시면 알겠지만 일반적인 상황이라면 제어할 수 있는 제어 플래그가 없습니다. 그도 그럴것이 뭐 DllMain이니깐염.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;DWORD dwLen &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetModuleFileName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rgchFullModulePath&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dwLen &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	TCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pszFilename &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;PathFindFileName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rgchFullModulePath&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pszFilename &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; rgchFullModulePath&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// filename portion of path ...&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pszFilename &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;token comment&quot;&gt;// the buffer passed to AfxLoadLangResourceDLL is filled with the path ...&lt;/span&gt;
		g_fLoadingResourcesForMFCDLL &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		hLangDLL &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AfxLoadLangResourceDLL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%s&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;MFC&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		g_fLoadingResourcesForMFCDLL &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

AFX_MODULE_STATE&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; pState &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AfxGetModuleState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
pState&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;m_appLangDLL &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; hLangDLL&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;VS 2013 MFC DLL DllMain 부분&lt;/strong&gt;
&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이 MFC 취약점에 얽혀 있다면 빠져 나가는 방법으로는 1) VS를 업그레이드 한다. 2) MFC DLL을 새로 빌드해서 사용한다. 3) MFC DLL 바이너리를 패치 한다, 정도가 있겠습니다. 바이너리를 패치하는 게 가장 쉬워 보일 수도 있습니다. 플래그 값만 교정해주면 되니까요. 아래처럼 리소스 DLL을 LoadLibraryEx 해서 로드하는 부분을 찾아서 0을 2로 변경해 주면 됩니다. mfc71.dll을 사용하신다면 일이 조금 골치아파질수도 있겠네요.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 619px; margin-bottom: 16px;&apos; data-url=&apos;./MFC_위성_DLL_취약점.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/070a527497535ed2addc4e8a9f44c652/80833/MFC_%EC%9C%84%EC%84%B1_DLL_%EC%B7%A8%EC%95%BD%EC%A0%90.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 34.21052631578947%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAIAAACHqfpvAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABYklEQVR42kWQ2W6DMBBF+f/P6ZpGqA2kbaouaiuWJISwJNjGYAwJGDAEXKd96DzMSDNnpKujqKo6mdwg1GWZoFSkaQvh0baTOK4Y645H3nUDRMe8KbKKFvXBSIx3+O5Sl9ZUmc206fTOtlvORdeNwyCEGGXJgVAZBPnh0DoO6ceONW1VN7zn/dCfxpMElPv7B1WdmmYDoajr8XReir/nJGEYs7LkppmSonR3iWmSGLFf4Iwpj/PZ4lkzDeSsyS5AGMUZiUkaFzn2tqGzDqI90DXje2ks3r7Vu6+l5VUllQDNUuVl8fT2+vT1CW0rgSDCMUgwkJ2kcLsNl5YPkL/be4EfeqG73a8dF/lhRnNU0Fi5uLy6ub3++GgBFBEY6/o/dhRJc0TG9vyCQk5IXhwo8PudJcBGXgdF1/X5XFut2iiStoemkW9S29kbxpXv5WXZblakCjm2mKNR4jRDKPh+ZIz/AN/Ge5aTSu64AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;MFC    DLL     md 0&apos; title=&apos;&apos; src=&apos;/static/070a527497535ed2addc4e8a9f44c652/80833/MFC_%EC%9C%84%EC%84%B1_DLL_%EC%B7%A8%EC%95%BD%EC%A0%90.md_0.png&apos; srcset=&apos;/static/070a527497535ed2addc4e8a9f44c652/08678/MFC_%EC%9C%84%EC%84%B1_DLL_%EC%B7%A8%EC%95%BD%EC%A0%90.md_0.png 190w,
/static/070a527497535ed2addc4e8a9f44c652/2edd7/MFC_%EC%9C%84%EC%84%B1_DLL_%EC%B7%A8%EC%95%BD%EC%A0%90.md_0.png 380w,
/static/070a527497535ed2addc4e8a9f44c652/80833/MFC_%EC%9C%84%EC%84%B1_DLL_%EC%B7%A8%EC%95%BD%EC%A0%90.md_0.png 619w&apos; sizes=&apos;(max-width: 619px) 100vw, 619px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;mfc100.dll을 사용하신다면 LoadLibraryEx에 사용되는 마지막 플래그를 0에서 2로 변경해 주시면 됩니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 617px; margin-bottom: 16px;&apos; data-url=&apos;./MFC_위성_DLL_취약점.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/eb1735b2e56495d35666ebffa24a34ce/8a174/MFC_%EC%9C%84%EC%84%B1_DLL_%EC%B7%A8%EC%95%BD%EC%A0%90.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 45.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABe0lEQVR42k2R21KDMBCGef8X8kJH69gLT0UKaZsSEAkEGjkFCCpFEpdSHXcyO5md/ef7d9d4fl5dXl5YluBcS6m01uOoIODz/i5dt2jbPgiqIvvKhEgkY03cH4epTY2GbTt3dzcYN4xB96zSv+Juv8+77ohxHhYxa1ghq7wckmTUp5jEy+XCskrf1wipJNEzHHKWdZTWIPa80gowLdih4bxspdQzw1ivbSAjVEOp79UwzOQp53kHtkEcRfVnN8qvTzEUzq6l4bnHcBx0e3uNcQ3MOFZN89+2BMOt7Gkgev6haqVT3cb6o9Nn26b5clpYtdloztVcncUn20LKI0LcpGuceG9Jeuy/Z+xEfnx8WiyuHKdx3bPmv20wLGVvWem0s6hCW55n3V+DAaeCmU1TwMIOBwWT/5E5l4RMp9puM0JKPzrYFCOfVaWuKi2ENlar+6eH5cbZpYym7I1FQRS6UUhiSl49l+zdMCCvvsdTCq/IY49QvEuRHexx/AMIEu+VxgSmCAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;MFC    DLL     md 1&apos; title=&apos;&apos; src=&apos;/static/eb1735b2e56495d35666ebffa24a34ce/8a174/MFC_%EC%9C%84%EC%84%B1_DLL_%EC%B7%A8%EC%95%BD%EC%A0%90.md_1.png&apos; srcset=&apos;/static/eb1735b2e56495d35666ebffa24a34ce/08678/MFC_%EC%9C%84%EC%84%B1_DLL_%EC%B7%A8%EC%95%BD%EC%A0%90.md_1.png 190w,
/static/eb1735b2e56495d35666ebffa24a34ce/2edd7/MFC_%EC%9C%84%EC%84%B1_DLL_%EC%B7%A8%EC%95%BD%EC%A0%90.md_1.png 380w,
/static/eb1735b2e56495d35666ebffa24a34ce/8a174/MFC_%EC%9C%84%EC%84%B1_DLL_%EC%B7%A8%EC%95%BD%EC%A0%90.md_1.png 617w&apos; sizes=&apos;(max-width: 617px) 100vw, 617px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;mfc71.dll을 사용하시나요? 일단 눈물 좀 닦고. 상상력을 발휘해 보세요.&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[뉴스타파 전국 유해 물질 데이터 지도]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/14215</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14215</guid><pubDate>Thu, 28 Aug 2014 23:59:51 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;주거지에 유해물질 유출… 세월호 이후도 안전대책은 제자리&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;내 집 주변에 위험물질이? 전국 유해물질 데이터 지도 공개&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;뉴스타파에서 전국 유해물질 데이터 지도를 공개했습니다. 참, 잘했어요. 짝짝짝. 심심해서 좀 살펴봤는데요. 씁쓸한 뒷맛만 남는군요. 지도가 궁금하신 분은 &lt;a href=&quot;https://www.google.com/fusiontables/embedviz?q=select+col2+from+1Vq_jabeFv6xRKWSiNn7GFjZc1TmFhOPSyg-R_vOh&amp;#x26;viz=MAP&amp;#x26;h=false&amp;#x26;lat=37.00650005319146&amp;#x26;lng=127.65704403161624&amp;#x26;t=1&amp;#x26;z=9&amp;#x26;l=col2&amp;#x26;y=5&amp;#x26;tmplt=7&amp;#x26;hml=GEOCODABLE&quot;&gt;여기서&lt;/a&gt; 살펴보시면 됩니다. 집 주변 한 번 확인해 보세요. 하나라도 유해물질 보관하는 곳이 있다면 포풍민원질로 공무원들을 쪼으도록 합시다. 그래야 그나마 조금이라도 철저하게 관리되겠지요.&lt;/p&gt;
&lt;p&gt;하루가 멀다하고 무슨 사건 사고가 이리 많이 터지는지 참 어처구니가 없는 시절이네요. 다들 몸조심 하세용 ^^;;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./뉴스타파_전국_유해_물질_데이터_지도.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/dbadb1967d1c0681b223d3a303076704/dface/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 66.84210526315789%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACf0lEQVR42hXSyW7bVgCFYb7/S3STIonrxlUGU4EHQbUoiqM4XvLOA+/AyUnbLFoUbV1ldZY/cPB5ApWaAafQpNky2VV3d0Gzif9Ms1Nb31fN8edwfR18uw7WpE5meaOwz7vDZJWVvccxGDhcRrEu1g2orPOr5G//kJvidsDJJHMG9uf0uDuTm3j5JR0O+asG+k4+KRp7mEaKwS+LMzTzg/pN/JL1Oe82ksBZQeP4l3VaR/mbjgm8uwqG16dvP53//Xie/Wzwsv4w4FKR0zEtfoz+8wv0VVytshglWjVeZr1YyHHRwoNEt6D44XMK3p3+uMr+eZO+eG3lV+X9fUZfRS+fyl7xj10YjbicJBgNxX1KYIK7iOKSE/93F+LuXX3ecfJQdXfebfH8Nnu5Kf56alPUXJv2VEcHyTsua0YqRsrRMmeIU1iwpG1rAGMqT1KljBy9t8F6E89lt53pRtfBJdWnG626eVSjYcs4rJcxaSf3UtC8CgHaA3IkPB8M9aLj+zb9YNBe4pKBAKNYVLcOPU1WzlYuo3KOS91SlWlLn23u2EPVJoPqRkM83Iake6IikgKg8lGAeEDxcL7WAxosVBZJDQU9O35enGK4UWjXlNu0uAc48hjnghbLpcJBix8YPLAuTYOAklrS2ln2PNtJS00zI6rvouodA3caphI/eJj0mvej5QXxIU+YaCTNuvqEir3pG6epNZiKhIBHmm0FyCiMCPwgm0fV/er1sHIGY5wX5DMzzeVVh88ax7rZWoYniSgLAdwOXXhBAtAnRvay3zl2WEjjYYaUbCctarrDIlysmMR3W0u1MX2m68TQUpMC04KyXLBHTkMnsq8rG0n1P8AMjoQfgC1rAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                     md 0&apos; title=&apos;&apos; src=&apos;/static/dbadb1967d1c0681b223d3a303076704/dface/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_0.png&apos; srcset=&apos;/static/dbadb1967d1c0681b223d3a303076704/08678/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_0.png 190w,
/static/dbadb1967d1c0681b223d3a303076704/2edd7/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_0.png 380w,
/static/dbadb1967d1c0681b223d3a303076704/dface/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_0.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;강남, 유해물질이 뭔가요? 씹어먹는 건가요?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./뉴스타파_전국_유해_물질_데이터_지도.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/52ca7a1133e3e7bc7c256c2d9c829879/dface/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 66.84210526315789%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACWklEQVR42h2SW3PTMBCF/f+f+BHMMMPwBJ0WHkhJb2mTOLEjS5Zl3S8rWXbSduAHIHjf3XO+PafKySyTszAq3oi+Vry1Gm+HOyUfMjiu9hOwZNuerGn7jJtrLa+HfqXEw2R/VTOo90vwQFuyYqxWBvXj7jj8GOUeK/JYHyV97I4rIbsiE5wRvG73d/j0yPpdFXwn9D2S3zt5axS20PXqIZj6DGOLbl5a5K1NQU1B5KgyaOuo8+Q8ufMcKqx/RpAqtODGJWrCd4TfZ3ug3VqI3gKdQSfPg2FT1P+vkNfFxMCNIZUP5H0WGehliQDAyIbTr+3xQQhxXpwwaI7GO6JU69zgDA4WaXkS8pijqTQ/CHLPTl+Gw4emadb7Z0FvTohGL8Fi47HRSBsS7ACGhUABxmDHYgECK8uUSGQsFvRJCNXQQYgDxmVaTp5TsROyLXEkxxl/2etvHrpLEfV1Y64rnRoUrpxt9LA1glrdbE/bzfN2il7JE+NbB+ycQ0qKh4a6fYjibU4pi5R4ReTVQd+4whZojKOxlOI1qjdcDka2jhMHo4XBAsvJZTCqgMCgfO+Kbcs3xjIpDtEhI7Hh6Niue/LYdvUUlBP0PEMhVOw4J7ukQstzdNJtmdhWoBurB9t/subU041gu7Z/6vtVjw602S3ZFeB58jnQ5Nkc9ZJ9jnouXwiy8urJ8L0nH0f3xNwmmH95lKrh+q5Hp+h5ibBovl6gkBfbl6zfXueSRQJVBYcX6KzCL+NnLG+txFI+S94hdL+/W3lNzwtMoM6z+/P7rbTqsoTXBYJl0bG/KxyedwIQXfwAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                     md 1&apos; title=&apos;&apos; src=&apos;/static/52ca7a1133e3e7bc7c256c2d9c829879/dface/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_1.png&apos; srcset=&apos;/static/52ca7a1133e3e7bc7c256c2d9c829879/08678/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_1.png 190w,
/static/52ca7a1133e3e7bc7c256c2d9c829879/2edd7/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_1.png 380w,
/static/52ca7a1133e3e7bc7c256c2d9c829879/dface/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_1.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;구로, 생각보단 작은뎅?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./뉴스타파_전국_유해_물질_데이터_지도.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/be85fb91963b667c838b535fe3896f9b/dface/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 66.84210526315789%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACmElEQVR42hVRSW/zVAD0HwcJznBEHDhyQRX9qPi6QJv0y9bYSbzFy7Oft7f5vXpf4sQt/YSEuYxGmhlpNCNtvHFmf11qUQ4XuSBlRlMSoBjiJKxKceqbIucTjpfhNUWc09eiyVhQF7zvKul0ase3cblzoC3naYgDPeNxmRGaeIHnCBYLBjnzu0YIjgkNU4GzjA19/X946JuP97NlGjBwSFYKkXVNdjmfJplTGCcQYwDRInTXfuQCdWctHxE49m3ZNbk0Xvp/Pt45Dl8s1aIyfRW5QG1T9G01OSYSxl4IdJiY8t3N888/eftNdNTOQzecWqkq6pKAIXywfJqkBiucsmTnvq5LgcMjjkyOHMvRNW3/5/fffv7uG+w7JLLrKjsNJ4lGMXLtlqos8gNr5miPGKdlVU2tgLYJbTmJzIC7pvpoq7Jrba3d3x5YmtEd5YqEKON5eXkbpyaU2EvlyjkuUTpNkUJ7S7Djek4cWOCwsr7MrINsuCtCXJLMWKxIe9hpfnnuirbKcuYz4bvB9al2+rqh2LAdRV/MjacHV154u7Wzflb/uktQCJ0Vgp50f/xXgQWkIEj0nKO2ENM2qn9bkpUdspUceouHl19/2Xx5oSk63F7LN7+Hu3kWGUWaSL8po0leEIe7aIM4iAI9CgyYqDqYbU3zj0Nzv4rnVzfa3mS+Ln+6+vzjD2B7G+zWDAJpej2r7L5pUpESBAiBPjkgAlJRUIaixFUcX7eV3fz66X4JD3OwnlXs2GSiLrDkIrOuium0LOOOoWBmJghgmrR5kiWrNNH6iuR1F6bN3hVb1TmoRuw9NXwFoCFtwPMx2rQlbqoMkzgMdMySFAWcwJxqVaoPp+7t0n+M3df3YbiMdde/FvXS4k+G+A939JoVnj+dhQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                     md 2&apos; title=&apos;&apos; src=&apos;/static/be85fb91963b667c838b535fe3896f9b/dface/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_2.png&apos; srcset=&apos;/static/be85fb91963b667c838b535fe3896f9b/08678/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_2.png 190w,
/static/be85fb91963b667c838b535fe3896f9b/2edd7/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_2.png 380w,
/static/be85fb91963b667c838b535fe3896f9b/dface/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_2.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;송도, 이건 뭔가요?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./뉴스타파_전국_유해_물질_데이터_지도.md_3.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/abfb77d0de8ab95e01f7bce5e81f2ab2/dface/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 66.84210526315789%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACK0lEQVR42iWSy27UQBBF/d98DRsEW3ZIMAKJTQYnMyRMEnsytttuu99d/QoSaEK4TqRaWO2qurdOVZWCzYkeSywlFeoCmRiISGvDH0sip4yc8FgyeaeN0SVnLZjoL/RYV+S14B2SUnS8v17YVYpm7ZXDa0Qy5G2KIcTg0UA8yOEiutGqvrJGsO6OsyMfD7dtd/j5jtRlTiUnH4NNwcFXCA6lcKSXZrj/pubWKCHEsfLoGqyYOj7gaSk5enVv1QBNssIqXgoaheB58p3m+xQoBmf0mlkhCSadkXIeiHxOKUUddZPi6jyGtPSfx+ZDdlz210TrRBCDCadYdeSJCVJaC+28h1WfcrH8MJ9qZ5jgjRh/iOkXBsEvkAOaBI5m5qcaxcGCA0UKEZZzdCvw6OVQ/5k2uXm/NBvMu84f3ZqwsnDBa4CsYGONHFCWogd2wMe4f33/b94+849h+2bqrwyGz4QAP2+F4CejpsqpeW0THDltlyklT14i4xzYE/v+rHbnOOr5pm8vX7cNw6d2r5YBSpWaJ5S9sJWS9zAGjDFSInmm4SkL0lKyu7m7sCBcAru7Ubx3ZsGBVBSwRkwSzDL27WGUrbLz75LRzlsJR14JNTYkr/yLhp5HqHuzwG8FhzCAesixpa3bTcNqbUWMVulpkScs1qkhuQ4Lt2oCOZwtmuKjQiUCa1jEuH/Y1M2n3fHrPdvvus31tNnefIG2mPb97VscQH5Jhj6Y5+T/A7poxnxNUwQOAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                     md 3&apos; title=&apos;&apos; src=&apos;/static/abfb77d0de8ab95e01f7bce5e81f2ab2/dface/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_3.png&apos; srcset=&apos;/static/abfb77d0de8ab95e01f7bce5e81f2ab2/08678/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_3.png 190w,
/static/abfb77d0de8ab95e01f7bce5e81f2ab2/2edd7/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_3.png 380w,
/static/abfb77d0de8ab95e01f7bce5e81f2ab2/dface/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_3.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;유출지, 개수가 중요한 건 아니라는거…&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 382px; margin-bottom: 16px;&apos; data-url=&apos;./뉴스타파_전국_유해_물질_데이터_지도.md_4.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/b752ac3db512f9f9fb1e9c3245ac64f9/29984/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 158.94736842105263%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAgCAIAAACdAM/hAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAGNklEQVR42nWU61Mb5xXG9Xd0ppPpF+dLJ+m4aepMnDbTyad0XDzNEDuNnaSxM3Xj2HFwjOPLFEhczCVgg4AYMDLBllhdVtpdIZBW2JJWErrsfWV0QxcLJAsJWRJYITZI2r6SgM6k6cw7O3uZ33nOnvOcI1lby2TX8sV8diMbWc+vFp6sFnOpTDKcTITTjxPJ5UhyORoKU5EQgzhSsGdTz4t7R7JRzOdya+vFfCEbe5IOlorpzGoyk02mM/F4kFiOuGNhd+ah8inds+CwQu4tjKtgXHUHjqXyubV06Um0+CRZTIc2CssrqRShgRgcWQrYGYFJ+G2i0C16P81bu5GFjE4QMba8A3vCPxr5zfRqOrwUXU4u0/eNd65cvvTHP8B9XaTHppeNZwSlyHWWqasV52dek3IMDWE+sSEuQcgfpmxPFbYczm7ghvuj51pkx45CVy56cW0i5PWbFQnbuBgfF12nqu6PA/o+eVe/yv0DgMGRoGxFz1V0dBkVxNvdQ+/+6pftTU3Spj/bp2XZ7NLK4ygByQR1X4G4GneNx0IWl3xI2ntPVxOvSBoxULYKk1uTo/rjrxw4/cpvbjW9PXH6n7QT592OictfWKFbtEXnZ/BowCoQqnvScTUNyibWYJSrGvgqxm5pXet3xlSfvfrSV68dGP/LoYkj78C9PYsLM0uE8sFtqUs14VuAzaOdFK4xUEUNWW0oV1BOVFgK30lnpe2jn7780tX9vx0+dfJKc7O+q+M+JDfcGlRfPLvIWONhgrjTx5lVatWsxvNM0shZS22jiGu65Yvpj97veO3giX372psOXTjwe+jSeQf6fTwZ8mKTlFG+EqGDpCmwAPsSWSVZTxthqyizHUisP/QJ0KUWqPXc1ImP2vfvb/vTmwQCpSJu3nA3HmVpo8pJzK/EyGR0QaBIhWV9p2BqsmJYFM2o1Tx4k7HOOaek1w8evPG3o2HanMuH56U95H1b3O/VS/si8VD2MU+zAYVjcwdGmApoPSrHZ/q7H0yNadu+HD1+VHbxfMBtjAkWr3o0GQ3nVhbDlBmkkIqRVHhVRYk7MGi1lhMhxGcf6TKNDECd3abhPtmH78lbLxgHe9zwODp8HZcNB72WZEpIBOzQmBbagzFgFUEcg1jpqU+mWi/c/PgDzo4zRk2Ee0Ca4Zlv2745/NbktcsBr9mtHLGNf9vRfERpTu6ZpKL3iTJs6TsprGg93/XWmzb5SDxGxVh90OcIUPNTl1u+fOfwyLF3h099Irt4bnroBurISYC/G8oIL2qdxQfYPDbQa1Xe4ayw36b0WeQ+izIVIqY6/tX/9+PY9XbSbbHeHUF6eiGisJs2V9VQVf18lJmDoO5ri37Wq510QQOMdkCwwfFHUS9ucKIQPtCr6mpvfeNA8+9el9t2WlXBeFFBlAjEEKcMFgyy3btNDHe41COs6e6jIBEMCdrB/ntft/WfPHGj+a8Xfv1i25mvtQ1vY2z9n8lSNpdCrrV1Hn474NQGCTgZ96wkHwaD3NjZ0/CV1q73j5x8cd/pF37Re6hZ5VwHNarBWrpq5MsLS2VChyrP/EPzzb+dsPxRxGWaHPTbUOfcHNzbiV36/GZL59AI+tWxsxNKTr9Y2ydgnoFDqrNUAUJJiwqibY4Q74k+tPN282TXzTOvHzSZPGZPWiEz3P78vBoTsLCICRWgB2ZRogMkX55nCyjOwaNjbly7HHBwgRju4DUzvu+HlCb/cx39XENtzXKbCPUMYco6umIWNlGmrqxlRCNTWmAjLjJkn9GTQmKGKlGLy7P0hkHYrok0tg0jovUR1NHbQjSvpeubBIjjvi0TWzJym/PuwIw7M8sDpqxjKjXP13dt3cK1A5TmmKc4ndVQu9UGVzCfeq5s4LaBYUC42oZgq3su2F30wA6iw78xy/4Iovx3h+lrCgCoM+CR/wm2A9eHH2RUu5E03jasAr6BHbqn9j8kSK2K1YMCEuS4623w57yo9Gyr7CUNLSJ15Z+Su6cBY2wdrpWBFTWWrIPgnHqMXVpD6PL/w+qkiNBbKvezHWWgBg+MBgi1Xaue5wugh9jPwWitutsIvW2gS8zS7kjqWHF6Lq40BhWGAAiENhrzc9kCTWAVHflcbwv9BxMznJHvHq+AAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                     md 4&apos; title=&apos;&apos; src=&apos;/static/b752ac3db512f9f9fb1e9c3245ac64f9/29984/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_4.png&apos; srcset=&apos;/static/b752ac3db512f9f9fb1e9c3245ac64f9/08678/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_4.png 190w,
/static/b752ac3db512f9f9fb1e9c3245ac64f9/2edd7/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_4.png 380w,
/static/b752ac3db512f9f9fb1e9c3245ac64f9/29984/%EB%89%B4%EC%8A%A4%ED%83%80%ED%8C%8C_%EC%A0%84%EA%B5%AD_%EC%9C%A0%ED%95%B4_%EB%AC%BC%EC%A7%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%A7%80%EB%8F%84.md_4.png 382w&apos; sizes=&apos;(max-width: 382px) 100vw, 382px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;유해물질 청정지역, 강원도로 오세염!!!&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[RPC를 APC로 구현하면 망하는 이유]]></title><description><![CDATA[어제 새 기능 버그를 잡고 있었는데 생각보다 일이 커졌다. 결국 RPC가 필요하다는 결론에 도달했다. RPC를 뭐로 만들지 고민을 한참했다. 어떤게 제일 손 안데고 코풀 수 있는 방법일까(?!) 고민한 끝에 APC…]]></description><link>https://jiniya.net/wp/archives/14201</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14201</guid><pubDate>Tue, 26 Aug 2014 23:59:50 GMT</pubDate><content:encoded>&lt;p&gt;어제 새 기능 버그를 잡고 있었는데 생각보다 일이 커졌다. 결국 RPC가 필요하다는 결론에 도달했다. RPC를 뭐로 만들지 고민을 한참했다. 어떤게 제일 손 안데고 코풀 수 있는 방법일까(?!) 고민한 끝에 APC를 사용한 꼼수로 구현하기로 했다. 메커니즘은 완벽했다. 마치 APC는 나에게 RPC 구현을 위해서 만들어 둔 통로처럼 느껴졌다. 둘다 procedure call이니 뭐 도찐개찐이기도 하고. 여튼 그렇게 지루한 코드를 제법 쓰고는 얼추 만들어서 테스트를 하는데 이건 뭐지?! 주구장창 크래시!!! 그러다 찾아본 QueueUserAPC 도움말. 설명을 해놔도 안 읽은 내 잘못이 컸다 ㅠㅜ~&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note Queuing APCs to threads outside the caller’s process is not recommended for a number of reasons. DLL rebasing can cause the addresses of functions used by the APC to be incorrect when the functions are executed outside the caller’s process. &lt;strong&gt;Similarly, if a 64-bit process queues an APC to a 32-bit process or vice versa, addresses will be incorrect and the application will crash.&lt;/strong&gt; Other factors can prevent successful function execution, even if the address is known.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/desktop/ms684954(v=vs.85).aspx&quot;&gt;http://msdn.microsoft.com/en-us/library/windows/desktop/ms684954(v=vs.85).aspx&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;믿을거라곤 이벤트와 뮤텍스, 그리고 파일맵 밖엔 없는듯… 아님 파이프가 나을래나?&lt;/p&gt;
&lt;p&gt;뭔가 일이 쉽게 풀린다 했지… ㅠㅜ&lt;/p&gt;
&lt;p&gt;오늘은 장사 접고 낼 해야겠다…&lt;/p&gt;</content:encoded></item><item><title><![CDATA[윈도우 스토어 앱 개발하긔~]]></title><description><![CDATA[iOS가 판도라의 상자를 연 이후로 요즘만큼 개발자들이 피곤한 시대가 또 있었을까 싶다. 초창기 윈도우 프로그래머로 일하던 시절에는 윈도우 9x…]]></description><link>https://jiniya.net/wp/archives/14118</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14118</guid><pubDate>Thu, 31 Jul 2014 23:59:49 GMT</pubDate><content:encoded>&lt;p&gt;iOS가 판도라의 상자를 연 이후로 요즘만큼 개발자들이 피곤한 시대가 또 있었을까 싶다. 초창기 윈도우 프로그래머로 일하던 시절에는 윈도우 9x만 없다면 뭐든지 다할수 있을 것 같다는 말들이 유행했었다. 그렇게 영원이 악몽같이 존재할 것 같던 윈도우 9x도 윈도우 비스타와 윈도우 7의 출현으로 역사의 뒤안길로 사라졌다. 그렇게 잠시나마 태평성대가 오나 싶더니만 iOS와 함께 온갖 종류의 플랫폼이 우후죽순 등장해 버렸다. 이제는 차라리 비슷했던 9x를 지원하는게 좋았다는 생각마저 들 정도다. 갈라파고스도 진짜 이보다는 상태가 나았지 싶다. iOS, 안드로이드, 윈폰, 블랙베리 같은 온갖 종류의 디바이스가 세상 밖으로 출몰해 버렸고 똑똑한 프로그래머라는 소리를 들으려면 그 온갖 종류의 디바이스에서 동작하는 프로그램을 다 만들 줄 알아야 하는 시대가 도래한 것이다. API 세트도 다르고, 언어도 다르며, 심지어는 OS, 더 나아가서는 CPU까지 다른 환경에 익숙해져야 하는 골치아픈 세상이 돼 버렸다.&lt;/p&gt;
&lt;p&gt;이쯤되니 요즘엔 윈도우가 PC 시장에서 그랬던 것처럼 누군가가 그냥 독점해 버렸으면 좋겠다는 마음마저 든다. 사용자에게는 선택권이 제한되고 개발 생태계에도 좋지 않은 일이란 걸 알지만 이런 온갖 종류의 디바이스에 들어가는 프로그램을 만들어야 하는 프로그래머의 고충도 보통 일은 아니기 때문이다. 하나 하기에도 바쁜데 하나 배우면 또 하나가 튀어나오는 식이다. 그.래.서. 요즘 개발자들은 정말 피곤하다.&lt;/p&gt;
&lt;p&gt;그런 피곤한 개발자들에게 윈도우 스토어 앱이라는 신세계가 또 열리고 있다. 지금은 시장 지배력이 낮지만 영원히 낮으라는 법은 없고, 아직까진 경쟁자가 별로 없는 블루오션 시장이라는 매력도 있는 그 윈도우 스토어 말이다. 남들보다 조금 일찍 배에 올라타려는 프로그래머를 위해서 스토어 개발에 관한 이야기를 몇 자 끄적여 보려고 한다. 모든 플랫폼이 그렇겠지만 기본적인 환경을 구축하고 돌아가는 메커니즘을 이해하고 나면 나머지는 그저 소소하게 변경된 API와 언어 뿐이라 생각보단 금방 접근할 수 있다. 그럼 이제 윈도우 스토어 프로그래밍에 관해서 한 번 알아보도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;백문이 불여일견이랬다. 일단 한 번 만들어보자. Visual Studio 2013을 사용하길 추천한다. 그리고 영문판으로 설치하길 권장한다. 이번에 컴퓨터를 새로 사면서 한글 윈도우를 설치했는데 내가 한 일 중에 가장 병신같은 짓이었던 것 같다. 프로그래머라면 영문판을 쓰자. 그게 검색하기도 편하고 문제 해결하기도 수월하다. Visual Studio 2013을 설치하고 Project, New를 선택하면 아래와 같은 깜찍한 다이알로그가 출력된다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./윈도우_스토어_앱_개발하긔~.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/372fbec30b9aba24f10c498ad588041d/dface/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 66.31578947368422%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABx0lEQVR42nVR23LTMBD1X9Nh2v5GH/kLHoEZLm1pSpmQ0FAcJ47txrauliVZ8iXpSoZAmHK0K2l25uw5KwXo+gW+OSOTc3L7V0zO0c0pnkD9DC4QUEw+vIzenYRvT7aXp1AHVhAtrr7M0jBGaak2ufSh4m0VLtOfEFHyWNACi4dVHq63D8sNZpJwRSuVYxGk4ecfURHFeclsTpqSNpgZROVqGXMmMCaMcUoZQkTpZhj2w+5PBAp9q4TOt49Db/cOO0htzHw6b22rtW4cdKP1ANRjBIbOoUdeFG9m5XVs1pWrNtauorWSCoEiocjDGON673ZHZDhs27/6RC/e09ezelS+n90bbWqAqKWUsIOLZ5Th6Fpbs1JyJEjJOW+MzZJMKw13XlUV7Iwxygghoq7/JaOyFLU6uGq7fno3lXUtlRQeXddBHcZ+xnblWvND1dj27vYrkCsHpyqlsn7mI9uNJ5dFAe0PykrpxXwBQ4JfN7UQo/2+d9qQvYdT7oc9QQhjDP/yS9nYy49XWZomSZJ6ZGmWeMRrt8Am9Aos+650u15Fy9Ct8T+6frDWQm8YFXLU6X5fem8A4Mi8Ukm8GR9m8Lb7o3f5L54AWGXV4TtPCPUAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                md 0&apos; title=&apos;&apos; src=&apos;/static/372fbec30b9aba24f10c498ad588041d/dface/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_0.png&apos; srcset=&apos;/static/372fbec30b9aba24f10c498ad588041d/08678/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_0.png 190w,
/static/372fbec30b9aba24f10c498ad588041d/2edd7/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_0.png 380w,
/static/372fbec30b9aba24f10c498ad588041d/dface/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_0.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;윈도우 스토어 앱 프로젝트&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Visual C++, Store Apps 아래에 우리가 선택할 수 있는 프로젝트 형태가 있다. 유니버셜 앱이라고 표기된 것은 PC 윈도우, 윈도우 폰 환경에서 모두 동작하는 앱을 개발하는 것을 의미한다. Windows Apps는 PC 윈도우에서 동작하는 앱을, Windows Phone Apps는 윈폰에서 돌아가는 앱을 개발하는 것을 의미한다. 유니버셜 앱이라고 특별한게 있는 건 아니고 공통 코드가 Shared로 빠져 있고, 각각 디바이스에 맞는 프로젝트 두 개가 생성되는 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;프로젝트 종류도 여러가지가 있는데 Blank App은 그냥 비어있는 앱을, DLL은 네이티브 DLL 코드를, Static Library는 정적 라이브러리 코드를, Windows Runtime Component는 윈도우 런타임을 사용하는 DLL을 만드는 것을 의미한다.&lt;/p&gt;
&lt;p&gt;유니버셜 앱의 Blank App을 선택하고 프로젝트명을 halo로 만들어 보자. 만들고 나면 솔루션 탐색기가 아래와 같이 구성된 것을 볼 수 있다. CTRL + F5를 눌러서 실행해 보자. 윈도우8 환경이라면 그냥 실행될 것이다. 개발자 환경 등록이 되지 않았으면 뭐 자질구레하게 묻는데 MS 계정으로 로그인해서 인증을 해주도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 350px; margin-bottom: 16px;&apos; data-url=&apos;./윈도우_스토어_앱_개발하긔~.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/cea0c5e8c7c7fcbb90c37b7338e48393/f8bcd/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 126.84210526315789%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAZCAIAAAC+dZmEAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAD3klEQVR42o1TS28bVRSeP8gKAgsWiAUKrVSqUhKogEYxVAToBhaEuEClskorkaRV7BDl4aTYCXFc25mx5/2eO/bYmRnbE8/DHo85YzePpgHx6czVle5853zn3O9iU4mFz77+5VOIrx5AfDwzPzW7MD3zw0dfzF///KdbMz9PzyanEslPYB1HIgm/3bn363Qiib3x3pe3Ew9v3k1evzN/a/a3m3cfTHz47cS1++9c+w4C9m9NzsH6dhxzb37wzcTk3Ls37r9/+8eJyXvY9/NPsofsZrayspZb3z1aTue2ctXVjYMnT3eWUtnUViGzTz1dL+zupojicq7A/XUoPM9zeVxbfJbDko+e6XWb4lDxiKnQMl7lKU4jKKlc4csES7KqjExWNBASrAap6Jai2zKyRLW5nnmBPVpctSyzVm8cm3atZpimXTcahtG0Wp3jY9Nxup7fC4Ke5/Vdb+B5AYTr+qZp7uVx7PHKJtJUUZAYhtM0JEsyQpCkwTIsw7CW3Y6iYT8cDAYRfOEgguj1B8PhsEpL2OLSer/ndS1N4hmgRVHUH6E3AhCGY0COU0CimMxI2NJqBnYtqykQXLVCkhSF43i5XOYFgSCIYuGwVMYlSZJleRC9Tk7twK7jOO2W00akIrJAtlotqO0Hvu97gACaDnrR5coyVI7JoDOKBk1D1jSVohlNUZEe96/IioY01/NGwkF6dEYmz8iu5/tuV2vWJVXjWEbghWqlwgtitUKQJCnLyhn/CnKv34eT7N4+z4uiKEmCxLIcQoihaSYeO8PzvKKojuOMyINXyNAY5JZVpMoSzwnwO2QQBbF74gZ+0O2edNptYML8z8nshZ79ICjihI4Q1KIoigXxgljTa7qu9/q94QW8lM0q2MLDFVk2imWWLLHp9O72zsHW9n46nUmlM3+uP9/YyKbWdrYzB38fHGX3irm9Uv6wUj7iRMlY28xjvz9e63YDQdRkXpOpEoETB/myIGmGYdXqZt2IQ4RTWVfVujRakd5sd9y9fPV0YD2wYGg3RIQUjuPB3JZtjmHb9rjVK2T/MXKY5wd930PNuox0mqJ4DtxWpSj6RaFQLJbAYHCVL686isLw1Wk7JydOp6PWDfAFQzNQXACIsm234MiyrDH5cuVT2WDGIF/CNRVkC1CcommW4ZqNplE3rpRNcSq2PPJ213WdhkPihKqqUJlmWAPaNu1jIBtGbKH/IFu2bWkmXHIsVhQZmnXdcz9ewjl5LNuHFxQEqGariiJKoiSIMML4v2jwOv8COTV2WAgPpt1oofhhcNDn8N9xuXIYhvHMO44FN3tshf3w/5D/AdHqHnS4R9VmAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                md 1&apos; title=&apos;&apos; src=&apos;/static/cea0c5e8c7c7fcbb90c37b7338e48393/f8bcd/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_1.png&apos; srcset=&apos;/static/cea0c5e8c7c7fcbb90c37b7338e48393/08678/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_1.png 190w,
/static/cea0c5e8c7c7fcbb90c37b7338e48393/f8bcd/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_1.png 350w&apos; sizes=&apos;(max-width: 350px) 100vw, 350px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;스토어 앱 솔루션 탐색기&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CTRL + F5를 눌러서 앱을 실행하면 어디서 실행되는 것일까? 센스 있는 프로그래머라면 알아차렸겠지만 CTRL + F5를 눌렀을 때 시스템에 설치되거나 해서 실행되지는 않는다. 아래와 같이 디버그 빌드된 폴더에서 실행된다는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 556px; margin-bottom: 16px;&apos; data-url=&apos;./윈도우_스토어_앱_개발하긔~.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/28fac8718e0b5d9d82e16384493adbed/68b51/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 67.89473684210526%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAIAAACgpqunAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACF0lEQVR42m1SyW7VMBTNV7IHJHis2fAjrPkLumBFK4pYI1G16XtxbOclL4PtOJ4yc9IBtRVXVzd2nDP43kTp+Sd+/rG4eC8uP4jL3X1t7vPHVrEtvr+7+fo6Pntze/YWa/lzd/flLnr1+eLLt1+jupFl3JY3VtwiZ8dHwybLR4vKRsODpr5NnSJBk6FLh44io6s8CDv2w2S63FrFj5XuTCPaVtuibFpt6kblRV2c6nGa13VdkMs6Leu8rNE6emd0CP0yB6w6hPHTPE3TOAxD6PtxeyL6ZZnHcdSdNc5NM4iWqO+yOP7DGAerlEqKynSFMXb9XwCs2g7WQgjzPEX7ovt9HR/2e++9Uko0VadAF2O7mYTFJzH0vZQS5oQQ1rlI6IFxXhQ5yJSSTSOU0kmSZJyXZWm6zcIyP3DAPAQAVqr1PkTKj1I0xnQ4A1/dNHXdcM5IQjhjWXY8nU5lWaEHd+BhAxvTKuVDiEo9QM0Ys4EbUVUlI7eccZpSxlir9VPzALeqhRIoNuWi8lIKvMUZKLTWh/0hpZQQFGatux/PI7iXD7YB9tGx1vEhySiuXeBtH/rrK/Sep2lKCXXOP2vYvztL6QAulSMwSGme52ANzvGE8SxjlKFhGPqzUcF2C9sGFb9GVCt7IIRAnB+FlPCvW0VhOyEY6Is5Y1SP3ZYwFSnbErbHbHA9a22/HcutYZTq57IvlL0PfwHTZgoq+PYMvgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                md 2&apos; title=&apos;&apos; src=&apos;/static/28fac8718e0b5d9d82e16384493adbed/68b51/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_2.png&apos; srcset=&apos;/static/28fac8718e0b5d9d82e16384493adbed/08678/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_2.png 190w,
/static/28fac8718e0b5d9d82e16384493adbed/2edd7/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_2.png 380w,
/static/28fac8718e0b5d9d82e16384493adbed/68b51/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_2.png 556w&apos; sizes=&apos;(max-width: 556px) 100vw, 556px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;Debug 빌드 폴더&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;그렇다면 여기에서 의문이 생긴다. 스토어에는 무슨 파일을 올리는 거지? 릴리즈로 빌드하면 뭔가 패키지 파일이 나올까? 하지만 그렇게 해봐도 패키지 파일은 나오지 않는다. 패키지 파일을 만들기 위해서는 Visual Studio 2013의 프로젝트 메뉴 아래 있는 스토어 메뉴를 활용해야 한다. 메뉴를 선택하면 아래와 같이 나오는데 여기서 Create App Packages 메뉴를 선택하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 577px; margin-bottom: 16px;&apos; data-url=&apos;./윈도우_스토어_앱_개발하긔~.md_3.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/72512e0999c441908c015f3491c53b1e/32e64/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 86.84210526315789%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAIAAABSJhvpAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAC50lEQVR42lVT6+vjRBTNXy/oB1n0J4iyuoIs7Mqi4iqsLPh1F7RuH3k0TZrmOY9kJslMHk2bpJ70BwsOt5dL6eGce+6p4fjU9PjGIR/s1DkWGGy/2B04OmrrENNlpstX23hjJ6Z9svaxFzDTCcNUGjv7FCT1xmV+rAt1y+ulqByPiY75xfGzP9/+sl7/9esfrz95ePnkmxdfPn316cPzz7549vD0J2O19o5xvXM52NL8wsqZV7eYnbcOtXwZxDTY/9YUb63dmx9evv7x1e/fPv/54fsXT75+9vlX3xlekLknYR5y1D4o6R2c8AFqD7GKSFNVuq4brdvh3Letvgz9ZThjnsarwYsWzB9sYnm5cxQh7QG+88/Qn/J2GIbb7TZP0zhO4zRNM8b5eh1RRkoqL6osr4DyTFywNpUTK6elV7eIqLbtAFZKUUqllPMM5JVznqWZoZprkCqALb8Ac0Q7IO818noBEwKMkLIsywofIURd1xjQjaLsvbDa7hlq7RAnkNB8r4kvzA0wbdtmWUYZI4QwxjAnSUopgWH0EEonKHFtkONCeXXj2LmcCjBnGvJAkhEahRHjudawEF+oWqm7YYlemdnKpCuThPQMn8AJw7B/TDXWU6qO4xhSsbYGutFFXsByo6lcmrwj8Xsl12Xxb6esx+q13audyF1RDae0dAMWZpV34kEimehJ3nHZGf7RO/iB5R79U+weT5brM1HJWnNZSaVF1RTlaHrC8sXGYW6kEn5hEKUXOwzbjXZ7BDtD3+7p2ski0iEwazuFkdhZVNety7cuxW/so8SOCO/dS20EQUAJwQFw/Hl5Swr+Xu/DMPL9Q5YxUY84Af4kIA/SJuFnpBh2LOCikMgAknO7v3le+mpzoJTBHp5LUY3ID0RtoM7lXlRHtIepYaaNx/R9fI/gfzYuPD2fe930AC8RutfOyx9jy3BF2hi3/7+PYAVc3+mm40Vn+8w6UNvnWydNWEfFwOQlJvV/rvaY5Mj5lwwAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                md 3&apos; title=&apos;&apos; src=&apos;/static/72512e0999c441908c015f3491c53b1e/32e64/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_3.png&apos; srcset=&apos;/static/72512e0999c441908c015f3491c53b1e/08678/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_3.png 190w,
/static/72512e0999c441908c015f3491c53b1e/2edd7/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_3.png 380w,
/static/72512e0999c441908c015f3491c53b1e/32e64/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_3.png 577w&apos; sizes=&apos;(max-width: 577px) 100vw, 577px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;스토어 메뉴&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;종종 스토어 메뉴 자체가 활성화가 되어 있지 않은 경우도 있다. 그런 경우에는 솔루션 탐색기의 Package.appxmanifest 파일을 선택해서 연다. 그럼 아래와 같은 화면이 출력될 것이다. 거기서 Packaging 항목에 있는 버전 정보를 수정해주면 활성화 된다. Packaging 항목에 보면 Publisher 항목이 있는 그 부분이 디지털 서명을 선택하는 항목이다. 시스템에 설치된 인증서가 있다면 거기서 선택해주면 해당 인증서로 서명이 된다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./윈도우_스토어_앱_개발하긔~.md_4.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/082b3a8c3b8d354adc57700833b098b0/dface/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 38.421052631578945%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAA7DAAAOwwHHb6hkAAABFElEQVR42j1Q2ZKEIAz0/z9w10edwgPkSJBDthzdBqempWI40t1JZ40tR7nvO8bIxO8Ga23OuR0GIrqu6zxPJgoh4NZ7v66ylNJpvVnrHJHRFSgjR0opJNbZrUIbY1C2N6SUEJkZSSeEwCXI5opFbXqVcsWnVIgx5YwV8TDn4yi5bbFqguJJTHgJGSGmZVmJ2e+791UE8SjlAJ5Y/+WvAXktJmJs0DASAF5h2zlGJ49b/zA1QGNtcM5BvEN7vlYxGjbWPbJYXwtIMDMMhb2Hu77vf357eIR493qN4zCAQkoJvjYMsDU9sDDDVP40ibaPx/anZzGJZZ5hUkwzprTvoRZ6v2g3SBqlGxEVa8KcwxdgTCn9A8mVw5uCcTddAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                md 4&apos; title=&apos;&apos; src=&apos;/static/082b3a8c3b8d354adc57700833b098b0/dface/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_4.png&apos; srcset=&apos;/static/082b3a8c3b8d354adc57700833b098b0/08678/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_4.png 190w,
/static/082b3a8c3b8d354adc57700833b098b0/2edd7/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_4.png 380w,
/static/082b3a8c3b8d354adc57700833b098b0/dface/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_4.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;Package.appxmanifest&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Create App Package 메뉴가 활성화되면 선택해서 패키지 파일을 만들 수 있다. 처음 물어보는 항목이 MS 계정과 연동해서 업로드 하겠냐는 질문인데 연동 작업을 할게 아니라면 NO를 선택해 주면된다. 그렇게 앱 패키지를 생성하면 마지막에 어떤 폴더에 생성이 되었는지 알려주는 화면이 출력된다. 클릭해서 해당 폴더로 이동해보면 아래와 같이 패키지 파일이 생성된 것을 볼 수 있다. halo.Windows_1.0.0.1_Win32_Debug.appxupload 파일을 스토어에 업로드하면 된다. halo.Windows_1.0.0.1_Win32_Debug_Test 폴더에 들어가보면 halo.Windows_1.0.0.1_Win32_Debug.appx 파일이 존재한다. 그 파일을 통해서 시스템에 직접 설치해 볼 수도 있다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 507px; margin-bottom: 16px;&apos; data-url=&apos;./윈도우_스토어_앱_개발하긔~.md_5.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/2d27ef19993df10a6f3d22d40a4ea73d/f03ec/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_5.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 43.15789473684211%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABfUlEQVR42o2QzU7jMBSF86QghDq8AAuegw0vwYLFjMRISEhAO7NBlDJimJKmjZ1/x/lxYzu2Y3vcIirYcfX5+PgufK7t5b9OivFxdjtCt9+a30d4PKonG8V3W8ajajxKrg9fvu/Nf+w7Da8Oqsmm7/D2zy5PL342YEKLaba46cuHCkycqvrJIauZqmeyemLo0bHOH1gxFfjxDe982t2DTsqBc9p1iPKhY4L1siGsIbyXQ8cF6XqHUNpaa6zVW5Sx3jBoY5RSQ8+JYHGFK9I2GJdZlqZJsl6Ttm1KhNI0dV7rYYcQvddSyxkzenurMS69Fy6K2s9lzM6YXdN7DSs/WDV1zRiTUjAulMRF+g/CLAQwR2WByrxAUZw4QhDlCKnBRRvtxsYtX6zAMgh834cwSuIYr/s5yJ79+M8rnIMiiEsfln+D5DmIZy+hazoflV0rrFfUdLGCMYRpklJKAQD6/Qkfhtzsb9b9kHZre/Aw4UsYhcsVADBLMkKI/XL9ByF37BvOD/Y0AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                md 5&apos; title=&apos;&apos; src=&apos;/static/2d27ef19993df10a6f3d22d40a4ea73d/f03ec/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_5.png&apos; srcset=&apos;/static/2d27ef19993df10a6f3d22d40a4ea73d/08678/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_5.png 190w,
/static/2d27ef19993df10a6f3d22d40a4ea73d/2edd7/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_5.png 380w,
/static/2d27ef19993df10a6f3d22d40a4ea73d/f03ec/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_5.png 507w&apos; sizes=&apos;(max-width: 507px) 100vw, 507px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;생성된 앱 폴더&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;스토어에 올리지않고 appx 파일을 시스템에 설치하기 위해서는 윈도우 그룹 정책을 변경해 주어야 한다. 실행 프롬프트에서 gpedit.msc를 실행하자. 그럼 아래와 같이 그룹 정책 편집기 화면이 출력된다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 562px; margin-bottom: 16px;&apos; data-url=&apos;./윈도우_스토어_앱_개발하긔~.md_6.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/83e2339d21a2af8e357d0f98f0cd3281/a4f00/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_6.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 50.526315789473685%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAB/0lEQVR42jWOSY/TQBCF/VM5IIKAjDjzCxAXNEIgIQ5wAIkRHLgwg8ISRckkTiab4yyO7cRLb+mO7fbu7METhqdPT69KVaoSSP2Z23zq1J94jaLbKHpikTeL81JhevlALz1UrgrKZQGUH3PxzDvh1M9g+ZHy/P74xT1BH14p04ltDiW5j6CqqWMEZ7LUosTIYicJaBKynDQnWp7IA11vQg4qwlQVNYsZxqgmm5Dh1gAMNTDSkYldRH1IfUQDzEKL+CbmBvJO7lo0NZSqEKEaZ6qq6pZt7fd7w7K//Sy/+1o+/1R6c/H77ZfKx5L04Xv7T1tvjuwbBdVlQxwaNRlJ3V9CCKucTgwTrLLseDwSsuh1u51OR5bl3CVJ6vb6sjxwnWXk83zA91gcBWEYR6Rzu0ztfl+SdU0Nosi2bULwepVt1ussTZMkzrJsu924Hm/3FQ163ZGuAYb4luOOEMAqQ2PLAsC2kjSFCENvjfyt47qHw+F40m671sDycy95Wc1eX6fn1eRV4zBRWkIIKi7sqepsPp9hDDHGCC8QWcRxtPqv/D7ntz/vcu33u902zyFuC9SoQ0QtgLkfEepAwpTpTB4pw7G6YF7eAZA6XsCDOIjSO8I4TPfMFAWl8b7f/AG064XRIvMm+edzMS8du8Os9tJuU+uGmnfk/RxmS2Bw8RdvUgVIm/yoxQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                md 6&apos; title=&apos;&apos; src=&apos;/static/83e2339d21a2af8e357d0f98f0cd3281/a4f00/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_6.png&apos; srcset=&apos;/static/83e2339d21a2af8e357d0f98f0cd3281/08678/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_6.png 190w,
/static/83e2339d21a2af8e357d0f98f0cd3281/2edd7/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_6.png 380w,
/static/83e2339d21a2af8e357d0f98f0cd3281/a4f00/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_6.png 562w&apos; sizes=&apos;(max-width: 562px) 100vw, 562px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;gpedit.msc 실행&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;여기서 로컬 컴퓨터 정책 =&gt; 컴퓨터 구성 =&gt; 관리 템플릿 =&gt; Windows 구성 요소 =&gt; 앱 패키지 배포 항목으로 이동해보자. 그럼 “Allow all trusted apps to install (모든 신뢰할 수 있는 앱을 설치할 수 있음)” 함목이 있는 것을 볼 수 있을 것이다. 기본적으로 비활성화 돼 있다. 그걸 선택해서 활성화시킨 다음 재부팅을 하면 appx 패키지를 설치할 수 있다. 정책을 바꾼 다음 재부팅을 해보자.&lt;/p&gt;
&lt;p&gt;재부팅을 했으면 앱을 명령 프롬프트에서 설치하기 위해서는 파워쉘의 add-appxpackages를, 제거하기 위해서는 remove-appxpackages를 사용하면 된다. “add-appxpackages appx파일명”을 입력하면 해당 앱이 설치되는 것을 볼 수 있다. 아래는 그렇게 앱을 설치하는 화면을 보여준다. 디버그로 실행해서 이전에 설치된 인스턴스가 있기에 제거후에 다시 설치시키는 장면이다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 597px; margin-bottom: 16px;&apos; data-url=&apos;./윈도우_스토어_앱_개발하긔~.md_7.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/c71ea19757a3531e6f9b8ea1bfd103c6/f523d/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_7.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 87.36842105263158%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAIAAABSJhvpAAAACXBIWXMAAA7DAAAOwwHHb6hkAAADd0lEQVR42i2RWW8aVxTHz8wAA0ZYMBgIYLZhsRlmWMyw743ipDY2TVwCNk5UOzI2BrPOYBjSqi+VqiZfoc+tHPWhD32p1MhuqiRSv1Qv40pHR/97z/Y798Kbn0bt0XggDvrisC8MBUlA/nLUb/f7J53Oq273tNebzARxIV6O++PZRHw9FRaiMJ3/+8cbOL84c2V7TKnDVnr+Unej0PHmL0KVrj9/7i92PLlzf7Zt4I6N3Iu1UEu/2bBHWja24ch03v/5C8y3NxKAJ7UrWY06SJJhkkyr1RmSzKnVqRVNVKN5qCIZnEjjijyOO3TrlJFd03mtrtI/f/0KkzIdBAjiWAggDBAD4AA2ADYBfABRAAaAl/0yjSA3SB2HK7cszN37G+iXaScqw7GonI0yXAARuYVP7rUFEMLwEK4MIMMIP65ArT1m5gMq7pZpO5qDY/cz47L3ACQB2OVkDHlapXtg5OwUY6NYhyFo09G0s/gBYc/K9LI9jqUACgAPAfJyi4Q8lpHJ73Va3stP6n3K1bCF+xsVX5TpJR6Bo4BXteqiOJshuG5g7AbGamCQcBoYC9IUY6SCelMM8zXAd7QS7SwfrFWmzWgrAvMjPAy3EyoboXISKjehcsiGdIBQeQkSUdh0TsxdVdq/0DHNJXatQmsRJ47xMpVVtnUZGK0dkJ8dYbOE2qNz2Vc9JkPArXM7nPkldrXiowAyhKqEKWKYMoEpcpgigiuTmLKAvgRXppAGPKCx6s0p01rcbOIpQ8RMP1kWNw5rmsBzS6RhCjeoUN0cO6S45/pQ3Rpt6oMHRraOLh9Emxb+RBs91fNn+viZnn9lyY8+3t7AlTDyPrqOVMXI3nXiqcQ/lZgvha3aPPhkwu6Im4/H3O4UhbidCbs9DD0e8jWR3xdKRz98un0HwmzC7UqpZ7P0gZSrL0rN72J7YvZria9dR3cFpOP708yBhCxaFeK168rR95XDbysvfvx89w66w6twVUp+JaafzWJVgd+fbu2hGiG+L6JjZGfCbA+c+Qt3sWNOntozbbp86Sqc+x8Jn+9u4KTTNaaGzsKVo9B3l4Z0ZWTP9pyFgS3bs6QurZnueu7KVRw4in1bpmfk21r2VMt+QyUGH29/g5/fvpyOj19Pjxfi/14SWkhIkyNJbM2F1kK8NxRCx8PpqDnp16Xpy0+/z/8DuPPjntNRgqIAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                md 7&apos; title=&apos;&apos; src=&apos;/static/c71ea19757a3531e6f9b8ea1bfd103c6/f523d/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_7.png&apos; srcset=&apos;/static/c71ea19757a3531e6f9b8ea1bfd103c6/08678/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_7.png 190w,
/static/c71ea19757a3531e6f9b8ea1bfd103c6/2edd7/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_7.png 380w,
/static/c71ea19757a3531e6f9b8ea1bfd103c6/f523d/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_7.png 597w&apos; sizes=&apos;(max-width: 597px) 100vw, 597px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;파워쉘을 통해 앱 설치 및 제거&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;파워쉘을 통해서 시스템에 직접 설치하면 아래 화면에 나오는 것처럼 Program Files 폴더의 WindowsApps 폴더에 빌드한 앱이 설치된 것을 볼 수 있다. WindowsApps 폴더는 기본적으로 관리자 권한을 가져도 들어가 볼 수 없다록 권한 설정이 되어 있다. 내부를 살펴보기 위해서는 해당 폴더의 소유자를 관리자로 변경해 주어야 한다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 550px; margin-bottom: 16px;&apos; data-url=&apos;./윈도우_스토어_앱_개발하긔~.md_8.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5600b4e84abef57654eb90be5c72fe9b/8c3ad/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_8.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 66.31578947368422%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACB0lEQVR42l2S247TMBCG85I8x24FlGt4DO655QE4bCUkLgoIsUAXBG1zcA62k/gcx3FOTFqQ6I6skeXM7/+bcYK7zdXn18+O755U28f8w5p/XNfbR5DFp/U5F+8f/np1FW5W+zfX0WZ12lwd3l4fb1bB0xcvHzz/fvM1nB2vq6w1TIvSt2roDKyxb0bf9E733vSnk2XvICvvdFCjrW7HYRic66xBWuu8IFVZKW2qmmV5Qcu6aWyeY0JKQkshFSG0wKRmPLDlbTfMnWtBP01D0xiljJDNPM/jOHrvu86P49D3vj8Fl5pWzBg7TWNg6G3OLC6KplkEbdt5VwuGKK0wxoAzXwaUARRka22g8RdSd7bR07R8c673LSb5DqUFtAAVDi7oOtiALRQYrZVSkISUgau+HbM6jmNaEM459OOs5DVO04wxBieUlhBFgc9ocKOUi1gqFfR8l1CRJCgOI1AmcWxgPAU+7g91VQshodn/sReZlH+dQZxSmaA0iWIwQQgZYwqMw2MIK01T33nQTOeuANucsfXi7NmOcHI4/o7CCOaAUgRQWZaFYRhHMcD7S2ezYMuzf+D5D0yj/f6nEAq+wYSBJ89yQMjSTGkFD3aJ/U+sTmLOUBTuGRfABuLGmJLSKAbbtO+He09lLsV3tIKyGAynkzNMFeacwz+FyT1bCGvh8uWdjTF/AJW4z2A9m/CZAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                md 8&apos; title=&apos;&apos; src=&apos;/static/5600b4e84abef57654eb90be5c72fe9b/8c3ad/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_8.png&apos; srcset=&apos;/static/5600b4e84abef57654eb90be5c72fe9b/08678/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_8.png 190w,
/static/5600b4e84abef57654eb90be5c72fe9b/2edd7/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_8.png 380w,
/static/5600b4e84abef57654eb90be5c72fe9b/8c3ad/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_8.png 550w&apos; sizes=&apos;(max-width: 550px) 100vw, 550px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;WindowsApps 폴더&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이렇게 개발한 appx 패키지를 친구한테 주고, gpedit 설정을 변경하는 것 까지 알려주어도 친구는 앱이 실행되지 않는다는 문제를 호소할 수 있다. 이벤트 로그를 살펴보면 0x80073CFC 오류가 발생하는 것을 볼 수 있다. 개발자 라이선스 갱신이 되지 않아서 발생하는 문제다. 관리자 권한으로 파워쉘을 실행한 다음 Show-WindowsDeveloperLicenseRegistration 명령어를 입력해서 개발자 라이선스를 갱신해 주면 문제가 해결된다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;지금까지 앱 설치 및 배포에 관한 기본적인 방법들을 살펴보았다. 이제 개발적인 측면을 살펴보도록 하자. Windows 8이 출시되면서 아래 그림과 같이 앱을 위한 WinRT API가 추가되었다. 앱 개발은 그 API를 사용해서 쪼물닥 거리는 것이라 생각하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; margin-bottom: 16px;&apos; data-url=&apos;./윈도우_스토어_앱_개발하긔~.md_9.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/083b2571a3bf8c33eb0b10208b585cc7/3e510/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_9.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 49.473684210526315%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACbUlEQVR42gFiAp39AB9Anh8ycx8eLx4eNB8fNTs7UDo5UDc2TTs8UD4+Ui8vRRscMh4dMhweOCknPUc+R0U/ST44QkdASDEuQQA1T6g2WHs8Y0RAa0NCbkJVe1ZQelFNeUxJcFRLc1dReFJGbkdHcEdEa0keZoUfdZ8kbZcgcpwodJwcaJUATWC0UISCXLBUYrlQaMBQe8ZqbL9YYbxIWq1WWatWccFgdMVgcsVdb7xdE6zTALf/BaTsALX6BKrxBqnwAENYr0p8f2G4RGauXWCvUFGbVVmpTm2zZGO1TVelUWStXHi5b3a4bGCoVhajyQez9Qae4AOv7gel5gui4wBLYLJHdoVbrE1msF1drlBVoFhfrFdytmllsFpTn1Zjrlp2uG9zt2paplQnqs0rwPkOouMRtPAOqOgjq+YAPVSsSniFbb5Ta7pWbLtXbrxYfcJqgMNuf8Nuc75daLlRaLlSabtRZ7NVFqbOALP3CKHjBLHxBqfoCqTmAD1Uq1B9i3nHWofKcYXKbX3HZHHBVYXKbX/HZXfDXHbDXIbKcIfMb3G7WRehywCq8Qmc3wGp6weh5Aec4QA9VKxTgIh8zk19y1R7ylJ9zFSL0WeJ0GWL0GeHz2J5yVF6yVN9zFN4wlcmpckWsfITnt4asOwPouMZouEAR12sR26dVZeJVpWLVpWKVZaLYJuTYp6SYZySX5uRW5qMXJuNXZuMW5eQQJTHO5rZK4zOLZTVLI/RMIzOAEdfqDpdrzlsxDttxDttxDlrw0l3yFmCzVeBzVF8ylF8y1V/zFaAzVR+y1qAwUVwt0Rwt0RvtkZxuEFqs8WmFd1fsUGxAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                md 9&apos; title=&apos;&apos; src=&apos;/static/083b2571a3bf8c33eb0b10208b585cc7/efd7b/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_9.png&apos; srcset=&apos;/static/083b2571a3bf8c33eb0b10208b585cc7/08678/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_9.png 190w,
/static/083b2571a3bf8c33eb0b10208b585cc7/2edd7/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_9.png 380w,
/static/083b2571a3bf8c33eb0b10208b585cc7/efd7b/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_9.png 760w,
/static/083b2571a3bf8c33eb0b10208b585cc7/dc896/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_9.png 1140w,
/static/083b2571a3bf8c33eb0b10208b585cc7/78873/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_9.png 1520w,
/static/083b2571a3bf8c33eb0b10208b585cc7/3e510/%EC%9C%88%EB%8F%84%EC%9A%B0_%EC%8A%A4%ED%86%A0%EC%96%B4_%EC%95%B1_%EA%B0%9C%EB%B0%9C%ED%95%98%EA%B8%94~.md_9.png 1616w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;윈도우 8 개발 아키텍처&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/apps/br211369.aspx&quot;&gt;마이크로소프트 공식 페이지를&lt;/a&gt; 살펴보면 C++ 개발자를 위해서는 두 가지 종류의 API가 제공되고 있는 것을 볼 수 있다. 하나가 그림에 있는 Windows Runtime이고 다른 하나가 Win32 and COM API다. Win32 and COM API가 지원된다늬? 그럼 그냥 다 쓸 수 있는건가? 라고 생각하면 천만의 말씀이다. &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/apps/br205762.aspx&quot;&gt;앱을 위해서 지원되는 API 목록을&lt;/a&gt; 보면 알겠지만 굉장히 제한적으로 지원되는 구조다. GetProcAddress는 있지만, GetModuleHandle은 없고, LoadLibrary는 없지만 LoadPackagedLibrary는 있는 것과 같은 식이다. CreateProcess는 당연히 없을 수도 있겠다고 생각이 들지만 CreateThread 마저도 없다. 결국 스레드를 쓰려면 Windows Runtime에 있는 Windows.System.Threading에서 지원해 주는 것을 사용할 수 밖에 없다. 이말은 기존 코드를 100% 재활용할 수는 없다는 것을 의미한다. 어떠한 형태로든 일정 수준 이상의 포팅 작업이 필요하다는 것을 의미한다. 물론 그렇다고 모두 다 새로 만들 필요는 없다. 이미 우리를 대신해 &lt;a href=&quot;http://blogs.msdn.com/b/shawnhar/archive/2012/03/12/createthread-for-windows-8-metro.aspx&quot;&gt;CraeteThread를 포팅해 주신 감사한 분들이&lt;/a&gt; 있기에 우리는 선검색 후포팅 하면 되겠다.&lt;/p&gt;
&lt;p&gt;오픈 소스를 활용해 개발을 진행하고 있다면 기존의 코드가 문제가 될 수 있다. 대다수 오픈 소스들이 _WIN32 전처리기가 있으면 윈도우 환경으로 인식하고 기존의 윈도우 API를 사용해서 코딩한 부분이 많이 존재하기 때문이다. 이런 경우는 범용적으로 컴파일되게 만들기 위해서는 좀 더 세분화해서 조건을 판단할 필요가 있다. 예를들어 아래와 같은 오픈 소스 코드가 문제가 될 수 있다는 것을 의미한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;_WIN32&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;windows.h&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MyFunc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;VirtualAlloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; param &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 코드의 경우 데스크톱 프로그램으로 컴파일 할 때는 VirtualAlloc이 존재하기 때문에 문제가 되지 않지만, 스토어 앱으로 개발할 때에는 VirtualAlloc이 없기에 문제가 된다. 당연히 윈도우 헤더부터 시작해서 MS에서도 이런 문제들을 겪었을 것이다. 그래서 이 상황을 판단할 수 있는 전처리기 매크로가 추가됐다. 아래 전처리기들이 그것이다. 위에서부터 PC앱, 폰앱, PC앱+폰앱, 데스크톱 애플리케이션 개발을 구분할 수 있는 전처리기다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token function&quot;&gt;WINAPI_FAMILY_PARTITION&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WINAPI_PARTITION_PC_APP&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token function&quot;&gt;WINAPI_FAMILY_PARTITION&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WINAPI_PARTITION_PHONE_APP&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token function&quot;&gt;WINAPI_FAMILY_PARTITION&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WINAPI_PARTITION_APP&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token function&quot;&gt;WINAPI_FAMILY_PARTITION&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WINAPI_PARTITION_DESKTOP&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;전처리기를 통해서 앞선 코드를 고쳐보면 다음과 같이 고칠 수 있다. 앱 개발 환경이면 malloc을 사용해서 컴파일하도록 만들어주는 것이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;_WIN32&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;windows.h&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MyFunc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token function&quot;&gt;WINAPI_FAMILY_PARTITION&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WINAPI_PARTITION_APP&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;malloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; param &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;VirtualAlloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; param &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;당.연.한. 소리겠지만 그 많은 소스 코드에 API 호출을 다 찾아서 이런 쌩쑈를 하고 있을 수는 없다. 좀 더 편리하게 문제를 해결하기 위해서는 API 자체를 포팅하는 것이 좋다. 다음과 같이 헤더를 만들어서 앱 개발 환경일 때에도 그 API가 존재하는 것처럼 만들어 주는 것이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;//windows_app.h&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token function&quot;&gt;WINAPI_FAMILY_PARTITION&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WINAPI_PARTITION_APP&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;inline&lt;/span&gt;
LPVOID
WINAPI
&lt;span class=&quot;token function&quot;&gt;VirtualAlloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;malloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위와같이 존재하지 않는 API를 포팅한 헤더를 만든 다음에는 그 헤더를 프로젝트에 포함시켜 주면 된다. 전체 참조 되는 헤더에 같이 추가해주면 데스크톱과 앱 개발 환경에서 모두 빌드 문제가 없도록 손쉽게 만들 수 있다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[BSOD: 신호와 소음]]></title><description><![CDATA[#0  2008 베이징 올림픽 개막식을 장식한 화려한 블루스크린 드라이버 개발자 10명을 불러다 놓고 어떤 말을 제일 싫어하십니까, 라고 물어보면 10명 모두 BSOD를 제일 싫어한다고 대답할 것이다. 그만큼 BSOD…]]></description><link>https://jiniya.net/wp/archives/14056</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14056</guid><pubDate>Tue, 22 Jul 2014 23:59:48 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; margin-bottom: 16px;&apos; data-url=&apos;./BSOD_신호와_소음.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5ea1548c2f3c066099b8b79087d39e9f/953fe/BSOD_%EC%8B%A0%ED%98%B8%EC%99%80_%EC%86%8C%EC%9D%8C.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAMBAgX/xAAVAQEBAAAAAAAAAAAAAAAAAAACA//aAAwDAQACEAMQAAABzmKvYqJJr//EABkQAAIDAQAAAAAAAAAAAAAAAAABAhARIf/aAAgBAQABBQKK0ccpHXX/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAWEQEBAQAAAAAAAAAAAAAAAAAAEiH/2gAIAQIBAT8BxT//xAAUEAEAAAAAAAAAAAAAAAAAAAAg/9oACAEBAAY/Al//xAAZEAADAAMAAAAAAAAAAAAAAAAAAREQIUH/2gAIAQEAAT8hq0PSscuKVZwZ/9oADAMBAAIAAwAAABCoD//EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAwEBPxDFbL//xAAXEQEAAwAAAAAAAAAAAAAAAAABEBEh/9oACAECAQE/ELBsP//EABkQAQEBAQEBAAAAAAAAAAAAAAERACExYf/aAAgBAQABPxBpwAdV3AE+OlDlyGVD8i90DJv/2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;BSOD        md 0&apos; title=&apos;&apos; src=&apos;/static/5ea1548c2f3c066099b8b79087d39e9f/953fe/BSOD_%EC%8B%A0%ED%98%B8%EC%99%80_%EC%86%8C%EC%9D%8C.md_0.jpg&apos; srcset=&apos;/static/5ea1548c2f3c066099b8b79087d39e9f/8ccab/BSOD_%EC%8B%A0%ED%98%B8%EC%99%80_%EC%86%8C%EC%9D%8C.md_0.jpg 190w,
/static/5ea1548c2f3c066099b8b79087d39e9f/ea4c8/BSOD_%EC%8B%A0%ED%98%B8%EC%99%80_%EC%86%8C%EC%9D%8C.md_0.jpg 380w,
/static/5ea1548c2f3c066099b8b79087d39e9f/953fe/BSOD_%EC%8B%A0%ED%98%B8%EC%99%80_%EC%86%8C%EC%9D%8C.md_0.jpg 500w&apos; sizes=&apos;(max-width: 500px) 100vw, 500px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;2008 베이징 올림픽 개막식을 장식한 화려한 블루스크린&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;드라이버 개발자 10명을 불러다 놓고 어떤 말을 제일 싫어하십니까, 라고 물어보면 10명 모두 BSOD를 제일 싫어한다고 대답할 것이다. 그만큼 BSOD는 드라이버 개발자에게는 제일 듣기 싫은 말이다. 자다가도 경기를 일으키고, 소리만 나와도 소스라치게 놀라며, 화면에 파란 도트만 보여도 커널 개발자를 겁에 질리게 만들어 버리는 녀석이 바로 BSOD다. BSOD는 Blue Screen Of Death의 약자로 우리말로 번역하면 죽음의 블루스크린 정도 되겠다. 2008년 베이징 올림픽 개막식에서 발생한 블루스크린이 전세계 공중파를 타면서 이제는 일반인들도 블루스크린이 뭔지를 알게 되었다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 466px; margin-bottom: 16px;&apos; data-url=&apos;./BSOD_신호와_소음.md_1.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/04e7de6ff6f0d28717a5691c7738f593/9e695/BSOD_%EC%8B%A0%ED%98%B8%EC%99%80_%EC%86%8C%EC%9D%8C.md_1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 101.57894736842105%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAUEAgb/xAAVAQEBAAAAAAAAAAAAAAAAAAACA//aAAwDAQACEAMQAAAB5xU5dxfbkVIklT64Rf8A/8QAGxAAAgIDAQAAAAAAAAAAAAAAAQIDBAASMRH/2gAIAQEAAQUCsTM8g2XILG0V8ePigBb/AHBz/8QAFREBAQAAAAAAAAAAAAAAAAAAEAH/2gAIAQMBAT8BKf/EABYRAAMAAAAAAAAAAAAAAAAAAAIQMf/aAAgBAgEBPwEYhi//xAAdEAEAAwABBQAAAAAAAAAAAAABAAIREBIxQXGB/9oACAEBAAY/AmppU8TTSHUO+pV4A7Sn3n//xAAbEAEBAQADAQEAAAAAAAAAAAABABEhMUGhwf/aAAgBAQABPyF0OA8bJNEPRto08KJ2AIxR1tjRAHRfP+LLov/aAAwDAQACAAMAAAAQ5BD8/8QAGBEAAgMAAAAAAAAAAAAAAAAAADEBECH/2gAIAQMBAT8QlmjV/8QAGBEAAwEBAAAAAAAAAAAAAAAAAAERMRD/2gAIAQIBAT8QhpBtXDPn/8QAHRABAAICAgMAAAAAAAAAAAAAAQARITFBkaGxwf/aAAgBAQABPxDFfxlg2p8gnRhAkvAmrlObCBWpwUtJV9xS5V3uA1QAUEMAWXLp9zwCf//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;BSOD        md 1&apos; title=&apos;&apos; src=&apos;/static/04e7de6ff6f0d28717a5691c7738f593/9e695/BSOD_%EC%8B%A0%ED%98%B8%EC%99%80_%EC%86%8C%EC%9D%8C.md_1.jpg&apos; srcset=&apos;/static/04e7de6ff6f0d28717a5691c7738f593/8ccab/BSOD_%EC%8B%A0%ED%98%B8%EC%99%80_%EC%86%8C%EC%9D%8C.md_1.jpg 190w,
/static/04e7de6ff6f0d28717a5691c7738f593/ea4c8/BSOD_%EC%8B%A0%ED%98%B8%EC%99%80_%EC%86%8C%EC%9D%8C.md_1.jpg 380w,
/static/04e7de6ff6f0d28717a5691c7738f593/9e695/BSOD_%EC%8B%A0%ED%98%B8%EC%99%80_%EC%86%8C%EC%9D%8C.md_1.jpg 466w&apos; sizes=&apos;(max-width: 466px) 100vw, 466px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;커널 개발자가 극혐하는 블루스크린이 출력된 티&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;BSOD에 대한 두려움을 경계한 개발자들은 BSOD 화면 보호기를 만들어서 담력을 키우기도 하고, 여자친구에게 블루스크린이 출력된 티셔츠를 선물해 보기도 하지만 큰 소용은 없다. 급기야 MS 개발자들은 윈도우 8부터는 블루스크린 이미지를 아주 친근한 형태로 변경했다. 색상을 파스텔톤의 파란색으로 바꾸었고, 화면에는 이모티콘도 넣었다. 블루스크린이 떴지만 쫄지말고 웃으라는 MS 개발자의 패기를 보여준다고 할 수 있겠다. 이런 노력에도 불구하고 커널 개발자들은 여전히 BSOD를 무서워 한다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; margin-bottom: 16px;&apos; data-url=&apos;./BSOD_신호와_소음.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/221e58d5c4724a75e2147dbd3ab473a7/e7448/BSOD_%EC%8B%A0%ED%98%B8%EC%99%80_%EC%86%8C%EC%9D%8C.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 56.315789473684205%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAsklEQVR42p2S6wrCMAyFWxWcInibuuk/X0DwLV27i25rwV/iix6bUXVgKVj4CGnhJCdNGZMIx3GVhYoHOVINHiYe5Tg/MbuCiW8JLm3O/eJhjtMDUQF2Ib0l6xDv6BYLTCsc74gbbFuK6warGommWUyyaa0pt3hS4aCxU8ReI+5KJAqponxc0lw+26b5B3PksmdYeGYWVNvYW9RYdsxv1DAqXa/l3rP44Y9P0lsPl76dvwA6eFfI3gf2DQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;BSOD        md 2&apos; title=&apos;&apos; src=&apos;/static/221e58d5c4724a75e2147dbd3ab473a7/efd7b/BSOD_%EC%8B%A0%ED%98%B8%EC%99%80_%EC%86%8C%EC%9D%8C.md_2.png&apos; srcset=&apos;/static/221e58d5c4724a75e2147dbd3ab473a7/08678/BSOD_%EC%8B%A0%ED%98%B8%EC%99%80_%EC%86%8C%EC%9D%8C.md_2.png 190w,
/static/221e58d5c4724a75e2147dbd3ab473a7/2edd7/BSOD_%EC%8B%A0%ED%98%B8%EC%99%80_%EC%86%8C%EC%9D%8C.md_2.png 380w,
/static/221e58d5c4724a75e2147dbd3ab473a7/efd7b/BSOD_%EC%8B%A0%ED%98%B8%EC%99%80_%EC%86%8C%EC%9D%8C.md_2.png 760w,
/static/221e58d5c4724a75e2147dbd3ab473a7/e7448/BSOD_%EC%8B%A0%ED%98%B8%EC%99%80_%EC%86%8C%EC%9D%8C.md_2.png 900w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;윈도우 8은 블루스크린 이미지를 친근하게 개선했다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이렇게 설명하니 블루스크린이 뭔가 대단한 것처럼 보이는데 사실은 그냥 커널 영역에서 발생하는 프로그램 오류에 불과하다. 일반 응용 프로그램이 오류를 발생시키면 “잘못된 연산을 수행하였습니다”같은 아주 친절한 메시지를 뿜꼬는 프로그램이 종료되는 정도로 끝이 난다. 그런 똑같은 일이 커널 영역에서 발생하면 드라이버 하나가 죽고 끝나는 것이 아니라 블루스크린이 발생하고 시스템은 정지된다. 동일한 오류지만 파급 효과가 다른 것이다. 하나는 프로그램만 죽고 끝나고, 다른 하나는 시스템 전체가 죽는…&lt;/p&gt;
&lt;p&gt;윈도우 9x 시절에는 블루스크린이 너무나 자주 발생해서 사람들은 블루스크린이 발생하는 줄도 몰랐다. 그저 또 껐다 켜야 하는구나라고 생각했다. 하지만 윈도우 2000이상부터 NT 커널이 도입되면서 블루스크린은 생각보다 보기 힘든 일이 되었다. 이후에도 다양한 보안 프로그램에서 많은 블루스크린을 발생시키곤 했지만 이 또한 MS의 꾸준한 노력으로 요즘은 정말 블루스크린 보기가 쉽지 않아졌다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;거창하게 썰을 풀었는데, 요는 이렇게 마주하기 싫은 블루스크린을 최근 다시 마주하게 되었다는 이야기를 하고 싶었던 것이었다. 따끈따끈한 신작 게임에 적용을 진행하면서 발생한 문제인데 당.연.히. 원인은 나의 어처구니 없는 멍청함에 있었다. 나의 멍청함을 인식하는데 다소 시간이 걸렸는데, 그 과정에 문제 해결을 방해하는 소음이 한 몫 했다.&lt;/p&gt;
&lt;p&gt;첫번째는 어째서 그 게임에서만 밥 먹듯이 블루스크린이 발생하냐는 점이었다. 그런 문제라면 적어도 이전에 수도 없이 적용된 게임에서 응당 발견되었어야 하지 않았을까라는 생각이었다. 결과론적으로 그 게임에서만 발생하는 이유가 있었고, 그 문제가 그 전에는 전혀 발견될 수 없는 종류의 문제였다. 둘째는 블루스크린에 출력된 함수 파라미터와 관련한 데이터들이 우리의 생각을 오염시켰다. 실제로 우리가 참고한 글에 나온대로 파라미터를 수정하면 블루스크린이 발생하지 않았기 때문이었다. 하지만 이는 최종적으로 함정같은 존재였다.&lt;/p&gt;
&lt;p&gt;이런 이유로 크래시 덤프 문제를 해결하는 과정이 생각보다 복잡 다단했다. 최종적으로는 정말 아주 사소한 문제에서 이 모든 것이 비롯됐다는 것을 알게 되었고, 그 도화선이 된 부분은 정말 실소를 금할 수 없을 정도로 어처구니 없는 내용이었다. 그래서 여기에 그 내용을 소개하면 다소 도움이 되지 않을까라는 생각에 글을 써본다.&lt;/p&gt;
&lt;p&gt;덤프의 내용은 다음과 같다. 논페이지드 영역에서 페이지 폴트가 발생해서 블루스크린이 발생한 것이다. 콜스택을 살펴보면 MmProbeAndLockPages라는 함수에서 참조하려고 한 논페이지드 영역이 존재하지 않는 영역이라 발생했다는 것을 알 수 있다. 이 문제와 관련된 내용을 다음 몇 차례의 글을 통해서 살펴볼 생각이다. 혹시 관심있는 독자 분들이 있다면 &lt;a href=&quot;/codewiz/assets/files/2015/conan.7z&quot;&gt;여기에서&lt;/a&gt; 관련 파일을 받을 수 있다. 64비트 시스템에서 conan_ldr을 관리자 권한으로 실행하면 블루스크린이 발생하는 것을 재현할 수 있다. conan.dmp는 그렇게 생성한 미니덤프 파일이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;kd&gt; !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced.  This cannot be protected by try-except,
it must be protected by a Probe.  Typically the address is just plain bad or it
is pointing at freed memory.
Arguments:
Arg1: ffffffff825f0000, memory referenced.
Arg2: 0000000000000000, value 0 = read operation, 1 = write operation.
Arg3: fffff80002af3798, If non-zero, the instruction address which referenced the bad memory
	address.
Arg4: 0000000000000005, (reserved)

Debugging Details:
------------------


Could not read faulting driver name

READ_ADDRESS: GetPointerFromAddress: unable to read from fffff80002d0f100
 ffffffff825f0000 

FAULTING_IP: 
nt!MmProbeAndLockPages+118
fffff800`02af3798 410fb601        movzx   eax,byte ptr [r9]

MM_INTERNAL_CODE:  5

DEFAULT_BUCKET_ID:  VISTA_DRIVER_FAULT

BUGCHECK_STR:  0x50

PROCESS_NAME:  conan_ldr.exe

CURRENT_IRQL:  0

TRAP_FRAME:  fffff8800454f6d0 -- (.trap 0xfffff8800454f6d0)
NOTE: The trap frame does not contain all registers.
Some register values may be zeroed or incorrect.
rax=0000000000000001 rbx=0000000000000000 rcx=0000000000000000
rdx=0000000000000001 rsi=0000000000000000 rdi=0000000000000000
rip=fffff80002af3798 rsp=fffff8800454f860 rbp=fffff8800454fca0
 r8=fffffa8001cd5cf0  r9=ffffffff825f0000 r10=0000000000000001
r11=0000000000000000 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=0000000000000000
iopl=0         nv up ei ng nz ac pe nc
nt!MmProbeAndLockPages+0x118:
fffff800`02af3798 410fb601        movzx   eax,byte ptr [r9] ds:5480:ffffffff`825f0000=??
Resetting default scope

LAST_CONTROL_TRANSFER:  from fffff80002b545b3 to fffff80002ad7bc0

STACK_TEXT:  
fffff880`0454f568 fffff800`02b545b3 : 00000000`... : nt!KeBugCheckEx
fffff880`0454f570 fffff800`02ad5cee : 00000000`... : nt! ?? ::FNODOBFM::`string&apos;+0x43801
fffff880`0454f6d0 fffff800`02af3798 : fffffa80`... : nt!KiPageFault+0x16e
fffff880`0454f860 fffff880`04baf04f : fffffa80`... : nt!MmProbeAndLockPages+0x118
fffff880`0454f970 fffffa80`01cd5cc0 : 00000000`... : conan+0x104f
fffff880`0454f978 00000000`00000000 : 00000000`... : 0xfffffa80`01cd5cc0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;덤프를 살펴보면 알겠지만 크래시 시점에 주요하게 관여된 함수로 MmProbeAndLockPages, MmMapLockedPages가 있다. 덤프를 제일 먼저 분석한 엔지니어는 아래 내용을 토대로 드라이버의 코드의 함수 파라미터를 고쳐야 한다는 이야기를 했었다. 덤프 분석에 떡밥 내지는 힌트 정도로 살펴보면 좋을 것 같다. 앞으로 차차 살펴보겠지만 여러분이 MmProbeAndLockPages와 MmMapLockedPages 함수에 사용되는 AccessMode의 용도에 관한 아래 글들의 내용에 대해서 충분히 상세히 알고 있다면 그것만으로도 자부심을 가져도 될 것 같다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The better idea would be to pass Irp-&gt;RequestorMode as the second parameter to MmProbeAndLockPages. In this case, if the requestor is UserMode and the buffer is a kernel address the API will immediately raise an exception instead of potentially crashing. Calling ProbeForWrite yourself would basically give you the same effect (it also checks to make sure the buffer supplied is a user address), which is why I asked if you were making this call earlier as it would point to this being a different type of bug.&lt;/p&gt;
&lt;p&gt;– &lt;a href=&quot;http://osronline.com/ShowThread.cfm?link=236232&quot;&gt;http://osronline.com/ShowThread.cfm?link=236232&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;If AccessMode is KernelMode and MmMapLockedPages cannot map the specified pages, the system issues a bug check. (For this reason, drivers should use MmMapLockedPagesSpecifyCache when available; that routine returns NULL on failure, rather than causing a bug check.) If AccessMode is UserMode and the specified pages cannot be mapped, the routine raises an exception. Callers that specify UserMode must wrap the call to MmMapLockedPages in a try/except block. For more information, see Handling Exceptions.&lt;/p&gt;
&lt;p&gt;– &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/hardware/ff554622(v=vs.85).aspx&quot;&gt;http://msdn.microsoft.com/en-us/library/windows/hardware/ff554622(v=vs.85).aspx&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;#3&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;앞으로 추가적인 몇 개의 글을 통해서 이 덤프의 정확한 원인을 추적하는 작업을 해 볼 생각입니다. 그전에 덤프에 대한 나름의 의미 있는 해석을 내렸다고 생각하는 분들은 codewiz at gmail.com으로 메일 주세요. &lt;a href=&quot;http://www.jiniya.net/wp/archives/12367&quot;&gt;함께 할만한 일들이 있을지도 모르잖아요&lt;/a&gt; ㅎㅎ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[드라이버 개발 환경 설정]]></title><description><![CDATA[시스템 설치할 때마다 여기 저기 검색해서 찾기 귀찮아서 정리한 페이지!!! NTSTATUS 코드표 https://msdn.microsoft.com/en-us/library/cc704588.aspx windbg 심벌 경로 srv*C:\WebSymbols…]]></description><link>https://jiniya.net/wp/archives/14027</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14027</guid><pubDate>Wed, 16 Jul 2014 23:59:47 GMT</pubDate><content:encoded>&lt;p&gt;시스템 설치할 때마다 여기 저기 검색해서 찾기 귀찮아서 정리한 페이지!!!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;NTSTATUS 코드표&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://msdn.microsoft.com/en-us/library/cc704588.aspx&quot;&gt;https://msdn.microsoft.com/en-us/library/cc704588.aspx&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;windbg 심벌 경로&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;srv*C:\WebSymbols*&lt;a href=&quot;http://msdl.microsoft.com/download/symbols&quot;&gt;http://msdl.microsoft.com/download/symbols&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;윈도 XP 커널 디버그 설정&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;boot.ini 편집&lt;/p&gt;
&lt;p&gt;multi(0)disk(0)rdisk(0)partition(1)\WINDOWS=”Debugging with Cable” /fastdetect /debug /debugport=COM1 /baudrate=115200&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;윈도 Vista+ 커널 디버그 설정&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;msconfig 들어가서 Advanced에서 디버그 옵션을 켜면됨&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;virtualbox 이미지&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;미리 구워논 이미지가 없으면 아래 사이트에서 다운로드 받아서 사용하면 편리함&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.modern.ie/en-us/virtualization-tools&quot;&gt;https://www.modern.ie/en-us/virtualization-tools&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;WDk 7.1.0&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;http://www.microsoft.com/en-us/download/details.aspx?id=11800&quot;&gt;http://www.microsoft.com/en-us/download/details.aspx?id=11800&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Windows Vista+ Debug Filter 설정&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;설정 안 하면 DbgPrint 출력안뎀. &lt;a href=&quot;/files/debug_filter.reg&quot;&gt;귀찮으면 레지 파일 다운받기&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter]&lt;/p&gt;
&lt;p&gt;“DEFAULT”=dword:0000000f&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;virtualbox 커널 디버깅용 파이프 설정&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;직렬포트, 호스트 파이프, 생성, \.\pipe&amp;#x3C;name&gt;&lt;/p&gt;
&lt;p&gt;windbg pipe 체크, 포트에 \.\pipe&amp;#x3C;name&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[우분투에서 네트워킹 안될때]]></title><description><![CDATA[VM 같은 거 복사했을 때 우분투에서 네트워킹 안되면 아래 파일을 지우고 재부팅해 봅시다. rm -rf /etc/udev/rules.d/70-persistent-net.rules shutdown -r now…]]></description><link>https://jiniya.net/wp/archives/14020</link><guid isPermaLink="false">https://jiniya.net/wp/archives/14020</guid><pubDate>Thu, 10 Jul 2014 23:59:46 GMT</pubDate><content:encoded>&lt;p&gt;VM 같은 거 복사했을 때 우분투에서 네트워킹 안되면 아래 파일을 지우고 재부팅해 봅시다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;h1&gt;rm -rf /etc/udev/rules.d/70-persistent-net.rules&lt;/h1&gt;
&lt;h1&gt;shutdown -r now&lt;/h1&gt;
&lt;/blockquote&gt;
&lt;p&gt;랜카드 맥어드레스가 변경되서 그런걸로 추정되는데…&lt;/p&gt;
&lt;p&gt;어쨌든 파일 지우고 나면 인터페이스가 정상적으로 인식됩니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[by accident]]></title><description><![CDATA[#0 점심 먹고 커피를 마시고 있었다. 이런 저런 이야기를 하다가 어쩌다가 나왔는지 by accident…]]></description><link>https://jiniya.net/wp/archives/13961</link><guid isPermaLink="false">https://jiniya.net/wp/archives/13961</guid><pubDate>Fri, 04 Jul 2014 23:59:45 GMT</pubDate><content:encoded>&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;점심 먹고 커피를 마시고 있었다. 이런 저런 이야기를 하다가 어쩌다가 나왔는지 by accident에 관한 이야기가 나왔다. 별 일 아닌 일이었지만 뭔가 재미있는 구석도 있는 것 같아서 여기다 옮겨 적어 본다. 사건의 전말은 이렇다. 한 독일 업체에서 우리쪽으로 아래와 같은 내용의 문장이 포함된 메일을 한 통 보냈다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;we found out by accident that Xigncode is writing logs on the Live Server.&lt;br&gt;
&lt;br&gt;
우리는 XIGNCODE가 라이브 서버에서 로그를 기록하는 것을 우연히 발견했다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;그걸 본 우리쪽 커뮤니케이션 담당자가 accident 부터 끊어서는 아래와 같은 질문을 보냈다. 이게 사고/사건이라니 무슨 의미냐고 재차 질문을 한 것이다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;accident that Xigncode is writing logs on the Live Server.&lt;br&gt;
&lt;br&gt;
XIGNCODE가 라이브 서버에서 로그를 기록하는 사건(?!)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;그랬더니 업체쪽에서는 사고가 있었다는 말이 아니라 by accident를 구글 번역기를 돌려서는 이게 우연히라는 영어 표현이라는 답장을 아래와 같이 보내왔다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“By accident” is an expression in English language. Google translation says it means임의in Korean language.&lt;br&gt;
&lt;br&gt;
“by accident” 영어에 있는 표현(숙어)이다. 구글 번역기는 그것의 의미가 한국말로 임의라고 나에게 말해주었지.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;커피를 마시다 이 이야기를 전해 들은 나는 핸펀으로 그 메일을 검색해서 살펴보고는 이걸 어떻게 이렇게 해석해서 재차 질문할 수 있지라는 생각을 했다. 그리곤 이 이야기를 전해준 직원에게 네이버 영어 사전에서 by accident를 찾아서 보여주며 이거 아니냐는 말을 건냈다. 그걸 들은 친구는 동료를 보호하기 위해서 accidently라고 썼어야 명확했을 거라는 힘겨운 실드를 쳤다. 한참을 듣고 계시던 사장님께서 한 말씀 덧붙인다. 야, 그게 표현이 뭐가 그리 중요하니 적당히 알아듣고 해달라는대로 처리해주면 되는 거잖아. 신택스가 아니라 시맨틱에 집중하라는 말씀.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;커피 마시고 올라와서는 친구 녀석이랑 톡질을 하다가 이 이야기가 다시 올라왔다. 영어 선생님을 하는 그 친구한테 우리 회사에서 이런 일이 있었다는 이야기를 하는데 그 친구는 내가 하는 말을 잘못 알아들어서는 내가 “we found out by accident that Xigncode is writing logs on the Live Server.”라는 문장을 썼다고 이해를 했다. 친구왈 “맹구야, 동사하고 목적어 사이에 부사가 있잖아”라는 이야기를 한다. “we found out that Xigncode is writing logs on the Live Server by accident.”라고 써야 한다는 말이다. 그래서 다시 네 말이 무슨 말인지 알겠는데 블라블라블라 긴 이야기를 돌고 돌아 사건의 전말을 전달했다. 친구왈 독일애들 그렇게 안 봤는데, 똑똑하지 않은 것 같다는 이야기를 한다. 난 걔들 입장에서도 외국어라는 말을 덧붙였다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;center&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 620px; margin-bottom: 16px;&apos; data-url=&apos;./by_accident.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/fe0eacd9822135db9bfc4e271171bac1/abf7b/by_accident.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 82.10526315789475%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAIAAACZeshMAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACF0lEQVR42n1Ty3LiMBDk/z9qUyk4ANkkJFBJsC2MJVsPW/LbZI0Ab8thq3II2we5a6TRdM/Ik/V6/fL6slws5vMF1tXz86+7u+VyOZ1OH5+ettsP8Pl8vlqtZrPZb4dHa0/DiMnDwxKB1/Vms1nf398vFosgIG7nMly+wQXceuXX5K7rjNY8SbIsY5TFjKVp1tRNXdVYmqZp27Zru7IsHW/a2sWA+ny5THBBWeSe5+92OxrRfbgnhGw/tu9v7yC+5wPEJyEJ9zuHwA8CRAiRSrnkrms5FzwRSikQFPrzecXhcBgrtxAxflsorcfq2J0M1lZS6jzXWaZSJaGf0lypqqpw9JvBHzBBC5qiSGE0TU2eKylFuOeUCiHAjTG4BYarsiqKAuRryU0+Vh4GyGGMCi5wNEkSmEnRvTTVmeZCaK1hJ0k4wgDnIBJ+TqfT2LCqcCGJokpy5Crkdn332R/6vj9aex7hpnS+fJGr7P7c79N9kZfa6DhLIkkFLpHc534Q+xCC7tz0fDr2Mg7TTDMSeP7aZwFjDIZ5wquqRs+stTeTre0ZI9BLSUADIkfEIvZiT+caIznf7vjkeLZhutsJIlIJq9DszCsZ8QizR2//O6phwKuLeYw5ORSFMbnRxmRmRI53cjP5Ym3JXYWyqgwm4XkqijBWYzTeFE6gvbc9n44sCTFkJ5eLJAyTiDJJ3+mbzNW/n+nn5L+cA4AIWwYEygAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;by accident md 0&apos; title=&apos;&apos; src=&apos;/static/fe0eacd9822135db9bfc4e271171bac1/abf7b/by_accident.md_0.png&apos; srcset=&apos;/static/fe0eacd9822135db9bfc4e271171bac1/08678/by_accident.md_0.png 190w,
/static/fe0eacd9822135db9bfc4e271171bac1/2edd7/by_accident.md_0.png 380w,
/static/fe0eacd9822135db9bfc4e271171bac1/abf7b/by_accident.md_0.png 620w&apos; sizes=&apos;(max-width: 620px) 100vw, 620px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;strong&gt;&lt;a href=&quot;http://www.grammarly.com/handbook/grammar/adjectives-and-adverbs/28/an-adverb-between-a-verb-and-its-direct-object/&quot;&gt;부사의 위치. 어렵지? 아마 어려울거야?&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;&lt;br&gt;  
&lt;p&gt;심심해서 부사의 위치를 찾아봤다. 머 당연한 이야기겠지만 영어 선생님인 놈이 틀릴 일은 없다. 부사는 동사와 그 동사의 목적어 사이에는 쓰지 않는 거란다라고 친절히 알려준다. 돌고 돌고 돌아서 다시 실드를 쳤던 직원 말을 재차 실드를 쳐보자면 “we accidently found out that Xigncode is writing logs on the Live Server.”라고 썼어야 한다는 말이었을 것이다.&lt;/p&gt;
&lt;p&gt;명확해야 한다는 관점만 놓고 본다면 업체간 공식적인 커뮤니케이션에서는 그냥 부사 형용사 따위는 없는게 더 좋지 않을까라는 생각이 든다. 우연히 발견했든, 면밀히 뒤지다 발견했든, 발견한 사실이 중요하지 그걸 한정짓는 한정 문구는 그닥 중요한 내용은 아니니 말이다.&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;별 일 아닌 이 사건이 재미있게 느껴졌던 이유는 동일한 사건을 바라보는 관점이 사람마다 너무나 극명하게 차이가 나타났기 때문이었다. 나는 어떻게 by accident를 모르고 accident that이라고 끊어서 해석할 수 있냐는 관점을, 담당자를 실드 치던 직원은 by accident가 아니라 accidently를 썼으면 명확했을 거라는 입장을, 사장님은 by accident든 accidently든 알아들었으면 적당하게 조치를 취해주면 되지 문법 그거 따져서 무엇하겠느냐는 말씀을, 영어 선생님인 친구는 미개인도 아닌 우리가 21세기에 어떻게 동사와 목적어 사이에 부사 따위를 쓸 수 있지라는 반응을 보였다. 하나 같이 다 틀린 말도 아니고, 딱 하나를 집어서 이게 정답이라는 입장도 없다.&lt;/p&gt;
&lt;h3&gt;#4&lt;/h3&gt;
&lt;p&gt;임백준씨는 &lt;a href=&quot;http://www.zdnet.co.kr/column/column_view.asp?artice_id=20131118093913&amp;#x26;type=det&quot;&gt;한 칼럼에서&lt;/a&gt; “버그는 프로그래머의 숙명이다. 김밥을 마는 손에 밥풀이 묻는 것처럼, 비트와 바이트를 만지는 손에는 버그가 달라붙는다.”라는 이야기를 했었다. 퍽이나 멋진 표현이라는 생각을 했었는데 이 말이 비단 프로그래머에게만 적용되는 이야기는 아닌 것 같다. 영어로 커뮤니케이션을 하는 직원들도 소통을 하다보면 실수를 할 수 있는 것이다. 하루에도 몇 통씩 영어로 메일을 읽고, 쓰고, 영어로 메신저질을 하다 보면 자연스레 실수할 때도 있는 법이다. 그걸 두고 by accident를 모르고 accident that으로 끊어서 해석을 하냐고 뭐라고 한 건 아닌지라는 생각에 괜스레 미안해졌다.&lt;/p&gt;
&lt;p&gt;언어는 불완전하고 커뮤니케이션은 어렵다. 상황은 복잡하고 입장은 다양하다. 이런 생각들이 머리속을 파고드니 그냥 우리가 죽자살자 집착하는 모든 일이 위에서 쳐다보면 죄다 우스워 보일수도 있겠다는 생각이 들었다. 그러다 떠오른 법정 스님의 시 한 수.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;오해 – 법정&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;‘나는 당신을 죽도록 사랑합니다’라는 말의 정체는&lt;br&gt;
&lt;br&gt;
‘나는 당신을 죽도록 오해합니다’일지도 모른다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;누가 나를 추켜세운다고 해서&lt;br&gt;
&lt;br&gt;
우쭐댈 것도 없고,&lt;br&gt;
&lt;br&gt;
헐뜯는다고 해서 화를 낼 일도 못 된다.&lt;br&gt;
&lt;br&gt;
그건 모두가 한쪽만을 보고 성급하게 판단한&lt;br&gt;
&lt;br&gt;
오해이기 때문이다.&lt;br&gt;
&lt;br&gt;
오해란 이해 이전의 상태가 아닌가.&lt;br&gt;
&lt;br&gt;
문제는 내가 지금 어떻게 살고 있는가에 달린 것이다.&lt;br&gt;
&lt;br&gt;
실상은 말 밖에 있는 것이고&lt;br&gt;
&lt;br&gt;
진리는 누가 뭐라 하든 흔들리지 않는다.&lt;br&gt;
&lt;br&gt;
온전한 이해는 그 어떤 관념에서가 아니라&lt;br&gt;
&lt;br&gt;
지혜의 눈을 통해서만 가능하다.&lt;br&gt;
&lt;br&gt;
그 이전에는 모두가 오해일 뿐이다.&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[비행운]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/12776</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12776</guid><pubDate>Thu, 03 Jul 2014 23:59:44 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;─ 신기해요. 어떤 음악을 들으면, 그 곡을 제게 처음 알려준 사람이 생각나요. 그것도 번번이요. 처음 가본 길, 처음 읽은 책도 마찬가지고요. 세상에 그런 게 있다는 걸 알려준 사람이 떠올라요. ‘이름을 알려준 사람의 이름’이라고 해야 하나? 그런 건 사물에 영원히 달라붙어버리는 것 같아요.&lt;/p&gt;
&lt;p&gt;나는 ‘아니, 내가 이렇게 멋있는 말을 하다니!’ 하고 혼자 감탄했다. 하지만 ‘선배의 쪽지’는 더 근사했다.&lt;/p&gt;
&lt;p&gt;─ 우리가 신을 잊을 수 없는 이유도 아마 그 때문일 거야.&lt;/p&gt;
&lt;p&gt;– 비행운, 김애란&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;김애란의 소설을 좋아한다. 달작지근한 문장으로 글을 읽는 재미를 흠뻑 느끼게 해주기 때문이다. 평범한 문장도 그녀의 글 속에서는 힘을 발한다. “우리가 신을 잊을 수 없는 이유도 아마 그 때문일 거야”라는 이 평범한 문장도 김애란이 만들어 낸 장면 속에서는 기가 막힌다. 아마 그 누구라도 소설 속에서 그 문장을 만난다면 해머로 머리를 한 대 맞는 느낌일거라는데 500원은 걸 수 있다. 그렇다고 그녀가 단지 언어의 연금술사이기 때문에 팬을 자처하는 것은 아니다. 소설 속 이야기들이 묘하게 소설이 아니라 진짜 우리 이야기 같다는 생각이 들기에 그녀의 소설을 더 좋아하는 것 같다. 주인공의 현실에 격하게 공감하면서도 이상하게 마음이 조금은 편해진다. 그래서 책을 덮을 즈음엔 신묘하게도 힐샤워를 받은 느낌이 드는 오묘한 마력이 있다.&lt;/p&gt;
&lt;p&gt;비행운도 그런 소설 중에 하나다. 이야기 하나하나가 모두 남의 일 같지 않은 그런 소설이다. 바로 옆에 있는 친구나 가족, 학교 선배나 후배, 또는 직장 상사나 동료들의 이야기라는 생각이 절로 든다. 달달한 문장에 취했다가도 주인공의 씁쓸한 현실을 보면 마음이 그리 편하진 않다. 우리 모두에게 이제는 행운이 함께 했으면 좋겠다는 생각이 드는 소설. 소설 속 주인공 모두에게, 그리고 또 지구에서 2014년을 보내고 있는 사람들 모두에게, May the Force be with you.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[시스템] 저수준 API 후킹 시에 유의할 점]]></title><description><![CDATA[저수준 API…]]></description><link>https://jiniya.net/wp/archives/4601</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4601</guid><pubDate>Tue, 01 Jul 2014 23:59:43 GMT</pubDate><content:encoded>&lt;p&gt;저수준 API를 후킹할 때에는 해당 훅 대상이 되는 함수에 대해서 면밀하게 살펴야합니다. 그렇지 않을 경우에는 엉뚱한 부분 때문에 디버깅에 상당히 많은 시간을 잡아먹을 수 있습니다.&lt;/p&gt;
&lt;p&gt;흔히 저지르는 실수는 훅 함수 내에서 후킹 대상 함수보다 높은 수준의 API를 호출하는 것입니다. 뭔소린가 싶은데 그냥 쉽게 설명하면 RtlAllocateHeap 따위의 함수를 후킹해놓고 해당 후킹 함수 내에서 동작을 살피기 위해서 OutputDebugStringW 따위를 호출하는 행위를 조심해야 한다는 것을 의미합니다. OutputDebugStringW 함수는 내부적으로 유니코드 문자열을 멀티바이트 문자열로 변경하기 위해서 힙을 할당하는 함수를 사용하는데 그러면 다시 후킹 함수가 호출되고, 그러면 다시 OutputDebugStringW가 호출되고, 다시 후킹 함수가 호출되고, 다시 OutputDebugStringW가 호출되고 하는 무한 재귀 루프에 빠져버립니다. 결국 스택을 다 소진할 때까지 반복하다 크래시가 발생하는 것이죠.&lt;/p&gt;
&lt;p&gt;위와 같은 단순한 경우 외에도 좀 복잡한 경우도 있습니다. 후킹을 하는 대상 함수가 특정한 시스템 락을 획득한 상태에서 호출되는 함수이고, 후킹 함수 내에서 호출하는 API가 그 락을 다시 요청하는 경우에 문제가 발생할 수 있습니다. 락이 재귀적으로 획득할 수 있도록 구성된 경우에는 문제가 없지만 재귀적으로 획득할 수 없도록 구성된 경우에는 문제가 발생할 수 있습니다.&lt;/p&gt;
&lt;p&gt;그래서 저수준 API를 후킹하는 함수를 작성할 때에는 해당 후킹 함수 내부에서 호출하는 함수 중에 혹시나 다시 후킹 함수를 호출하게 될 가능성이 있는건 없는지를 꼼꼼히 살펴야 합니다. 물론 함수를 본다고 해당 함수가 어떤 내부 함수를 호출하는지를 다 알수는 없는 법이죠. 결론은 그냥 후킹 함수는 최대한 간단하게 작성하는 것이 좋습니다. 없는듯이 작성하고, 복잡한 연산은 훅 함수가 아닌 다른 곳에서 처리하도록 보류 시키는 것이 좋은 전략입니다. 당연한 소리지만 그것보다 더 좋은 전략은 후킹을 사용하지 않는 겁니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 메일 메트릭]]></title><description><![CDATA[#0 난 엄마 뱃속부터 테일러리즘을 싫어했다고 느낀다. 200…]]></description><link>https://jiniya.net/wp/archives/13762</link><guid isPermaLink="false">https://jiniya.net/wp/archives/13762</guid><pubDate>Thu, 19 Jun 2014 23:59:42 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;난 엄마 뱃속부터 테일러리즘을 싫어했다고 느낀다. 2008년 여름 처음 팀장이 되면서 약간의 관리 업무를 맡게 될 당시에도 그런 생각은 확고했다. 자유와 여유, 그 모든 것이 주어진다면 인간은 무한대의 창조성을 발휘할 것이라 믿었다. 동일한 환경이 주어진다면 모두 공평하게 노력할 것이라 생각했다. 그렇게 몇년이 흘렀다. 안타깝게도 나의 가설은 틀린 것처럼 보였다. 2011년 10월에 작성한 아래 노트는 그런 생각 변화를 보여준다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 370px; margin-bottom: 16px;&apos; data-url=&apos;./메일_메트릭.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/dfd298c01b04ce5e4dd12b99229b3e2c/3ac6e/%EB%A9%94%EC%9D%BC_%EB%A9%94%ED%8A%B8%EB%A6%AD.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 24.736842105263158%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAIAAADKYVtkAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAArklEQVR42o2P3Q7CIAyF9/4P6eYPUGjHGAPMHJseool3xpPetOk5X9ut6xrjrLQSdkTWsRv6PpXy/EPdvu/b9liWJYTJGKP17dT3I+RHYcEQBY0i3iNfSi4555RTM78zjuPIKRER7FhldiyMxjm+nAfMlVKGWktaS4tlUD/mWuu9FA3u9TqHQJawhwiDTyyllGOMuG6JkZ0dfTtnq/VLTo3swuSBtxDYItroH/+/ADW/HBQictSJAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 0&apos; title=&apos;&apos; src=&apos;/static/dfd298c01b04ce5e4dd12b99229b3e2c/3ac6e/%EB%A9%94%EC%9D%BC_%EB%A9%94%ED%8A%B8%EB%A6%AD.md_0.png&apos; srcset=&apos;/static/dfd298c01b04ce5e4dd12b99229b3e2c/08678/%EB%A9%94%EC%9D%BC_%EB%A9%94%ED%8A%B8%EB%A6%AD.md_0.png 190w,
/static/dfd298c01b04ce5e4dd12b99229b3e2c/3ac6e/%EB%A9%94%EC%9D%BC_%EB%A9%94%ED%8A%B8%EB%A6%AD.md_0.png 370w&apos; sizes=&apos;(max-width: 370px) 100vw, 370px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;2011년 10월에 작성한 노트&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;물론 난 지금도 테일러리즘을 싫어한다. 그리고 인간이 인간을 관리한다는 생각 자체도 너무 우습다고 생각한다. 똑같은 인간끼리 뭘 관리한다는 말인가? 하지만 기존의 생각과는 다른 몇 가지 생각은 확실하게 변했는데, 그 중 하나가 일등은 일등대로의 방식이 있고, 꼴찌는 꼴찌의 방식이 있다는 생각이다. 많은 교과서에서 말하는 좋은 기업의 조건이나 관리 방식은 사실상 내가 생각했을 때에는 일등의 방식이다. 최고의 인재를 모아서 물쓰듯 자본을 쓸 수 있는 환경에서나 가능한 일들이란 이야기다. 동일한 사항을 그렇지 않은 환경에 적용한다면 당연히 여러가지 문제점이 발생할 수 밖에 없다.&lt;/p&gt;
&lt;p&gt;어쨌든 그맘때부터 난 한 가지 생각은 뚜렸했다. 1) 사람은 관리할 수 없지만 업무는 관리할 수 있다. 2) 측정 불가능한 업무는 관리 불가능하다. 3) 자동화된 측정이 아닌 사람을 통한 측정은 효과가 불투명하다. 이런 전제 아래에서 나는 업무와 관련된 상당히 많은 데이터를 수집하고 분석하기 시작했다. 일부는 직원들에게 공유하기도 했고, 일부는 그냥 혼자 데이터를 보고 넘기기도 하는 형태다. 이런 내용을 토대로 한 가지 발견한 사실은 직원들의 업무에는 종류를 불문하고 엄청난 양의 불균형이 존재하고, 그것에 대해서 대부분의 직원들은 자각하지 못한다는 사실이다. 그런 데이터 중에 하나가 메일 메트릭이다. 우리 회사 지원 업무의 상당수는 메일을 통해서 이루어지는데 그 업무 회수를 측정한 자료다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 612px; margin-bottom: 16px;&apos; data-url=&apos;./메일_메트릭.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/19469b2454ca7dad15283442daf365d6/dbf98/%EB%A9%94%EC%9D%BC_%EB%A9%94%ED%8A%B8%EB%A6%AD.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 58.42105263157894%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACWklEQVR42iWSS2/TQBDH8zkQx0pW3nESP+LYjlPb8bt24l07dpwEJyhNK0WKSgqi4l0FUKlUDkgg9QAcUHvgChzgAN+MSbLSrkaz/5/+s7OTyeVyxWKxWq3SNN1sNlutlqqqURSl6SRJktF4PBgMFEWBPNyChiRJ0ANFEESmWCqVKxWaouBOkiQgTdMaJMkkTUfDYTqZwGmaJuTb7TZoKIqqVCqFQiGbzWbq9TrLMBzHAdnpdEB3sFuu63me60LkwN7xoAElIKVSCcwzguqg5SXf5PZlWdd10PV6PYxxEARhCEeAMYKM4ziGYciyzPM8FA/m+Xw+I5pB/9V3qS1rHcWxbfDzfX9Lhv3tghgyruvuzAVBYBhmV3mmoeP769vradufnvTnjzzbwFsSehbHMZwQQyHdbte2bXgXdI5lWWjwBqY1fLi++Tcv45Mr/+FHy+hgv9cPcNTvR1tngBHC8H7LssBZFEWAoecbmNJw+uLL73RPO3p7+vz9WbQfzlZ4OA2jeDQ9RAHUjQPUg9aZlq2qCsAMOO/gqoJGzz7/Hd3hZu8+vTm/HRLa+s/12dHxZBxf/JonKD5+HC5emoZuaJqsqrwgUPVauVzewKTk4OXlDb7LjZ6er5Yf/D1u9e3nA2MxROjJ1x/zurd4HZ9eJVZLDWcX9zpIbtCSUa/VNl8FQ0IzrMgxvChpmmbpqum4UGXX83wchL7ruF7XdQ50ta1ZpiI1WYZq8OC8GRLYxUKhTJI0TcEAiC1J3pcU3ez5KPCsro8MQ4fZgnyTY2sU/DBZLOSzuSxBEP8B44LUzV4F9PoAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 1&apos; title=&apos;&apos; src=&apos;/static/19469b2454ca7dad15283442daf365d6/dbf98/%EB%A9%94%EC%9D%BC_%EB%A9%94%ED%8A%B8%EB%A6%AD.md_1.png&apos; srcset=&apos;/static/19469b2454ca7dad15283442daf365d6/08678/%EB%A9%94%EC%9D%BC_%EB%A9%94%ED%8A%B8%EB%A6%AD.md_1.png 190w,
/static/19469b2454ca7dad15283442daf365d6/2edd7/%EB%A9%94%EC%9D%BC_%EB%A9%94%ED%8A%B8%EB%A6%AD.md_1.png 380w,
/static/19469b2454ca7dad15283442daf365d6/dbf98/%EB%A9%94%EC%9D%BC_%EB%A9%94%ED%8A%B8%EB%A6%AD.md_1.png 612w&apos; sizes=&apos;(max-width: 612px) 100vw, 612px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
7명의 직원이 근 한달간 메일 업무를 한 내용을 정리한 그래프다. 일반이라고 표시된 것은 업데이트가 아닌 일반 메일로 주로 업체에서 특정 사항에 대한 문의나 요청을 한 것에 대한 회신의 회수를 의미하고, 업데이트는 우리 제품의 새로운 업데이트 안내 메일을 발송한 회수를 표시한 것이다. 그러니 일반은 약간 (업체에 의해서 강제된) 비자발적 메일, 업데이트는 자발적 메일 발송이라고 볼 수 있다. 물론 업데이트 또한 요청에 의해서 발송되는 경우도 있기 때문에 100% 자발적 메일 발송이라고 보기에는 무리가 있다.&lt;/p&gt;
&lt;p&gt;이 그래프를 살펴보면 눈에 확 들어오는 것은 당연 1번 직원이다. 이 직원이 지난 한 달간 발송한 모든 메일은 3번 직원부터 7번 직원까지의 메일을 다 합친 것 보다 많다. 자발적 메일 발송이라 볼 수 있는 업데이트의 경우는 그 정도가 더 심한데 1번 직원을 제외한 나머지 직원을 다 합친 수치와 맞먹는다는 점이다. 얜 뭐지? 슈퍼맨인가 하는 생각이 절로 들게 마련이다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 609px; margin-bottom: 16px;&apos; data-url=&apos;./메일_메트릭.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/4755f33110e33d5d51475f14ff503688/71467/%EB%A9%94%EC%9D%BC_%EB%A9%94%ED%8A%B8%EB%A6%AD.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 57.89473684210527%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACRElEQVR42oVRSW/TQBj1v2k2x0uczUlsjxMnjpd4iT124sSpklCWClRQkAJRkaCIpRc4VEJqASHCpRKI7cAVDly594T4J3ypkZC4MCONPr1v3rz3vSGymUyeothCoVwu12o1WZZxgONxPBwOp9PpaDSK4zgMAkmSoAt3WJbN5/PZbDaVShEkSdI0XSwWoYcQarfbQJtMtqMoms/n4ziezWZQA57wS6USwzDASqfTBMPQlWpVkpAoioqiaJqm63rPNG3btmDblmmagACe8Hme5ziOoigQJ2iKxMvjYPFUbPDdrgZXHcfxPA/7foDh8KEGBHBVVZvNZr1eB/E/ZJYiR4dfooNTJPC6sRHs9/sY4yAIwhCGhRcwIICDOFgTBCGZHJwTHEt5Bx/8/TctqeH2XVie5yfMwfmCOhE3DAOcw3SVSuUv2b73ybm9hsbO0bdw52bfNnEQDsIQkvsPmaVJ7e5HfflKaXem61/+lTv9nhqF57axH/jexrbn/2M7CXwzc2f/nbp4LjcV//jMmi7w9qX5w1MPh/GF3cnOVdeFuDRD1yAw+MskMJpmcrkcweRz8q23rRsngiSbz8608TX74ip8+dNxvejB++Gjz5ahjffuW0HcbjXVTqdarXIFlsqTmUxmQ5auv5B3nwgiUg+/dweX9XjPePzVsh1r9bq3WvcMHR/9MKZL1Q7c5QkvoJrU4lEnnU4R8F00WyiWypVyRUQykuWWoqi6ASY1w+xqm5AUtSshuSGiGuoUChzNciTFpLa2fgMt29m14fLDDQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 2&apos; title=&apos;&apos; src=&apos;/static/4755f33110e33d5d51475f14ff503688/71467/%EB%A9%94%EC%9D%BC_%EB%A9%94%ED%8A%B8%EB%A6%AD.md_2.png&apos; srcset=&apos;/static/4755f33110e33d5d51475f14ff503688/08678/%EB%A9%94%EC%9D%BC_%EB%A9%94%ED%8A%B8%EB%A6%AD.md_2.png 190w,
/static/4755f33110e33d5d51475f14ff503688/2edd7/%EB%A9%94%EC%9D%BC_%EB%A9%94%ED%8A%B8%EB%A6%AD.md_2.png 380w,
/static/4755f33110e33d5d51475f14ff503688/71467/%EB%A9%94%EC%9D%BC_%EB%A9%94%ED%8A%B8%EB%A6%AD.md_2.png 609w&apos; sizes=&apos;(max-width: 609px) 100vw, 609px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
위 그래프는 해당 기간 동안에 하루 평균 몇 통의 메일을 보냈는지를 나타내는 그래프다. 1번 직원의 고충이 좀 더 선명하게 드러나는데 나머지 직원과의 비교는 둘째 치더라도 이 직원이 하루 평균 7통의 메일을 보낸다는 사실에서 심각한 격무에 시달리고 있음을 알 수 있다. 8시간 근무라고 가정했을 때 통상적으로 한 시간에 한 통의 메일을 보냈다는 점이다. 업무 일수가 아닌 단순 기간으로 나눈 통계이기 때문에 업무 일수로 나눈다면 그 정도가 훨씬 심해질 것이다. 실제로 1번 직원은 “요즘 정말 정신없이 바빠서 뭔가 다른 걸 생각할 엄두가 나지 않는다”라는 이야기를 했다. 그말이 그저 하는 엄살은 아니라는 걸 보여주는 그래프인 것 같아 더 씁쓸하다.&lt;/p&gt;
&lt;p&gt;이쯤되면 몇 가지 생각이 들게 마련이다. 왜 이 친구들은 동일한 업무를 수행함에 있어서 이 정도로 심각한 불평등 상황에 직면했는데 이 상황을 개선하려고 하지 않을까가 그 첫번째 의문이다. 이 정도면 사실 데이터를 뽑지 않아도 1번 직원이 과도하게 격무에 시달린다는 생각을 할 법하고 업무 배분을 좀 더 새롭게 할수도 있을 것 같은데 그러지 않는다는 점이다. 두번째는 왜 다른 직원들은 1번 직원의 이런 초과 업무에 대해서 도와주지 않을까라는 생각이 들기도 한다. 옆에 동료가 평균 한 시간에 한통의 메일을 써야 할 정도로 정신이 없다면 옆에서 보기 딱해서라도 몇 개 정도는 내가 도와줄게요라고 말할수도 있지 않을까하는 점이다. 그런데 대부분의 경우 그런 일은 거의 벌어지지 않는다. 물론 그렇다고 사이가 좋지 않은 것은 아니다. 옆에서 보기엔 참 화기애애해 보인다.&lt;/p&gt;
&lt;p&gt;이런 모든 걸 차치하고서라도 내가 생각하기에 더 재미난 사실은 저 업무에 참여한 모든 직원이 다들 우린 똑같이 힘들다고 말한다는 점이다. 3, 4, 5번 직원은 비슷한 수준의 업무 강도를 느끼고 있다고 생각할 수 있지만 그들이 1, 2번 직원과 똑같이 힘들다고 한다면 그건 분명 공평한 일은 아니다. 그런데 이상하게도 보상에 아주 근소한 차이가 있다면 3, 4, 5, 6, 7번 직원은 불만을 느끼거나, 불공평하다고 느끼거나, 내가 개인적인 친밀감 같은 것을 토대로 잘못된 판단을 내리고 있다고 생각한다. 그러니 이 상황에서 공정한 보상이 주어진다면 1, 2번 직원은 다소 실망할 것이고, 불균등한 보상이 주어진다면 3, 4, 5, 6, 7번 직원이 실망할 것이다. 벤담의 공리주의를 따른다면 균등한 보상이 주어지는 것이 맞는 상황인 것이다. 하지만 쳐다보는 입장은 또 그게 마음이 편하진 않다. 그래서 다른 부분에서 그들이 더 보상을 받을 수 있도록 기회적인 요소를 추가해서 균형을 맞추고 싶어한다. 그런데 또 웃긴것은 기회적인 요소를 여기에다 추가를 하면 그 기회에서 제외된 나머지 직원들은 내가 친밀감 따위를 토대로 기회를 제공하는 사람이라고 생각해 버린다는 것이다. 그러니 모두가 공평하게 행복한 상황은 애초에 만들 수가 없다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 615px; margin-bottom: 16px;&apos; data-url=&apos;./메일_메트릭.md_3.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/6c19dc079679c58db4398460ea15149e/8ab79/%EB%A9%94%EC%9D%BC_%EB%A9%94%ED%8A%B8%EB%A6%AD.md_3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 51.578947368421055%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABDElEQVR42l1QW46DMAzMxQA7D+I4wG5b1Er8lH5073+EdWJBoaPRxIk9WIwhImut2yB13/fP5/p6vf7e72VZ1nUVlcevMTGalBjQAgBWaEEViVPRROLcW7uGEMw4/fhh9t6HCl9hz5BVOqBdLWKMhnN249354M7Quc/V+a+BYs7MYrZirhuO2/R61L2l0Yg52fGBzltEfZUDy6FyUoXW1ZzI5hn5UuPqEFrcwtu+8FHlwcxcBvmGwwP5ijSB78GW/KFrKxtom031pe3aRkIzOXMJXhqyOCSII+QZ8h34BnyFJLxA+gWaMI6VgxD6IRAbyb3rOltXOflfycNiyTnEQIOLOfDkaDiqp7Gwp3/DP6FO8INgrgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 3&apos; title=&apos;&apos; src=&apos;/static/6c19dc079679c58db4398460ea15149e/8ab79/%EB%A9%94%EC%9D%BC_%EB%A9%94%ED%8A%B8%EB%A6%AD.md_3.png&apos; srcset=&apos;/static/6c19dc079679c58db4398460ea15149e/08678/%EB%A9%94%EC%9D%BC_%EB%A9%94%ED%8A%B8%EB%A6%AD.md_3.png 190w,
/static/6c19dc079679c58db4398460ea15149e/2edd7/%EB%A9%94%EC%9D%BC_%EB%A9%94%ED%8A%B8%EB%A6%AD.md_3.png 380w,
/static/6c19dc079679c58db4398460ea15149e/8ab79/%EB%A9%94%EC%9D%BC_%EB%A9%94%ED%8A%B8%EB%A6%AD.md_3.png 615w&apos; sizes=&apos;(max-width: 615px) 100vw, 615px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
상황을 좀 더 세밀하게 이해하기 위해서는 결과만 바라볼 것이 아닌 원인도 같이 고려해야 한다. 그런 이면을 보여주는 것이 이 그래프다. 그래프는 지난 한달간 우리에게 적어도 1회 이상 요청 메일을 보낸 업체를 보여주고 있다. 60여개 정도의 업체에서 1통 이상의 요청이나 문의 메일을 보냈는데 살펴보면 데이터가 좀 재미있다. 바로 요청의 대부분을 자주 요청하는 업체에서 거의 독식하고 있다는 점이다. 특히나 1위를 기록한 업체는 근 100여번의 요청을 했는데, 전체에서 차지하는 비중이 무려 16%에 이른다. 당연한 이야기겠지만 그 업체 담당자가 1번 직원이다. 이 업체는 일 평균 2.43통의 요청 메일을 보냈는데, 내가 생각하기에 거기에 병목 지점이 있다. 즉, 그 업체가 지속적으로 뭔가를 요청하는 메일을 보낸다는 것은 상황이 좋지 않다는 것을 의미하기 때문이다. 우리에게 요청을하지 않아도 문제를 해결할 수 있도록 개선된다면 100통의 메일을 처리할 필요가 없어진다는 점이다. 그리고 실제로 그 업체에서 요청하는 상당수 메일을 살펴보면 개선할 여지가 있는 요청 메일이다.&lt;/p&gt;
&lt;p&gt;물론 1번 업체의 요청 메일 하나를 개선한다고 1번 직원의 격무가 사라지는 것은 아니다. 어느 정도 완화되겠지만 그 요청 메일을 차치하더라도 다른 직원과의 격차는 굉장히 크다. 당연히 유능한 관리자라면 그 격차가 줄 수 있도록 방향을 제시해 주어야 한다. 가장 이상적인 상태라면 저 모든 직원들이 일 평균 3통 정도의 메일을 처리하는 상태라 할 수 있을 것이다. 그 이상이 넘어간다면 추가 인원 투입이 필요한 시점이라고 할 수 있다. 하지만 테일러 할아버지, 아니 고조 할아버지가 와도 저 상황을 개선할 수는 없다. 아주 잠깐 동안의 평형 상태는 만들 수 있어도 한달만 지나면 딱 지금의 그래프와 똑같은 상황이 만들어지기 때문이다. 실제로 과거 데이터가 그것을 말해주고 있다. 이 업무가 균등해지기 위한 유일한 길은 업무에 참여하는 모든 사람이 불균등함이 존재한다는 사실을 인정하고 그걸 개선하려고 노력할 때에만 가능하다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;종종 직원들한테 하는 이야기 중에 하나가 체인이 빠진 자전거 바퀴를 돌리고 있는 것 같다는 말이 있다. 우리 회사 직원들은 다들 열심히 일한다. 옆에서 보기 안스러울 정도로 열심이다. 그런데 가끔 그 이면을 살펴보면 체인이 빠진 자전거 바퀴를 열심히 돌리고 있는 것 같아서 씁쓸할 때가 많다. 조금만 변화를 주어도 극적으로 상황을 개선할 수 있음에도 그런 변화를 아무도 만들려고 하지 않는다. 그저 바퀴를 더 열심히 굴리는 일에만 집중할 뿐이다. 현실에 치여서 그러질 못한다는 이야기를 많이 하는데 그래서는 전투에선 이길 수 있을지 몰라도 전쟁에서는 패할 수 밖에 없다.&lt;/p&gt;
&lt;p&gt;작은 업체는 항상 모든 게 부족하다. 돈도 부족하고, 사람도 부족하고, 시간도 부족하다. 예전에 우리가 1.0 버전을 만들고 있을 때 회사에 같이 계셨던 분은 그랬었다. 우리는 돈도 없고 사람도 없으니 1.0을 만드는 것 외에는 할 수 있는게 없다. 그때 난 모든게 부족해도 2.0을 설계하고 만들어야 한다는 이야기를 했었다. 아마 그때 우리가 1.0만 만들고 있었다면 지금도 1.0만 있거나 아니면 망했을 것이다. 현실이 아무리 각박하고 초라해도 미래를 위해서 일정 시간을 떼어내서 투자해야 한다. 다윗이 골리앗을 이기는 유일한 길이 바로 거기에 있기 때문이다.&lt;/p&gt;
&lt;p&gt;언젠간 우리 회사 직원들도 다들 이런 생각을 가졌으면 좋겠다는 생각을 해본다. 스스로 자신의 업무를 측정하고, 분석해서 문제점을 찾고, 개선해 나갈 수 있는 방향을 토론하는 그런 분위기가 된다면 더할 나위 없이 좋겠다는 생각도 해보지만 한편으론 너무 많은 것을 바라는 건 아닐까라는 생각에 조심스럽기도 하다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Allman Style]]></title><description><![CDATA[Allman vs K&R 답없는 종교 전쟁을 또 다시 시작하자는 이야기는 아니구요. 페북에 재미난 그림이 있어서 퍼왔습니다. Allman과 K&R 스타일을 비교한 것 같은데요. 전 개인적으론 Allman…]]></description><link>https://jiniya.net/wp/archives/13372</link><guid isPermaLink="false">https://jiniya.net/wp/archives/13372</guid><pubDate>Wed, 18 Jun 2014 23:59:41 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; margin-bottom: 16px;&apos; data-url=&apos;./Allman_Style.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/3a777bd6929d3ae349ce88c99f322b4d/b0db9/Allman_Style.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 70.52631578947368%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAIAAACgpqunAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACbUlEQVR42k1SaW/aQBDlhyQ+Fh/Y2MZ72eu1MWAOhxIICTQCHEiBpkqqqv//Y8eQSpGe1rPj93ZGM68R+D0d0Vsl1HSmqgSAEFPgqn0GqoIh1nVmGlFN0GqOplEdscZy9XI8/9nuzrPZ8/KxWn//MSmfDq/vi4ddebfav75vNqfFYjeePB0O76vVfrXePz8f3379LUbLhhfkxXA+HD/ItCyKZb8/Z7wAfZpNhRiv1odiuOzmMyFGg8FiUj7mvdnddH03/S6SSQMZ4lYlNypRNHaj0luVIiOCjIaY3uSKRhW9hqrD35pw4ZALgTe0JsNhIcU4lb0sGYik8HHW9ruGJUw7AUDg+92YD/N0kMm+lEWUjLxOTWioOhFxyXCWMp5zwYkwWiQIe01TwG8ABEEnx6Ese8l9VxQy9XHidTLIQ2XiB13Hp1EURzju+NR0iNfJv4prqkMcFtkuNWxstogfdi9iREKc2y63KEUm1k0Mlf0vYmTEmPYdL7JCajgYWbh+/SpWdAxzIyz3sQzC1O+kAU6DMG8a/8VmjElOaOYFIggTQIhlB8PrMUybWXZi28JxpOumrivdtmy1pGWnVisBmLa8nKLlSqedAiCAaz0ww4rg0/a6MHYF3AOL0Qi4TdO5hihsC2LosO3nsMJ6cxqFLV6bajRN7nhZVb1ttqdtddrv347Hj+rl53Z7qqoTWGo+35zPv0+nj832uNmdX48f4Ch4FLZYV4au2l7G+aicrPLevcy+RaKMxDgSQ3Ab5cNYjEPS59FIptNETikbfVY2rPiyj/jaIbStIqahCAwEgGSdRxx6hhN8dnFedBX/A4xdrdLh1J8hAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Allman Style md 0&apos; title=&apos;&apos; src=&apos;/static/3a777bd6929d3ae349ce88c99f322b4d/b0db9/Allman_Style.md_0.png&apos; srcset=&apos;/static/3a777bd6929d3ae349ce88c99f322b4d/08678/Allman_Style.md_0.png 190w,
/static/3a777bd6929d3ae349ce88c99f322b4d/2edd7/Allman_Style.md_0.png 380w,
/static/3a777bd6929d3ae349ce88c99f322b4d/b0db9/Allman_Style.md_0.png 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;Allman vs K&amp;#x26;R&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;답없는 종교 전쟁을 또 다시 시작하자는 이야기는 아니구요. 페북에 재미난 그림이 있어서 퍼왔습니다. Allman과 K&amp;#x26;R 스타일을 비교한 것 같은데요. 전 개인적으론 Allman 스타일을 선호합니다. 이유는 &lt;a href=&quot;http://en.wikipedia.org/wiki/Indent_style&quot;&gt;위키 페이지에&lt;/a&gt; 나와 있는 아래 코드와 같은 장점들 때문입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;//while (x == y)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;something&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;somethingelse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;//for (int i=0; i &amp;lt; x; i++)&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//while (x == y)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;something&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;somethingelse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;HAS_GETCH&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getchar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;EOF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;do_something&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;결국 이 이야기 끝에는 블록 단위로 복사, 붙여넣기 편하다는 장점이 위치할 것 같습니다. K&amp;#x26;R 스타일을 사용할 경우 블록 단위 복사, 붙여넣기를 하려면 결국 셀 선택을 해야하는 불편함이 있거든요. 물론 이런 이야기를 하면 사이비 프로그래머니까 창조성 없는 복붙 프로그래밍이나 하는것 아니냐는 반론을 감수하긴 해야겠지요. 창조적인 프로그래머 아저씨, 리누스 토발즈옹은 K&amp;#x26;R에 대한 신념을 언급한 적이 있었지요.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;C 스타일과 관련돼서 항상 튀어나오는 다른 이슈는 괄호를 어디다 위치시키냐 하는 것이다. 인덴트 사이즈와 다르게, 다른 것을 배제하고 한 가지 배치 전략을 선택하는 것은 아주 조금의 기술적인 이유밖에 없다. 그러나 좋아라 하는 방법은 열기 괄호는 라인 끝에 위치시키고, 닫기 괄호는 라인의 처음에 위치시키는 것이다. 이러한 방법은 커닝헌과 리치와 같은 선지자들이 우리에게 보여준 것이기도 하다. 아래와 같이 될 것 이다.&lt;/p&gt;
&lt;p&gt;if (x is true) {&lt;/p&gt;
&lt;p&gt;    we do y&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;그러나, 거기에는 함수라는 한가지 특별한 경우가 있다. : 그것들은 다음과 같이 열기 괄호를 다음 줄의 시작에 위치시킨다.&lt;/p&gt;
&lt;p&gt;int function(int x)&lt;/p&gt;
&lt;p&gt;{&lt;/p&gt;
&lt;p&gt;    body of function&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;전세계에 분포한 이단자들은 이것은 모순이다... 음 불완전하다...,라는 주장을 펼친다. 그러나 바르게 생각하는 모든 사람은 (a) K&amp;#x26;R은 올바르며 (b) K&amp;#x26;R도 옳다는 것을 알고 있다. 게다가, 함수는 어쨌든 특별하다 (C에서 함수는 중첩이 불가능하다).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/lecture/translate/linux_kstyle.html&quot;&gt;리눅스 커널 코딩 스타일, 리누스 토발즈&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;여러분은 어떤 스타일을 선호하시나요? 특별한 이유가 있으신가요?&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 분급]]></title><description><![CDATA[정동진, 이곳이 해가 뜨는 곳이기에… 부디 좋은 곳에서 편히 쉬시길… #…]]></description><link>https://jiniya.net/wp/archives/13362</link><guid isPermaLink="false">https://jiniya.net/wp/archives/13362</guid><pubDate>Tue, 17 Jun 2014 23:59:40 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;정동진, 이곳이 해가 뜨는 곳이기에…&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;부디 좋은 곳에서 편히 쉬시길…&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;정동진에서 서른네 살의 노동자가 자살했다. “이곳이 해가 뜨는 곳이기에”라는 말을 유서에 남겼다. “더 이상 누구의 희생도 아픔도 보지 못하겠으며 조합원들의 힘든 모습도 보지 못하겠기에 절 바칩니다”라는 말도 유서에 적혀 있다. 막 꽃피어야 할 한창나이의 젊음이 자신의 최후로 선택한 정동진엔 오늘도 변함없이 해가 뜬다. 그가 전하고 싶었던 소망과 절망감을 다시 또 알려주기라도 하는 듯이.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;삼성전자서비스 직원인 그의 지난달 월급은 45만원 정도였다고 한다. 그 전달에는 70여만원이었다. 분당으로 받는 급여를 뜻하는 ‘분급’에 의해 지급된 것이라 한다. 분급이라는 말. 근래 들어본 가장 끔찍한 단어이다. 이런 임금체계를 현실로 시스템화하는 곳이 바로 삼성이다. 이동시간, 고객에게 설명하는 시간, 수리 준비 시간 등을 다 빼고 오직 제품 고치는 시간만 계산해 1분당 225원을 받는 노동자라니. 이런 끔찍한 착취 앞에 저항하지 못한다면 우리는 대체 누구이며, 내일은 또 무엇을 할 수 있을까. 무노조 경영의 악착같은 착취를 ‘초일류기업’의 세련된 이미지로 포장하는 이건희 일가의 재산 13조원을 만들어준 노동자들 중 누구는 백혈병과 희귀병으로 죽어가고 누구는 견디다 못한 자살로 죽어간다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;전세계 139개 나라 중 한국의 노동권이 최하위인 5등급으로 분류되었다는 뉴스가 흘러나온다. 여기가 대한민국호가 서 있는 자리다. 해 뜨는 곳 정동진으로 노랗게 해가 진다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;-- &lt;a href=&quot;http://www.hani.co.kr/arti/opinion/column/638861.html&quot;&gt;한겨레, 김선우 시인·소설가&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;얼마 전 “코딩 호러가 들려주는 진짜 소프트웨어 개발 이야기”란 책을 사러 서점을 가는 길에 서점에 책이 없을 수도 있겠다 싶어서 지하철 앞에서는 핸펀으로 재고 검색을 하다 핸펀을 떨어뜨렸다. 핸펀을 바닥과 접촉시키는 일이야 늘상 벌어지지만 그날은 재수가 없었는지 액정이 깨져 버렸다. 갤럭시 S4 LTE-A, 산지도 얼마 안된 핸펀 액정이 또 깨지다뉘. 절망하면서 핸펀을 다시 켜는데 어랏. 액정이 아예 켜지지도 않았다. 진짜 액정이 깨진 것이다. 액정 앞에 강화유리(?!)가 깨진게 아니라. 고약한 일이 벌어진 것이다.&lt;/p&gt;
&lt;p&gt;이를 어쩌지 하면서 삼성전자 서비스 센터를 갔다. 서비스 센터 앞에서는 전형적인 블랙 컨슈머 흉내를 낸다. 천연덕스럽게 액정이 안 나와서 왔다며 바보 코스프레에 들어갔다. 센터 직원 아저씨가 친절하게 안경 닦는 천으로 닦더니 안이 깨져서 화면이 나오질 않는다고 외부에서 충격을 가한 것 같다는 설명을 덧붙였다. 모르겠다는 표정을 지으니 오른쪽 모서리에 스크래치가 난 자국을 문제 삼으며 이쪽으로 충격이 가해지면서 안에 있는 액정이 깨졌을 것이란 놀랍도록 정확한 추론을 펼쳤다. 난 여전히 모르겠다는 표정을 지으며 오른쪽 모서리는 원래 그랬고, 충격을 가한 적도 없으며, 그 충격을 가해서 안쪽 액정이 깨졌다는 것을 내가 증명해야 하는 문제냐고 했다. 증명이란 단어에 아저씨는 머리가 조금 아파하는 표정을 짓더니 안에다 물어보고 오겠다고 했다. 그리곤 잠시 후 나오더니 원래 공짜로 되지 않는 것인데 애매한 상황이라 공짜로 해주는 것이라며 10만원 상당의 액정 모듈 교체를 공짜로 해주었다. 친절 사원 쓰는 곳에 난 센터 직원 아저씨 이름 옆에 짱짱맨을 적어주며 기분 좋게 나왔다.&lt;/p&gt;
&lt;p&gt;난 삼성이란 기업을 그다지 좋아하지 않았다. 그런데 그 공짜 수리 사건으로 급 호감이 갔다. 담에도 삼성 폰을 사야지 이러면서. 더 부끄러운 사실은 이 쪽팔린 공짜 수리 사건을 무슨 무용담이라도 되는양 의기양양하게 주변에 떠벌리고 다녔다는 점이다. 당연한 이야기겠지만 그 무용담에서 삼성이란 기업은 철저하게 착한 기업으로 각색돼 있었다. 물론 이런 행위에 드는 비용 일체가 핸드폰 가격에 포함돼 있고, 그래서 우리가 호구처럼 비싼 가격에 핸드폰을 사야한다는 사실을 모르지도 않는 사람이 그랬다는 사실이 더 창피할 뿐이다. 분급이란 기사를 보니 있으니 이런 나의 어리석은 행동이 더 민망하게 느껴졌다. 다음엔 꼭 LG 폰을 사야겠다. 옵지3가 잘 빠졌다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 360px; margin-bottom: 16px;&apos; data-url=&apos;./분급.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/62eb3949e93d8730600326fc0bcaa105/543cd/%EB%B6%84%EA%B8%89.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 63.68421052631579%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIEAf/EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAFconmlGE//xAAaEAADAAMBAAAAAAAAAAAAAAAAAQIDEyEE/9oACAEBAAEFAtUorzwaZE+Vj66P/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGxAAAgEFAAAAAAAAAAAAAAAAAAEQAhExQWH/2gAIAQEABj8CXTJuLupx/8QAGRABAQEAAwAAAAAAAAAAAAAAAQARIUGB/9oACAEBAAE/IdGRRYyOxBHCppukfZBv/9oADAMBAAIAAwAAABDYz//EABURAQEAAAAAAAAAAAAAAAAAAAAh/9oACAEDAQE/EEf/xAAVEQEBAAAAAAAAAAAAAAAAAAAAIf/aAAgBAgEBPxCq/8QAGhABAAMBAQEAAAAAAAAAAAAAAQARMSFBgf/aAAgBAQABPxACqChQCtezmbNHPkrBR6RgRSAzd2You6jEer25/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;   md 0&apos; title=&apos;&apos; src=&apos;/static/62eb3949e93d8730600326fc0bcaa105/543cd/%EB%B6%84%EA%B8%89.md_0.jpg&apos; srcset=&apos;/static/62eb3949e93d8730600326fc0bcaa105/8ccab/%EB%B6%84%EA%B8%89.md_0.jpg 190w,
/static/62eb3949e93d8730600326fc0bcaa105/543cd/%EB%B6%84%EA%B8%89.md_0.jpg 360w&apos; sizes=&apos;(max-width: 360px) 100vw, 360px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;죽은 고기만 먹기에 소녀가 죽기를 기다리는 독수리&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;내가 바라보는 자본주의의 민낯&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;난 자본주의를 딱 저 사진처럼 느낀다. 따스함이란 없는 무자비한 약육강식의 세계, 일말의 공정함도 기대하기는 힘든 시스템. 이건 비단 사용자와 노동자 사이의 관계에서만 그런 것은 아니다. 기업이 제품을 파는 일도 똑같다. 좋은 제품을 만들면 잘 팔릴 것 같지만 꼭 그렇지도 않다. 그 중간에 온갖 정치, 음해, 공작 같은 것들이 있고, 시장을 비정상적으로 왜곡시키는 광고나 마케팅 효과도 있기 때문이다. 지금 한껏 주가를 올리고 있는 그 표절 게임만 해도 그렇다. 지나가는 게임 개발자 100명에게 물어보면 100명 모두 그 게임이 그렇게 매출 순위가 높은 게임이 되는 건 공정하지 않다고 말할 것이다. 하지만 시장에서 그 게임은 엄청난 매출을 올리고 있다. 내가 바라보는 자본주의 시장은 그렇다. 제 아무리 좋은 걸 만들어도 하나도 못 팔 수도 있고, 쓰레기를 만들어도 날개 돋친 듯 팔릴 수도 있다.&lt;/p&gt;
&lt;p&gt;가끔 직원들과 이야기를 하다보면 깜짝 놀랄때가 있는데, 그들이 나와는 정반대의 세계관을 가지고 있을때다. 자본주의 시스템에 대해서 굉장한 퐌타지와 이데아를 가지고 있는 경우라 할 수 있겠다. 난 그런 이야기를 들을 때마다 내가 세상을 너무 냉소적으로 바라보고 있거나 잘못 알고 있었던 것일까, 라는 생각을 했다. 왜냐하면 그들 말에 따르자면 구조조정이란 단어는 세상 밖으로 나오지도 않았을 것이고 전 지구를 협동조합이라는 가장 우수한 조직 시스템이 장악했을 것이기 때문이다. 그런데 현실은 뉴스에 감기처럼 달고 나오는 게 구조조정이고, 주식회사라는 시스템이 전 지구를 뒤덮었다.&lt;/p&gt;
&lt;p&gt;이런 묘한 아이러니 속에서 난 도대체 왜일까라는 의문이 생겼고 자본주의를 좀 더 제대로 알아야 겠다는 생각에 얼마 전 “자본주의 이해하기”라는 책을 샀다. 이 책을 통해서 난 자본주의 시스템에 대해서 충격을 더 받게 되었는데 그 이유는 내가 무엇을 상상하든 그 이상으로 자본주의는 냉정하고 차갑고 비정하며, 또한 무기력한 시스템이었기 때문이었다. 그 중에 하나가 실업 문제에 대한 결론이었다. 사실 분급이라는 게 따지고 따지고 따지고 또 따지고 들어보면 좋은 일자리가 많이 없다는 결론으로 더 파고 들면 실업 문제로 귀결된다고 할 수 있다. 책에서는 실업에 대해서 아래와 같이 너무나도 냉혹한 결론을 너무나도 논리 정연하게 기술하고 있기에 일말의 반박을 할 여지조차 주지 않고 있었다. “고용주도 노동자들도 이러한 상황을 개선할 수 없다”라는 결론은 정말이지 떨떠름할 따름이다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;케인스는 이 논리를 거부했다. 그에 따르면 실업은 임금이 너무 높아서 생기는 문제가 아니라, 노동이 생산한 재화에 대한 수요가 너무 적기 때문에 발생하는 것이다. 그리고 “문제가 생산물에 대한 대한 수요가 불충분하기 때문이라면 해결책은 임금을 낮추는 것이 아니라 높이는 것”이라고 케인스는 말했다. 그는 사람들이 물건을 사기 위해 지불하는 소득의 근원이 임금이고 경제의 산출물에 대한 수요의 상당 부분이 바로 임금에 의해 뒷받침되므로, 고임금은 수요의 증가를 낳고, 수요의 증가가 이번에는 산출의 증가로, 고용의 증가로, 그리고 실업의 감소로 이어질 것이라고 생각했다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;케인스의 이론이 보여주는 것은 1) 자본주의는 실업을 해결할 수 있는 자동적 메커니즘을 갖고 있지 못하며, 2) 자본주의 경제에서 실업은 비자발적인 것이며 임금이 낮아진다고 해도 실업은 사라지지 않을 것이라는 점이다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;… 중략 …&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;셋째, 고용주의 입장에서 임금을 낮추는 것이 이윤 극대화에 도움이 되지 않을 수도 있다는 것이다. 최적 임금 w’보다 임금이 낮으면 단위 노동비용은 오히려 상승한다. 임금을 낮추어 비용을 절감할 수 있지만 그 결과 노동강도(e)가 낮아지고 산출량이 감소해 임금 하락으로 얻은 비용 절감분보다 노력 지출량 저하에 따른 손해가 더 커지기 때문이다. 즉 고용주는 임금을 w’이하로 낮출 유인을 갖지 않는다. 현재 임금수준 w’보다 낮은 수준에서도 기꺼이 일할 용의가 있는 사람들이 있더라도 이들을 낮은 임금으로 고용하려고 하지 않는다. 임금을 낮춤으로써 단위 노동비용이 상승할 것을 우려하기 때문이다. 이 결론은 중요하다. 바로 우리가 4장에서 본 케인스의 주장, 즉 실업자들이 현재보다 낮은 임금수준을 받아들일 용의가 있음에도 실업은 사라지지 않을 것이고, 바로 이 때문에 자본주의 경제에서 비자발적 실업은 보편적인 현상이라는 주장과 일맥상통하기 때문이다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;실업 상태에 놓여 있는 사람들이 현행 임금보다 낮은 임금을 받아들일 용의가 있음에도 일자리를 찾지 못한다는 사실은 자본주의사회에서 실업이 항구적일 수 있다는 것을 의미한다. 더 나아가 노동시장에서 초과 공급이 존재하는 상황에서도 임금이 더는 하락하지 않을 것임을 말해준다. 초과 공급이 존재하고 더 낮은 임금을 받아들일 준비가 되어 있음에도 아무도 이들을 데려가려고 하지 않는다. 고용주도 노동자들도 이러한 상황을 개선할 수 없다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;-- 자본주의 이해하기, 새뮤얼 보울스, 리처드 에드워즈, 프랭크 루스벨트&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;언젠가 친구네 회사가 회식비와 경비 일체에 대해서 3개월간 시험적으로 제한을 없앴다는 이야기를 했다. 즉, 회식 때 마음껏 먹고 마시고 놀아도 된다는 것이다. 니들이 한강에서 요트를 타고 선상 파뤼를 하며 회식을 하더라도 다 처리해 주겠다는 대인배적 마인드라 할 수 있겠다. 이 사건과 몇 가지 행동을 두고 친구 녀석은 회사 대표가 착한 사람 같다는 표현을 썼었다. 그때 난 그 사람이 절대 착하지 않다고 이야기를 했다. 그 사람이 그렇게 제한을 풀고 복지를 늘리고 하는 것도 다 이유가 있기 때문일거라는 막연한 소리만 했었다. 그런데 “자본주의 이해하기”라는 책을 보면 그 대표가 왜 그런 행동을 하는지를 너무나도 논리 정연하게 설명해 놓고 있다. 두 글자로 그 대표가 취하는 행동에 대해서 기술하고 있는데 단어가 너무 언짢아서 차마 여기다 옮겨 적기는 좀 그런 것 같다. 궁금하신 분들은 책을 사서 읽어 보도록 하자.&lt;/p&gt;
&lt;p&gt;난 더 많은 사람들이 이런 책을 읽고 자본주의 시스템이 돌아가는 기본적인 원리나 생리에 대해서 알아야 한다고 생각한다. 현실을 사는데는 퐌타지나 이데아 보다는 이러한 차가운 진실들이 더 도움이 된다고 믿기 때문이다. 게임의 법칙을 알아야 게임에서 이길 확률이 올라갈 것이고, 적어도 지더라도 왜 졌는지 원인 분석은 될 테니까 말이다. 그런데 진짜 아이러니 한 사실은 이런 책을 읽지 말아야 할 사람들은 더 꼼꼼하게 밑줄 쳐가면서 읽고 정작 읽고 이해해야 할 사람들은 막연하게 퐌타지만 가지고 세상을 살아간다는 점이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;1890년 촬영된 이 사진은 높다란 마천루 안에 은밀하게 숨겨진 뉴욕 빈곤층의 생활을 보여주고 있다.&lt;br&gt;
&lt;br&gt;
노동자의 노령 연금과 의료비를 보장하려는 기업은 없었다.&lt;br&gt;
&lt;br&gt;
법원 역시 작업 중 입은 재해는 노동자가 책임져야 하며 근로기준법은 위헌이라고 판결했다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;미국 노동자들은 거대한 기업 권력에 관해 이렇게 밝혔다.&lt;br&gt;
&lt;br&gt;
우리는 투표를 통해 그들을 쓰러뜨릴 수 있지만 투표함은 그들이 점유하고 있죠.&lt;br&gt;
&lt;br&gt;
우리는 법원에서 정의를 찾을 수 있지만 법원은 그들이 세운 겁니다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;… 중략 …&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;1903년 2월 대로우는 이렇게 변론했다.&lt;br&gt;
&lt;br&gt;
미국의 문명이 광부와 노동자들의 굶주림으로 이루어졌고&lt;br&gt;
&lt;br&gt;
겨우 열두서너살 된 아이가 먼지 날리는 무연탄 광산에서 석탄을 주워 생활을 영위한다면&lt;br&gt;
&lt;br&gt;
빨리 이 문명을 포기하고 새로운 문명을 시작하는 것이 인류에게 좋을 것이다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;-- 기업의 힘 E04&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;자본주의 역사가 정확하게 어떻게 되는지는 모르겠지만 100년 전에도 지금과 비슷했던 것은 틀림이 없는 것 같다. 인간은 역사로부터 아무것도 배우지 못하는 존재라고들 한다. 그래서 역사는 반복되는지도 모르겠다. 불평등이 극에 달했던 시스템은 모두 파괴되고 붕괴되었다. 자본주의 시스템이 아슬아슬한 줄타기를 하며 계속 유지될지 아닐지는 모르겠지만 부디 힘을 가진 높으신 분들이 바리케이드의 역사를 잊지 않는 지혜를 가졌으면 하는 바램이다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;최고의 시절이자 최악의 시절, 지혜의 시대이자 어리석음의 시대였다. 믿음의 세기이자 의심의 세기였으며, 빛의 계절이자 어둠의 계절이었다. 희망의 봄이면서 곧 절망의 겨울이었다. 우리 앞에는 모든 것이 있었지만 한편으로 아무것도 없었다. 우리는 모두 천국으로 향해 가고자 했지만 우리는 엉뚱한 방향으로 걸었다. 말하자면, 지금과 너무 흡사하게, 그 시절 목청 큰 권위자들 역시 좋든 나쁘든 간에 오직 극단적인 비교로만 그 시대를 규정하려고 했다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;-- 두 도시 이야기, 찰스 디킨스&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[iOS 입문]]></title><description><![CDATA[#0  Android 78.1%, iOS 17.6%, Windows Phone 3.0%, From IDC 아이폰 하면 무슨 느낌이 드시나요? 제가 처음 쓴 맛폰이 갤s였고, 그 담에 아이폰4를 썼습니다. 갤s 쓰다가 아이폰4를 쓰니 신세계였죠. 갤s…]]></description><link>https://jiniya.net/wp/archives/13532</link><guid isPermaLink="false">https://jiniya.net/wp/archives/13532</guid><pubDate>Thu, 05 Jun 2014 23:59:39 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 576px; margin-bottom: 16px;&apos; data-url=&apos;./iOS_입문.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/1519c572a876b90622dda350ec57d35b/694da/iOS_%EC%9E%85%EB%AC%B8.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 64.73684210526316%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACSElEQVR42l1SS2/TQBDOX+GUd/NO1CR27F3bu07cpPb6mTRChdCEHEACRKUeCrRFSNBDoQLUSxGVOFFx4XFDghtI9MaFA78CceeLfICyWsszO9+3M9/sJJLJZCaTWVpaqlQqjUZjeXmZcz4MQ9fzxuOx7wpXiCga6rqOEADlchlgUFKpVAK/fD5fKpXq9Xqr1VIUhXHetX3XD6az6ejSXLiuM+jhRoTa7TZgAIOSTqcT2Wy2WCzWarVms6koHWSgvHe4Tr/vuc+eH0yPvs6OvgXX7nMDEQ18wAAuFAogJuK0qEeWJF2jKrNOr0q/7lSfbvDRKHLHV4Y396cnP9a2j7mhYcmyHBefy+USsVroIaoi6+a23/q9eeF6wOhq6HleAMWWIS7O109+2pPbBukoKkHyarUK4oIMC75GVEnvvpyz17Om6QSjMAjjFY1E3wx2T/29N4zIhFK05hwZPk65Tpz9z86tQ9+2gjCKFwxv1RI3DsSjT8zQCCEAQ/a5zIRQXDzYe+dsvfAG3SAaxolhwHW2jhFitAPY38xoWKxZUVSDyOZ0p//4zPECz+n7QYgNQ3hB/8lZd7ZrqBI0A4yGgZhA0+JuS5KsoXLG+L231oOPztqGK2xsGHBxiBClVJIkgEFZdBvPhUeLK18k1yizbH3zlfHwC9/5wHfew4C7ONQoAOfe+d8Ja7elhXJdM5nB/Ik+uYvN/MtwMSHo6P8Thg93QH25XGrJxDS7FqMrVq+/0hODnm2ZtqUKYTPTJBonqhrPNiipVOoPKgDjF36YHhYAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;iOS    md 0&apos; title=&apos;&apos; src=&apos;/static/1519c572a876b90622dda350ec57d35b/694da/iOS_%EC%9E%85%EB%AC%B8.md_0.png&apos; srcset=&apos;/static/1519c572a876b90622dda350ec57d35b/08678/iOS_%EC%9E%85%EB%AC%B8.md_0.png 190w,
/static/1519c572a876b90622dda350ec57d35b/2edd7/iOS_%EC%9E%85%EB%AC%B8.md_0.png 380w,
/static/1519c572a876b90622dda350ec57d35b/694da/iOS_%EC%9E%85%EB%AC%B8.md_0.png 576w&apos; sizes=&apos;(max-width: 576px) 100vw, 576px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;&lt;a href=&quot;http://www.idc.com/getdoc.jsp?containerId=prUS24676414&quot;&gt;Android 78.1%, iOS 17.6%, Windows Phone 3.0%, From IDC&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;아이폰 하면 무슨 느낌이 드시나요? 제가 처음 쓴 맛폰이 갤s였고, 그 담에 아이폰4를 썼습니다. 갤s 쓰다가 아이폰4를 쓰니 신세계였죠. 갤s는 좀 아니었거든요. 아이폰4는 그랬습니다. 견고하고 빈틈없고 단단했습니다. 된다고 약속한 기능은 확실하게 동작했습니다. 아이폰4를 쓰면서 음악이 튀는 현상을 저는 경험해 본 적이 없었습니다. 쓸만한 스마트폰이었습니다. 하지만 결정적인 단점이 있었는데 바로 제 폰이 아니라 잡스횽 폰 같다는 느낌이었습니다. 저는 폰에 있는 파일들이나 시스템 설정들 또는 제가 필요한 데이터를 알아서 잘 관리할 수 있음에도 아이폰은 저에게 그런 여지를 허락하지 않더군요. 윈도용 아이튠즈는 정말 가관이었습니다. 다시 안드로이드 폰으로 갈아탈 수 밖에 없었죠. 그렇게 &lt;a href=&quot;http://www.jiniya.net/wp/archives/9960&quot;&gt;안드로이드 입문&lt;/a&gt;을 한지도 일년 넘는 시간이 지났습니다.&lt;/p&gt;
&lt;p&gt;그간 아이폰의 시장 점유율을 유심히 지켜보았습니다. 내심 속으로는 아이폰의 점유율이 과거 맥이 그랬던것처럼 쪼그라들길 바랬습니다. 하지만 그건 단순한 제 바램일 뿐이었습니다. 아이폰은 너무나 견고하게 자신만의 독자적인 세력과 점유율을 유지하고 있는 것처럼 보여집니다. 네 맞습니다. 아이폰 코딩을 시작할 시점이 됐다는 말이죠. 멀티 플랫폼 시대의 개발자는 정말 피곤한 직업인 것 같습니다. 과거 윈도우만 해도 먹고 사는데 문제가 없었던 시절이 그립네요. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;많은 사람들이 아이폰 보안이 좋다고 이야기합니다. 견고하다고 하죠. 안드로이드가 그렇게 두드려 맞는 동안에도 아이폰은 크게 이슈가 없었던 것 같습니다. 전 뭐 엔지니어로써 아이폰이라고 그닥 크게 보안성이 뛰어나다고 생각하진 않습니다. 막아 놓은 것들이 많고 사용자가 안드로이드 대비 적으니 덜 뚫린다고 생각하는 입장입니다. 어쨌든 그렇게 첩첩산중 막고 또 막고, 가리고 또 가리고, 숨기고 또 숨기고 해서 아이폰을 구매한 사용자에게는 제법 안전하다는 인식을 제공하고 있는 것 같습니다. 그렇다면 앱스토에 앱을 올리는 개발자 입장에서는 어떨까요?&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 577px; margin-bottom: 16px;&apos; data-url=&apos;./iOS_입문.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/dfee6193ffa602e10ed54985e92ea0e8/32e64/iOS_%EC%9E%85%EB%AC%B8.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 77.36842105263158%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABcklEQVR42o2S646CMBCF+/5P5N/94QOsWsGVSwLeoDcosAvF0j1CYtR1E75MJoe20zmdQKrVWn6uKkobz6u325vwfRNFJgy7IGj3+29KbZoOzg3WDs8QtlxSzws9L/B9f7MJd7svShE7StMoEnl+ieOr7zswDO4ZwhYL+vHB0TCK6iBAroJA7/cIkyQuz12auvX6fbEVAmGy7DoKy/mVc4hBqQGCMZtltijg2P6BtMbkqjxzLrQum0ZVlarrn763ziGGe7yD9F0nxQ3OWKEUMufcdN3N5GO8g1xH7MMkJ21nQEzf33pxXhSFHIEwxrh/rD7ZxjlUZll2uVyOxyM0Y6yD7Rk82Z662dmQotRCyLIs4RZZKYXcY9pziquqgmdUwjY853le17WbB7n7fBnGtP3yeV+ZBCm1FlKiW9M0yFrrtm1xVz+CcdzzIxgzFgkeifFizrANz3hCkiTjXyNOp1OaptjFyuFwOJ/PU8bJOI6llL81J18Pg9u+OAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;iOS    md 1&apos; title=&apos;&apos; src=&apos;/static/dfee6193ffa602e10ed54985e92ea0e8/32e64/iOS_%EC%9E%85%EB%AC%B8.md_1.png&apos; srcset=&apos;/static/dfee6193ffa602e10ed54985e92ea0e8/08678/iOS_%EC%9E%85%EB%AC%B8.md_1.png 190w,
/static/dfee6193ffa602e10ed54985e92ea0e8/2edd7/iOS_%EC%9E%85%EB%AC%B8.md_1.png 380w,
/static/dfee6193ffa602e10ed54985e92ea0e8/32e64/iOS_%EC%9E%85%EB%AC%B8.md_1.png 577w&apos; sizes=&apos;(max-width: 577px) 100vw, 577px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;알만한 사람들은 다 아는 치트계의 블루오션 iOS&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;맞습니다. 지옥이죠. 그 잘난 샌드박스 덕분에 여러분이 할 수 있는건 아마 거의 없을 겁니다. 아이폰을 구매한 사용자가 맘먹고 앱을 공격하겠다고 생각하는 순간 앱은 감옥(샌드박스) 속에서 속수무책 당할 수 밖에 없습니다. 요즘 치트 좀 하는 사람들은 다 공공연히 알고 있는 사실이지만 아이폰은 치트계의 진정한 블루오션입니다. 앱을 보호해 줄 그 어떤 보안장치도 없거든요. 여러가지 이유가 있지만 삼성 공화국인 국내에서는 사용자가 많지 않아서 다소 무시 당했다는 점도 한 몫 했다고 봅니다. 하지만 더이상 그렇게 방치하기에는 아이폰 점유율이 무시할 수준은 아닌 것 같습니다. 아이폰이 독점적인 점유율을 누리는 국가들도 있고, 탈옥을 하지 않고도 앱을 위변조해서 사용하는 기법들도 속속 등장하는 지금, 이제는 뭔가 필요할 때가 되긴 한 것 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; margin-bottom: 16px;&apos; data-url=&apos;./iOS_입문.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/64829644cf4f3228a817a7ab83bf5b68/0eb09/iOS_%EC%9E%85%EB%AC%B8.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 98.42105263157895%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAErElEQVR42m2Oe0xTdxzFfzomMILEguiA6aToUKriA0Xmg23ObaDLdI/4yNx0usTpposj4mZji0hL3+W2t71tubfvW6AUCrS4IlBoxZLFdYJWBUvHoA5BFNrSB3/tur89+eSbk29ycg7IylxBoVDWU/K2Fmw+9vVhtVbldrtpNDoAYPeO/M8/3XP8q31njpf88sNBetlR5pXjnKvfCq6dhKtOSRinwQIQB16hBQSvLYyLX7QoOSkpjZSSlZG2mpy5IW/Vtk1r9hTlffz+pkOlhWDNrm05RQVvF+Rn5edlUnKXryYvycpYvCw9OS0tcXFKfFJSXHzCgoWvLABgeQElo3Bj5s5NbxVvyd5XmLt/d95n7xGsO1C8dv+utaVFuSXv5pYU5X60/Z0Ptqwu3pyzc312Ye7KLTmZlBUgbsUykEEC6SkgLRksSQRLEsDSRJCRCJYTJgGkJYD0N8CbyWBlCiCTFpJT47JTXyenxpNJCWQSYLGqq5iMiuuVVyroZdTfzpeXff/zTwdPHNn/zZclxw7tOfDh9k+K8/fu2LivcN3ereQdeVmbc9I3rCStyUhZtRTwKlkQq6ZWVKuEMQIdotbJ1BoYqxVI6xQqXIbqJIhaJGpQIEY5bJAKtSIWyquQMC8L6OeBXCxXwKhMXAsLEYgngbhiiAsjkEwilHCruDAPUghhGU+IcLhSFhNmXIMqqXxaOfvXC8zys8DabO1s7+y22bt+77ZZbvbe7HV2OZxdvX09jqZ6k5gnQgSwlFuDcAUwmyOpZvAqqBVlF+gXz1HPnwYdFluryWIymE16UyPebDa2tTRaWoxt1mYLrtSr5UocVemI8VKZGobVYgjhMNQQy4TycXEluM6tgwVyrc6EmW5gaqMKw1Wo4f+rU8o1uArHMa0eVekVqE6m0EpgVMjRS/htaqhFwQRXaWIqleO2dXuqWP3tHY1N7aaGNlzTYNAacVVdva6hQV+PKzUGTKWTK8x6TaMKOfrFEeqlS0yGAChkemaNcoTNbydlm6UNnV19LaYb5kYLgcVsdTluuXocjo4Op+1Gr7Xtjt3WZTb8+N0pEYMm4bPBgdLDJ0+c++evewbMbHV6/L6xx0M+75B3+OHwkOfhg4HBwT/vDP7RP+i6NXC7516fvaMJJ2YP9TUP2DDgdLg0yvpAKBKbnw8HgtPTM1OT0xP/TjwZ9/tHR8e83pFHnpH7A75Bd5PFyUPMpnqjUVEz7Gq9360Ho74xNWZC5QZYpBaLNWJIWcNHBVwZlwWzGVB1Jb+KVn2Nep1+mXbh3MUzp87SL5XfrMNG+ls9dj2Ynnpm73TV8DAhB4UEKrFQI4U0MlirkGpRqRZDNCiiVEoxmRBm0yphNqtVWzt02zriMg85DCAcDAZnAqHA3FwoPBeMECYUCM0FiM9saOZ58PnUzNMnL/y+Kd+DMc+dcY9r4p7T7+709ZuHnQYQjYSi0XAsFp2fjxGKRqOxSDgSngvPEXkiPDn7dHzG750e9Ux67/of3B6/ax93d/zdTzTrQDT6MkwkYrFINBp56aPhSISYMRsKPgs8n5idHH3x5PH06P2nXrf/ocs/YB9z23yu5kc92v8AkQyOqOn7oEwAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;iOS    md 2&apos; title=&apos;&apos; src=&apos;/static/64829644cf4f3228a817a7ab83bf5b68/0eb09/iOS_%EC%9E%85%EB%AC%B8.md_2.png&apos; srcset=&apos;/static/64829644cf4f3228a817a7ab83bf5b68/08678/iOS_%EC%9E%85%EB%AC%B8.md_2.png 190w,
/static/64829644cf4f3228a817a7ab83bf5b68/2edd7/iOS_%EC%9E%85%EB%AC%B8.md_2.png 380w,
/static/64829644cf4f3228a817a7ab83bf5b68/0eb09/iOS_%EC%9E%85%EB%AC%B8.md_2.png 500w&apos; sizes=&apos;(max-width: 500px) 100vw, 500px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;Objective-C도, BSD도, MACH도, 샌드박스도 아니었다. 최고의 진입장벽… 맥 그 자체!!!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;치트의 공격에 손가락만 빨고 있는 여린 앱들을 위해서 iOS 연구를 시작했습니다. 맥 미니도 사고, 버렸던 아이폰4도 다시 켜서는 운영체제 업데이트도 했습니다. 애플에 개발자 등록도 하고 드디어 Xcode를 켰습니다. 이제 아이폰의 속살을 좀 들여다 볼까 하는데 난관에 봉착했습니다. 아이폰 개발은 그렇게 바로 시작할 수 있는게 아니더군요. 내 아이폰에 내가 만든 코드를 넣기 위해서는 여러 수십만 단계를 더 거쳐야 한다는 사실을 알게 되었습니다. 헐~ 블로그 검색질로 따라하면서 온갖 인증서를 만들고 온갖 디바이스 정보를 넣어서 등록을 했습니다. 드디어 모든 단계를 마쳤다고 생각했는데 거기가 또 끝이 아니더군요. 맥에서 아이폰을 인식하지 못하는 아스트랄한 상황이 벌어진 것이었습니다. Objective-C를 쳐다보기도 전에 탈진할 것 같은 상황. 모든 iOS 개발자들이 존경스러워지는 순간이었습니다.&lt;/p&gt;
&lt;p&gt;장치관리자가 있긴 있는건지?! 이 상황을 어떻게 해야 하는건지 도무지 몰라서 맥 좀 사용한 친구 녀석한테 어케 해야 하냐고 물어봤더니 아이튠즈를 다시 설치하라고 하더군요. 그렇게 몇 번의 재부팅을 거치고 나서야 드디어 마법처럼 인식이 되었습니다. 아이폰4 화면에 텅 빈 Hello, World! 앱이 뜨는데 뻥 좀 보태서 예전 X 윈도우를 처음 띄우고는 X 아이콘을 마주했을 때처럼 눈물이 약간 났습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;어떤 시스템에서 동작하는 보안 솔루션을 만들기 위해서 제일 처음 검토해야 하는 것은 당연한 소리겠지만 우리가 할 수 있는 것과 할 수 없는 것을 구분하는 작업입니다. 그래야 그 시스템에서 우리가 만들 수 있는 것과 만들 수 없는 것을 명확하게 알 수 있거든요.&lt;/p&gt;
&lt;p&gt;iOS의 속살을 파헤치기 전까지 저는 그저 안드로이드와 유사한 권한 체계를 통해서 운영체제를 구성했다고 생각했습니다. 다만 안드로이드가 읽기 권한을 줬다면 iOS는 읽기 권한 마저 제거했다고 어렴풋이 추측했을 뿐이었죠. 하지만 완전 번지수를 잘못 짚었던 착각이었습니다. iOS는 단지 리눅스/BSD의 기본 권한 체계를 사용한 권한 장난질로 샌드박스를 구현하고 있는 게 아니었습니다. 진짜 샌드박스가 있는 구조더군요. 이 말은 우리가 특정 파일에 접근할 수 있는 모든 권한을 가졌다 하더라도 샌드박스에서 그 파일 접근을 불허하면 파일 열기에 실패한다는 이야기입니다. 그럼 iOS 샌드박스가 어떤 것들을 제한하는지 한 번 살펴봅시다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;iOS — the Sandbox as a jail&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Inability to break out of the app’s directory. The app effectively sees its own directory (/var/mobile/Applications/) as the root, similar to the chroot (2) system call. As a corollary, the app has no knowledge of any other installed apps, and cannot access system files.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;역주: 너희 영역 말고는 쳐다볼 엄두도 내지 마셈. 백신?! 스캐너?! 만들 수도 없고 만들 필요도 없음.&lt;/strong&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;
&lt;p&gt;Inability to access any other process on the system, even if that process is owned by the same UID. The app effectively sees itself as the only process executing on the system.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;역주: 다른 프로세스 접근?! 꿈도 꾸지 마셈. 번지수 잘못 짚었음.&lt;/strong&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;
&lt;p&gt;Inability to directly use any of the hardware devices without going through Apple’s Frameworks.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;역주: 우리가 만들어 준 것만 우리한테 허락 받고 쓰셈. 필요해도 없으면 그냥 손가락만 빨도록…&lt;/strong&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;
&lt;p&gt;Inability to dynamically generate code. The low-level implementations of the mmap (2) and mprotect (2) system calls are intentionally modified to circumvent any attempts to make writable memory pages also executable.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;역주: 난독화? 그딴거 만들고 싶어도 못만들거임. 정 만들고 싶으면 인터프리터, 트랜슬레이터 정도 고려해보셈.&lt;/strong&gt;&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;
&lt;p&gt;Inability to perform any operations but a subset of the ones allowed for the user mobile. Root permissions for an app (aside for Apple’s own) are unheard of.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;역주: 우리 혼자 짱짱맨. 서드파티가 뭔가요? 씹어먹는 건가요?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;– Mac OS X and iOS Internals, Jonathan Levin&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;말 그대로 감옥이죠. 되는 게 없다고 보는 게 맞는 것 같습니다. iOS는 아니지만 맥 OS의 샌드박스 기능이 궁금하신 분들은 &lt;a href=&quot;http://reverse.put.as/wp-content/uploads/2011/06/The-Apple-Sandbox-BHDC2011-Paper.pdf&quot;&gt;The Apple Sandbox&lt;/a&gt;를 같이 참고해 보시면 도움이 될 것 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#4&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;iOS 샌드박스를 보면서 느낀 점은 구글과는 정말 철학 자체가 다르다는 생각이었습니다. 구글의 안드로이드는 아래 크로미움 샌드박스 디자인 원칙에 나와 있는 것처럼 기존의 있는 것을 활용하자는 생각이 강합니다. 바퀴를 새로 만들지 말자는 입장이죠. 그래서 안드로이드도 권한 장난질로 얄팍하게 흉내낸 샌드박스 구조로 되어 있습니다. 물론 세세하게 TrustedBSD까지 올라가서 바퀴를 누가 만들었냐를 따지자는 것도 아니고, 옳다 그르다를 따지자는 것도, 좋다 나쁘다를 가리자는 것도 아닙니다. 그간 애플의 행보를 보자면 바퀴를 새로 만드는 것을 좋아하는 것처럼 느껴졌다는 이야깁니다. 적어도 저한테는요…&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Design principles&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do not re-invent the wheel:&lt;/strong&gt; It is tempting to extend the OS kernel with a better security model. Don’t. Let the operating system apply its security to the objects it controls. On the other hand, it is OK to create application-level objects (abstractions) that have a custom security model.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;역주: 기술 부심 부리겠다고 바퀴 따위 새로 발명하지 말자.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;– &lt;a href=&quot;http://www.chromium.org/developers/design-documents/sandbox&quot;&gt;Sandbox, The Chromium Projects&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;#5&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 280px; margin-bottom: 16px;&apos; data-url=&apos;./iOS_입문.md_3.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/9c24af181c00b4ac1e3a820c632a0972/2a48b/iOS_%EC%9E%85%EB%AC%B8.md_3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 150%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAIAAACjcKk8AAAACXBIWXMAAA7DAAAOwwHHb6hkAAADRUlEQVR42mXVx1IjQQwG4Hlf3oNnoIoD6QY3jrt7o4iLTTC2sU02mSUHB9J+0wIveHXo0qhbv6Rf6p5sampqbGxscnJydHR0fHx8enr6V5KJiYmhoaHh4eGRkRGfP5L8/JSBgYHBwcFsc3OzUqlYy+VytVqt1+vb29uNRmMzCQs7YyNJKFtbW8vLy2tra1mz2dzY2GB1Dsr+/v7x8XGtVmsmub29PTg4cJo9PEE/Pj6+J8m63W6r1Wq3290kz8/PdOvLywu7lc5OsXY6Hbv0tyQZYJCiUU5PT3d2di4uLqpJrq6uxNnb2+tZHh4e3r9I1gOmdD5Ftvf394Lc3d1JksLC07FvzqIdHh5GhUdHR/S+E33y9im5s5xnZmZ4csPT+vq6VHd3d1msR0noZ2dn/wNlCFxYWODDs5JEbSsrKzpRLBaXlpZWV1cLhYKOIBzK+fm5MAKoLgP/O8ni4qITfMpJuNGh6LZWgaCzCyMXxaou77ND1svLS/QCtnFzc/MnCSPOnp6eEG6LXVO08CNtkWdnZ+3h3DmsOqHC8L++voYIoq9J/2rmHEMnN1lYTR8irHNzc6VSqZBETAmaCJE0MndmQhWSFMMfYU7DUn8tCZ5i+ItJ2FUuqdzZADE5xMFqAwRu6KIhVi+l41i0TQmojrIz8+iQykUItn1yljZlfn4+LpAA6pdwkAIFR3naK0mUCt6qBECaBzfaTok7p7ToFl0LMsRKDIQTW0lAsPCXTuzaOjk5iauiHL38YDtuwnOS7qfEeMcA9031VyVTPTDZxpOibGwzBgTc19fXdpI+z9xZ32ToNM96Elgyj8qtCLfqRV8iuTPqFcxZtWKqk7M1XjLQ2LbylEK8Id/usz1zC14/4jFzK+SPJJ+mSkXiOwZdw3p05GkTNMatRGwMVoTVYRaV956x3gOWOytMx41b3MR4IoXtPclArSDi6aXHbOYPIGuMcTjT+ZgZQ+LcapL1JJQYYVvR6gxP8UqrB5CsojfRpHiMI22f8STHROTO4KWt5lISwWFBZI+fQZCPPJ9BBMvHxUAjVjRMDfDENLRCxZ+A7hmIKaS3kngzBM+dJWwkOMdzKZRV5BhvofTGIOhf9IVR/tHnv8G/QwCx0UBUAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;iOS    md 3&apos; title=&apos;&apos; src=&apos;/static/9c24af181c00b4ac1e3a820c632a0972/2a48b/iOS_%EC%9E%85%EB%AC%B8.md_3.png&apos; srcset=&apos;/static/9c24af181c00b4ac1e3a820c632a0972/08678/iOS_%EC%9E%85%EB%AC%B8.md_3.png 190w,
/static/9c24af181c00b4ac1e3a820c632a0972/2a48b/iOS_%EC%9E%85%EB%AC%B8.md_3.png 280w&apos; sizes=&apos;(max-width: 280px) 100vw, 280px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;XIGNCODE3의 역사가 iOS에서도 함께합니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;그닥 쉽지는 않았습니다. 맥을 새롭게 익히는 것도 Xcode에서 Objective-C++ 접착제 코드를 만드는 것도, BSD 시스템 콜을 익히는 것도요. BSD에서 시스템 프로그래밍을 해본 경험은 없고, 맥은 더더욱 새롭기에 이 생경한 시스템에 익숙해지는 것은 생각보다 쉽지 않았습니다. 물론 샌드박스도 한 몫 했지요. 여튼 그런 아주 험난한 과정을 거치긴 했지만 결국 우리가 안드로이드에서 사용했던 대다수 기법들이 거의 모두 아이폰에도 동일하게 적용할 수 있다는 사실을 확인했습니다. 이제 곧 XIGNCODE3 for iOS가 출시된다는 말이죠.&lt;/p&gt;
&lt;p&gt;이 글이 재앙이 될 프로그래머 분들을 위해서 초콜렛을 하나 준비했습니다. 애플이 굉장히 폐쇄적인 줄 알았는데 생각보다 거의 오픈 소스에 가깝더군요. BSD 라이선스라 굳이 그럴 필요도 없을 것 같은데 말입니다.&lt;/p&gt;
&lt;p&gt;xnu 커널 소스 코드&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://opensource.apple.com/source/xnu/xnu-2422.90.20/&quot;&gt;http://opensource.apple.com/source/xnu/xnu-2422.90.20/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;top 소스 코드&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://opensource.apple.com/source/top/top-89.1.2/&quot;&gt;http://opensource.apple.com/source/top/top-89.1.2/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;ps 소스 코드&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://opensource.apple.com/source/adv_cmds/adv_cmds-153/ps/&quot;&gt;http://opensource.apple.com/source/adv_cmds/adv_cmds-153/ps/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./iOS_%EC%9E%85%EB%AC%B8.md_4.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;
&lt;strong&gt;일단 폰부터 테스트 하구요. 패드는 그 다음에 하는걸로…&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;애플빠는 아닙니다. 결코 ㅋ~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#6&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 566px; margin-bottom: 16px;&apos; data-url=&apos;./iOS_입문.md_5.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/563cd5ba5c32516412b550781cca2b24/7ef45/iOS_%EC%9E%85%EB%AC%B8.md_5.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 176.8421052631579%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAjCAYAAACU9ioYAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAJjElEQVR42iWWeVDU5xnHf51p2k4yMeYwXogHciOyHAJyLodcC8JyL+susMvuCiv3IiDLLSC34Mp9KCCggAEPYoxWDV4xmkNjTJp2kqbTdpK0iZNOx0zMfPqb6fvP+/7zPu/zPN/3+5lHkIV5ok70JW1vOKb6wxysaaZYm4aXhxuennZEhwXj6W6LW6A73jIZu/ZmcfhIO/qKWoyHW3n6j7/x9eef8fPTq9w6a0Hw9XLDpItnuMPMwkcPGRg8hlktxzswFPvIZPRpqdRqlGwOUuOaYSavxER5dSMTY2OsvHedC0NHmW2s5spkO12FaoQQfx/qyoq5evsD/vjwCXXFWQTtsEW6S8LLe8rwMp6hoXuCmtwickpbOGXpYGLAQmVhLk35WZiiQhjLN9Chi6FKGYDg4+5KYvQelIUHCYpJwFss1W67DRs2WvFiXA+rS+7hXjpHZNkYycXtTIgZLcyOo1enIdstIT3AA0PabiwNBur27EJY/9sXcLJ1RurrSWxkKBJ3CY5WG9n2xjpeU1lYnW5hnX6K1QWLxJV1MmDpJC09kXxjDqa8fSyd6GBx6jCH8tNpTklAiF+/CW1QOPuV6URHhCCPiSbbw5+wzVvxyTKxU9vGWkULW2Q5ePvuRmM4QHpOLiqVipjwMMyqeFqLdHjZWKHbl4ZgCAplKFVBRXY+IVHpJMQqMIaHovG2xlyQSFuDURTBQKNZgSoplLCIRDKSUoiJiEDq6ky2gzXhG14n9LUXibLZiBC9xZpKeRS62EDyNL4og13RxEQS6WFLcW4Kf38yw9fvjzLbU8XxehOtpjxG+7pRS/1o9nWhz/4NCreu43SKJ00JuxFCE7JwisknOlJOcWUuMWKWIeI5OCSOqCAfZnsPcGO6kaa8BI4211CmSkC/L4OUzdvIsrUl0suTgj0ezOUFURDpgzBz/c/EaVpIk0aSFZNGUsUkdc3ldLRW4bkrgPjoWBaGzPz1/X7Oz4+hUyXhL/5diYMHvm4+BDo7IHNxIH6HCzHbbRFydHJadErqs9QUKZSYVGn0nThIw7BRVDONkiIzxTlaaisL0CcHUJ4dgiJSgu369fjbb0XpYU2qhxWZga4kSOwQjuwvoS4lhNb9ckz7U2g0elNXLeHAAUec3f1RqAz4BMeyzsaHtRu3s93Jk60Ou3F66QWCNr+K0tuOMn8JRf5uRDhaI5zvGWBMfH2+vZyhUjn1yRKaYt0o8LVh3ZoNNOrTCPfZif22rTjb2xESEIgxW4edgyOBosu6lf48PJrC8aRdBAf7I9y8XMNwWx7L872c7Tdz6WQDKxdaODfbib1UjyZLi7unJxJHB+y3bECjUrJ4/hYeAXuQStxZyPXmh/tGvmyTkum3A2H5ZAHj3RmMN6QyU6Hm/EAN1cYUWkrVbJRk4BTXwDbR09a+GtZ7ZGHlGMSq1zYjcfMVredMcZgbncnejGT6kxkqQbi+0Mu3X33KyvQQZ7QpWJRJmPbtZbjF/Gucvu65TNWAPKMNQ9l5yupnCEluRZJcRHRUBJlhuwh3d8TPwxk/NycCnO0RGrLDGS5LpC/HmzmdPTVBdigSfDEa1c+7Bt56dvdMO8tDfXyyPMnK2RNUGaqZfPsa+0Sb7XZx5qBsMwOxr1DtvgrZ6wLClbOnOX1ikLuX57j3zhnmFqYYnhpnaXn5+c0j/c/erhX7Oabj/eUYLk71MlvZwJO3+qlVJhOx043SaC+q/NeTtXMTCi8nhH99/z3p2kL6z33M0tlLnBkY4trVazz/+Zfnd08tPpvsPMXcsUrODCUy2dtEY9FJagqaOS36fU4Ea49RIyocRYU0gPFDRQifP/mMPWGRyORm+ocWePzoC3766Sf+/eMPz985d/LnM6dOMDQyjd5YRkGRhsqKPFTZKualUnoLdBw3ZXNon56VdhVTRXKERw8/or2xnmPdfbT1DPKc/68fnz7lQO5+qmtrGZuYJ0+toqSwiGwxmLGgkMbgEGY1OSJcFbg6BVKfEU2rOhqhONcgwnUX+9UZJEn9OdFcyd2lMa7Mz6AXLzRmplCYmYkuPYnq/fs5nKdDp9cjd/HEkqJn1GCgUx5KfpSMw0mBCIEOouTbt2O/+gU0QTZiT/w5c0jJUJaS2jwFk23VjFraaa6t5FhdAQPdtfTny7nk7MPUKkcW3N3I8HUnJ9yPXq1I7ABnCRFuDuz1eBOF3yY0EZtI9femVZXDcbWXWEYQrQo/SsK3UBFqTXvqDubzgnlvzVba7d8Uufkyr296hdLkKIZigxBc/yCwdtUfcLaywnXNGgLdPSjV6nFfvxY3O2v8PVzY5eqIVpFIQ2MzDb19qNMSSfd4hbiIl4hIcCfVx4Zz5Qa6PaUInQ1ZRMan4JNTgqs6j5SqI9R19aHMTsPO2Ql7EQI7ffwobGxhuH+Yytx8HP0C2bLtVfZG7MQUEcm0owvm4EhcNjojHL//BRcvLVE/eA7tyA2M976mq6uC7OpK3CLkIlEC8QiRIU3WkKvPpbzAgPZQFV5TVwifeYB5+l1SO8+ScGwG/8Y+hKbREUbL9lIcG0FFXj2lF+5T1dODoTCH7WK5Wx3sCI1PJioxgxhlJqFyJdLYFBIf/BPdN79iOH+H8tFBKmbmyH70X4TC474UGXeQV7cXQ203CcWVjE+28vhSM12qKPqzZdy/UE/nrU9Ju/wDxot3MN/4Cx0fP6P+q1+5NjXBTHkzI8OnaPjmFwTruCi2RsWyW5GCVByE7MN1uO0pIFmWQIsylKPFch6fO8TJDz/B0tHKsSPiHHT7PjNLH3BlcIT33prixHgPp2ZqWbr7CEF4I43IoEKaynupLj2CKqOQ31klsMY6jsHOGi5O1HN3LIv5D1aY7rYwnBxO08J1BrosLOdlUqdPoqdQRV26FI1MtN5vNsiJi9awuHCWc0tXaTXXssZGxqub48hSaemsL2JhpJwrNwe4fOc013q1XLzQLQZRM14j52RREn+abuDzG+PcnVcg/N4qCb/UNjSHb2A4dBm9aZQ3XbS8uDacqsxwLAfTaa0ooqpcTVV9CZdvLvDgQhPtQb7cHq3ku8ulfFrsyC8rZv7z5RWEwcFJSkoa0Ji6MHdPk7jPRLLCSJGpjGsLjdyZq+SWJZDFHiMVB7SMLC7zztIAE4oQbh/N4puzCpY6bHhyIZ3v7r2LcPncLNenhrm9coHF2T4WJ/vF/QSnJnr55MEK3315jcen4/n2poWlkV4GmnKZfruRmIJQse9RmLRRyGWBxKZH8OFnD/kfS+I7yTF9WAgAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;iOS    md 5&apos; title=&apos;&apos; src=&apos;/static/563cd5ba5c32516412b550781cca2b24/7ef45/iOS_%EC%9E%85%EB%AC%B8.md_5.png&apos; srcset=&apos;/static/563cd5ba5c32516412b550781cca2b24/08678/iOS_%EC%9E%85%EB%AC%B8.md_5.png 190w,
/static/563cd5ba5c32516412b550781cca2b24/2edd7/iOS_%EC%9E%85%EB%AC%B8.md_5.png 380w,
/static/563cd5ba5c32516412b550781cca2b24/7ef45/iOS_%EC%9E%85%EB%AC%B8.md_5.png 566w&apos; sizes=&apos;(max-width: 566px) 100vw, 566px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;iOS 버전도 준비 중이신가요? 그럼 더더욱 &lt;a href=&quot;http://www.wellbia.com&quot;&gt;XIGNCODE3&lt;/a&gt;죠.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;느낌아니까… ㅋ~&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 벌써 10년…]]></title><description><![CDATA[#0 2004년 8월 2…]]></description><link>https://jiniya.net/wp/archives/13369</link><guid isPermaLink="false">https://jiniya.net/wp/archives/13369</guid><pubDate>Sat, 31 May 2014 23:59:38 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;2004년 8월 28일. 병역특례의 끝이 한달여 남짓 남은 그때. 학교 선배가 서울을 왔다며 연락이 왔다. 취직이 잘 안 돼 고민하던 형이었는데 떡하니 대기업엘 붙었다는 이야기를 했다. 자축을 하자며 들떠 있던 우리는 만나서 몇 마디 하다가는 그 분을 보러 가자는 이야기를 했다. 계획도 없었고, 약속도 없었다. 그렇게 고속터미널에서는 대전행 버스를 탔다. 목적지는 KAIST. 우리의 정신적 지주였던 선배가 있던 곳이었다.&lt;/p&gt;
&lt;p&gt;깜짝 놀래켜 주자며 출동한 우리는 금새 문제에 봉착했다. KAIST를 왔지만 정작 선배가 어느 건물에서 공부하는지도, 어디에 있는지도 몰랐던 것이다. 물어물어 선배의 연구실이 있는 곳을 찾았지만 문은 잠겨 있고 선배는 연락이 닿질 않았다. 서울에서 여기까지 왔는데 정말 아스트랄한 상황. 하지만 궁하면 통한다 했던가 겨우겨우 선배 본가의 전화 번호를 알아 내서는 연락을 했다. 어머니께서 받으셨는데 집에도 연락을 잘 하지는 않는데 아마 출강 갔을 거라는 이야기를 했다. 그리고는 지금쯤 도착할거라는 이야기를 덧붙였다. 여기까지 왔는데 어쩔 수 없는 노릇. 기다려 보기로 했다. 제법 지루할만큼 시간이 지났을 때였다. 마치 TV는 사랑을 싣고에 나오는 것처럼 멀리서 선배가 걸어오는 모습을 보게 되었다. 그렇게 기적처럼 우리는 KAIST에서 만났다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;우리가 찾아간 선배는 학교에서 기인으로 통하는 형이었다. 기계과로 입학해서는 전자과를 거쳐 컴공까지 왔다. 학교 다닐때 전산실에서 우연히 떠오른 아이디어를 ACM에 제출했는데 그해 최우수 논문상을 받았다. 형은 컴공과에 와서도 취미삼아 다른과에서 개설한 양자역학 수업을 들었다. 난 그당시 양자역학이 그렇게 어려운 학문인지도 몰랐다. 가난한 고학생임에도 IEEE를 정기 구독했었다. 도서관에서 무료로 볼 수 있는데도 말이다. IEEE를 아이트리플이라고 읽는다는 것도 형이 가르쳐줬었다 ㅋㅋ~ GRE를 치러 간다는 사람이 팔짱에는 능률보카를 끼고 있었고, 더 황당한 건 그러고도 GRE에서 상당히 높은 점수를 받았다는 사실이다. 시스템 프로그래밍 수업을 같이 들을 때였다. 내가 온갖 문자열 처리 함수로 SIC/XE 어셈블러를 주먹구구식으로 만들고 있을 때 형은 파스 트리라는 신세계를 나에게 보여줬었다. 형이 테이블에 명령어를 추가하자 마법같이 명령어들이 번역됐다.&lt;/p&gt;
&lt;p&gt;컴공과 교수님 한분은 형에게 네 정체가 뭐냐는 질문을 했었고, 다른 교수님은 카멜레온 같다는 이야기를 했었다. 가난했지만 형은 자기 밥값을 털어서는 술값으로 용돈을 다 날려 책을 못사는 후배 책값을 대주는 그런 사람이었다. 말수는 적었지만 필요할때면 후배들에게 &lt;a href=&quot;http://jiniya.net/tt/592&quot;&gt;정말 멋진 이야기&lt;/a&gt;들을 한번씩 해주기도 했었다. 구도에서 공부를 할때면 종종 예쁜 여학생들이 같이 공부하자며 형에게 선물이며 추파를 던지곤 했는데 형은 절대로 넘어가는 법이 없었다. 형의 첫사랑은 고등학교 때였는데 그 여학생이 수녀가 됐다는 진짜 드라마 같은 이야기만 반복했다. 공부하는 머신이라고 놀려대면 형은 태연하게 그랬다. 대학교 1학년때 술마시고 모텔에서 수영한 적이 있었다고…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;아무 연락도 없이 찾아온 우리가 귀찮을수도 있을텐데 형은 싫은 내색 하나 없이 KAIST 구석구석을 구경시켜 주었다. 구경하면서 드라마 카이스트와는 정말 다르구나 하는 생각만 연신 하고 있었다. 형은 그 당시 KAIST에서 석사 과정으로 안테나 공부를 하고 있었다. 여기 아이들은 과고 출신이라 빠르게 졸업한 애들이 많아서 어리고 똑똑한 친구가 정말 많다는 이야기를 했다. 우리가 우스개소리로 걔들이 똑똑하긴 한데 형이 1등이죠? 했더니, 형은 아주 해맑은 얼굴로 그렇긴 하다고 했다. 진짜 말 그대로 괴짜였고, 기인이었다.&lt;/p&gt;
&lt;p&gt;그날 우리는 KAIST를 돌아다니며 정말 많은 이야기를 했었다. 그도 그럴것이 같이 간 형은 대기업에 입사해서는 이제 사회에 첫 진출을 하는터라 풍운의 꿈을 잔뜩 가지고 있었고, 난 지긋지긋한 병특이 끝나고 학교로 복학할 단꿈에 젖어 있었다. 안테나를 공부하던 선배는 얼른 석사를 마치고 미국으로 유학갈 꿈에 부풀어 있었다. 그렇게 20대의 우리는 모든 걸 가진듯 했고, 모든 걸 가질 수 있을 것 같다는 포부에 가득차 있었다. 이런 저런 이야기를 하다가 KAIST 어딘가에서 각자 독사진을 찍어주며 10년 후에는 뭘 하고 있을지 말해보자는 이야기를 했었다. 그리고 10년 후에 여기서 다시 보자며… (손발이 오그라드는 ㅋㅋㅋ)&lt;/p&gt;
&lt;p&gt;나름 장난기 충만해서는, 또 나름 정말 진지하게 우리는 이야기를 했다. 취직한 형은 입사한 그 회사의 부사장이 되겠다고 했다. 왜 사장이 아니라 부사장인지는 좀 의문이다. 아마 그 당시에 사장은 너무 멀고 부사장 정도는 될 수 있다고 자신했던 것 같다. 난 제법 구체적이었는데 20명 정도 규모의 회사에 20-30억 매출하는 그런 벤처를 창업해서 CTO를 하겠다는 이야기를 했다. 내 이야기도 좀 웃긴데 창업을 하겠다고는 CEO가 아닌 CTO를 지목했다는 점이다. 우리의 정신적 지주였던 KAIST 선배는 ARM과 같은 회사를 창업하겠다는 이야기를 했다. 형은 ARM이 칩 설계만 하고 제조를 하지 않는 점과 그 일이 굉장한 고부가가치 사업이라는 점에 집중했었다. 형이 계속 해오던 일도 칩설계 쪽이라 뭔가 잘 맞는 것 같기도 했다. 근데 선배의 이야기에서도 의문인게 칩 설계하면 INTEL을 떠올릴법 한데 ARM을 지목했다는 점이다. 물론 지금에 와서는 ARM이 INTEL을 견제할정도로 컸지만 그 당시는 잘나가는 변방의 벤처 정도였다.&lt;/p&gt;
&lt;p&gt;그렇다. 여기엔 한가지 공통점이 있었다. 우리는 모두 약간씩 마이너한 근성을 가지고 있었다는 점이다. 그래서 죽이 잘 맞았는지도 모를일이다. 어쨌든 2004년 8월 28일은 다소 그런 말도 안되는 꿈들을 이야기하고, 서로 그 정도는 할 수 있을거라며 다독거려주는 그런 따뜻한 여름 날이었다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;얼마 전 그때 같이 KAIST로 무작정 떠났던 학교 선배를 만났다. 둘이 마주 앉아서는 양꼬치를 뜯으며 이런 저런 이야기를 한다. 형은 지금까지 그때 입사한 회사를 다니고 있는데 지금은 다소 대기업에 회의적인 입장이 되었다. 거기다 최근에는 고강도의 구조조정이 시작되서 약간 사내 분위기가 살벌하다는 이야기를 했다. 요즘엔 첼로 연주에 한창 빠져 있는데 조금 있으면 연주회를 한다고 했다. 초대할테니 꼭 오라는 말을 덧붙였다. 그런 온갖 이야기 끝에 KAIST 선배 이야기가 또 올라왔다. 마주 앉은 형이 긁는다. 미쿡으로 가자고, 그때처럼 가서 놀래켜 주자고 말이다. 선배의 조언을 들으면 앞으로 10년은 또 문제 없이 헤쳐나갈 수 있을 것 같다고 했다. 그러고는 내가 가겠다면 자기는 갈 수 있다는 최후의 허세 카드를 작렬한다. 나도 질 수 없기에 알겠다고, 내가 연락처를 수소문 해보겠다며, 연락되면 바로 떠나자고 맞불을 놓았다.&lt;/p&gt;
&lt;p&gt;헤어지고 집에 돌아와서는 구글에다 KAIST 선배의 영문 이름을 입력한다. MIT 연구소 페이지로 연결됐다. 거기에 형은 내가 아는 메일 주소로 기재돼 있었다. 2-3년 전 연락이 끊긴 그 메일 주소. 다시 메일을 보내볼까? 아니면 연구소에 형의 근황을 물어볼까? 하는 생각을 하다 그냥 관두기로 했다. 메일을 제대로 쓸 수 있는 정신이 아니었다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#4&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/gMbqagfXSWw?si=LB1-hSAPwc8StGVC&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt;   &lt;/div&gt;
&lt;p&gt;&lt;strong&gt;진짜 말하는대로, 생각하는대로 되는게 인생이고 꿈이란 사실&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;10년 사이 내가 배운 한 가지&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;양꼬치 사건은 한때 호기로 남아 기억의 저편으로 넘어가고 있을 무렵이었다. 어젠가 그제 코드 여기저기를 수정하다 정말 오래된 코드가 Visual Studio에 로딩됐다. 바이너리를 변환하는 유틸리티 코드였다. 막내 녀석이 최근 해커들이 바이너리 파일에 있는 익스포트 이름과 디버그 정보에 있는 pdb 경로로 꿀을 빨고 있다는 제보를 했던 터라 그 부분을 지워버리는 코드를 추가하기 위해서 프로젝트를 열었던 것이다. 코드 수정 작업은 간단했다. 수정하고 테스트 하고 커밋을 하려는데 그 파일에 주석 처리된 함수가 마음에 걸렸다. 지워버릴까 라는 생각과 놔두자는 생각 사이의 갈등이었다. 아주 오래된 코드였지만 그때 기억이 선명하게 났기 때문이었다. 그날이 언제였는지 궁금해서 블로그를 뒤졌더니 날짜가 나왔다. &lt;a href=&quot;http://jiniya.net/tt/738&quot;&gt;2008년 11월 19일&lt;/a&gt;. 그 주석 처리된 코드는 패딩을 제거하는 코드였다. 압축 효율이 떨어져서는 만들어놓고 주석 처리를 해둔 터였다. 시간이 참 많이 흘렀다는 감상에 잠시 젖었다 결국은 그 코드를 제거하지 않고 커밋했다.&lt;/p&gt;
&lt;p&gt;몇년이 지났는지를 머리속으로 곰곰 헤아리다 다시 그 KAIST의 밤이 떠올랐다. 10년이 지났는지 안 지났는지가 궁금해진 것이다. 2004년 인거 같기도 하고 2003년인거 같기도 하고 그랬다. 그러다 그날 찍은 사진의 EXIF 정보에서 정확한 날짜와 시간을 알아냈다. 2004-08-28 21:06. 그랬다. 올해가 꼭 10년이 되는 해였다.&lt;/p&gt;
&lt;p&gt;야심한 밤에 10년 전 어린 내가 꾸었던 꿈을 마주한다. 아마 그때는 벤처, CTO 이런 단어에 허세가 가득차 있었던 건 아닐까라는 생각에 웃음이 난다. 그리곤 이내 현재 상황과 그 꿈을 오버랩 시켜본다. 2006년 9월에 창업한 회사의 CTO가 되었고, 회사 규모도 그때 내가 예측했던 범주에 다가가고 있다. 이제는 사실 그 꿈이 불가능보다는 가능이 훨씬 더 쉬운 상황이 돼 버렸구나 하는 느낌이 들었다. 신기한 사실은 그 꿈을 그때 이후로 상기한 적이 거의 없었는데 현재 상황이 그때 내가 말한 상황과 얼추 비슷한 시츄에이션이 됐다는 점이다. 시크릿의 끌어당김의 법칙 같은 말들을 개소리로 치부하면서 사는 입장인데 그 순간 만큼은 진짜 그런게 있는것도 아닐까라는 느낌이 잠시 들었다.&lt;/p&gt;
&lt;p&gt;형들도 그날 이야기들을 기억하고 있을지를 추측해본다. 그리곤 이내 우리가 진짜 다시 10년 만에 재회한다면 이번엔 무슨 꿈을 말할지를 곰곰 떠올려본다. 내가 지난 10년간 배운게 있다면 진짜 생각하는대로 말하는대로 이루어진다는 것이다. 그래서 감당하기 힘들만큼 아주 큰 꿈을 말할지 아니면 그저 소박한 꿈을 말하는 것이 좋을지가 고민됐다. 어떤 걸 말하는게 좋을지 정하진 못했지만 진짜 신중하게 말해야 겠다는 다짐은 분명히 했다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#5&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;꿈이 없는 시대라고 한다. 이제 더 이상 예전 세대의 영광은 없을 거라는 말들을 한다. 하지만 피끓는 청춘들은 지금 이 순간에도 어디에선가 우리가 10년전 그랬던 것처럼 미래를 꿈꾸며 이런 저런 이야기를 하고 있을 것 같다. 그런 청춘들에게 꼭 하나 보여주고 싶은게 있다. 회사를 같이 창업해서 지금 대표를 하고 있는 형이 몇 해전 우리가 아주 힘든 시기를 지나고 있을 때 메일로 보내준 &lt;a href=&quot;http://www.sadjunu.com/zboard/zboard.php?id=cartoon&amp;#x26;page=6&amp;#x26;sn1=&amp;#x26;divpage=1&amp;#x26;sn=off&amp;#x26;ss=on&amp;#x26;sc=on&amp;#x26;select_arrange=headnum&amp;#x26;desc=desc&amp;#x26;no=150&quot;&gt;“‘포기[抛棄]’에 관한 단상[斷想] …”&lt;/a&gt; 이라는 웹툰이다. 그 웹툰을 보면서 우린 쪽팔리지 말자는 이야기를 했었다.&lt;/p&gt;
&lt;p&gt;모든 꿈이 그렇겠지만 이루어 나가는 과정은 그리 순탄하지도 않고 녹록하지도 않을 수 밖에 없다. 그 험난한 과정을 버티기 위해서 가장 먼저 구비해야 하는 아이템이 있다면 아마 ‘인내’가 아닐까라는 생각을 해본다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#6&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;중요한 신제품을 만들어내는 것은 대개 시간이 걸리는 일이다. 프렌드피드는 6년 전의 지메일이 그랬던 것처럼 지속적인 변화와 개선을 필요로 한다. 프렌드피드는 많은 가능성을 보여주고 있지만 아직은 “성장하고 있는 중”이다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;내가 기대하는 바는 커다란 성공이라는 것이 여러 해에 걸친 노력을 요구하는 일이며, 이러한 원칙에 반하는 예는 (아직 제대로 된 수입을 올리지 못하고 있는 유튜브 정도를 제외하면) 거의 없다는 사실이다. 페이스북은 매우 빠르게 성장했지만 사실은 벌써 5년 정도가 지났다. 래리와 세르게이는 구글을 1996년에 시작했는데, 내가 1999년부터 구글에서 근무하기 시작했을 때만 해도 구글을 아는 사람은 별로 없었다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;하룻밤 사이에 성공을 거둔다는 개념은 상당히 왜곡된 생각이며, 심지어 위험하기까지 하다. 뭔가 새로운 것을 시작한다면 멀고 긴 여행을 염두에 둬야 한다. 물론 굼뜨게 행동하는 것을 변명하려는 것은 아니다. 그와 반대로 매우 빠르게 움직여야 한다. 그렇게 하지 않으면 그것은 너무나 먼 장거리 여행이라서 목적지에 도달하지 못할 수도 있다! 근검절약 정신이 중요한 것도 같은 이유에서다. 산의 중턱에 도달했을 때 먹을 것이 다 떨어져서 굶어죽기를 바라는 사람은 아무도 없기 때문이다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;– &lt;a href=&quot;http://paulbuchheit.blogspot.kr/2009/01/overnight-success-takes-long-time.html&quot;&gt;Overnight success takes a long time, Paul Buchheit&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;center&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 400px; margin-bottom: 16px;&apos; data-url=&apos;./벌써_10년.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/fefbe8c9640a3950a04a32796e9e76f4/d9f49/%EB%B2%8C%EC%8D%A8_10%EB%85%84.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 152.63157894736844%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAfCAIAAABoLHqZAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAGlElEQVR42kVV2VcaaRYvFguoKgqKvUARQQi4sLggRBREjKJJXJLuRNExKihQLEVVsSkISTRJnxg1mz1mOWbp03N6zszDvPfTnDn91g/90E/zME/zf8yHzpn5Hqrqfuf7/e69v3u/WxCfzxdcLiFYAkHL4AvgNrBaG7Cw9W4Zl/tCfuvZQvBbL+gKfAkUYChmtzlIUi9oAWAYFl1ytIEzwLhiF155usRD/3UrEKoUKoe979bc7dhKzO5wIAgqFiMGsiMcCnd1mSEIgi+J/k/BF0BXTDar3e8LuFwDq8srjxsPs1RuazOxsrJ23Te2NH8nQ+WcLg8IERyGr/IRtChA2DxcRowFJkLjk65+z+pyrLG726ztvzx9fXZ2vhXfvrv0DeCiqNzU1DSKYjweXyQSXaXZylmt0Q0P+iYnpjyugbXYHxp7tYeN5tHzFxcXn968fbOxvlHI0ulkOpvJ378X02pJHo935R/i8/jmLot3yBeZvOF0ehJbiceN5sHjxyfHJx8+Xrx7/z5DZUtMMZfJAf8ZKr++HjdbrMAtDLcBIaD+PicA34jMDHiGFxfv0PnCo4ePTk9Oz999eP/xIzCLbKmQY+gsTaWzqWQ2EplpE8L/A7uv+wKT4Rse19BqbC2VpNYfbB4ePvn06fPXH76yDFMtVViaKzJFOsvkMkxseQ3HZa2weXx+b59rbDQ4MT4xNOClUumD5sNqZffpk2cvjk+OT0/oPF0qlirFcrVY5QpFOsfuJNIatbYlGGgDV797cuIGwHuHRnYS2/Xdvf1a/eTk9I/vPzw/fpFMJhkaRF4sFrgyW2bzXD5T6DKZgdKQTCZ3uwYmQpFgYMLv9QPP+7VatVx5+uzZxecvX3/4whRotkBXSyWOLnA0x+ZZhubcLo+Ax4MM+vYB99DC3EJkYmo8EKTSFKhTba92eHD48tXrd+/O67U6W2B2S+USw5ZYrpCjgX6h8RAf4kEggFH/2HQkOj4aCvjHQKma9UZ9r370/Oj8/Pzk5atGo8kx3G6lms/m6Fy+BS5wc9FZ0N6QzWoLjAb9I4GJYOT2rQUqRQFws9E8fnH86eLixz/9uLtb29+rU+nU3K25SrFSLBTz2cLdpbuoBGmBw6Epv3d09f7q1kacSqb3d+tPDg7fvn1zBPBfvlQqVYBJpZLBcJClWSbP0hl660FcSRCQw+EAOWvVOnCrguPhxNb2dwdPQ4HQ7MwsaM+f/vxTvbafSWXobD62GisXixxQLVvIpDPtJAlJUSm4aCJYpCIIg0YhlyIKmRwRI2qlKr4Vr7WUr1ZK1eZ+o8wWC7k8k2eS8RSg67XaILFIhCIoIsa0auXSzHhm89upcY/b0e7u7TbqVVqFrNdu93lH1lZiRZYrc6UCzSR3qPhmwuv2QIhEgooRHMUQRIJKJAad1mw0mNq1U0H/wszo6IC5z2rQEBJbl5Gl6TLHZals64aks+FgCIDFOILJUQzHEAyViEUwoEDEEpCIqA2WSaUaJUGq5Q6bmWPYaqXM5GlwyeOJ7cW5WUiKoDJUqsABtuUZzB4+BIER0yZsAxkRclyjUgJTJpOFQ6GV+/d3tnf2QbfHd+7OL0CETKIlpFIJqlbgHRrM5TBxyZuLEVd0zNmuJtQKuQzHlHJUgaM8CDRka/L4zJ0+g95A6qDY3KSjs9dvMTW2ojVq/qi0/tvf//bqu73z48Z02E9qlc4+x2xkcNDZqVXKTSSQECfkCILAYBpDm7PTcgnZq9O4OzXXjO2uDpVC0iaGRToFoVMrO/U6cwdJyDERLFDIMbUSBx9KQiLHgVYwNNht6DGSeoVCAPGGrlmt7R1OW8/Og7hRgSuliArHgYhgTAvbBIgYVspQNYHbTSajTqWSoVB00LM8PeuydOtwmRbHFZjUYbXfic5c0yoRGO412+dHbN0aBJeI5FJQT4kcQx0mi7XDAAoI7cdjdlKnxTADodLKCAwW4bDIQEgtWlXUiSemHamwecyEWbREfxc5aNGPWMlAT4dJp2pXK6CXmW8yN6+vBV2TLnOgp3vO25ePum4P9AxbTNN9ZNCu7+vQOjs0PjMZ7TNuBGyVm/3UpEMKC6UiIXSWnaemBo43Zv7584fPjxJnxXu//uVZMza1OtS1NmJd9Xav+7rXvOblIfOSu2varg+ZyX5S2fp9gbqd7UTpueF//PXi37//cpq5+Toz+69ff/6+nFjxGAFmdbhzedB4z21c7G+f7dFHbOSYRec3a0kcEfCg/wB++sHLTTxatgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;   10  md 1&apos; title=&apos;&apos; src=&apos;/static/fefbe8c9640a3950a04a32796e9e76f4/d9f49/%EB%B2%8C%EC%8D%A8_10%EB%85%84.md_1.png&apos; srcset=&apos;/static/fefbe8c9640a3950a04a32796e9e76f4/08678/%EB%B2%8C%EC%8D%A8_10%EB%85%84.md_1.png 190w,
/static/fefbe8c9640a3950a04a32796e9e76f4/2edd7/%EB%B2%8C%EC%8D%A8_10%EB%85%84.md_1.png 380w,
/static/fefbe8c9640a3950a04a32796e9e76f4/d9f49/%EB%B2%8C%EC%8D%A8_10%EB%85%84.md_1.png 400w&apos; sizes=&apos;(max-width: 400px) 100vw, 400px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;불이 켜지지 않는다고 조급해 할 필요는 없다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;**모든 배선이 끝나면 불은 마법처럼 한 순간에 들어온다.**&lt;strong&gt;포기하지 않고 한땀 한땀 열심히 배선을 해야 하는 이유가 거기에 있다.&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;</content:encoded></item><item><title><![CDATA[[소고] 증명 하기…]]></title><description><![CDATA[#0 올초에 경리 면접을 볼 때였다. 대표님과 둘이 회의실에 앉았다. 2…]]></description><link>https://jiniya.net/wp/archives/13258</link><guid isPermaLink="false">https://jiniya.net/wp/archives/13258</guid><pubDate>Mon, 26 May 2014 23:59:37 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;올초에 경리 면접을 볼 때였다. 대표님과 둘이 회의실에 앉았다. 20대 중반의 대학을 갓 졸업한 파릇파릇한 여학생이 왔다. 면접 전에 이력서를 잠깐 훓어보았는데 굉장히 특이한 이력의 소유자였다. 경리를 채용하는데 무려 국립대학교 컴퓨터 공학과를 우수한 성적으로(?!) 졸업한 친구가 지원한 것이었다. 신기하다는 생각과 함께 면접을 시작했다. 사실 경리를 뽑는데 내가 물어볼 만한 질문이 크게 많지는 않다. 내가 경리 직원이 해야 하는 업무에 대해서 잘 아는 것도 아니고 추후에 업무 지시를 할 일이 많지도 않기 때문이다. 어떤 친구인지 보는 정도가 전부다. 3가지 정도 질문을 했던 것 같다. 우리 회사가 뭐하는 회사인지 아는지, 좋아하는 게임이 있는지, 컴퓨터 공학과를 졸업했는데 경리를 지원한 계기가 뭐냐 같은 것들…&lt;/p&gt;
&lt;p&gt;그렇게 면접이 이어지는데 순간 이 모든 상황이 너무 우습다는 생각이 들었다. 왜냐하면 국립대학교 컴퓨터 공학과를 우수한 성적으로 졸업하고, 해외 봉사 활동을 했으며, 토익 성적도 나쁘지 않고, 다른 곳에서 인턴 경험까지 있는 이 친구가 조그만 업체의 연봉도 그다지 높지 않은 경리 자리를 꿰차기 위해서 자신의 이력서에 비어 있는 시간 동안에는 무엇을 했는지, 왜 그런 선택을 했는지를 일일이 답하고 있었기 때문이다. 오버스펙도 이런 오버스펙이 없을텐데. 그 친구는 그 자리에 앉아서는 나름 최선을 다해서 자신의 빈틈을 답변을 통해서 메우고 있었던 것이다.&lt;/p&gt;
&lt;p&gt;그 상황이 더욱 아이러니하게 느껴졌던 이유는 그 친구를 선택할지 말지 고민하며 구름위의 심판자처럼 앉아 있는 두 사람이 불과 2-3시간 전에는 그다지 상황도 좋지 않은 중견기업 하청 업체 앞에서 똑같은 과정을 거치고 있었다는 점이다. 물론 그때는 그 두명이 온갖 것들에 대한 답변을 해주면서 자신들의 존재를 온몸으로 증명해야 하는 입장이었다. 그냥 그런 상황 자체가 너무 우습고 어처구니 없게 느껴졌다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;10년 전이었다. 부산에서 병특 자리를 알아보던 나는 부산에서 그나마 괜찮은 GIS 업체 면접실에 앉아 있었다. 임원 중에 포공 출신이 있었는지 면접 대기실엔 유달리 포공 학생들이 많았다. 다들 뭘 그리도 많이 출력해 왔는지 마치 그 많은 서류 더미들이 자신의 존재를 증명해 주기라도 하듯 신주단지 모시듯이 살펴보며 읽고 또 읽고, 외우고 또 외우고 있었다. 그리곤 종이 한 장 없이 뻘쭘하게 앉아 있는 나에게 무슨 프로젝트에 참여해 봤냐는 질문을 했다. 나는 참여해 본 프로젝트가 없다고 했다. 그러다 내 차례가 와서는 면접실로 이동했다. 면접실 그 자리… 나는 80만원 급여의 병특 자리를 얻기 위해 지난 여름 방학에 내가 캐나다 스탠리 파크에서 무얼 했는지까지 이야기를 해야 했다. 최종적으로 한명 뽑는 그 자리에 뽑혔지만, 일주일 정도 다니다 때려쳤다. 아직도 빈정거리는 말투로 질문을 하던 면접관의 인상이 선하다.&lt;/p&gt;
&lt;center&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 562px; margin-bottom: 16px;&apos; data-url=&apos;./증명_하기.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/2fe49c1eca339256fa2e2f02353ad541/a4f00/%EC%A6%9D%EB%AA%85_%ED%95%98%EA%B8%B0.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 13.684210526315791%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAIAAAAcOLh5AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAmklEQVR42hXJ2xaCIBAAQP//5zK0Tveig0jqkhFxcd21mtcp1lcoL/3F+NamBlJrQ/dK4PN9cNt7X8nubEZ458f4Lw1JDbG+QXWDWtrCDKPpn86nCZcJ6Spxf2BR80rMmx2KDYp6LgUfT6wNpkwZGV6+7WxvXRHCJ4aAODHTDyICkJSkFGlNTcNKsW7IuV/NRPOyUM7J+3eM4QskDKdaS+fI4wAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;      md 0&apos; title=&apos;&apos; src=&apos;/static/2fe49c1eca339256fa2e2f02353ad541/a4f00/%EC%A6%9D%EB%AA%85_%ED%95%98%EA%B8%B0.md_0.png&apos; srcset=&apos;/static/2fe49c1eca339256fa2e2f02353ad541/08678/%EC%A6%9D%EB%AA%85_%ED%95%98%EA%B8%B0.md_0.png 190w,
/static/2fe49c1eca339256fa2e2f02353ad541/2edd7/%EC%A6%9D%EB%AA%85_%ED%95%98%EA%B8%B0.md_0.png 380w,
/static/2fe49c1eca339256fa2e2f02353ad541/a4f00/%EC%A6%9D%EB%AA%85_%ED%95%98%EA%B8%B0.md_0.png 562w&apos; sizes=&apos;(max-width: 562px) 100vw, 562px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;글쓰다 궁금해서 찾아봤더니 그 당시 그래도 나름 부산에서 잘 나가던 그 업체, 망했다.&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;이후에 이직을 하면서 면접을 서너 번 정도 더 볼 기회가 있었다. 그 모든 면접이 전부 그렇게 유쾌한 경험은 아니었다. 자신의 존재를 스스로 증명해야 하는 일이 원래 다 그렇게 비루하고 구차한 법이다. 그러면서 자연스레 나중엔 내가 증명을 하는 입장이 아닌 시키는 입장으로 살아야겠다는 생각을 했다. 당시엔 적어도 그게 편해 보였다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;대학교 4학년 여름 방학. 지인들 덕에 무리에 끼여서 창업을 할 수 있는 기회가 생겼다. 난 그때까지만해도 적어도 이 일이 나를 증명하는 입장에서 증명을 시키는 입장으로 바꿔줄거라 믿었다. 인생을 온통 핑크빛으로 낙관하는 풋내기 20대였던 나는 아무 생각 없이 그렇게 창업에 동참했다.&lt;/p&gt;
&lt;p&gt;하지만 사업을 시작한다는 것은 그 어떤 일보다 더 많은 증명을 나에게 요구했다. 스타트업이 제품을 만든다는 자체가 정말 상상도 못할 온갖 증명을 다해야 하는 일이란 걸 미처 몰랐던 것이다. 특히나 B2B 형태의 사업은 그 정도가 더 심하다. 넌더리 날 정도로 많은 증명을 필요로 한다. 이 제품이 실질적으로 효과가 있는지, 안정적인지 등에 관한 건 증명 축에도 끼지 못한다. 3-4년 전까지만 해도 내가 가장 빈번하게 그리고 가장 충격적으로 들었던 증명 요구 중에 하나는 회사가 망하지 않는다는 걸 증명하라는 이야기였다. 사실 그걸 어떻게 증명하겠는가? 미래에 벌어질 일을 내가 신도 아닌데 어떻게 개런티한단 말인가? 정말 터무니 없는 말이고 요구다. 그런데 그런 것들을 증명하고 다독이고 해야 겨우 한 카피 제품을 팔 수 있는게 사업이고, 시장이었다.&lt;/p&gt;
&lt;p&gt;이건 여담인데 우리 이야기는 아니지만 모 업체는 외국 회사와 계약하면서 대한민국에 전쟁이 나면 어떻게 하냐는 이야기를 들었다고 한다. 그런데 더 황당한건 그 업체는 그 상황에 대한 대안을 증명함으로써 그 거래를 성사시켰다는 이야기. 이런게 B2B다 ㅠㅜ~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;그런 넌더리 나는 요구들에 대해서 때로는 증명하며, 때로는 영업력으로 뛰어 넘으며 몇 년 동안 착실히 일했다. 그 시간 동안 우리는 적어도 두개 정도 제품에 대해서 제품-시장 핏을 달성했다고 생각한다. 그말인 즉슨 그 제품들에 대해서는 더이상 과도하게 불필요한 증명 요구를 받지는 않는다는 이야기고, 제품의 기능적인 측면외의 부차적인 것들이 우리의 발목을 잡는 회수가 많이 줄었다는 의미다. 어쨌든 스스로 뭔가를 증명하지 않아도 알아주는 사람들이 있다는 것은 분명 행복한 일이다.&lt;/p&gt;
&lt;p&gt;그렇게 한동안 증명이 뭔지를 잊고 살았던 나에게 오늘 한 장의 페이퍼가 도착했다. 종이에 씌여진 질문들의 면면을 살펴본다. 종이에 씌여진 질문들이 향하는 지점은 한 곳이다. 너네 회사가 얼마나 괜찮은 회사인지, 얼마나 기술력이 있는 회사인지를 증명하라는 이야기다. 잊었던 증명을 또 해야 하는 상황이 왔구나라는 생각. 페이퍼에 소설을 몇 자 끄적이다 다짐했다. 기필코 반드시 몇 년 후에는 이 따위 증명을 다시는 요구 받지 않겠노라고…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#4&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;면접을 보던 경리, 업체 앞에서 프리젠테이션을 하던 우리, 그리고 그 수많은 제품 판매 과정들을 생각해 본다. 지긋지긋한 증명을 해야 하는 과정은 끝이 없어 보인다. 그러다 불현듯 그런 생각이 들었다. 이 지긋지긋한 증명 요구를 끊을 수 있는 유일한 길은 세상에서 요구하는 그 모든 것에 대해서 미리 다 증명을 해 놓는게 아닌가라는 생각?!&lt;/p&gt;
&lt;p&gt;… 생각의 퀀텀 점프 …&lt;/p&gt;
&lt;p&gt;많은 프로그래머들이 오픈 소스 활동을 하는 것에 회의적이다. 당장 돈이 되지 않는 일이기도 하고, 현업에 치여서 바쁜데 그런 것까지 할 시간이 있겠냐는 생각이 지배적이다. 하지만 증명이란 관점에서 바라보면 좀 다른 생각이 든다. 오픈 소스 활동을 시작하고 그것이 쌓이는 순간 적어도 우리가 칠판 앞에 서서는 내가 이 바보같은 문제를 풀 수 있는 사람인지 아닌지, 리스트에서 성이 “김”씨인 사람이 몇 명인지 헤아리는 프로그램을 작성할 수 있는 사람인지 아닌지, 멀티스레드 환경에서 동기화 처리를 할 줄 아는 사람인지 아닌지 따위를 증명하기 위해서 시간 낭비를 하지는 않아도 될 것이라는 생각말이다.&lt;/p&gt;
&lt;p&gt;github 계정을 만들고 그간 만들어 두었던 조악한 소스 코드라도 업로드를 해야겠다는 다짐을 했다. 적어도 그 작업들이 나중에 혹여나 프로그래머 신영진을 증명해야 하는 일이 생기더라도 그 귀찮은 작업들을 건너뛰게는 만들어줄거란 생각이 들어서였다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#5&lt;/strong&gt;&lt;/p&gt;
&lt;center&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 403px; margin-bottom: 16px;&apos; data-url=&apos;./증명_하기.md_1.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/487983c3744553a176f6d85301b67390/ecda3/%EC%A6%9D%EB%AA%85_%ED%95%98%EA%B8%B0.md_1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAUDBAH/xAAYAQADAQEAAAAAAAAAAAAAAAAAAQIDBP/aAAwDAQACEAMQAAABz6Iug66Yk4qY69GfR//EAB4QAQABAwUBAAAAAAAAAAAAAAEDAhETABIhIjEy/9oACAEBAAEFAoZDdlLX4EKjsEbqr6jqcR5//8QAGBEAAgMAAAAAAAAAAAAAAAAAABEBAhD/2gAIAQMBAT8BYpK5/8QAGBEAAgMAAAAAAAAAAAAAAAAAAAEQETH/2gAIAQIBAT8BKQ8j/8QAHhAAAgEDBQAAAAAAAAAAAAAAAAECEBEhIjFBgZH/2gAIAQEABj8CzZjj2R0x2HfArI49GKn/xAAcEAADAAIDAQAAAAAAAAAAAAAAAREhMXGBkaH/2gAIAQEAAT8hpxgiHdrdvDUGrc3NrsQHsJmPMIrew+8U8x2x/9oADAMBAAIAAwAAABCbEAL/xAAaEQACAgMAAAAAAAAAAAAAAAAAARARITFx/9oACAEDAQE/EMFqBbb4Uj//xAAYEQEBAAMAAAAAAAAAAAAAAAABABARMf/aAAgBAgEBPxDssx3h/8QAHBABAAMBAQEBAQAAAAAAAAAAAQARITFRgWFx/9oACAEBAAE/EKXXMHVFX5ABbYFXjLjvJHFnciUcOCx/IwNpmH2/Isol3gwVou+/2Ew5XfkIt1fgT//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;      md 1&apos; title=&apos;&apos; src=&apos;/static/487983c3744553a176f6d85301b67390/ecda3/%EC%A6%9D%EB%AA%85_%ED%95%98%EA%B8%B0.md_1.jpg&apos; srcset=&apos;/static/487983c3744553a176f6d85301b67390/8ccab/%EC%A6%9D%EB%AA%85_%ED%95%98%EA%B8%B0.md_1.jpg 190w,
/static/487983c3744553a176f6d85301b67390/ea4c8/%EC%A6%9D%EB%AA%85_%ED%95%98%EA%B8%B0.md_1.jpg 380w,
/static/487983c3744553a176f6d85301b67390/ecda3/%EC%A6%9D%EB%AA%85_%ED%95%98%EA%B8%B0.md_1.jpg 403w&apos; sizes=&apos;(max-width: 403px) 100vw, 403px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;앤디워홀은 이런 말을 했다고 한다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;유명해진다는 건 어쩌면 자신이 앞으로 해야 할 모든 증명을 한순간에 다 해버리는건 아닐까?!&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;</content:encoded></item><item><title><![CDATA[유튜브의 위엄: 구글 프로그래머가 돈을 많이 버는 이유]]></title><description><![CDATA[이것이 의미하는 것은, 복사본이 원본의 일부분이거나 느린 동작으로 실행되거나 오디오와 영상의 질을 낮춘다 해도 우리는 일치되는 것을 찾아낼 수 있다는 것입니다. 그리고 우리는 이것을 비디오가 유튜브에 등록 될 때마다 하는데 그것은 1분당 2…]]></description><link>https://jiniya.net/wp/archives/13221</link><guid isPermaLink="false">https://jiniya.net/wp/archives/13221</guid><pubDate>Wed, 21 May 2014 23:59:36 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;이것이 의미하는 것은, &lt;strong&gt;복사본이 원본의 일부분이거나 느린 동작으로 실행되거나 오디오와 영상의 질을 낮춘다 해도 우리는 일치되는 것을 찾아낼 수 있다는 것입니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;그리고 우리는 이것을 비디오가 유튜브에 등록 될 때마다 하는데 그것은 1분당 20시간 분량이 넘습니다. 이 시스템의 규모와 속도는 정말 엄청난 것입니다.&lt;/p&gt;
&lt;p&gt;우리는 겨우 비디오 몇 개를 이야기하고 있는 것이 아닙니다. 우리는 지금 매일 업로드 되는 100년 분량 이상의 비디오들을 새롭게 업로드 되는 것들 및 기존의 비디오와 비교하는 것, 우리가 보통 말하는 사이트의 모든 내용을 스캔 하는 것을 이야기하고 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;이것은 36,000명의 사람들이 36,000개의 모니터를 매일매일 휴식 시간도 없이 들여다 보고 있는 것과 마찬가지 입니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;– 유튜브는 저작권에 대하여 어떻게 생각하는가&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;정말 쩐다는 말 밖에는 안 나오네요. 구글 프로그래머는 분명히 기필코 반드시 외계인과 결탁했을 가능성이 농후합니다. 그렇지 않고서야… 이건 지구인의 기술력이 아니잖아요 ㅋㅋ~ 심심하신 분들은 &lt;a href=&quot;http://deminoth.tumblr.com/post/65396678669/jeff-dean-facts&quot;&gt;제프 딘의 진실&lt;/a&gt;도 한 번 살펴보세요. 쓰러집니다. (다시 봐도 진짜 욱기네요 ㅋㅋㅋ)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[닥터 이방인]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/13225</link><guid isPermaLink="false">https://jiniya.net/wp/archives/13225</guid><pubDate>Tue, 20 May 2014 23:59:35 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; margin-bottom: 16px;&apos; data-url=&apos;./닥터_이방인.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a7697558e465e4729eb998ad3f1e41d1/953fe/%EB%8B%A5%ED%84%B0_%EC%9D%B4%EB%B0%A9%EC%9D%B8.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGQABAAIDAAAAAAAAAAAAAAAAAAMEAQIF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAZpM7Ea4K1Qs6Il//8QAHBAAAgICAwAAAAAAAAAAAAAAAQIDEgAEISIj/9oACAEBAAEFAiGuY2dK0xJVLmTpVXyXiHXHkrmv/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwEf/8QAFREBAQAAAAAAAAAAAAAAAAAAASD/2gAIAQIBAT8BY//EAB0QAAICAQUAAAAAAAAAAAAAAAABESECEkFRYYL/2gAIAQEABj8Clt12cMjJml43FjyV3BI3vB6Ef//EABsQAQADAQEBAQAAAAAAAAAAAAEAESFBYTHx/9oACAEBAAE/IR7ImGNyGi9NZbEvm8jn4q9ZBLtHSABV5CDHp2G6PxNRT957P//aAAwDAQACAAMAAAAQ5MdC/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQAREP/aAAgBAwEBPxAdsI5//8QAGREBAAIDAAAAAAAAAAAAAAAAAQAQETFB/9oACAECAQE/EBMvCO6//8QAIBABAAICAQQDAAAAAAAAAAAAAREhADFRQWFxsYGRwf/aAAgBAQABPxCKPDUC4ThBhtRh4TzTjQES7NqvrWJmlIiSSh7w4YZAWrvx3wS3USek6+5wdxxbU7fnC8Fpe8iPbiXDJZ4I/M//2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 0&apos; title=&apos;&apos; src=&apos;/static/a7697558e465e4729eb998ad3f1e41d1/953fe/%EB%8B%A5%ED%84%B0_%EC%9D%B4%EB%B0%A9%EC%9D%B8.md_0.jpg&apos; srcset=&apos;/static/a7697558e465e4729eb998ad3f1e41d1/8ccab/%EB%8B%A5%ED%84%B0_%EC%9D%B4%EB%B0%A9%EC%9D%B8.md_0.jpg 190w,
/static/a7697558e465e4729eb998ad3f1e41d1/ea4c8/%EB%8B%A5%ED%84%B0_%EC%9D%B4%EB%B0%A9%EC%9D%B8.md_0.jpg 380w,
/static/a7697558e465e4729eb998ad3f1e41d1/953fe/%EB%8B%A5%ED%84%B0_%EC%9D%B4%EB%B0%A9%EC%9D%B8.md_0.jpg 500w&apos; sizes=&apos;(max-width: 500px) 100vw, 500px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;개연성 (蓋然性)[개ː연썽]&lt;/p&gt;
&lt;p&gt;[명사] &amp;#x3C;논리&gt; 절대적으로 확실하지 않으나 아마 그럴 것이라고 생각되는 성질.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;드라마 작가가 아직 개연성에 대해서 배우질 못한 듯. 꿈에서 생각나는 대로 써도 이거보다는 더 말이 되는 스토리가 나올것 같은 느낌?! 창작자에 대한 최소한의 존중을 하고 싶어도 이건 뭐 ㅠㅜ~ 의학, 정치, 스릴러, 액션, 히어로, 러브 스토리 다 짬뽕하고 싶었던 욕심이었을까? ㅋㅋ~&lt;/p&gt;
&lt;p&gt;하도 기가차서 드라마 작가를 찾아보기는 또 첨인듯…&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 덤프의 색깔을 찾아서…]]></title><description><![CDATA[덤프 이미지 분석은 내가 갑~ 왼쪽에 그림이 덤프 이미지입니다. 화욜날 간만에 댓글의 reinhard, zoops 횽들을 만나서 술을 한 잔 했습니다. 그러면서 이런저런 이야기를 하는데 reinhard…]]></description><link>https://jiniya.net/wp/archives/13168</link><guid isPermaLink="false">https://jiniya.net/wp/archives/13168</guid><pubDate>Thu, 15 May 2014 23:59:34 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 410px; margin-bottom: 16px;&apos; data-url=&apos;./덤프의_색깔을_찾아서.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/3545fb8df5eadc20714c2e9849d9954b/cb1d0/%EB%8D%A4%ED%94%84%EC%9D%98_%EC%83%89%EA%B9%94%EC%9D%84_%EC%B0%BE%EC%95%84%EC%84%9C.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 66.84210526315789%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAA7DAAAOwwHHb6hkAAADEklEQVR42hXOWU8TawDG8RcTL1xuqkHF6AUV3Fq2VC0UBUVxoXSjrVVbZun0nc7WmWmn0w0UitKWKlKgliBioKDR5ByPhyPXR+M5X8GvoLEFK5po9ALH5Jfn7kn+gOon/W7S74F+NyQVHsigEL/KpIcdlcqWb9+rEvw5SJCZuDw/KGdILMHBLOtOQ2eWdgKcwDAfQkCUIFAIvRASkETd132ZlOXDB7BWBk9n8WA8nBsKRTBnxG5jb2B+kzGF2CcZKxBoVhLFkMCLFCfQDM+yAkuzPmlyzLW+Dj5vgL+L/onJAuLuOVK/3aDf12mo1rc23w2SKW83iAlyIhiNiXJUkCNCOBqUY2FJZOKFKaT0EZQq4O0zm5ycPaUzNGm393Tvb9erNHU1D2VL2tsBJCEUEiVJkGRRlkOyFJQioRBPx6dzSLkM1tbB63+YMT7WoTvZbtjZ3rqrQbOtVVc7G8GeDngBQ1CMj2J9FAdplqQ4P8VTNETFe5mr65+qlPKVv9L/v1phb/RaupudpjbjlWaTsWuQhE/iJBCwAI9xPBLgUC6AcRzGcjjtuy6Oj7gqFbCxAVZfJuanH82MBV4tXPtzwb36HFnJOcZpvED5gK3a1FdtVtgVe8x9e82Oml7jDlvi8tmPpd/ZL4v9AiHO3c//uzhxJx64OxpdDqJ/JLkx4TboqzUrHLUWp9rqUFvtaour3mrcZ49ZO5Xnxmew9JjIDhBLqcDySGzYj2Rx54gHu4N5KJgEDSqNolGlVVar0mhUxxt3H1Nv1V7rUn/5WvXjO7iXp4ozcD4CFyLscjLwZIifCnlSuE3GJNBW19R2qMlQ36w/1Nhy4KihrqXz2AndwZPQcaSkZK+BFzPWqSE8iHtWM+4XoqtI9YyS3pTHlg8zoPeS2XLFeqHz0khi+Mv7cvHB3K2glE/PTo/3l8rgUwW8WzTdhOdRu+2/PFJI8rm4n+6xZPn+MArB6RZ9h85w4nBjXIr+3NxcXF4aGEyMT8yNDvX9/AE2N0F2QBcNc7nb4TcF9CbmEk1nLmtrvI4u+8WOXzq4R0lSKyOaAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;            md 2&apos; title=&apos;&apos; src=&apos;/static/3545fb8df5eadc20714c2e9849d9954b/cb1d0/%EB%8D%A4%ED%94%84%EC%9D%98_%EC%83%89%EA%B9%94%EC%9D%84_%EC%B0%BE%EC%95%84%EC%84%9C.md_2.png&apos; srcset=&apos;/static/3545fb8df5eadc20714c2e9849d9954b/08678/%EB%8D%A4%ED%94%84%EC%9D%98_%EC%83%89%EA%B9%94%EC%9D%84_%EC%B0%BE%EC%95%84%EC%84%9C.md_2.png 190w,
/static/3545fb8df5eadc20714c2e9849d9954b/2edd7/%EB%8D%A4%ED%94%84%EC%9D%98_%EC%83%89%EA%B9%94%EC%9D%84_%EC%B0%BE%EC%95%84%EC%84%9C.md_2.png 380w,
/static/3545fb8df5eadc20714c2e9849d9954b/cb1d0/%EB%8D%A4%ED%94%84%EC%9D%98_%EC%83%89%EA%B9%94%EC%9D%84_%EC%B0%BE%EC%95%84%EC%84%9C.md_2.png 410w&apos; sizes=&apos;(max-width: 410px) 100vw, 410px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;덤프 이미지 분석은 내가 갑~ 왼쪽에 그림이 덤프 이미지입니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;화욜날 간만에 &lt;a href=&quot;http://www.jiniya.net/wp/archives/13045&quot;&gt;댓글의 reinhard, zoops 횽들을&lt;/a&gt; 만나서 술을 한 잔 했습니다. 그러면서 이런저런 이야기를 하는데 reinhard 님께서 드미트리옹께서 크래시 덤프의 이미지를 만들어서 재미를 보고 계셨다는 이야기를 해주시더군요. 제가 또 드미트리옹과 페친 아니겠습니까? 드미트리옹의 책도 다 샀는데 눈 뜬 장님이었더군요. 책 표지 자체가 크래시 덤프 이미지였다는 사실을 알고는 충격과 공포에 빠졌습니다. 역시 사람은 아는만큼 보인다는 옛 이야기가 다 헛말이 아니었습니다. 핡~&lt;/p&gt;
&lt;p&gt;그래서 저도 해봤습니다. 제가 가진 게임 덤프 파일 중에 하나를 돌려보았지요. 가운데 텅 빈 공간이 웬지 무한한 우주 공간에서 찰나의 순간을 살다가는 인간이라는 존재의 한없는 고독함을 나타내 주고 있는듯한 느낌입니다 ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; margin-bottom: 16px;&apos; data-url=&apos;./덤프의_색깔을_찾아서.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/c81d4930175d620c9bf2298f7e9c14f3/b0db9/%EB%8D%A4%ED%94%84%EC%9D%98_%EC%83%89%EA%B9%94%EC%9D%84_%EC%B0%BE%EC%95%84%EC%84%9C.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAAsSAAALEgHS3X78AAACK0lEQVR42qWU35KaMBjF4/au+hargm7v1EfoCrSuBZypuEIArYJ/rivofVXQfeWeL4F1d6a96PSXL8nJycGRmRBmWdbItkejkWla34BJWJaNbqJhpMEyzXLDtq0SFobBbDabC2hGnwk5m4UhqcVi8QPM5yHWKJFGKAgC5roe59z1vClwpx4n4Xme7/sYOcfguQiJESAjki6eYtvNFqxXa/z6Ko63m00cRRDRMorjeLlYRstlDBlF69UK/ipabdYbSCRZmqRJkhz26T5NoTHuE4jkkO4P+wOc3W5H/ecu2YkoiR3F0pT5BP5/4HM0KQOaQ7RC00YQcO7jNWjLLwZ6mEsrDKTNaS1DYl28vC/e3pOI3/OZc2OMmgiewWQyfb7hTJzvYDweO9Qp6zhsOBw+DZ4GX8GXwWDw9MrwjURGLLE9oFARY7VatVqtScq59rquvufj+yWrVCp3gspfwA7Vn7bY3Y0P/1KUZ/9F+4H4JGgLWq1ikqhq64FChdd+AzudTnmeXwVZlkHnl/ycZefzOc/yy+XyIri+XKGxifzxF3E8HhkX4IspDpM8HMXB4vKc0Bnhvlt8Gq48LDhIrNvt9nrdbqdDBUF0ekRpFg4tO9IRAg5rKK16U6031PuGUm8qDUVtqsKhUu5R5JOJJKqptusK7UKzvmb0dZ1K0zVd1w1DM+AYmm7AedS0xz5VvxRwPvf7csnErULXELAJumhGpbALSzTTkh7dQML5DWXiR4dGFqCEAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;            md 1&apos; title=&apos;&apos; src=&apos;/static/c81d4930175d620c9bf2298f7e9c14f3/b0db9/%EB%8D%A4%ED%94%84%EC%9D%98_%EC%83%89%EA%B9%94%EC%9D%84_%EC%B0%BE%EC%95%84%EC%84%9C.md_1.png&apos; srcset=&apos;/static/c81d4930175d620c9bf2298f7e9c14f3/08678/%EB%8D%A4%ED%94%84%EC%9D%98_%EC%83%89%EA%B9%94%EC%9D%84_%EC%B0%BE%EC%95%84%EC%84%9C.md_1.png 190w,
/static/c81d4930175d620c9bf2298f7e9c14f3/2edd7/%EB%8D%A4%ED%94%84%EC%9D%98_%EC%83%89%EA%B9%94%EC%9D%84_%EC%B0%BE%EC%95%84%EC%84%9C.md_1.png 380w,
/static/c81d4930175d620c9bf2298f7e9c14f3/b0db9/%EB%8D%A4%ED%94%84%EC%9D%98_%EC%83%89%EA%B9%94%EC%9D%84_%EC%B0%BE%EC%95%84%EC%84%9C.md_1.png 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;한 게임의 크래시 덤프&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;글을 보고는 바이너리를 이미지로 변환을 어떻게 하시는지 궁금해 하시는 분들이 계시는 듯 하여 소스 코드도 같이 올려드립니다. 지난 번에 작업한 스크립트 파일은 앞에 비트맵 헤더 붙이고 귀찮아서 뒤에다 0으로 전부 패딩을 넣었었는데요, 이번 버전은 비트맵 의도대로 중간 중간에 패딩을 넣도록 한 버전입니다. bin2img.py input.tar output.bmp 하시면 됩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;py&quot;&gt;&lt;pre class=&quot;language-py&quot;&gt;&lt;code class=&quot;language-py&quot;&gt;&lt;span class=&quot;token triple-quoted-string string&quot;&gt;&apos;&apos;&apos;

	Copyright 2014 YoungJin Shin &amp;lt;codewiz@gmail.com&gt;

	bin2img.py input.tar output.bmp

&apos;&apos;&apos;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; math
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; struct
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; sys

BPP &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;24&lt;/span&gt;
BPP_BYTES &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; BPP &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;
BMP_HDR_SIZE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;14&lt;/span&gt;
DIB_HDR_SIZE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;40&lt;/span&gt;
DPI &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2835&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetImageFileSize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sz&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
	px &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ceil&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sz &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BPP_BYTES&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	wpx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ceil&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sqrt&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;px&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

	xbytes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;floor&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wpx &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; BPP &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;32.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wpx &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; xbytes&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; wpx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; wpx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; xbytes&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetBmpHeader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sz&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; w&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; h&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; struct&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pack&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;=BBLHHLLLLHHLLLLLL&apos;&lt;/span&gt;
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x42&lt;/span&gt;
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x4d&lt;/span&gt;
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sz &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; BMP_HDR_SIZE &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; DIB_HDR_SIZE
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; BMP_HDR_SIZE &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; DIB_HDR_SIZE
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DIB_HDR_SIZE
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; w
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; h
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; BPP 
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sz
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DPI
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DPI
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetPadBuffer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sz&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
	pad &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sz&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
		pad &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; struct&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pack&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;=B&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; pad

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BinaryToImage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bin_path&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; img_path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
	inf &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bin_path&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;rb&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token builtin&quot;&gt;buffer&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; inf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;read&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	inf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;close&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

	buffer_size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

	fsz&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; w&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; h&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; wbytes_pad &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; GetImageFileSize&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer_size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

	hdr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; GetBmpHeader&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fsz&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; w&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; h&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

	outf &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;img_path&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;wb&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	outf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;write&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hdr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

	wbytes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; w &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; BPP_BYTES
	pad_size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; wbytes_pad &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; wbytes

	pos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;h&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
		remain &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; buffer_size &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; pos
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; remain &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; wbytes&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
			pad_size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; wbytes_pad &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; remain

		outf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;write&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;pos &lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; pos &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; wbytes&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

		outf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;write&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;GetPadBuffer&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pad_size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		
		pos &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; wbytes

	outf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;close&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; __name__ &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;__main__&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
	BinaryToImage&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sys&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;argv&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sys&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;argv&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[[소고] 당신의 코드는 무슨 색깔인가요?]]></title><description><![CDATA[언젠가 학교 선배가 자바스크립트 코드 컨테스트에서 누군가가 코드 바이트를 줄이기 위해서 PNG…]]></description><link>https://jiniya.net/wp/archives/13045</link><guid isPermaLink="false">https://jiniya.net/wp/archives/13045</guid><pubDate>Sat, 10 May 2014 23:59:33 GMT</pubDate><content:encoded>&lt;p&gt;언젠가 학교 선배가 자바스크립트 코드 컨테스트에서 누군가가 코드 바이트를 줄이기 위해서 PNG에다 코드를 인코딩해서 사용했다는 이야기를 했습니다. 문득 그 이야기를 곱씹다가 내가 만든 코드는 무슨 색깔일까 하는 생각이 들더군요. 이 거대한 코드를 컬러로 바꾸면 무슨 그림이 나올까, 하는 생각. 그래서 한 번 해봤습니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 320px; margin-bottom: 16px;&apos; data-url=&apos;./당신의_코드는_무슨_색깔인가요.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/8815cdce7b6afe0473e320a96a750c63/dd4a7/%EB%8B%B9%EC%8B%A0%EC%9D%98_%EC%BD%94%EB%93%9C%EB%8A%94_%EB%AC%B4%EC%8A%A8_%EC%83%89%EA%B9%94%EC%9D%B8%EA%B0%80%EC%9A%94.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 99.47368421052632%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAAsSAAALEgHS3X78AAAB20lEQVR42l2TzW7iQBCE+2WIOWG8jwBE/BxxkNY2e1iQwD+YSDEEOyecJ09V9zg4+Wh6aqqaHCYzMvJ9f+z/CYLxOEBHBdQ+CwkI2DA18kdjlTpA5KnD81DecDiEHgwGusPWo//kDTWy1GMxlTiKkiSO9cu+hcAKtokFydZQa5u4NImiSIoizwty6lGcihyfE/1csxIfDUoboFlIrqRp5kiz9HjUQjseDgd02DaWZ7lp/BRN2vZTcQvW9n5v7y1Bv/9A3damUdI0zcdH09RNXePbUNZaTX273egqDX06NFVjQHa73V7rF/v9XqN9z3DQ+09Lrtf3a48fG+Vi7fIYeO8C4WG68+6ww7TzL7X03Lv/RKFFRyaTyXQ6nU1nAEuHKjpmzRzPz0gmHbJcLpZ9Vg85n88XD+igf29Wq5XgazYm+38EEy5yu4VbTGhJGIYvIVmv15Dawxdls9l0oQ6wwWRkPxC9XrhOqbs+WcYD1Mukp0b5uLR6WrmbyAX3+y+qBzaREce28K300X0UR7K158MHFOs8Vz6gf/aqYr4nm0jcg7M3Bi38bwO9B7+o6F/cwOUhLKmqSiCq6g2o46JKedP+7TnRJZByPr+eQVmiwNlB8eoSZrolmpUmvgCEM7nxamUqpwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                 md 0&apos; title=&apos;&apos; src=&apos;/static/8815cdce7b6afe0473e320a96a750c63/dd4a7/%EB%8B%B9%EC%8B%A0%EC%9D%98_%EC%BD%94%EB%93%9C%EB%8A%94_%EB%AC%B4%EC%8A%A8_%EC%83%89%EA%B9%94%EC%9D%B8%EA%B0%80%EC%9A%94.md_0.png&apos; srcset=&apos;/static/8815cdce7b6afe0473e320a96a750c63/08678/%EB%8B%B9%EC%8B%A0%EC%9D%98_%EC%BD%94%EB%93%9C%EB%8A%94_%EB%AC%B4%EC%8A%A8_%EC%83%89%EA%B9%94%EC%9D%B8%EA%B0%80%EC%9A%94.md_0.png 190w,
/static/8815cdce7b6afe0473e320a96a750c63/dd4a7/%EB%8B%B9%EC%8B%A0%EC%9D%98_%EC%BD%94%EB%93%9C%EB%8A%94_%EB%AC%B4%EC%8A%A8_%EC%83%89%EA%B9%94%EC%9D%B8%EA%B0%80%EC%9A%94.md_0.png 320w&apos; sizes=&apos;(max-width: 320px) 100vw, 320px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;XIGNCODE3 250M&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;레거시 코드를 제외한 XIGNCODE3 전체 소스 트리를 이미지로 변환한 겁니다. 어떤가요? 처음에 결과를 보고는 적잖게 당황했습니다. 내가 만든 코드가 이렇게 칙칙한 회색 빛깔이었다늬, 이러면서 말이죠. 결과를 보기 전까지 전 총쳔연색의 아주 아름다운 뭔가가 나타날거라 상상했거든요. 늘 상상과 현실은 거리가 있게 마련이죠 ㅋㅋ~ 그래도 뭔가 가로 줄무늬가 나이테 같기도 하고 퇴적암의 퇴적층 같기도 한 그런 느낌도 들긴 했습니다. 풉, 맞습니다. 우리만 당하고 있을 순 없죠. 다른 프로젝트 소스 트리에 대해서도 스크립트를 돌려봤습니다. ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 320px; margin-bottom: 16px;&apos; data-url=&apos;./당신의_코드는_무슨_색깔인가요.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/4aabe7519f97a453c9c6e976d96396cb/dd4a7/%EB%8B%B9%EC%8B%A0%EC%9D%98_%EC%BD%94%EB%93%9C%EB%8A%94_%EB%AC%B4%EC%8A%A8_%EC%83%89%EA%B9%94%EC%9D%B8%EA%B0%80%EC%9A%94.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 98.94736842105263%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAAsSAAALEgHS3X78AAABd0lEQVR42mVUAbaEIAjkWn+7wO+bbJrW/W/ygQF1385uhgOmDRDtgj8g/S1Gwgy+JLPhnaAsYM6cBw5BBs2D0mElD11BRzoCKdkgWyxUcEm3RzBIATmVsNTMZN604IjLkfFkevNbYMPJdhsM4zrFlsMqe55wIYKptdZ7b4bruqpc7WqB4eqtY6xVQ4SXOGJDDjFCDxUk+ENuuhF7CMSTP0FeX8eL6KGvksyRgTwMAb0UP68vbNtrmxNn1NgcwpC+B9AmLgXeObx92tBCQNPb+/3cz/Pc920ThXtb69/69UaoqE8kSWQk1ZPub4tSO7wISZImnIkSgnFGtU4Syn+WMJvasy4zSifPx69FOjbM2cuPBje9az/w0i3xFGRZa7vUUg3F8G1L1U3SPcWmlaoHfS4z8goGJVmXleAJpx8fBHS+fyDEsK+BjPvvHpH7iKHTmuU8cX+XYcvPHKVYK3nUiFSW5DzFTojs1yguOyd6zJvNJWiXRhvzD3Qea+6qlLSLAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                 md 1&apos; title=&apos;&apos; src=&apos;/static/4aabe7519f97a453c9c6e976d96396cb/dd4a7/%EB%8B%B9%EC%8B%A0%EC%9D%98_%EC%BD%94%EB%93%9C%EB%8A%94_%EB%AC%B4%EC%8A%A8_%EC%83%89%EA%B9%94%EC%9D%B8%EA%B0%80%EC%9A%94.md_1.png&apos; srcset=&apos;/static/4aabe7519f97a453c9c6e976d96396cb/08678/%EB%8B%B9%EC%8B%A0%EC%9D%98_%EC%BD%94%EB%93%9C%EB%8A%94_%EB%AC%B4%EC%8A%A8_%EC%83%89%EA%B9%94%EC%9D%B8%EA%B0%80%EC%9A%94.md_1.png 190w,
/static/4aabe7519f97a453c9c6e976d96396cb/dd4a7/%EB%8B%B9%EC%8B%A0%EC%9D%98_%EC%BD%94%EB%93%9C%EB%8A%94_%EB%AC%B4%EC%8A%A8_%EC%83%89%EA%B9%94%EC%9D%B8%EA%B0%80%EC%9A%94.md_1.png 320w&apos; sizes=&apos;(max-width: 320px) 100vw, 320px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;boost 150M&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 320px; margin-bottom: 16px;&apos; data-url=&apos;./당신의_코드는_무슨_색깔인가요.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/0e11d2c0da1e6d42dc8d6bcb05a9fc56/dd4a7/%EB%8B%B9%EC%8B%A0%EC%9D%98_%EC%BD%94%EB%93%9C%EB%8A%94_%EB%AC%B4%EC%8A%A8_%EC%83%89%EA%B9%94%EC%9D%B8%EA%B0%80%EC%9A%94.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 99.47368421052632%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAAsSAAALEgHS3X78AAABCElEQVR42qWT627DIAyFz5OVSVnTBEKqKZc/I3n/x5gvkBJWpqn94mD72JVqAuhfpuswn5nmaZrlEaIoflkWiR8iLONsBcfUdIdt33YhOgqE6BJFGljawVEI9KaWXWtiXNCGki18h6B/2/ZduR1WHjWq/6qy4eMN0DTNJ9GI0UKpKho/Q3V6YYy5FJgLi6YKNWgVt0Qr/BE/xDYC+lyDG9gEd4LSweb5kDolxnh/mRGuiq2pRwHrsqrR0dUl45SvQoxEAU9/7EDOLd+acv/oJxRj/Bf+qYqvN0C62Ay546KXN19Pf5ef7h7ZUFdFo1aDJIp+TX3qWoze00C8+DiY974YUQWfOGb+AR5YY/gHRX8aAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                 md 2&apos; title=&apos;&apos; src=&apos;/static/0e11d2c0da1e6d42dc8d6bcb05a9fc56/dd4a7/%EB%8B%B9%EC%8B%A0%EC%9D%98_%EC%BD%94%EB%93%9C%EB%8A%94_%EB%AC%B4%EC%8A%A8_%EC%83%89%EA%B9%94%EC%9D%B8%EA%B0%80%EC%9A%94.md_2.png&apos; srcset=&apos;/static/0e11d2c0da1e6d42dc8d6bcb05a9fc56/08678/%EB%8B%B9%EC%8B%A0%EC%9D%98_%EC%BD%94%EB%93%9C%EB%8A%94_%EB%AC%B4%EC%8A%A8_%EC%83%89%EA%B9%94%EC%9D%B8%EA%B0%80%EC%9A%94.md_2.png 190w,
/static/0e11d2c0da1e6d42dc8d6bcb05a9fc56/dd4a7/%EB%8B%B9%EC%8B%A0%EC%9D%98_%EC%BD%94%EB%93%9C%EB%8A%94_%EB%AC%B4%EC%8A%A8_%EC%83%89%EA%B9%94%EC%9D%B8%EA%B0%80%EC%9A%94.md_2.png 320w&apos; sizes=&apos;(max-width: 320px) 100vw, 320px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;chromium 1.5G&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;XIGNCODE3 프로젝트는 그래도 밝은 편이었습니다. 부스트랑 크로미움 소스 코드에 비하면 말이죠 ㅋㅋㅋ~ 이 그림들을 보고 있노라뉘 이제부터 소스 코드에 대해서는 청사진(blue print)이 아니라 흑사진(black print)이라는 표현을 써야 할지도 모르겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 320px; margin-bottom: 16px;&apos; data-url=&apos;./당신의_코드는_무슨_색깔인가요.md_3.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/fda27d980dd83172332668f974e82094/dd4a7/%EB%8B%B9%EC%8B%A0%EC%9D%98_%EC%BD%94%EB%93%9C%EB%8A%94_%EB%AC%B4%EC%8A%A8_%EC%83%89%EA%B9%94%EC%9D%B8%EA%B0%80%EC%9A%94.md_3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAEaElEQVR42gXBWW/aBgAAYP+Gvk3TpElVD6naemyporVKaQKhJkAo92GMwcY3BoMPjLE5CsYcJdwhNCEsXZImitJ1q6p27cMe97P2fUDkRXGjLL54dHn6WC/9CuMBXU2HR5LAmbpvH1UK7PAd2pNQ7g0uL7ucFj6cRfYK8ubHU4f4ErDfhtxCRVM54dZgRLjMXpUm6XCMV8bva8XesEit5As3jD0POpoecD3l2IAwGqs6BnzBFgZSbXmf6s7VNDQzqB4dpRWqARbKN3k8H20XrjBtjzyQB+rbM7awn3afM+IHT1MMbiSPmmIdWIzqgW6GGpi+swwhoK9J51gBOcbB+J4ESv44tOZMhpZXPvWSWReU/B6X8TMfN0FPAIn5DWDHwW7r8fSrpJEohpg/1eTRYk20qfQWIuMQO7AK8KssHPFJC0/DCPDBggDXpMV6JYKyt12AeiffZf3H7DVzry6CAcEaVRLxAuXM70yf0RXtxl6zOkWpsaj9MAhSJT8XstYtO7l2pOE37UC9eMUzemPDQO7rma301BSbeTeXbpUyYM98EG8O+uKycqwRB1labxIoX4oz9BrPuc7d2gQYPdWd7b5C7lUzJllN6Ctx0WWiFcu998NikeTJKT/Xmb779OS/0jFs0Z1hNoJn2a3uuRyVgA6N6TZZBzXf3NLiYIWXoXpPoxg3N0o6ah+xxREFKbtOUJqky6V2viEmsFqnnemfMSgN/KiVrETAFge3R57ybpQINTyUjORHTHRAxw/mZhbubt+6f/f7Z5vYmkzZtslr7+lqGCX3U9dh4E7psT2ABF07F/agQNVPKq0I9S8G1YxCxmsJP40m7yJV/L6FiFhtjdB3hWx2hiqPwIfIfiBgBTLRZl54ajyRx1iZuLAQrV2cy1tD02Iad7o9aMwVy2cyxZu+nM2V01I5PivQRdK7FnP9hPwMvCvm/j4ajnjMti+teJGnlmdErRcdseoBPCI/D+0sW6JfRwqfvjU61/Wl0JvCny6b2Zk6lNyA8tBrVozaYFDJ1VrU/BV2/Ha9DLWRB38xqOc3AkS6A56sOiowUW+Txi7Ke6MXmjrvNhuoBiQUMyjY6UILzGLWKTomPXERgys+dlXtew9HZn9AZ9OIDqfIQ/il6a1KkH9yqHiXdfKzAHihoORdnl18PZTqjaBre8Knv06+yPJYwsO1BeY6YxX+Cfh74pc8hHxgEO1dKTPH32YdnVhxCoSMlWIOkTfnG+XPArWptOMxTTlPMhMLho/VvDSTdrrb+FwljQupdAWVD1z9hCKh51PkOAcE5MbIrMpvYsKG50SItVQOjZsSd4Jh3KPNmKEoeFMbEZqmNzopcvRcPTF6ry9F9arKdSZAfULWHc14jPhD5feas1my3MJxJ43HwQQoBpa/O/DCVqX0jcc/ZFO9FuLuzdHhEl2041rAABizg8zy7Vb/eUe7UTOgWTJkqdrs/6Q6k91culmkr4peKQ7hKS8rVOdgoC2dntS/LHrWVTL6P1Z1EUNS9QxtAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                 md 3&apos; title=&apos;&apos; src=&apos;/static/fda27d980dd83172332668f974e82094/dd4a7/%EB%8B%B9%EC%8B%A0%EC%9D%98_%EC%BD%94%EB%93%9C%EB%8A%94_%EB%AC%B4%EC%8A%A8_%EC%83%89%EA%B9%94%EC%9D%B8%EA%B0%80%EC%9A%94.md_3.png&apos; srcset=&apos;/static/fda27d980dd83172332668f974e82094/08678/%EB%8B%B9%EC%8B%A0%EC%9D%98_%EC%BD%94%EB%93%9C%EB%8A%94_%EB%AC%B4%EC%8A%A8_%EC%83%89%EA%B9%94%EC%9D%B8%EA%B0%80%EC%9A%94.md_3.png 190w,
/static/fda27d980dd83172332668f974e82094/dd4a7/%EB%8B%B9%EC%8B%A0%EC%9D%98_%EC%BD%94%EB%93%9C%EB%8A%94_%EB%AC%B4%EC%8A%A8_%EC%83%89%EA%B9%94%EC%9D%B8%EA%B0%80%EC%9A%94.md_3.png 320w&apos; sizes=&apos;(max-width: 320px) 100vw, 320px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;XIGNCODE3 250M&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;우중충한 그림들에 다소 충격을 받았을 여러분을 위해서 조금 희망적인 이야기가 필요할지도 모르겠습니다. 사실 회색빛깔이 전부는 아닙니다. 그 회색빛깔 사이로 무한 확대 작업을 해보면 실질적으로 그 내부에는 이와 같이 총천연색으로 이루어져 있거든요. 이쯤에서 채플린옹의 이야기를 한번 떠올려주면 되겠습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Life is a tragedy when seen in close-up, but a comedy in long-shot.&lt;/p&gt;
&lt;p&gt;인생은 가까이서 보면 비극이지만 멀리서 보면 희극이다.&lt;/p&gt;
&lt;p&gt;– Charles Chaplin&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 118px; margin-bottom: 16px;&apos; data-url=&apos;./당신의_코드는_무슨_색깔인가요.md_4.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/40087a931af132a42d65106251c374dd/48743/%EB%8B%B9%EC%8B%A0%EC%9D%98_%EC%BD%94%EB%93%9C%EB%8A%94_%EB%AC%B4%EC%8A%A8_%EC%83%89%EA%B9%94%EC%9D%B8%EA%B0%80%EC%9A%94.md_4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 55.93220338983051%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABqUlEQVR42hWRa3IcIQyE5z6plCv2egAJvQXMeNe+/3GCfyKpqe6vj8DuiJSZMFA9U75GdykEc61nME+7SL1+ftS3Vt4+sIA1ON/Pt8ff46NIqG/RIiWchQw6P7pN1EBpvaT35KZB+hr+j6HxFmxF4XFkD4ocZt71GibufA148PqK9ZR8+TC/7bnGen1dt/gQoxp+rWvEcRp6u7oqJfr2C6IOJW1FiEVjDqspKuYmOkf4UnYhclc4yjblJVqNcOSQNbau42mF95ESQ4Fku4cQ/PAyjqJYexFjOxq4RDx9Juu8t8fJks3BkfQhztJ1pd4/qUZW99ZYKzCngR3wjlKaZqknNKIJGxLt2XCSLrALGJNZm9s7baeNdeNppoo6jz+ViXqTM3a0j5NMB6QAWxeFDX3BXpvvgm65vGID+FQwpq85DwLuO36uyGnS7wi0sBha0HZDztwoXGpxh9ivXoCR7uXT8vBea20Vf9lsM9l3zluXAzRoQifo2TbADWTiMtq/yndeSCQTjrTczXL3pvBymZo4GyoOte94DreA3kWmsFVEq8LUH78DuOZ/rQGi+WRcyMAAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                 md 4&apos; title=&apos;&apos; src=&apos;/static/40087a931af132a42d65106251c374dd/48743/%EB%8B%B9%EC%8B%A0%EC%9D%98_%EC%BD%94%EB%93%9C%EB%8A%94_%EB%AC%B4%EC%8A%A8_%EC%83%89%EA%B9%94%EC%9D%B8%EA%B0%80%EC%9A%94.md_4.png&apos; srcset=&apos;/static/40087a931af132a42d65106251c374dd/48743/%EB%8B%B9%EC%8B%A0%EC%9D%98_%EC%BD%94%EB%93%9C%EB%8A%94_%EB%AC%B4%EC%8A%A8_%EC%83%89%EA%B9%94%EC%9D%B8%EA%B0%80%EC%9A%94.md_4.png 118w&apos; sizes=&apos;(max-width: 118px) 100vw, 118px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;매직아이같은 이 색깔의 코드는 무엇에 쓰는 물건일까요?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;이 코드의 비밀을 알아낸 분은 codewiz at &lt;a href=&quot;http://gmail.com&quot;&gt;gmail.com&lt;/a&gt;으로 메일을 보내 주시면 감사하겠습니다.****&lt;a href=&quot;http://www.jiniya.net/wp/archives/12367&quot;&gt;같이 할만한 일이 있을지도 모르잖아요 ^^;;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 책임…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/12954</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12954</guid><pubDate>Thu, 08 May 2014 23:59:32 GMT</pubDate><content:encoded>&lt;center&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; margin-bottom: 16px;&apos; data-url=&apos;./책임.md_1.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a5a56458f2a9c3e9b84218bce4ccc612/a22ce/%EC%B1%85%EC%9E%84.md_1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 56.315789473684205%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABAABA//EABQBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAQDcIeVkn//EABoQAAICAwAAAAAAAAAAAAAAAAEDAAIRIjP/2gAIAQEAAQUCXUZuNjFkhLes/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFREBAQAAAAAAAAAAAAAAAAAAEBH/2gAIAQIBAT8Bh//EABsQAAEEAwAAAAAAAAAAAAAAAAEAAhARIUFx/9oACAEBAAY/AqOUYYdgp3Y//8QAHRABAAEDBQAAAAAAAAAAAAAAAQARITEQQWGBof/aAAgBAQABPyFlIcG0yWzSZQQNwD2T2tP/2gAMAwEAAgADAAAAEMgP/8QAFhEAAwAAAAAAAAAAAAAAAAAAEBEh/9oACAEDAQE/EHB//8QAFxEAAwEAAAAAAAAAAAAAAAAAARARIf/aAAgBAgEBPxDBq//EAB4QAQACAQQDAAAAAAAAAAAAAAEAESEQMVGhgZHw/9oACAEBAAE/EM/YFJ0ZQYyuBw1Fe6/EMMJgFDZ7fc+Vzp//2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;   md 1&apos; title=&apos;&apos; src=&apos;/static/a5a56458f2a9c3e9b84218bce4ccc612/a22ce/%EC%B1%85%EC%9E%84.md_1.jpg&apos; srcset=&apos;/static/a5a56458f2a9c3e9b84218bce4ccc612/8ccab/%EC%B1%85%EC%9E%84.md_1.jpg 190w,
/static/a5a56458f2a9c3e9b84218bce4ccc612/ea4c8/%EC%B1%85%EC%9E%84.md_1.jpg 380w,
/static/a5a56458f2a9c3e9b84218bce4ccc612/a22ce/%EC%B1%85%EC%9E%84.md_1.jpg 680w&apos; sizes=&apos;(max-width: 680px) 100vw, 680px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;“제가 남 탓을 할 수 없는 까닭은 제가 최종 책임자이기 때문입니다. 책임은 제게 있습니다.” – 버락 오바마&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;blockquote&gt;
&lt;p&gt;사고 이튿날, 박근혜 대통령이 실종자 가족이 모여 있는 진도 실내체육관을 찾았다. 이 자리에서 대통령은 이런 말을 한다. “있을 수 없는 일이 일어난 데 대해 철저한 조사와 원인 규명을 해서, 책임질 사람은 모두 엄벌토록 할 것이다.” 많은 언론은 이 발언을 대통령의 단호한 의지를 보여준다는 식으로 보도했다.&lt;/p&gt;
&lt;p&gt;하지만 이 발언의 핵심은 다른 데 있었다. 이 결정적 발언으로 대통령은, ‘시스템의 최종 책임자’에서 ‘구름 위의 심판자’로 자신을 옮겨놓았다. 시스템이 무너져내리는 가운데, 최종 책임자는 자신의 책임을 말하는 대신 ‘책임질 사람에 대한 색출 의지’를 과시하는 단죄자의 자리를 자연스럽게 차지했다. 침몰하는 시스템에서, 대통령은 그렇게 가장 먼저 ‘탈출’했다.&lt;/p&gt;
&lt;p&gt;– &lt;a href=&quot;http://www.sisainlive.com/news/articleView.html?idxno=20059&quot;&gt;시사인&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;http://img.viewsnnews.com/article/2014/04/2313191807338200.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 클라우드의 역습]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/13018</link><guid isPermaLink="false">https://jiniya.net/wp/archives/13018</guid><pubDate>Sat, 03 May 2014 23:59:31 GMT</pubDate><content:encoded>&lt;p&gt;몇해전 클라우드에 관해서 &lt;a href=&quot;http://www.jiniya.net/wp/archives/6103&quot;&gt;깜찍한 글을&lt;/a&gt; 하나 썼었다. 제법 당시 상황을 잘 반영했는지 반응이 그리 나쁘지 않았다. 지금 시점에서 생각해보면 정말 깜찍한 글이 아닐 수 없다. 왜냐면 그 사이 우리는 거의 모든 서비스를 죄다 클라우드로 전환했기 때문이다. 더 아이러니한 사실은 세포 덩어리로 옮겼다는 점 ㅋㅋㅋ~ 한치 앞도 모르는게 사람 일이다. 어쨌든 지금 우리는 물리 서버 대비 거의 절반 가격에 서버를 돌리고 있다. 더 큰 대역폭의 네트워크 회선은 덤일뿐 ㅋ~&lt;/p&gt;
&lt;p&gt;그간 만족하면서 잘 썼는데 오늘 장애가 발생했다. 처음에는 우리 문젠줄 알았는데 알고보니 클라우드 서비스 자체의 장애 상황인 것 같다. 열심히 고치고는 있는 것 같지만 4시간이 지나도 상황은 개선될 조짐조차 보이질 않고 ㅠㅜ~ 손가락만 빨고 앉아 있을 수 밖에 없는 작금의 사태가 참 안타깝다.&lt;/p&gt;
&lt;p&gt;세상에 모든 것이 다 그렇지만 클라우드 또한 양날의 검이다. 편리한 만큼 문제가 생기면 손쓸 방법이 없는건… 거대 기업의 기술력을 믿을 뿐 ㅠㅜ~ 제발 한번만 살려주세요. 담부터는 비싸도 미쿡에다 서버를 만들겠습니다.&lt;/p&gt;
&lt;center&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 604px; margin-bottom: 16px;&apos; data-url=&apos;./클라우드의_역습.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/cd10bdc6c2d72fe57bc8a7b341b0eb0a/1994c/%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C%EC%9D%98_%EC%97%AD%EC%8A%B5.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 54.21052631578947%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABnUlEQVR42nVQ2XKjMBD0//9bah3HODanxH0JAboBJ9usyVbtw6q6pgahnu7p0zh0TOhlWZ7/P9u2CSEGzge9crONduv1VsvlpGeWF2XfttZabZQ12mqNan7q61hjnLXOaLc/UIs148BOcmZpWceECqWl0gXXKdfZaPLJ0NH00mrrlLHKOGnsD5yyS9Ozk1lX6Zai6Zp+KNqun+ayG4KE+gkNSBrS9BElcZr5UeLHBPdBTD79MCRUuRXkJ+CeX3bbsX59l0138T69uw8CyYokK0heRDSNaUaLCp9gkrzUy7aTpV3aYezHuWF8lJpNIq+aqmPAMEvcj1INk8A9+n4SHZ+4kCDuZMyYlAHAhBlEcP7w3s6X8/UGC+jfr7dflyvqx+2OG/RxmsPmQRbGvYAeCllZp2WV121W1UXdYRxczNoCEHjhUP5rG3U2Djt7j8B7+Pcg8v/Egw2xcJjQRxgjMzQRzcA6lF9T4Ry2sRLZQypRoZkWVTtw2OFCYVU2SQTBZ3mk/Y+ytj2fMDgiKURe2Qbk0IxJhl8t43ij3PobkUBiyuioH2QAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;         md 0&apos; title=&apos;&apos; src=&apos;/static/cd10bdc6c2d72fe57bc8a7b341b0eb0a/1994c/%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C%EC%9D%98_%EC%97%AD%EC%8A%B5.md_0.png&apos; srcset=&apos;/static/cd10bdc6c2d72fe57bc8a7b341b0eb0a/08678/%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C%EC%9D%98_%EC%97%AD%EC%8A%B5.md_0.png 190w,
/static/cd10bdc6c2d72fe57bc8a7b341b0eb0a/2edd7/%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C%EC%9D%98_%EC%97%AD%EC%8A%B5.md_0.png 380w,
/static/cd10bdc6c2d72fe57bc8a7b341b0eb0a/1994c/%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C%EC%9D%98_%EC%97%AD%EC%8A%B5.md_0.png 604w&apos; sizes=&apos;(max-width: 604px) 100vw, 604px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;오늘의 교훈&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;**동아시아에는 서버를 만드는게 아니란다…**&lt;strong&gt;똑같은 상황이 미쿡과 동아시아에서 발생한다면 어디가 먼저 고쳐지겠니???&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;덧) 8시간만에 장애는 해결됐다. 그러고도 안 살아나서 초큼 당황했는데 침착하게 파워쉘로 강제 종료하고 켜니 잘 켜졌다. 서버가 다시 살아나서 천.만.다.행… 그래도 매 시간 서비스 상태를 알려주는 페이지를 통해서 작업 진행 상황을 알려줘서 덜 당황할 수 있었다. 역시MS. 우리가 손가락만 빨면서 침묵한건 함정 ㅠㅜ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[역린, 2014]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/12968</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12968</guid><pubDate>Fri, 02 May 2014 23:59:30 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;작은 일도 무시하지 않고 최선을 다해야 한다.&lt;/p&gt;
&lt;p&gt;작은 일에도 최선을 다하면 정성스럽게 된다.&lt;/p&gt;
&lt;p&gt;정성스럽게 되면 겉에 배어 나오고&lt;/p&gt;
&lt;p&gt;겉에 배어 나오면 겉으로 드러나고&lt;/p&gt;
&lt;p&gt;겉으로 드러나면 이내 밝아지고&lt;/p&gt;
&lt;p&gt;밝아지면 남을 감동시키고&lt;/p&gt;
&lt;p&gt;남을 감동시키면 이내 변하게 되고&lt;/p&gt;
&lt;p&gt;변하면 생육된다.&lt;/p&gt;
&lt;p&gt;그러니 오직 세상에서 지극히 정성을 다하는 사람만이 나와 세상을 변하게 할 수 있는 것이다&lt;/p&gt;
&lt;p&gt;– 중용 23장&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;소문난 잔치에 먹을 거 없다고 했던가? 그렇게 광고를 해댄 것에 비해서는 큰 임팩트는 없었던 영화. 내용이 인상 깊지도 않았고, 액션이 박진감 넘치지도 않았고, 영상이 화려하지도 않았다. 보고 나서 기억에 남는건 중용 23장과 한지민의 미모 정도?!&lt;/p&gt;
&lt;p&gt;고전이 괜히 고전은 아니라는 생각. 그 어떤 상황 어떤 시대에 읽어도 의미가 통하는 걸 보면…&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 358px; margin-bottom: 16px;&apos; data-url=&apos;./역린,_2014.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ba345ecfe1749d86484d79e8b94846cc/af061/%EC%97%AD%EB%A6%B0%2C_2014.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 123.6842105263158%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAZABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAMEBQL/xAAVAQEBAAAAAAAAAAAAAAAAAAACAf/aAAwDAQACEAMQAAABelsUt4oQ6zq8wLVOhT//xAAdEAACAwACAwAAAAAAAAAAAAABAgADBBESIiMz/9oACAEBAAEFArF4BJS0qXmg+ehuXqs9el+srYRVE0fSVz//xAAWEQADAAAAAAAAAAAAAAAAAAABIDH/2gAIAQMBAT8BET//xAAWEQADAAAAAAAAAAAAAAAAAAABIDH/2gAIAQIBAT8BNT//xAAhEAACAgECBwAAAAAAAAAAAAAAAREhAhJBEyIxUWFygf/aAAgBAQAGPwJuCOI4a3JVmGKW9i5VXRi1D7ujRla28DV04F9EZ+zP/8QAHBAAAgMBAQEBAAAAAAAAAAAAAREAITFBUXGh/9oACAEBAAE/IbgIdeTwYzNRSDKYh0a9MUWEaH2IQJJuqghXzHwSkMENj1DQbWCn7IG/U1F//9oADAMBAAIAAwAAABDgPrP/xAAYEQADAQEAAAAAAAAAAAAAAAAAAREhQf/aAAgBAwEBPxCEzM6VrSH/xAAYEQADAQEAAAAAAAAAAAAAAAAAATERIf/aAAgBAgEBPxBng6UUP//EACIQAQACAAUEAwAAAAAAAAAAAAEAESExQVGxYXGh8IGR0f/aAAgBAQABPxBXSJuA0czVvE5rzGq4BJqSzkNQ4ri30wlAh1TRydpfL3s6VdZfEs4N7jucxDckRj+DDjQ2eg6/bPebE8RzPfbz/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;    2014 md 0&apos; title=&apos;&apos; src=&apos;/static/ba345ecfe1749d86484d79e8b94846cc/af061/%EC%97%AD%EB%A6%B0%2C_2014.md_0.jpg&apos; srcset=&apos;/static/ba345ecfe1749d86484d79e8b94846cc/8ccab/%EC%97%AD%EB%A6%B0%2C_2014.md_0.jpg 190w,
/static/ba345ecfe1749d86484d79e8b94846cc/af061/%EC%97%AD%EB%A6%B0%2C_2014.md_0.jpg 358w&apos; sizes=&apos;(max-width: 358px) 100vw, 358px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;한지민은 이뻤다. 이건 팩트 ㅋ~&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 게임 보안: 스프레드, 스프레드, 스프레드]]></title><description><![CDATA[#0 서울에서는 삼성전자 주식이 5만원에 거래되고, 부산에서는 삼성전자 주식이…]]></description><link>https://jiniya.net/wp/archives/9292</link><guid isPermaLink="false">https://jiniya.net/wp/archives/9292</guid><pubDate>Thu, 24 Apr 2014 23:59:29 GMT</pubDate><content:encoded>&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;서울에서는 삼성전자 주식이 5만원에 거래되고, 부산에서는 삼성전자 주식이 8만원에 유통된다면 우리는 무엇을 할 수 있을까? 맞다. 채소 가게를 하는 아저씨도 서울에서 삼성전자 주식을 사서는 부산에서 그 주식을 모조리 팔아 버릴 것이다. 한 주를 팔 때마다 3만원의 차익이 생기기 때문이다. 말도 안되는 이야기 같지만 통신이 발달하지 않은 예전에는 흔하게 있었던 일이다. 말 그대로 정보가 돈이던 시절이었다.&lt;/p&gt;
&lt;p&gt;하지만 통신이 발달했고 이제 더 이상 이런 말도 안되는 일은 벌어지지 않는다. 머나먼 미쿡 땅의 주식 가격도 소말리아나 대한민쿡이나 그놈이 그놈이다. 물론 요즘이라고 이런 일들이 아예 없는 것은 아니다. 우리가 인지하지 못하는 찰나의 순간을 컴퓨터가 포착해서는 이런 거래들을 성사시키곤 한다. 어쨌든 이렇게 차이가 발생하는 것을 두고 우리는 스프레드가 존재한다는 표현을 쓰곤 한다.&lt;/p&gt;
&lt;p&gt;그런데 이 스프레드가 타이밍 만큼이나 게임 보안에서는 아주 중요한 이슈 중에 하나다. 솔루션 업체 입장에서는 스프레드를 제로에 가깝게 만드는 것이 중요하다. 어떻게 이것을 줄일 것이냐를 고민해야 하고, 이 스프레드를 적게 만드는 제품이 좋은 제품이라고 할 수 있다. 기술력이 유사한 제품이라면 이 스프레드 관리가 그 제품 평판의 전부라고 할 수 있을 정도로 굉장히 중요한 요소다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_스프레드,_스프레드,_스프레드.md_0.jpg&apos; data-alt=&apos;지금 밤 하늘에 찬란하게 빛나는 것 갈지만 600만년 전의 모습일수도 있다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/d64d59bb154740dc5e74d30f800ce0ee/09658/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 57.89473684210527%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABAACA//EABYBAQEBAAAAAAAAAAAAAAAAAAEAAv/aAAwDAQACEAMQAAABAgXc1uJT/8QAGhAAAwADAQAAAAAAAAAAAAAAAAECAxESMf/aAAgBAQABBQLiRYhqE58dPR//xAAYEQACAwAAAAAAAAAAAAAAAAAAARIhUf/aAAgBAwEBPwGCZWH/xAAYEQACAwAAAAAAAAAAAAAAAAAAARIiUf/aAAgBAgEBPwGbRbT/xAAYEAACAwAAAAAAAAAAAAAAAAAAMQEgIf/aAAgBAQAGPwLJGKn/xAAcEAADAQACAwAAAAAAAAAAAAAAAREhMUFRYXH/2gAIAQEAAT8h2t0K5eCQ17ozj6IY7H5p/9oADAMBAAIAAwAAABCsL//EABcRAQADAAAAAAAAAAAAAAAAAAABETH/2gAIAQMBAT8Q0ypf/8QAFxEBAAMAAAAAAAAAAAAAAAAAAAERMf/aAAgBAgEBPxDHCx//xAAcEAEAAgIDAQAAAAAAAAAAAAABABEhMUFRYYH/2gAIAQEAAT8Q8+dmvJVsfOZWDqdMEguIpSqlrzEtJK9s/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;지금 밤 하늘에 찬란하게 빛나는 것 갈지만 600만년 전의 모습일수도 있다.&apos; title=&apos;&apos; src=&apos;/static/d64d59bb154740dc5e74d30f800ce0ee/a6335/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_0.jpg&apos; srcset=&apos;/static/d64d59bb154740dc5e74d30f800ce0ee/8ccab/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_0.jpg 190w,
/static/d64d59bb154740dc5e74d30f800ce0ee/ea4c8/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_0.jpg 380w,
/static/d64d59bb154740dc5e74d30f800ce0ee/a6335/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_0.jpg 760w,
/static/d64d59bb154740dc5e74d30f800ce0ee/06dbb/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_0.jpg 1140w,
/static/d64d59bb154740dc5e74d30f800ce0ee/2d81f/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_0.jpg 1520w,
/static/d64d59bb154740dc5e74d30f800ce0ee/09658/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_0.jpg 2048w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;지금 밤 하늘에 찬란하게 빛나는 것 갈지만 600만년 전의 모습일수도 있다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;우라가 겪는 첫번째 스프레드는 시간 스프레드다. 무슨 이야기냐면 우리가 수집해서 관찰하는 해킹툴과 실제 게임에서 사용되는 해킹툴 사이에 존재하는 시간 차이를 의미한다. 안타깝게도 대부분의 게임 보안 업체는 게임사에서 수집한 내지는 신고 받은 해킹툴을 차단하는 패치를 만들어서 게임사에 전달하는 과정을 따른다. 별 문제 없어 보이는 이 과정속에 엄청난 함정이 숨어있다. 바로 시간이다. 왜냐하면 게임사에서 수집을 해서 게임 보안 업체에 전달을 할 정도면 사실 그 해킹툴은 버얼써 구석기시대 해킹툴일 가능성이 높기 때문이다.&lt;/p&gt;
&lt;p&gt;이 정도로 느린 속도로 해킹툴을 추적해서는 답이 없다. 그래서 조금 똑똑한 게임 보안 업체들은 사람들을 고용해서 직접 해킹툴을 찾아 나선다. 처음에는 국내 해킹툴을 수집하기 위한 아르바이트생들을 고용한다. 그러다 사이트가 늘어나면서 어라 중국에서 해킹툴이 제조되는 경우가 많네 라는 생각과 함께 중국어를 하는 친구들을 채용한다. 그런데 중국이 전부가 아니다. 태국 해킹툴을 찾기 위해서 태국어를 하는 사람을, 히브리어 해킹툴을 찾기 위해서 히브리어를 하는 사람을 고용해야 한다는 사실을 깨닫게 된다. 물론 이 모든 것이 안 하는 것보다는 좋겠지만 사실상 이런 방식을 통해서 실질적인 효과를 보기란 쉽지 않다. 더욱이 현재 게임 보안 업체가 벌어들이는 수익으로 이런 짓을 했다가는 단언컨대 곧 망한다. 물론 우리 아빠가 빌게이츤데요 하는 친구들은 예외다.&lt;/p&gt;
&lt;p&gt;그럼 어떻게 해야 할까? 백엔드 시스템을 강화해야 한다. “Writing Solid Code”란 책을 보면 저자는 그렇게 이야기한다. 버그를 찾아 나서서는 곤란하다고, 버그가 있는 즉시 우리에게 다가와서는 깜찍하게 저 여기 버그 있어요. 좀 봐주세요. 이렇게 인사를 하도록 만들어야 한다는 것이다. 시간 스프레드를 제어하기 위해서 게임 보안 업체에서 해야 하는 일도 이와 동일하다. 누군가 해킹툴을 제작하면 제가 지금 해킹툴을 제작하고 있거든요. 관심 좀 가져주세요. 이렇게 자동으로 보고가 되는 시스템을 만들어야 한다. 누군가 취약점을 공격하고 있으면 제가 지금 이 취약점을 발견해서 꿀을 빨고 있어요. 이렇게 자동으로 보고가 되고 솔루션 개발자가 적절한 조치를 취할 수 있도록 만들어져야 한다.&lt;/p&gt;
&lt;p&gt;물론 이상계에서는 이런 형태의 보고가 아닌 시스템이 자동으로 학습해서 사이트에 대한 제어 수준을 적당히 조절하는 형태로 동작하긴 할 것이다. 하지만 현실 세계에서 그 정도 수준까지 바라기는 힘들다. 그저 자동으로 문제가 있다는 사실이나 해킹툴이 어떤 방식을 통해서 제작되고 있는지만 보고 되어도 시간 스프레드를 줄일 수 있는 유용한 시스템이 된다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_스프레드,_스프레드,_스프레드.md_1.png&apos; data-alt=&apos;우리는 매 순간 모든 사이트의 보안 수준을 체크한다. 모두 AWESOME이길 바라면서…&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/7542833230304f13f7162fc09789c298/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 61.578947368421055%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAB0ElEQVR42l1Q227aQBScld2PsJS+WulbioGmSaPcXivloconR/2CiAZC8WXZ9YXE9toLhCLo4SDaqvZoNGf2rOccYzQejZ5Hgx+Dh+8Pj4PHLT8beg9ij//8vYad2VrX62a9tVuCSU2t6uXrknhVrVZmZQu7sRujjc0ttZFPPU3WvJk33Kv7k58nV9Or2+b2ZnnTHXaDYXCWnHXGnXN5fqEu+mH/Or3ujXv9qH+ZXgY66Mle56lzl93BL3xkEIXAAlgCU4YCckCzzgDJuuDSQtQCEbzcw7E+Rgx34jqZ48wdJ3aciDlhJsiDKZlfHbdwMcSRPuJkBZEIpNiFS/58yoEpB+b/CJqogagE5XkzDx9SHwncsXA13DmcBA4NEsIlM4JLWh605LLCuxeBJ7zX3iFZCbS8c3LYMGUoHmH/F1IWlFwKhLzzN+V3EnwKxWeNLxb9CL0JuiG6MfMfESEIEUxwWuK0EB+f8ZUuV5lfKZRSrA22SxQxqKw1mgxthkqjzWFSGC5LhV8t5pVoC6ysByn9OEGciLLCfI4wRBQjisgnc6flFNywQxihLJHngk7r2oPWvlKYzURrsVggjnfXCGROp3/FHnRqDF5eBJlN4/0GjuJvy+Pci/YAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;우리는 매 순간 모든 사이트의 보안 수준을 체크한다. 모두 AWESOME이길 바라면서…&apos; title=&apos;&apos; src=&apos;/static/7542833230304f13f7162fc09789c298/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_1.png&apos; srcset=&apos;/static/7542833230304f13f7162fc09789c298/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_1.png 190w,
/static/7542833230304f13f7162fc09789c298/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_1.png 380w,
/static/7542833230304f13f7162fc09789c298/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_1.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;우리는 매 순간 모든 사이트의 보안 수준을 체크한다. 모두 AWESOME이길 바라면서…&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;게임 보안 업체에서 겪는 두번째 스프레드는 보안 수준 스프레드다. 이는 비단 게임 보안에서만 문제되는 이야기는 아니다. 모든 보안 관련 요소의 가장 중요한 부분 중에 하나다. 윈도우가 왜 보안 업데이트의 디폴트 옵션을 강제 설치로 해 두었는지를 보면 알 수 있다. 허구헌날 보안 패치를 해도 사용자가 설치해서 적용하지 않으니 윈도우는 취약한 운영체제라는 오명을 쓰게 된 것이다. 게임 보안 솔루션도 이와 마찬가지다. 제 아무리 좋은 대응 좋은 기능을 만들어도 고객에게 적절한 속도로 공급되지 않으면 무용지물이다.&lt;/p&gt;
&lt;p&gt;이런 이야기를 하면 으레 듣는 소리가 그게 뭐가 힘든가요, 기능 만들기가 어려워서 그렇지 고객에게 공급하는거야 그냥 뿌리면 되는 거 아닌가요, 라는 이야기들이다. 한번도 B2B로 뭔가를 해본 적이 없는 사람들이 하는 소리다. 이게 생각보다 쉽지 않다. 특히나 사이트가 한두군데일때야 쉽겠지만 100개, 200개, 1000개, 2000개가 되면 전혀 다른 문제가 된다. 우선은 그 많은 사이트에 동일하게 기능을 제공하는 것도 어려울 뿐더러 보안 패치를 업데이트 하지 않는 사용자처럼 적용하지 않는 업체들도 많기 때문이다. 이는 정말 어떤 기술적인 문제가 아니라 전적으로 해당 업체를 지원하는 지원 담당자의 역량에 따른다.&lt;/p&gt;
&lt;p&gt;그럼 지원 담당자들을 쪼으면 되지 않냐는 이야기도 할 법한데 이게 전혀 다른 문제다. 패치를 전달하는 것과 고객이 그 패치를 적용하게 만드는 것에는 하늘과 땅 만큼의 차이가 있기 때문이다. 패치를 전달하는 거야 누구나 할 수 있지만, 고객이 적용하게 만드는 것은 누구나 할 수 있는 문제가 이니다. 볼펜 하나를 던져주고 그것을 팔아보라는 문제와 동일하다. 팔 수 있는 사람과 그렇지 않은 사람이 있는 것이다. 여튼 이 문제에 있어서는 전적으로 훌륭한 지원 담당자를 채용하는 것 외에는 답이 없다.&lt;/p&gt;
&lt;p&gt;그렇다고 결국 지원 담당자의 역량이니 손놓고 있으면 된다는 생각은 곤란하다. 모든 세부 사항이 다 그렇겠지만 추적 관찰 가능한 상태에 있는 것과 그렇지 않은 것에는 천지 차이가 있기 때문이다. 그렇다고 이걸 일일이 사람한테 시켜서 수동으로 만드는 것도 문제가 있다. 백방 오류가 발생하고 수집 시간이 더디기 때문이다. 모든 사항이 자동으로 추적 관찰 되도록 만들어야 한다. 그래야 모두가 현재 우리 서비스 품질 수준에 대해서 정확하게 인지할 수 있고 어떤 곳을 어떻게 더 강화해야 하는지를 판단할 수 있다.&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_스프레드,_스프레드,_스프레드.md_2.png&apos; data-alt=&apos;160개가 넘는 옵션들. 이 값들에 따라 깡통이 되기도 하고, 이지스함이 되기도 한다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 604px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/b1433adc03d25a4840ac0fed47183a00/1994c/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 55.78947368421052%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABx0lEQVR42k2Si46jMAxF+ZOZTglpaSEP8iCEEJ5DoVBm9v8/Zg3VSitdWVEk29fHDtBjJtqlRIui1M6rsoJHKtTXJQZ9Rpd7JnXlGbkZigTFikaSRIJgQaIgfK7ajbnq+nkd19e0/UK0TZtk8ny9fSAsbfV4/XgVL/qzl2ErQ4idPPfyHITzwkxNmTG+KdveNl1RtyCe24RL6JwKXTStYLHjYc4i6GxYVOxCe2duGsaKwreQDCVs3Vb9t3JVGN8gmUgN/5rHdXY2DEGm5ajk6Eiel/9tj+sG+l5eVTeE8f2f7Q1sv/Ld9gBSEM+j2m2vqXYJUcBJWgfM4IHvBGjBzDswnklbMhJriliKebqjgpilOADawvZSeN+PzTh1j7mbnmBeGPumzU3RTnMh4l58+QyBqiPWGYLkJzc14wWM6rredUNmLFX5nYsTvkIyhZm7QR0zA6ec7qiKY+wALSvNPaE5bBgaGl+D7UtCr4ThJD1oK/jPaFwylB9L1nQvAeTfwB4AbJjXefszb7/T9qOsg844IR9hBEUf277npz4dGw4B1VsBmhaSV3Bhb1r7kn1DlYaeJxyf8HFhzmcsBrcASaTHkVE4sugvTtOLiPAfcUMAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;160개가 넘는 옵션들. 이 값들에 따라 깡통이 되기도 하고, 이지스함이 되기도 한다.&apos; title=&apos;&apos; src=&apos;/static/b1433adc03d25a4840ac0fed47183a00/1994c/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_2.png&apos; srcset=&apos;/static/b1433adc03d25a4840ac0fed47183a00/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_2.png 190w,
/static/b1433adc03d25a4840ac0fed47183a00/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_2.png 380w,
/static/b1433adc03d25a4840ac0fed47183a00/1994c/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_2.png 604w&apos; sizes=&apos;(max-width: 604px) 100vw, 604px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;160개가 넘는 옵션들. 이 값들에 따라 깡통이 되기도 하고, 이지스함이 되기도 한다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;마지막 스프레드는 옵션 스프레드다. 우리는 프로그래머가 많지 않고, 코드를 매번 새롭게 컴파일하는 것에는 위험 부담이 따른다는 것을 일찍이 알고 있었기에 대부분의 기능들에 대해서 옵션 처리가 되도록 만들었다. 요즘은 그 정도가 더 심해져서 기능이 있는 곳에 옵션이 있어야 한다는 주의로 만들고 있다. 어쨌든 풍부한 옵션은 프로그래머가 직접 개입하지 않아도 특정 문제들을 빠르게 해결할 수 있는 가능성을 제공한다는 장점이 있다.&lt;/p&gt;
&lt;p&gt;하지만 항상 포스의 어두운 면과 밝은 면이 공종하는 것처럼 이 또한 장점만 있는 것은 아니다. 옵션을 제어하는 사람이 충분히 숙련된 엔지니어라면 문제가 없겠지만 옵션 사항의 정확한 동작 구조에 대해서 잘 모르는 담당자라면 문제가 심각해진다. 왜냐하면 그 친구가 패치 생성 시에 옵션을 어떻게 지정했는지에 따라 제품이 깡통이 되기도 하고 이지스함이 될 수도 있기 때문이다. 더욱이 자동화된 추적 장치가 없다면 담당자 입장에서는 자신이 옵션을 변경했었다는 사실을 까먹는 경우도 많다.&lt;/p&gt;
&lt;p&gt;옵션 사항에 대해서도 스프레드가 자동으로 관리될 수 있도록 담당자가 패치 빌드를 생성하면 매번 어떤 옵션 설정이 잘못되어 있음을 자동으로 노티해 주는 장치가 필요하다. 더불어 모든 사이트의 옵션 사항들에 대해서 일괄되게 추적할 수 있는 시스템을 가지는 것이 중요하다.&lt;/p&gt;
&lt;h3&gt;#4&lt;/h3&gt;
&lt;p&gt;맥도날드가 전 세계에서 가장 유명한 햄버거 가게가 된 비결은 딱 두 가지라고 한다. 하나는 서울의 빅맥과 뉴욕의 빅맥의 맛이 납득할 수 있는 범위 내에서 동일하다는 것, 다른 하나는 어떤 바보가 오더라도 맥도날드의 프로시저대로만 하면 유사한 품질의 빅맥을 만들어 낼 수 있다는 점이다. 분야는 다르지만 맥도날드는 스프레드를 잘 제어해서 균등한 품질의 제품을 생산했기 때문에 성공했다고 할 수 있다. 게임 보안도 다르지 않다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_스프레드,_스프레드,_스프레드.md_3.png&apos; data-alt=&apos;해킹툴을 어떻게 숨기나요?&lt;br&gt;&lt;br&gt;해킹툴을 실행하고 XIGNCODE3가 못보게 종이로 가리세요 ㅋㅋ&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 540px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/0547e138bf79f7f0c1d38764434e67fa/03ec9/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 111.05263157894738%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAWCAIAAABPIytRAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAE+0lEQVR42m2S+09TZxjHz3+w7If9NGPigiTb3A9iNmacZg4BUVEqCqIUgXIpDLquLb1AaWlLW057Ts/99Jz2nN5BQBEGw8uWDI3YTpgGGcaQbV6WCbS02ovg9hM7uF/35vu+7/O8ySffvM/zAM+fPXv65ElqPZEUlFxfTyTSL1PCHY+vCvttlIjH15KJxPbTymoul93YeL25uSEISK5Fnz+dXX4cffJHLBF/uLqysLq6uBZfWltdjK8tJpOP1hOP1lYWXsYfCel6/Nf0q+Vs+vdU6nEmswykf4s+/fnHcDDC8EFfaGhoaOTP+7eWpkODFgVjlFEQhDgQ54Cz39Sv1XXrDXqJVKJUtQ+HqPnYDDDM+8YDlzg6YLLRaiNGwux1l5VXNNtqymXHD7eL21ob1fUXOqpOS0pKq8qOV32097Pi0mLUYbl5bRowWUGbg3ahPOjiLE6vEFgbxeoTR6CGatmxooZjFVKprkmiaGlRSjvVFy627i08UFRSgsK2H65/D3TpTToLZoO8VqfXBvFjo1NjfEDfVG84L+o8VdZSIeqSa7Vqg77X0md1KLr0rW0yO+icmLg6dy8KyNU9mn7cCnOmAXYA8V+bmL45dcNPkiZpg1JcbVIrYVs/4nRgLhjHcDfNhEKDS4tLW1tbKysvgDa5SmVCLIjPCHrsqH9qfHpy7LvhQBiz26w9OtjaD4MO2OF0QRCKIBiG4wRF0p6ZW3disSggaZfJeyEz4uuDeBAPTVyZHB8eG/SFOMpNuhAcglEHhDghBIYQxIWhGEGQbjdLuVmjxQKIm6Qd3Q4zGuyDAg5icGx4bDQ8HPGFfCxHYwSJ4jiMIhCMCD2DYdTlQhFU4CEIFlXXAFV1Dc1dViPs15pBEA2OhkcuBSIhzs8zXkbwIGkKp3EER2HXW23zJEGYzeZ9+w8AovO1YpnRCPnVZtIO+wVyyB8KeP0sxbC0INZNMds8SmAuFHMhAkwRhE6nzfv4E+DUufPiDr0RCioNhNXBR/hgxBfwulmO8XAs53F73JSHJhmSoAmMxIR/Q04SRzs7O3buzgfKq6rPNCp6Qd+3PbjF7g1z/jDvD3A87+W9LMe6PQz9H+zGcQpxCV0DCQxtbGrckZcHlJ+tOlkj1Vs9cg1ssjAB1hfkfD6B9HAexrsNC+Y0S1MMIZgTJIaiJIGdPVedv2cPcPLMmaMV4h4T/Y3KYTASPoYT6sy/9aQIt1AdcAA194EateHrDlWtuKGotLTw4MGd+fknReXAidOnDx6p1OhRuWpA2+1ygqTdivUZYJ1uQKm0dHb0NkvUdbUykai+7Gh1QcGBnXm79hUWFB8tMhk1QHll5f7D5QotKFP0d2kcKrVTqbTL5QJmaJd2tzarGy/Ka2vaRBV1ZaVVBQWf7/4w/2JdJWjthh0m4FBJ8Qd7CiXS7jqJskXaLW3raWnRNEm66uvkF2raKivqy0qrS49UHvri+KcFX72/Y9e7771zqvxLrUrap1cCFOM29w8MDV6NhC8PRa5cvjQxMnR1RJi00GjQG/bRPEtzFOFBEbcTxHp7jboejddDCDM8PTUG/DNz+83Cwsa9e2/mf9mYm0vPzmajsczdaDYW25yfz8zN/z3z09bm5tb/LWD52o3745MPJ6cXp64L5/Pbd/6ajQp6cTeWuv8g+eDBq7m5XCqVzeUymWw6nclk0tmskOVe53L/AgC4+mU7zvqcAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;해킹툴을 어떻게 숨기나요?&lt;br&gt;&lt;br&gt;해킹툴을 실행하고 XIGNCODE3가 못보게 종이로 가리세요 ㅋㅋ&apos; title=&apos;&apos; src=&apos;/static/0547e138bf79f7f0c1d38764434e67fa/03ec9/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_3.png&apos; srcset=&apos;/static/0547e138bf79f7f0c1d38764434e67fa/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_3.png 190w,
/static/0547e138bf79f7f0c1d38764434e67fa/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_3.png 380w,
/static/0547e138bf79f7f0c1d38764434e67fa/03ec9/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_3.png 540w&apos; sizes=&apos;(max-width: 540px) 100vw, 540px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;해킹툴을 어떻게 숨기나요?&lt;br&gt;&lt;br&gt;해킹툴을 실행하고 XIGNCODE3가 못보게 종이로 가리세요 ㅋㅋ&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_스프레드,_스프레드,_스프레드.md_4.png&apos; data-alt=&apos;온라인과 모바일 환경에서 모두 효과성이 검증된 게임 보안 솔루션은 XIGNCODE3가 유일합니다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 566px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a97136d8c92264184be42a15cfa5aabd/7ef45/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 46.8421052631579%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABaUlEQVR42n1RXUvDQBDM//8vPkihWKyCLYViHiohfbASmvbS3FfucjFtLl+9OEYU9MFhGZa7253ZPe9C04IcLpQ2UtZCWM4RndbDMCilNptNEATb7TYMQ7DWum3b4Rve++3taT4/3d3tJxMyne5ubvRy6Z6eBudMUfi+v1qtUBlFUZZlw294TojrGD2Y855z5G58Z61NkiTP87Isodn3/d/i0tqqd0a1/flS9Z1t20tdn629Xq8mz992u0xKKUSulFYq1xoJDtCr6zqvMIZRylKWEsIY44xBB57RuKqqmJCU8zhJqJQJY+ATY+mIuq69pmm+XGEkzjkYPqFWwXSWva7XxyDYPT8nYfjm+/HLyz4I9lGEdcCah/aoFEJQSgkhqIf+IY7LpmnXazad0sfHZDZjDw/p/f1xNjsvFsPX5pzzIAs1/AoEwehijMEsn9fGOCkHrZ1Sv+L7tzw8heBpRFEUP5t049j/4wNEJfJ3IWpQ5gAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;온라인과 모바일 환경에서 모두 효과성이 검증된 게임 보안 솔루션은 XIGNCODE3가 유일합니다.&apos; title=&apos;&apos; src=&apos;/static/a97136d8c92264184be42a15cfa5aabd/7ef45/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_4.png&apos; srcset=&apos;/static/a97136d8c92264184be42a15cfa5aabd/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_4.png 190w,
/static/a97136d8c92264184be42a15cfa5aabd/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_4.png 380w,
/static/a97136d8c92264184be42a15cfa5aabd/7ef45/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C%2C_%EC%8A%A4%ED%94%84%EB%A0%88%EB%93%9C.md_4.png 566w&apos; sizes=&apos;(max-width: 566px) 100vw, 566px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;온라인과 모바일 환경에서 모두 효과성이 검증된 게임 보안 솔루션은 XIGNCODE3가 유일합니다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[GCC 공유 라이브러리 심벌 문제 (Draft)]]></title><description><![CDATA[몇해전에 boost의 ABI와 관련된 글을 적은 일이 있다. http://www.jiniya.net/wp/archives/7543 그때 우리는 문제를 -Dboost=boost2로 해결을 했는데 최근에 동일한 문제가 발생했다. 이번엔 boost…]]></description><link>https://jiniya.net/wp/archives/12820</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12820</guid><pubDate>Fri, 04 Apr 2014 23:59:28 GMT</pubDate><content:encoded>&lt;p&gt;몇해전에 boost의 ABI와 관련된 글을 적은 일이 있다. &lt;a href=&quot;http://www.jiniya.net/wp/archives/7543&quot;&gt;http://www.jiniya.net/wp/archives/7543&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;그때 우리는 문제를 -Dboost=boost2로 해결을 했는데 최근에 동일한 문제가 발생했다. 이번엔 boost 같은 외부 라이브러리가 아닌 libstdc++.so라는 G++ 공유 라이브러리가 문제였다. 대다수 업체는 libstdc++.so.6을 사용하는데 한 업체에서 아주 오래된 libstdc++.so.5를 사용하면서 문제가 생긴 것이다.&lt;/p&gt;
&lt;p&gt;libstdc++.so.5와 libstdc++.so.6은 ABI가 호환되지 않는다. &lt;a href=&quot;http://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html&quot;&gt;http://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;그래서 이번에 이 문제에 대한 근본적인 원인에 대해서 파헤쳐 보게 되었다. 근본적인 원인은 boost 글에도 있는 것처럼 심벌을 다른 so 파일에서 찾는 것이 문제다. 간단한 예제를 만들어서 테스트 해 보자.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;a.cpp 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Foo in liba.so\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BarA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;BarA in liba.so\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;b.cpp 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Foo in libb.so\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BarB&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;BarB in libb.so\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;main.cpp 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BarA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;BarB&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;BarA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;BarB&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이제 아래와 같이 컴파일을 해보자&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;g++ -shared -o liba.so a.cpp
g++ -shared -o libb.so b.cpp
g++ -L. -o main main.cpp -la -lb&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 553px; margin-bottom: 16px;&apos; data-url=&apos;./GCC_공유_라이브러리_심벌_문제_(Draft).md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/52c074f163958dad3d0d5923458ee8ed/d35da/GCC_%EA%B3%B5%EC%9C%A0_%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC_%EC%8B%AC%EB%B2%8C_%EB%AC%B8%EC%A0%9C_(Draft).md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 32.631578947368425%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAIAAACHqfpvAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABJ0lEQVR42mPIWPE+HYwyV31MW/IicdaNhJnXE2fdTJ57N3nevaTZt5Nn306adQsoDpTNWv0pY8W71IWPF5b0r8ltZIhILYnOqg1OKvaOyg6Mz3cNSfaPyXUJTLD1jrL3jbHziYYje784B/8EB/94e/8E58CE6WuOMLg7WgUH+AX4eJoZ6Rnoahnp6hjr6xrqaRvqaYGRNhwZ6GoCkaGulr6OprG+5prNOxk8XF38A4N8fP2srKwtzC2N7UyMzIyNjU2NTXAiI2NTMzPTlZv2MLg6O3p6+Tg7u9jZOzg7uhj7mBhaEaHZ1GT15r0MOqpyetrqelpq+trq+tpqBpoaBtoaBjr4kL62hrGu+uIVaxmcQjKcI/Kcw3OhKIwwcgrNdYvI7Vl2EAAcyoYrvbYALgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;GCC                 Draft  md 0&apos; title=&apos;&apos; src=&apos;/static/52c074f163958dad3d0d5923458ee8ed/d35da/GCC_%EA%B3%B5%EC%9C%A0_%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC_%EC%8B%AC%EB%B2%8C_%EB%AC%B8%EC%A0%9C_(Draft).md_0.png&apos; srcset=&apos;/static/52c074f163958dad3d0d5923458ee8ed/08678/GCC_%EA%B3%B5%EC%9C%A0_%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC_%EC%8B%AC%EB%B2%8C_%EB%AC%B8%EC%A0%9C_(Draft).md_0.png 190w,
/static/52c074f163958dad3d0d5923458ee8ed/2edd7/GCC_%EA%B3%B5%EC%9C%A0_%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC_%EC%8B%AC%EB%B2%8C_%EB%AC%B8%EC%A0%9C_(Draft).md_0.png 380w,
/static/52c074f163958dad3d0d5923458ee8ed/d35da/GCC_%EA%B3%B5%EC%9C%A0_%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC_%EC%8B%AC%EB%B2%8C_%EB%AC%B8%EC%A0%9C_(Draft).md_0.png 553w&apos; sizes=&apos;(max-width: 553px) 100vw, 553px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;결과를 보면 libb.so의 BarB에서 호출하는 Foo가 libb.so에 있는 Foo가 아닌 liba.so에 Foo로 링크된 것을 알 수 있다. 티끌만한 것도 찾아서 공유하는 정신이 GNU 스럽다고 할 수 있겠지만 심벌 이름이 충돌 나는 경우에는 여간 성가신 문제가 아닐 수 없다. 특히나 boost 같이 우리가 컴파일 하는 경우에는 -Dboost=boost2같은 꼼수라도 쓰겠지만 컴파일 할 수 없는 심벌인 경우에는 문제가 많아진다.&lt;/p&gt;
&lt;p&gt;물론 GNU 애들도 바보가 아닌 이상 이런 문제가 굉장히 성가시다는 걸 몰랐을 리는 없다. 그래서 만들어진 -Wl,-Bsymbolic 이라는 마법같은 옵션이 있다. so 파일을 링크할 때 저 옵션을 넣어주고 링크하면 so 파일 내의 심벌을 먼저 참조하도록 설정된다.&lt;/p&gt;
&lt;p&gt;참고할만한 글&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://bottomupcs.sourceforge.net/csbu/x4012.htm&quot;&gt;http://bottomupcs.sourceforge.net/csbu/x4012.htm&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 리소스 관리]]></title><description><![CDATA[전통적으로 프로그래밍의 가장 복잡한 문제 중에 하나가 리소스 관리다. — 작성하는 중인 글… 코드만 참고합시다. — 이 구조의 가장 핵심은 변수들의 초기화다. 위 코드는 모든 변수가 정상적으로 초기화 되지 않았기 때문에 if(!resourcea…]]></description><link>https://jiniya.net/wp/archives/12805</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12805</guid><pubDate>Fri, 14 Mar 2014 23:59:27 GMT</pubDate><content:encoded>&lt;p&gt;전통적으로 프로그래밍의 가장 복잡한 문제 중에 하나가 리소스 관리다.&lt;/p&gt;
&lt;p&gt;— 작성하는 중인 글… 코드만 참고합시다. —&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;xstatus &lt;span class=&quot;token function&quot;&gt;some_func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	xstatus s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	xhandle resourcea&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	xhandle resourceb&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	resourcea &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateResourceA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;resourcea&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;goto&lt;/span&gt; $cleanup&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	resourceb &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateResourceB&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;resourceb&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;goto&lt;/span&gt; $cleanup&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	s &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; SUCCESS&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

$cleanup&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resourcea&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;FreeResourceA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;resourceb&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;FreeResourceB&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 구조의 가장 핵심은 변수들의 초기화다. 위 코드는 모든 변수가 정상적으로 초기화 되지 않았기 때문에 if(!resourcea)나 if(!resourceb)에 걸리면 의도하지 않은 결과가 나올 수 있다. 상기 패턴으로 코드를 만들 때 가장 신경써야 하는 부분은 아래와 같이 변수를 정상적으로 초기화 시켜 주는 것이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;xstatus &lt;span class=&quot;token function&quot;&gt;some_func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	xstatus s &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; FAIL&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	xhandle resourcea &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	xhandle resourceb &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	xhandle resourcea &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateResourceA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;resourcea&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	xhandle resourceb &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateResourceB&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;resourceb&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token comment&quot;&gt;// processing...&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;FreeResourceA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;FreeResourceB&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;초보 프로그래머들이 많이 하는 루프 내 리소스 관리 실수. break에 걸리는 순간 이전에 획득한 리소스가 정상적으로 해제되지 않는다. if(!resourceb) 구문을 타는 순간이다.&lt;/p&gt;
&lt;p&gt;C++의 RAII를 활용하자. 머리가 들 아프다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 사설 서버 대응 전략]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/2014/01/strategy-for-dealing-with-private-servers/</link><guid isPermaLink="false">https://jiniya.net/2014/01/strategy-for-dealing-with-private-servers/</guid><pubDate>Fri, 14 Mar 2014 23:59:27 GMT</pubDate><content:encoded>&lt;p&gt;어느 분야나 난제 혹은 미제 같은 문제들이 항상 있기 마련이다. 이런 문제들은 새롭게 도메인에 접근하는 이들에게는 자신의 존재감을 증명할 수 있는 새로운 기회로 다가가기도 하고, 기존에 그 분야에 일하는 종사자들에게는 혹 같은 느낌이기도 하고, 실제로 피해를 당하는 입장에서는 골치 덩어리이기도 하다.&lt;/p&gt;
&lt;p&gt;게임 보안 분야에서는 사설 서버 혹은 무료 서버라고 불리는 것들도 이런 문제 중에 하나다. 현재까지 해당 문제에 대해서 이렇다 할만한 뚜렷한 대응책도 존재하지 않고, 문제가 발생해 버리면 사실상 통제하기도 힘든 상태다. 그렇다고 사설 서버 문제가 심각하지 않은 것도 아니다. 일부 유명 게임의 경우에는 사설 서버가 웬만한 정식 게임 서비스보다 규모가 더 큰 경우도 심심찮게 존재한다.&lt;/p&gt;
&lt;p&gt;사설 서버란 정식으로 인가 받지 않은 사람 또는 회사가 게임을 불법적으로 서비스하는 행위를 말한다. 사설 서버는 어찌 보면 온라인 게임이란 서비스와 그 유래를 같이 한다고 볼 수 있다. 온라인 게임의 초창기에 유행했던 사설 서버 중에 하나로 프리 배틀넷이 있다. 초창기 배틀넷은 스타크래프트란 게임을 구매한 사용자들끼리 인터넷을 통해서 같이 게임을 즐길 수 있도록 만들어주는 중계 서버 역할을 했다. 배틀넷에 접속하기 위해서는 게임을 구매한 내역에 해당하는 시디키라는 것이 있어야 한다. 시디키가 없다면 불법 복제로 간주되어 배틀넷 서버에 접속할 수가 없다. 불법 복제가 만연하던 시절, 불법 복제 사용자들의 배틀넷 욕구를 채워준 것이 프리 배틀넷이다. 프리 배틀넷은 스타크래프 제작사인 블리자드가 운영하는 것이 아닌 개인이 임의로 서버를 구축해서 운영하는 사설 서버였기 때문에 불법 복제 시디로 게임을 하는 사용자도 접속할 수 있었다.&lt;/p&gt;
&lt;p&gt;초창기 사설 서버는 프리 배틀넷과 마찬가지로 이윤 창출 보다는 개인의 호기심과 참을 수 없는 무한 공유 정신에 그 기반을 두고 있다. 그렇기에 이윤과는 무관한 경우가 많았고 운영 또한 영세하게 이루어지는 경우가 많았다. 하지만 요즘의 사설 서버는 이런 초창기 목적과는 많이 달라졌다. 대부분 영리를 목적으로 유료로 운영하는 경우가 많고, 규모 또한 경우에 따라서는 무척 크기도 하다. 게임사 입장에서는 당연히 정식 서비스로 유입되어야 하는 트래픽을 사설 서버에게 뺏기는 셈이 되기 때문에 상당한 피해를 본다고 할 수 있다. 프리 배틀넷의 경우에도 영세한 규모이긴 하지만 블리자드 입장에서는 시디 구매로 이어져야 할 수요가 프리 배틀넷의 존재 때문에 연결되지 않았기 때문에 일정부분 피해를 입었다고 할 수 있다.&lt;/p&gt;
&lt;p&gt;그렇다면 이렇게 게임사의 골치를 썩이는 사설 서버는 도대체 왜 생겨나는 것일까? 자본주의 사회에서 벌어지는 모든 나쁜 문제들이 그렇겠지만 이 또한 그 근본적인 원인에는 ‘돈’이 있다. 불법적으로 손쉽게 돈을 벌려고 하는 사설 서버 운영자, 그들에게 바이너리 파일이나 소스 코드를 유출시켜 부당한 이윤을 취득하고 싶어하는 게임 퍼블리셔나 게임 개발사의 관계자, 정식 서비스의 비싼 컨텐츠 사용료를 감당하지 못하기에 보다 저렴한 비용으로 컨텐츠를 체험해 보고 싶어하는 사용자 들의 이해관계가 복잡하게 얽혀서 사설 서버 생태계는 유지된다.&lt;/p&gt;
&lt;p&gt;그렇다면 무료 사설서버야 그렇겠지만 유로로 운영하는 사설 서버는 어떻게 유지되는 것일까? 게이머 입장에서는 어차피 굳이 비용을 지불해야 한다면 합법적인 서비스를 이용하는 편이 마음도 편할 테니 말이다. 여기에도 정말 다양한 이유가 있다.&lt;/p&gt;
&lt;p&gt;첫째는 가격이다. 유료로 운영한다고는 하지만 정식 서비스 보다는 훨씬 저렴한 비용으로 즐길 수 있는 경우가 대부분이다. 이는 사설 서버의 경우에는 정식 서비스만큼 충분한 수의 운영 인력을 유지할 필요도 없고, 정식 서비스의 인기에 편승해서 운영하는 것이기 때문에 별도로 마케팅 비용을 지출할 필요도 없다. 그리고 가장 중요한 문제이지만 사설 서버 운영자는 게임 컨텐츠 개발에 투입되는 비용 중 단돈 1원도 지불하지 않았기 때문에 정식 서비스보다는 훨씬 저렴하게 운영해도 유지가 되는 것이다.&lt;/p&gt;
&lt;p&gt;둘째는 접근 가능한 컨텐츠의 범위다. 정식 서비스에서는 제공하지 않은 게임 마스터가 사용할 수 있는 아이템을 사용해 볼 수 있다거나, 정식 서비스에서는 절대로 불가능한 터무니 없는 능력치의 아이템이나 이동 불가능한 지역과 갈은 컨텐츠를 사용해 볼 수 있다. 심지어는 드물긴 하지만 사설 서버가 정식 서비스보다 더 빠르게 신규 컨텐츠를 제공하는 경우도 있다. 말이 안 되는 것 같은데, 이게 가능한 이유는 게임사에서 대규모 패치를 하기 전에는 일반적으로 일정 기간 전부터 관련 컨텐츠 파일을 조금씩 클라이언트에 미리 전달하는 경우가 있기에 가능하다. 이렇게 미리 전송된 클라이언트 정보를 분석해서 사설 서버에서 컨텐츠를 먼저 오픈해 버리는 것이다.&lt;/p&gt;
&lt;p&gt;끝으로 대다수 경우는 아니지만 정식 서비스보다 더 나은 운영 품질을 사설 서버가 제공하기에 그곳에서 게임하는 사용자들도 존재한다. 정식 서비스의 경우에는 아무래도 규모가 크다 보니 소규모 커뮤니티와 같은 친밀감은 느끼기가 힘들다. 하지만 사설 서버는 상대적으로 사용자가 적기 때문에 운영자와 유대감을 형성하기가 훨씬 더 쉽다는 측면이 있다.&lt;/p&gt;
&lt;h3&gt;사설 서버의 탄생 배경에 따른 대응 전략&lt;/h3&gt;
&lt;p&gt;사설 서버가 무엇인지 그리고 그 생태계가 어떻게 구성되는지에 대해서 살펴 보았다. 지금부터는 기술적으로 사설 서버가 만들어지는 경로에 대해서 살펴보도록 하자. 이 내용을 이해하는 것은 무척 중요한 문제인데, 왜냐하면 생성 경로에 따라서 대응 전략도 달라져야 하기 때문이다. 사설 서버는 크게 세가지 정도의 경로를 통해서 만들어진다.&lt;/p&gt;
&lt;p&gt;첫째는 서버 바이너리 파일이 유출되는 경우다. 여기에도 세부적으로 유출되는 여러 가지 요인이 있다. 게임 개발사나 게임 운영사의 관계자가 유출시키는 경우, 바이너리 파일이 담겨 있는 서버가 해킹 당해서 해커에 의해 탈취되는 경우, 심지어는 게임 서버 자체가 물리적으로 도난 또는 교체되는 경우도 있다.&lt;/p&gt;
&lt;p&gt;바이너리 유출을 원천적으로 차단할 수 있는 방법은 없다. 인재의 경우는 각종 보안 장치들을 강화해서 절대 그런 일이 없도록 만들겠다는 의지를 불태울 수 있겠지만 미봉책에 불과할 뿐이다. 왜냐하면 누군가는 반드시 파일에 접근해서 작업할 수 있는 높은 권한을 가질 수 밖에 없기 때문이다. 그런 사람이 나쁜 마음을 먹는다면 얼마든지 사고는 벌어질 수 있다. 따라서 사람을 거쳐서 유출되는 것을 원천적으로 차단한다는 것은 불가능에 가깝다. 서버 머신의 물리적인 도난도 자연재해와 마찬가지로 벌어진다면 그걸 피할 방법은 사실상 없다. 그나마 대응할 수 있는 영역이 해킹을 해서 파일을 탈취하는 행위다. 이 경우는 각종 보안 시스템을 강화해서 일정 수준 이상의 보안 수준을 유지함으로써 어느 정도 대비를 할 수 있다.&lt;/p&gt;
&lt;p&gt;바이너리 파일 유출의 경우 사전에 방지할 수 있는 근본적인 방법은 없기 때문에 파일 유출이 벌어지더라도 의미가 없도록 만드는 사후 대응 전략이 보다 효과적이다. 인가되지 않은 곳에서 바이너리 파일을 들고 가서 서버를 켜더라도 정상적으로 동작하지 않도록 만드는 것이다. 이런 전략의 하나로는 게임 서버에 대한 인증 서버를 두는 방법이 많이 사용된다. 게임 서버가 별도의 인증 서버의 인증을 통과해야만 동작하도록 만드는 것이다. 통상적으로 이러한 인증 서버를 마스터 서버라고 부른다. 마스터 서버가 단순한 온/오프 식의 인증 처리만 해서는 사실상 소용이 없다. 파일을 탈취할 정도라면 그 정도 인증은 손쉽게 무력화 시킬 수 있기 때문이다. 그보다는 좀 더 복잡한 대응이 필요하다. 일반적으로는 게임 서버 구동에 필요한 각종 데이터를 마스터 서버에 의존하도록 만드는 방법을 많이 사용한다. 해당 데이터는 마스터 서버와의 인증이 되는 순간 마스터 서버로부터 전송을 받고 파일로 기록은 하지 않는 형태로 구성해야 한다. 그래야 실질적으로 바이너리 파일 유출에 대한 통제를 할 수 있다. 물론 이 경우에도 마스터 서버가 가지고 있는 데이터 셋이나 마스터 서버의 바이너리가 똑같이 다 유출된다면 막을 방법은 없다. 하지만 마스터 서버의 경우 서버간 통신만 발생하기 때문에 서버 자체를 게임 개발사에서 보유할 수 있다는 점 때문에 유출의 위험성이 일반 게임 서버 보다는 훨씬 낮다는 정도로 생각하는 것이 좋겠다.&lt;/p&gt;
&lt;p&gt;두 번째 유출 경로는 소스 코드가 유출되는 경우다. 이 경우도 바이너리 유출과 마찬가지로 사람을 통해서 유출되는 경우가 있을 수 있고, 해커에 의해 탈취 당하는 경우가 있을 수 있다. 소스 코드 유출이기 때문에 앞선 바이너리 유출 보다는 상황이 더 심각하지만 안타깝게도 앞선 바이너리 유출과 마찬가지로 원천적인 차단 방법은 존재하지 않는다. 이 경우에 할 수 있는 사후 대응은 서버의 구조를 확 변경하는 작업이지만 이 또한 쉽지 않다. 사전에 예방할 수 있는 방법으로는 소스 코드를 분산 배치 시키는 방법을 들 수 있다. 해커가 소스 코드를 탈취하더라도 게임 서버의 전체 코드가 아닌 일부 코드가 되도록 만드는 것이다.&lt;/p&gt;
&lt;p&gt;마지막 생성 경로는 말 그대로 해커들의 리버싱을 통해서 만들어지는 경우를 들 수 있다. 클라이언트와 해당 클라이언트가 정식 서버와 통신하는 내용을 토대로 상상에 나래를 펼쳐서 서버를 바닥부터 직접 제작하는 것이다. 이렇게 무식하게 만드는 경우가 있을까 싶지만 오래된 게임들의 경우는 상당 시간 동안 분석이 진행되기 때문에 이렇게 직접적으로 모두 제작한 사설 서버가 나오기도 한다. 이런 서버는 게임 서버의 상태가 불안정하다는 점과 정식 게임 서버는 윈도우 기반인데 사설 서버는 리눅스 기반으로 만들어지는 경우와 같이 정식 게임 서버와는 전혀 다른 플랫폼으로 제작되는 경우가 있다는 점이 특징이다.&lt;/p&gt;
&lt;h3&gt;사설 서버와 보안 코드&lt;/h3&gt;
&lt;p&gt;현대적인 게임 제작에는 천문학적인 금액이 투입되는 만큼 보안에도 철저하게 신경을 쓰는 추세로 바뀌고 있다. 다양한 보안 장벽을 통해서 물리적인 보안에 대해서 강화를 해 나가는 동시에 게임 프로그램 자체의 보안에도 많은 신경을 쓴다. 그러다 보니 자연스럽게 외부 보안 코드를 사용하기도 하고, 내부 개발팀에서 제작한 보안 코드를 사용하기도 한다. 그러다 보면 게임 프로그래머 입장에서는 자연스럽게 왜 그런 코드들을 통해서 사설 서버에 대응할 수 없는지 궁금증이 생긴다. 여기에는 기존 보안 코드 체계가 가진 구조적인 특징에 기인한다고 할 수 있다. 사설 서버가 만들어지는 자세한 과정을 통해서 왜 기존 보안 코드 체계가 사설 서버에 대응력을 가지지 못하는지에 대해서 알아보도록 하자.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;그림 1&gt;에는 일반적인 온라인 게임 구조가 나와 있다. 게임 클라이언트가 있고, 네트워크를 통해서 게임 서버에 접속해서 게임을 하는 구조의 많은 게임들이 &amp;#x3C;그림 1&gt;과 같은 구조로 동작한다. 요즘은 여기에다 별도로 추가적으로 외부 보안 솔루션 코드나 게임사에서 개발한 자체 보안 코드를 추가하는 작업을 한다. 그렇게 하면 &amp;#x3C;그림 2&gt;와 같은 구조로 게임 구성이 변경된다. 기존의 게임 클라이언트/서버에 각각 보안 코드와 인터페이싱하는 부분이 추가되어 있다.&lt;/p&gt;
&lt;p&gt;게임 클라이언트에 추가된 보안 코드는 각종 해킹툴 탐지, 게임 클라이언트의 무결성 검증, 정상적인 게임 서버와 통신을 하는지에 대한 체크 등을 수행한다. 게임 서버에 탑재된 보안 코드는 게임 서버가 정상적인 게임 클라이언트와 통신을 하고 있는지에 대한 인증을 수행한다. 각각의 코드를 통해서 우리는 게임 클라이언트와 서버 모두에서 양쪽을 검증할 수 있는 체계를 갖출 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;private1.png&apos; data-alt=&apos;그림 1 일반적인 게임의 클라이언트/서버 통신 구조&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/0e32958ce95f241a75ae18d1a3402769/f537a/private1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 14.210526315789473%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAvUlEQVR42mNwVAj7H2qe8T/du+K/h0bsb3eVuP8uyhFTGYAglCGUmQEJ2Nvbs4BokLyHavx/N7Xo36leZf/DLbP+OyqE/3dRifzP4KQYDhZI8yr/760dDzUwcqK3XJSgi2q4pqtajKKzapQSiHZUjtC21wrlcVGKnOQBVOejkwA2MNouD6QHjBlARJhF5v9k99L/XppxKC60l4/nMDZOY4VhC4tQTpgL3ZXj/vsbJP9Ociv5HwM00FUlCmwgAGzZUW7Y6ErvAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그림 1 일반적인 게임의 클라이언트/서버 통신 구조&apos; title=&apos;&apos; src=&apos;/static/0e32958ce95f241a75ae18d1a3402769/efd7b/private1.png&apos; srcset=&apos;/static/0e32958ce95f241a75ae18d1a3402769/08678/private1.png 190w,
/static/0e32958ce95f241a75ae18d1a3402769/2edd7/private1.png 380w,
/static/0e32958ce95f241a75ae18d1a3402769/efd7b/private1.png 760w,
/static/0e32958ce95f241a75ae18d1a3402769/dc896/private1.png 1140w,
/static/0e32958ce95f241a75ae18d1a3402769/78873/private1.png 1520w,
/static/0e32958ce95f241a75ae18d1a3402769/f537a/private1.png 1730w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그림 1 일반적인 게임의 클라이언트/서버 통신 구조&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;private2.png&apos; data-alt=&apos;그림 2 게임 보안 적용 후의 클라이언트/서버 통신 구조&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a2bd2149d0b9c04a82568c038d7a19de/f537a/private2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 41.578947368421055%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAAAsTAAALEwEAmpwYAAABbElEQVR42p2Pz0sCQRTH3+aakIeiIDNjq7U1TaWDBFsXI130EFHUqrithkalKUKFRUUDHTp16N9wDOyv61A7vXa2H7eQ/MKHefMd3ve9AQRgKEkMYzGG8TjDSOTd9tAC0AFRMKe3J5Kz5TFOatqcSAIRtYXCnhYsYiZkvFezF8xcb7GUnGfpYIEBb0ZRRAyHEaNRRK+Xce91yF2ANB3V5U1pQ9EDnLSsS+qSPp4JlXJZ5QA3Y9WP+tYtVrQ2ZpSSAw+kKAgU/X5qb0rR4+nY3ssHgAq27HoIvkWAOHV6Iaem5vO97OJ+x0g2n/NrtW5KLlAO9JHwBz9vkAzszGg+zfvbwTdwIOSL7zv0lxO4OlWcTfiPRmAQEfI1yDgRVfNU7DWupU7jZq57ThRaa09Soy7QfwXqOrj4eXju2ju+cuPlQ5DdPS7j/dMKtu58WDnjnxsgsHw6vFtqurDc8r5dPySsMxKyjLrLMhtu6xNRtopWEXIXZAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그림 2 게임 보안 적용 후의 클라이언트/서버 통신 구조&apos; title=&apos;&apos; src=&apos;/static/a2bd2149d0b9c04a82568c038d7a19de/efd7b/private2.png&apos; srcset=&apos;/static/a2bd2149d0b9c04a82568c038d7a19de/08678/private2.png 190w,
/static/a2bd2149d0b9c04a82568c038d7a19de/2edd7/private2.png 380w,
/static/a2bd2149d0b9c04a82568c038d7a19de/efd7b/private2.png 760w,
/static/a2bd2149d0b9c04a82568c038d7a19de/dc896/private2.png 1140w,
/static/a2bd2149d0b9c04a82568c038d7a19de/78873/private2.png 1520w,
/static/a2bd2149d0b9c04a82568c038d7a19de/f537a/private2.png 1730w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그림 2 게임 보안 적용 후의 클라이언트/서버 통신 구조&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&amp;#x3C;그림 3&gt;에는 &amp;#x3C;그림 2&gt;와 같은 상황에서 해커가 게임 클라이언트를 공격하면 어떤 일이 벌어지는지를 보여준다. 해커는 게임 클라이언트 파일을 언팩하고 보안 코드와 연동된 부위를 제거하는 작업을 진행해서 게임 클라이언트에 포함된 보안 장치들을 무력화 시킨다. 이렇게 할 경우 게임 클라이언트가 구동하더라도 보안 코드는 아예 실행되지 않는다. 앞서도 언급한 것처럼 서버 쪽에 보안 코드가 있다면 그를 통해서 클라이언트의 무결성을 검증할 수 있다는 가능성은 있기 때문에 &amp;#x3C;그림 3&gt;의 단계에서는 아직까지 어떻게든 대응 해볼 수 있는 상태다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;private3.png&apos; data-alt=&apos;그림 3 논클라이언트/바이패스 프로그램의 동작 구조&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/27e456d0c6801c6364a285968df56e74/f537a/private3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 41.578947368421055%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAAAsTAAALEwEAmpwYAAABtUlEQVR42n2P60vbYBTG37bJHPjBscEUhVabpJNR8UMV6lAye40ofnC2zXJppBbX1nSR6OqltsFt+EEE/TeaDPTvW/P2mFfMlDH3wAMP5/LjHJRhRJyeKmFpUce19WOcY6V+jpHAqxcRsoLpcfUNH9FeEd9nZFFZVtzMejP5mNzfFg6w+tHA6WgJExbKc2XIsSqUeRNqq21YmdbwCrcFAqeJmWhhxHM4xRUmiElOvs+9zsfKRcGbWYtvDxrrp1DJtoBwiFE6KtrEpYW6LS3pTpb93EtFxdsMW0wiT5Z3JXqQn0nP++pGeKf0ZN74VfpQd3wOeqrlyY1IIrFDPykFnrHfQwtjGxE+wr9E/9LSqDL1F/B/Cvg7AmoO/anKjYBdb72197qsbXQYp9kO26pOOcpXOn7/poUeX37Ico1KqrvUjX4S7untScfscg5hEBaqmAEwzyagcxGHs6u5wbcfYageUFDdH0qR5UIBhXygn6v7oc0vRzQcnjO4ezkL36/nweiOQsUMAlJ12pXqQXevw7itnzN9uUG5ik4PFP15oLb74lO5GQLNGP59cp5wTSvmyo2QS1h3Ncak9u+MUAkAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그림 3 논클라이언트/바이패스 프로그램의 동작 구조&apos; title=&apos;&apos; src=&apos;/static/27e456d0c6801c6364a285968df56e74/efd7b/private3.png&apos; srcset=&apos;/static/27e456d0c6801c6364a285968df56e74/08678/private3.png 190w,
/static/27e456d0c6801c6364a285968df56e74/2edd7/private3.png 380w,
/static/27e456d0c6801c6364a285968df56e74/efd7b/private3.png 760w,
/static/27e456d0c6801c6364a285968df56e74/dc896/private3.png 1140w,
/static/27e456d0c6801c6364a285968df56e74/78873/private3.png 1520w,
/static/27e456d0c6801c6364a285968df56e74/f537a/private3.png 1730w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그림 3 논클라이언트/바이패스 프로그램의 동작 구조&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&amp;#x3C;그림 4&gt;는 &amp;#x3C;그림 3&gt;과는 반대로 해커가 게임 서버 쪽을 공격한 예가 나와 있다. 게임 서버를 유출 시키거나 게임 프로토콜을 리버싱해서 직접 만든 서버를 운영하는 것이다. 이 경우에도 클라이언트 쪽에는 보안 코드가 있기 때문에 이를 통해서 합법적인 게임 서버로의 접근인지에 대한 유효성을 간접적으로 검증할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;private4.png&apos; data-alt=&apos;그림 4 사설 서버의 동작 구조&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/8a86ab8c8edd76abf40e8707a140aeb9/f537a/private4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 14.210526315789473%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAsElEQVR42k2PTQrCQAyF0zpQoUVxV1p0qJ0plP7QAwizEPdCF4J4Am9ToWtX3sjbzOI507FiIDxCkpcvhDQFyhLIMqCqNBgDiEYyYXRBf2Fq9tUR2x3QdRqc2z2XQQBCGAJ5DtQ1kCTaDFvDgQ6vzVleylNxy47yurfa531F93dk+g+s1g5ASqBtHZDvG0PPw3SlaYAomg0nwkGIQCnF5nxyvvwR2k+E0CgKRxfHdg8fWGhe1FdvXo0AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그림 4 사설 서버의 동작 구조&apos; title=&apos;&apos; src=&apos;/static/8a86ab8c8edd76abf40e8707a140aeb9/efd7b/private4.png&apos; srcset=&apos;/static/8a86ab8c8edd76abf40e8707a140aeb9/08678/private4.png 190w,
/static/8a86ab8c8edd76abf40e8707a140aeb9/2edd7/private4.png 380w,
/static/8a86ab8c8edd76abf40e8707a140aeb9/efd7b/private4.png 760w,
/static/8a86ab8c8edd76abf40e8707a140aeb9/dc896/private4.png 1140w,
/static/8a86ab8c8edd76abf40e8707a140aeb9/78873/private4.png 1520w,
/static/8a86ab8c8edd76abf40e8707a140aeb9/f537a/private4.png 1730w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그림 4 사설 서버의 동작 구조&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&amp;#x3C;그림 3&gt;에 나와 있는 클라이언트 측의 공격이나 &amp;#x3C;그림 4&gt;에 나와 있는 서버 쪽의 공격이 단편적으로 벌어지는 경우에는 여전히 반대쪽의 보안 코드가 있기 때문에 무엇을 해볼 수 있는 여지가 있다. 진짜 무서운 일은 이 둘이 결합했을 때 벌어진다. &amp;#x3C;그림 5&gt;에는 이렇게 클라이언트와 서버 쪽을 모두 공격해서 둘 다 교체한 상태를 보여준다. 말 그대로 클라이언트, 서버 모두 변조된 상태고, 둘 모두에서 보안 코드는 제거되었다. 이런 구조적인 특징 때문에 이 상황에서 보안 코드가 할 수 있는 일은 아무것도 없다. 이건 사실 클라이언트, 서버의 공격이라고 하기 보다는 아예 또 다른 게임이 하나 더 만들어진 것과 같은 상황이라고 할 수 있다. 안타깝지만 불편한 진실은 현실 세계에서 통용되는 대다수의 사설 서버가 &amp;#x3C;그림 5&gt;와 같은 구조로 동작한다는 점이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;private5.png&apos; data-alt=&apos;그림 5 논클라이언트/바이패스와 사설 서버가 결합한 구조&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/184254d7f326bb34416218c424c6e170/f537a/private5.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 41.578947368421055%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAAAsTAAALEwEAmpwYAAABb0lEQVR42p2P20oCURSGlyfyrrCgNHJydOjAXCQmBRWSTlYQEdGY6UxKSKhMB6yEqJii7rroAXoCtxf1Bj1X6PZvJoIkCqoPPlhrbfbiX6SEszwV2ua5eYOX1895OpJrpcM5LEW2VSI4UgG9PyEU+mz1wEY/vcDdItrCwAAQj7cwMcEhyxzRKIfXy2lZ2kU6omM3UUN57QKr40W+KhWxIhWyiqj0KqIaTErqsK0qrgUp/eh7JcrA5QKfnOxgbAyYmgJGRgArAaXELLNVZypsZ85opsSdRlLMPiuRzCxZmGQ66QPrw3vdIZq16if4/Q1LBkFg8PmYNWPUzeLophCL7Xu6Ro4f/B0Lg1roy8JvsZI47LQwzU/t3r4gX3WwSn2I1UyJHV2FmwcXAtMNd1M79MjvJ5vkpL+wV3Oidh3A5b2Mm4fpztltEKVTN0onPUn7XVXJ9aeFuuFp5yrO9vFVuF2/k1v5qrutGZ6OZvxv4RvSY40n5mbzwQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그림 5 논클라이언트/바이패스와 사설 서버가 결합한 구조&apos; title=&apos;&apos; src=&apos;/static/184254d7f326bb34416218c424c6e170/efd7b/private5.png&apos; srcset=&apos;/static/184254d7f326bb34416218c424c6e170/08678/private5.png 190w,
/static/184254d7f326bb34416218c424c6e170/2edd7/private5.png 380w,
/static/184254d7f326bb34416218c424c6e170/efd7b/private5.png 760w,
/static/184254d7f326bb34416218c424c6e170/dc896/private5.png 1140w,
/static/184254d7f326bb34416218c424c6e170/78873/private5.png 1520w,
/static/184254d7f326bb34416218c424c6e170/f537a/private5.png 1730w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그림 5 논클라이언트/바이패스와 사설 서버가 결합한 구조&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;사설 서버 대응의 가장 본질적인 어려움은 &amp;#x3C;그림 5&gt;와 같은 단계가 일단 되고 나면 해당 상황까지 해커가 만든 결과물을 제어하는 일이 사실상 통제 불가능한 상황에 도달한다는 점에 있다. 이게 무슨 말이냐 하면 &amp;#x3C;그림 5&gt;의 단계에 이르면 그 어떤 방법으로도 이미 유포된 사설 서버를 제어할 수 없다는 의미다. 게임에 보안 코드를 강화하고 추가적인 바이너리 패치를 하고, 서버 구조를 변경하여도 이미 사설 서버용으로 배포된 과거의 클라이언트와 서버는 여전히 동작 가능하기 때문이다. 최근 인터넷에서 논란이 되고 있는 ‘잊혀질 권리’라는 것이 사설 서버에는 존재하지 않는 셈이다. 법적 대응을 제외하고 과거 버전으로 운영되는 사설 서버에 대응할 방법은 전혀 없다.&lt;/p&gt;
&lt;p&gt;사설 서버 문제를 제대로 바라보기 위해서는 우리가 무엇을 도난 당하고 있는지에 대해서 냉철하게 생각할 필요가 있다. 과연 우리는 무엇을 도난 당한 것일까? 서버 코드, 게임 서버 머신, 프로토콜 설계, 클라이언트의 동작 구조, 클라이언트 소스 코드 이런 것들일까? 안타깝지만 본질은 그곳에 있지 않다. 사설 서버 운영자가 저런 것들을 모두 들고 있다고 해서 사용자들이 거기에 비용을 지불하는 것은 아니기 때문이다. 게임사에서 도난 당한 진짜 보물은 게임 사용자들이 비용을 지불하는 본질, 바로 게임 컨텐츠에 있다.&lt;/p&gt;
&lt;p&gt;문제의 본질이 컨텐츠에 있다는 것이 어떻게 보면 사설 서버 대응의 새로운 가능성을 제시해 준다. 온라인 게임은 운영이 지속되는 동안 컨텐츠 또한 지속적으로 업데이트된다. &amp;#x3C;그림 5&gt;와 같은 단계가 되면 과거 버전까지의 컨텐츠는 모두 도난 당한 것이라고 생각할 수 있지만 앞으로 만들 컨텐츠까지 도난 당한 것은 아니다. 따라서 우리가 충분히 신경 쓴다면 앞으로 생산할 컨텐츠는 사설 서버로부터 보호할 수 있다. 사설 서버 대응의 초점은 바로 신규 컨텐츠 보호에 맞추어야 한다.&lt;/p&gt;
&lt;h3&gt;플랫폼으로서의 보안&lt;/h3&gt;
&lt;p&gt;아이러니하게도 보안의 관점에서 보자면 사설 서버에 대한 대응은 클라이언트 측면에서 먼저 이루어져야 한다. 앞서도 살펴본 것과 같이 클라이언트 측의 보안 코드가 너무 쉽게 제거된다는 것에서 모든 문제가 출발하기 때문이다. 일반적으로 클라이언트 보안 코드의 무결성은 게임 서버에 의존하는 경우가 많다. 하지만 사설 서버의 경우에는 게임 서버가 독립적으로 제작되기 때문에 이러한 방식이 통하지 않는다. 따라서 클라이언트 자체적으로 게임과 분리가 어렵도록 만드는 작업을 먼저 해야 한다.&lt;/p&gt;
&lt;p&gt;그렇다면 보안 코드와 게임은 왜 손쉽게 분리될까? 이는 소프트웨어 공학적으로 이야기하면 보안 코드와 게임 코드 사이에 결합도가 높지 않기 때문이다. 소프트웨어 공학적으로만 이야기하자면 좋은 구조인 셈이다. 하지만 이렇게 결합도가 낮다는 것은 해커 입장에서는 손쉽게 떼어낼 수 있다는 것을 의미한다. 이뿐이 아니다. 통상적으로 보안 코드가 외부 확장 모듈에 존재하는 경우가 많은데 이는 해커들의 작업을 더욱 쉽게 만든다.&lt;/p&gt;
&lt;p&gt;이런 논의가 출발에는 대부분 보안 코드의 노출되는 API 종류를 늘리고 API가 게임과 인터페이싱 하는 형태를 복잡하게 만들어서 결합도를 높여야 한다는 의견이 나온다. 하지만 이는 크게 의미 없는 행위다. 왜냐하면 인터페이스 코드가 아무리 복잡해져도 여전히 보안 코드는 게임 구동에 필수적인 요소는 아니기 때문이다.&lt;/p&gt;
&lt;p&gt;약간 생각을 바꿔서 이런 질문을 해보자. 왜 보안 코드는 손쉽게 제거할 수 있는데 운영체제 코드는 제거할 수 없을까? 보안 코드를 제거하듯이 게임에서 윈도우 관련 코드를 제거하고 리눅스에서 실행시킬 수는 없을까? 왜 보안 코드보다 윈도우 코드를 제거하는 일이 어려울까? 윈도우 코드도 모두 외부 확장 모듈에 존재하는데 말이다.&lt;/p&gt;
&lt;p&gt;그건 바로 윈도우 코드와 보안 코드가 게임에 가지는 의미가 다르기 때문이다. 보안 코드는 없어도 게임이 실행되는데 아무런 영향이 없지만 윈도우 코드가 없으면 게임이 실행조차 될 수 없다는 의미다. 즉, 앞서 API를 복잡하게 만들자는 생각은 형식론적인 관점에서 결합도를 높이자는 이야기다. 하지만 이런 전략은 도움이 되지 않는다. 왜냐하면 아무리 형식론적인 관점에서 결합도를 높여봤자 내용적인 측면에서 여전히 보안 코드는 게임 구동을 위한 필수 요소는 아니라는 점에는 변함이 없기 때문이다. 형식적인 측면에서의 결합도를 높이는 작업이 아닌 내용적인 측면에서의 결합도를 높여야 한다.&lt;/p&gt;
&lt;p&gt;보안 코드 자체가 게임에게 일종의 플랫폼으로 다가가야 한다. 게임이 실행되기 위해서는 반드시 필요한 서비스들이 있다. 파일을 읽고 쓰는 작업, 메모리를 할당하고 해제하는 작업, 외부 확정 모듈을 로드하고 언로드하는 작업, 그래픽 드라이버를 구동시키고 화면 제어를 하는 작업, 사운드 카드를 제어하는 작업 등등. 실제로 게임이 구동되기 위해서는 반드시 필요한 핵심 서비스들이 있다. 일반적으로 이러한 서비스는 운영체제에서 제공해 준다. 하지만 이제는 보안 코드에서 이러한 서비스들을 제공해 주도록 변경해야 한다. 설령 그것이 운영체제와 게임 사이에서 대리인 역할만 할지라도 말이다. 그렇게 내용적인 측면의 결합도가 높아져야 해커 입장에서 본질적으로 보안 코드를 제거하기가 어려워진다.&lt;/p&gt;
&lt;h3&gt;프로토콜 보호&lt;/h3&gt;
&lt;p&gt;게임 클라이언트와 보안 코드 사이의 내용적인 결합도를 일정수준 이상으로 높였다면 그 다음은 프로토콜을 손볼 차례다. 해커 입장에서 사설 서버를 제작하기 위해서는 반드시 게임 프로토콜을 전부 이해해야 하기 때문에 프로토콜은 매우 중요한 부분이다. 중요한 부분이지만 여기에도 대응하기가 쉽지 않은 부분이 있다. 바로 완성된 게임의 경우에는 게임 프로토콜을 손쉽게 변경할 수 없다는 점이다. 게임 서비스의 안정성과도 밀접한 연관이 있기 때문이다.&lt;/p&gt;
&lt;p&gt;모든 보안이 그렇겠지만 프로토콜이 노출되지 않도록 만드는 것은 불가능하다. 일단 프로토콜은 노출된다는 것을 전제에 두고 생각해야 한다. 따라서 프로토콜을 복잡하게 만들어서 절대 분석하지 못하도록 만들겠다는 전략보다는 프로토콜이 노출되더라도 손쉽고 안전하게 전체 구조를 변경할 수 있는 장치를 만드는 것이 더 좋은 전략이다. 여기에도 게임을 처음부터 새롭게 만든다면 프로토콜 설계를 그러한 방식으로 할 수 있겠지만 이미 만들어진 게임이라면 전체 구조를 변경할 수 있는 장치를 추가하는 것도 쉬운 일은 아니다. 이럴 때 쓸 수 있는 전략 중에 하나가 바이트 스트림 변형기를 이용하는 방법이다.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;그림 6&gt;에는 기존 게임 클라이언트, 서버에 스트림 변형기가 추가된 구조를 보여준다. 게임 클라이언트와 서버가 직접 통신하던 전에 방식이 아니라 네트워크 어댑터라고 불리는 스트림 변형기를 통해서 통신을 진행한다. 이렇게 하면 기존의 프로토콜 코드는 손대지 않고서 네트워크를 통해서 전송되는 바이트의 형태만 변형해서 실제로 프로토콜이 변경된 것처럼 보여지게 만드는 작업을 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;private6.png&apos; data-alt=&apos;그림 6 게임 클라이언트와 서버 사이에 네트워크 어댑터 추가&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/c8c1a3ef59c1df6c613f8fc7d840aacc/2561a/private6.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 90.52631578947368%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAACXBIWXMAAAsTAAALEwEAmpwYAAAEc0lEQVR42lWPa0xTZxjH39LC2DKRe0AoTI0oDBB0m3Kx4MLUycp90AI9vekmtFBAjJRbC4iLdAK67Jp929dBuciljIGIOJS46L4sMWwalyy7Ai0LWE7PefacFxbZh3/+7/t/fu//OYeQgRWgsqP6loH0r2xpmScDyxwZ2wAy5ExB5jXi8ADNhHnfynPWjtnIujBbJCLh0rfMSced3JEZF3dwykkVPeHyYClLRp7ho79TcOFhkVDet8zGTTq5o8gmTrm4JFTQiJMlQ/8Adj0i4gEnbnBC6KgLXp1chb0TLoj5ZhUix12818AK5zXGgmTrC8UOTvgTLtqxCnGUXYUDyGIhR248Ay/7yk+EONy/kImNp8SBGnVv+tiWJjaeoP7E7DCZdCciu0QzYTa6jXOwAvcbzmdJamb7B6nHLL3psvYeWaa1J52qnSoto/1qqszymexI876MDEtkmsz6aZrM0i3bmv/nwpvUjLbe9LSmLlIQrFgqDC6F3IBiHgVU/pvKD1SwilAN5IWUnSgMViQXhzCQH6Tgcv3fhbzA51xeQAkUBCuhIKQUiHyX6o+cSIY3F3RuWMtsbF22lW1RXmGbFVdY1UHjem6YBnKitFk50apkeZgalLHn3B3qbtb4ppm9kNvBtjPdbH1OO5sbybDy8HKWFESol4qkOmDiKnkmzgBMbCVoE6tBE28Exe4zrEL6HhRKdSfyo8oOlUjPQlGUltMkVEF5TAVltIlV9E2RVAuFERogOYGar94J1A6+7afqP7mjzH7Kr8x+ckcpdXmA5mt5oHbydIg6KTtUu0cepBuXB2n6KUO5Tfa0n8qOnF0erBkkTK2oT2UiN/T1Lw5XtYYPVzaFUH/fvHNYVUMGcf5t+XkSX1rrnSCchUyYCYyRsmHDugu+Q+U1ZJypEX1B9HW+axqTF1y8tJ+3ffIWXL4mg57Ps6Ht6hugNUk8FQ2+oK31zdCbxJnCWV3lxXX2pkHXx1lw+boMrn2ZA+etr3D6OjHoa30XCWP0XlEZvTcYo4+7yhzhNjbscpuaot1n6/zdKoNkTVfjA2VGyTHGJJFp8VxukKyfqdvprmwIRz7SXd0odetML60zRgmoDN4/klKDz5qiUgyaWn/+0vVTYO0+TlXdGgPF50QedZ0PKCskGSUGcaa61kfIuBrrARDYpq5UaOvNAn19CKc0ikBp8F4kra3izrYW8YfWVrHNbCa2RpT5IrE1N4ptbRZxF+YfWRpe2NPRRPYKZyFrbhQhK0J20y0tlOuxtEgaCNwmD2GOPEV/DLPkyf80R37G/Hf0ZPQU1F80287cpnqM+a/oM4SfEy3BHQIw78fDw0MAD+IBvt8HsBDOI8DBfQL8PDmK5+PwQARYwsFCBMAPryObCHB/N8AdHw7uYcccWSQwjVun8dGtlz2wkISDBFQsx38X4YEpwgrL+GksnCaZcBcLaRaOpcmb7N39HMx4s7gIkHlEEF6CW/TCIwxU01v3m/g181g4i4U38Qvv0Zyj8+2swM1RX/wXtID38iVVLRIAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그림 6 게임 클라이언트와 서버 사이에 네트워크 어댑터 추가&apos; title=&apos;&apos; src=&apos;/static/c8c1a3ef59c1df6c613f8fc7d840aacc/efd7b/private6.png&apos; srcset=&apos;/static/c8c1a3ef59c1df6c613f8fc7d840aacc/08678/private6.png 190w,
/static/c8c1a3ef59c1df6c613f8fc7d840aacc/2edd7/private6.png 380w,
/static/c8c1a3ef59c1df6c613f8fc7d840aacc/efd7b/private6.png 760w,
/static/c8c1a3ef59c1df6c613f8fc7d840aacc/dc896/private6.png 1140w,
/static/c8c1a3ef59c1df6c613f8fc7d840aacc/2561a/private6.png 1180w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그림 6 게임 클라이언트와 서버 사이에 네트워크 어댑터 추가&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&amp;#x3C;그림 6&gt;에는 네트워크 어댑터를 통해서 통신이 진행되는 실질적인 과정이 나와 있다. 왼쪽이 클라이언트, 오른쪽이 서버인 경우에 클라이언트에서 서버로 전송하는 과정을 나타낸 그림이다. 왼쪽부터 살펴보면 프로토콜 레이어에서 내려온 바이트를 전송 큐에 넣은 것을 최종적으로 전송하기 전에 네트워크 어탭터를 통해서 바이트 스트림을 변형해서 전송한다. 마찬가지로 서버 쪽에서도 받은 데이터를 네트워크 어댑터를 통해서 바이트 변환을 복구한 다음 수신 큐에 데이터를 넣는 구조로 되어 있다. 이렇게 작성할 경우에 기존 프로토콜 코드는 건드리지 않고 실질적으로 네트워크를 통해서 전달되는 패킷의 구조를 다르게 변형시킬 수 있다. 더불어 해커가 네트워크 어댑터 코드를 분석했다고 하더라도 해당 어댑터 코드만 새롭게 변형해서 손쉽게 다른 구조로 변경할 수 있다는 장점이 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;private7.png&apos; data-alt=&apos;그림 7 네트워크 어탭터를 통한 송수신 구조&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/b8ff8b40e51f02a4f74aa1f49d6e90c6/f537a/private7.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 41.578947368421055%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAAAsTAAALEwEAmpwYAAABwElEQVR42mNwUY7466wY/jfKJudvhl/lXzeVqN9uylH/nRQjQhiAIJQhlJkBCmBsN5XIYFegGne16N/JHiV/Yx3y/zorhf8FmcXgrhr3300l9n+cfdH/DO/q/54a8X891RL/e6jE4TQQJOehmvDfRyf5b5Zfzf8k17L/IHNAmMFZKWIVCIdbZq6Kss1Z7awSudJJKWKDi0qYBUhzPUM9E8xAGBskB/TVeg/1mJUxDnmrI6yyVsHMYUAGlgpB8sbGaawMxAFGEGEtGSpnL2/PgVWFrXioojEDioGMODDcQJAeD4ZcdriO6GzGWclFvGsK6lRWFdWprc6pkF4Znc20ITqXBeLlegaEl6HseKBcdBbj+sxyiZUlDRqrC+tUVycX8a+KzmJexZBYxPQit0bwf0Ov0b+2ydb/y9tU/qaWMf5PLeSOMGCYKOpm6KviqhaqCMJuWr4qpgz1EinFHGGppYz/S5sV/7VMNPvfMtH8f26N8P+kIqb/DDE5LE/j8zj+lzXr/C5v0fuTUSb+KzaX6X9cLhs4ll31XLnt5eM5QBjEBrswjy04Npf5f0aZ2K+KFv0/JY2afxILuP/EZLP8AQA13KQAKben+AAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그림 7 네트워크 어탭터를 통한 송수신 구조&apos; title=&apos;&apos; src=&apos;/static/b8ff8b40e51f02a4f74aa1f49d6e90c6/efd7b/private7.png&apos; srcset=&apos;/static/b8ff8b40e51f02a4f74aa1f49d6e90c6/08678/private7.png 190w,
/static/b8ff8b40e51f02a4f74aa1f49d6e90c6/2edd7/private7.png 380w,
/static/b8ff8b40e51f02a4f74aa1f49d6e90c6/efd7b/private7.png 760w,
/static/b8ff8b40e51f02a4f74aa1f49d6e90c6/dc896/private7.png 1140w,
/static/b8ff8b40e51f02a4f74aa1f49d6e90c6/78873/private7.png 1520w,
/static/b8ff8b40e51f02a4f74aa1f49d6e90c6/f537a/private7.png 1730w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그림 7 네트워크 어탭터를 통한 송수신 구조&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&amp;#x3C;그림 7&gt;의 네트워크 어댑터의 경우에는 기존 프로토콜 코드를 하나도 수정하지 않고 변형하는 형태이기 때문에 변형이 바이트 단위의 작업으로 제한된다. 결국 비트 연산 외에는 할 수 있는 작업이 없다. 비트 단위의 연산 또한 문맥을 고려하기 어렵기 때문에 궁극적으로 대칭적인 구조의 변형 작업밖에는 할 수 없다는 단점이 있다. 이런 단점을 극복하기 위해서는 결국 바이트 단위가 아닌 조금 더 큰 규모에서 변형을 가할 수 있어야 한다. 추가적인 개발 리소스 투입이 가능한 상황이라면 프로토콜을 이중화 시키는 방법 또한 생각해 볼 수 있다. 프로토콜 이중화란 기존 프로토콜을 새로운 형태의 프로토콜로 감싸는 작업을 하는 것을 말한다. 물론 신규 프로토콜은 일정 양의 데이터를 전송하는 기능을 하는 메타 프로토콜이기 때문에 복잡하게 구성할 필요는 없다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 사이드 이펙트, 그리고 함수 디자인]]></title><description><![CDATA[위와 같은 함수를 생각해 봅시다. url로 넘어온 경로를 다운로드 해서 buffer에다 저장하는 함수입니다. 결과 상태를 리턴 합니다. 그런데 이 함수에는 한 가지 단점이 있습니다. 웹 서버가 40…]]></description><link>https://jiniya.net/wp/archives/12789</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12789</guid><pubDate>Wed, 12 Mar 2014 23:59:26 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Downloader&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
	xstatus &lt;span class=&quot;token function&quot;&gt;DownloadUrl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;string url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_t buffer_size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위와 같은 함수를 생각해 봅시다. url로 넘어온 경로를 다운로드 해서 buffer에다 저장하는 함수입니다. 결과 상태를 리턴 합니다. 그런데 이 함수에는 한 가지 단점이 있습니다. 웹 서버가 404 오류 같은 것을 뿜어도 성공을 리턴한다는 것이죠. 404 페이지를 그냥 다운로드 받습니다. 뭐 함수 디자인이 그렇게 된 것이니 버그는 아닌 셈이죠. 여기에다 404 오류 코드 같은 결과 값을 알 수 있는 기능을 추가한다고 생각해 봅시다. 어떻게 작업 하는 것이 좋을까요? 당연한 이야기겠지만 그 결과값은 DownloadUrl 함수를 수행하는 동안에만 알 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Downloader&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
	xulong return_code_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	xstatus &lt;span class=&quot;token function&quot;&gt;DownloadUrl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;string url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_t buffer_size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token comment&quot;&gt;// processing&lt;/span&gt;
		return_code_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get_return_code&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; status&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	xulong &lt;span class=&quot;token function&quot;&gt;GetReturnCode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; return_code_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위의 코드는 그러한 작업을 해 본 한 가지 샘플 코드입니다. DownloadUrl의 인터페이스를 수정하지 않아서 기존 코드와의 호환성을 유지 시켰습니다. 그리고 GetReturnCode라는 함수를 추가해서 DownloadUrl을 수행하는 동안 발생한 리턴 코드 값을 확인할 수 있도록 하는 인터페이스를 추가했죠. 호환성을 유지하면서 잘 확장한 디자인 같아 보이지만 이는 함정입니다.&lt;/p&gt;
&lt;p&gt;첫번째 문제는 DownloadUrl과 GetReturnCode 사이에 어떠한 연관성도 찾을 수 없다는 점입니다. 즉, 이 클래스의 내부를 보지 않은 프로그래머가 DownloadUrl의 리턴 코드 값을 확인하기 위해서 GetReturnCode를 호출해야 한다는 점을 알 수 없습니다. 매뉴얼을 보고 익혔다고 하더라도 나중에 계속 기억하기가 쉽지 않죠.&lt;/p&gt;
&lt;p&gt;두번째는 스레드 세이프하지 않다는 점입니다. DownloadUrl 함수를 호출하면 return_code_ 값이 변경됩니다. 이렇게 함수 호출로 인해서 다른 상태 값이 변경되는 것을 우리는 사이드 이펙트라고 부릅니다. 일반적으로 이러한 사이드 이펙트가 많으면 많을 수록 스레드에 안전하도록 만들기가 어렵고 복잡해 집니다. 특히나 요즘 같이 멀티 스레드가 대세인 환경에서는 다른 프로그래머에게 이 함수는 스레드 세이프하지 않아. 라고 아이기를 해주어야 하죠.&lt;/p&gt;
&lt;p&gt;끝으로 마지막 문제는 스레드 세이프하지 않다는 점에 더해서 그 스레드 세이프하지 않음을 외부에서 제어할 방법이 전혀 없다는 점입니다. DownloadUrl과 GetReturnCode를 하나로 외부에서 묶기가 힘들다는 것이죠. 결국 외부에서 묶으려면 이를 포장한 Downloader2라는 클래스를 새로 만들어서 소스 코드 전체에 그 녀석을 쓰는 방법 밖에는 없습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Downloader&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
	xulong return_code_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	xstatus &lt;span class=&quot;token function&quot;&gt;DownloadUrl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;string url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_t buffer_size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DownloadUrl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; buffer_size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	xstatus &lt;span class=&quot;token function&quot;&gt;DownloadUrl&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;xpulong rcode&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; string url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_t buffer_size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token comment&quot;&gt;// processing&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rcode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rcode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get_return_code&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; status&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위 코드는 일반적으로 올바른 방향의 재구조화된 코드를 보여줍니다. 앞선 코드와 가장 큰 차이점은 사이드 이펙트를 없앴다는 점입니다. 기존 함수 인터페이스는 유지하고 새로운 return_code를 전달 받는 함수 시그니처를 추가했습니다. 기존 함수 코드는 새로운 함수에 옮겨 쓰고, return_code 인자가 있는 경우에는 해당 값을 전달하도록 만든 것이죠. 그리고 기존 함수는 새로운 함수를 호출하도록 만들어서 소스 코드의 중복을 없애고 있습니다.&lt;/p&gt;
&lt;p&gt;대체로 함수형 언어가 멀티 코어에 유리한 이유는 사이드 이펙트가 없기 때문입니다. 함수 디자인을 할 때에도 대체로 사이드 이펙트가 없도록 디자인 하는 것이 멀티 스레드, 멀티 코어 환경에서 훨씬 수월하게 동작할 수 있도록 만드는 지름길입니다. 함수에 어떤 사이드 이펙트가 존재한다면 이게 반드시 필요한 것인지 항상 물어보는 습관을 가지는 것이 중요하겠습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 게임 보안: 당신의 메모리는 안녕하십니까?]]></title><description><![CDATA[640K ought to be enough for anybody. 640K는 누구에게나 충분한 메모리다. – Bill Gates 한 시대를 풍미했던 컴퓨터 엔지니어, 컴퓨터로 쌓을 수 있는 최고의 부를 거머쥔 사람, 빌 게이츠도 한때 640K…]]></description><link>https://jiniya.net/wp/archives/12674</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12674</guid><pubDate>Thu, 19 Dec 2013 23:59:25 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;640K ought to be enough for anybody.&lt;/p&gt;
&lt;p&gt;640K는 누구에게나 충분한 메모리다.&lt;/p&gt;
&lt;p&gt;– Bill Gates&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;한 시대를 풍미했던 컴퓨터 엔지니어, 컴퓨터로 쌓을 수 있는 최고의 부를 거머쥔 사람, 빌 게이츠도 한때 640K 메모리면 온세상 프로그램을 다 돌릴 수 있다고 생각했던 시절이 있었던 것 같다. 빌 게이츠가 실제로 저 말을 했는지 안 했는지는 모르겠지만 한 가지 분명한 사실은 저 이야기가 통용되던 때로부터 시간이 한참은 흘렀다는 점이다. 그 사이 CPU도 변했고, 운영체제도 변했고, 프로그램도 변했다. 이제는 640K로만 돌아가는 프로그램이 있다면 그게 더 신기할 지경인 세상이다.&lt;/p&gt;
&lt;p&gt;현대적인 프로그램은 상상하기도 힘들만큼 많은 메모리를 사용한다. 그중에 백미는 역시 게임이다. 게임은 여전히 가장 많은 메모리와 CPU 자원을 필요로 하는 프로그램 중에 하나다. 게임 보안 소프트웨어는 그런 프로그램과 동시에 실행되어야 하기 때문에 다양한 제약 사항들이 존재한다. 메모리도 그 중 하나다. 모 게임의 경우에는 게임 보안 솔루션 때문에 대규모 컨텐츠 패치가 불가능한 상황이라 우리 제품으로 윈백한 경우도 있었다. 보안 제품이 너무 많은 메모리를 사용했던 것이다. 어쨌든 많은 메모리를 필요로 하는 게임, 그리고 동작하기 위해서는 반드시 메모리를 사용할 수 밖에 없는 보안 솔루션의 한집 살이가 쉽지 않다는 사실에는 이견의 여지가 없다.&lt;/p&gt;
&lt;p&gt;CPU 이슈는 종종 제기됐지만 메모리 이슈는 크게 부각되지 않았기에 우리는 그간 메모리가 안녕하신줄 알았다. 하지만 최근에 출시한 따끈따끈한 게임은 기존 게임들보다는 더 많은 메모리를 필요로 했기에 메모리는 안녕하지 못했다. 우리는 그 핫한 게임과 한집 살림을 하기 위해서 몇 가지 주요한 기능들을 포기해 가면서 메모리를 좀 더 아껴쓰게 만드는 작업들을 했는데 이 과정이 생각보다 재밌었기에 여기에 조금 소개해볼까 한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;처음 제기된 이슈는 메모리 단편화였다. 사실 우리가 터무니 없이 많은 메모리를 사용하지는 않기 때문에 단편화에 영향을 줬다면 딱 하나 밖에는 없다. ASLR(Address Space Layout Randomization)이다. 우리는 지난 글에도 썼지만 코드의 분석을 어렵게 하기 위해서 ASLR을 사용한다. 코드를 메모리 여기 저기에 분산 배치시키는 기능을 의미한다. 그런데 이게 아주 큰 연속적인 공간을 필요로 한다면 문제가 될 수 있다. 우리는 이 옵션을 껐고, 게임은 잘 동작했다. 이렇게 문제가 해결되는 것처럼 보였다. 나중에 시간나면 단편화에 영향을 최소한으로 주는 ASLR 알고리즘을 만들어야겠다는 생각을 하면서…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;그런데 그 사라졌을 것 같은 이슈는 사라진 게 아니었다. 단지 지연됐을 뿐이었다. 게임을 오래하면 단편화 문제가 계속 발생한다는 것이었다. ASLR을 껐지만 우리도 게임 실행 중 메모리 할당과 해제를 반복하기 때문에 당연히 영향을 줄 수 밖에 없다.&lt;/p&gt;
&lt;p&gt;게임 메모리 단편화에 단 한톨의 영향도 끼치지 않겠다는 생각으로 대규모 토목 공사가 시작됐다. 메모리 풀을 만들고 덩어리 메모리를 할당하는 곳은 모두 그 풀에서 동작하도록 구조를 변경하는 작업이 진행됐다. 그러면 할당과 해제를 반복해도 초기에 고정된 풀 내에서만 벌어지기 때문에 게임에 주는 영향은 최소화할 수 있기 때문에 게임 내 메모리 단편화 현상을 피할 수 있다는 생각에서였다.&lt;/p&gt;
&lt;p&gt;ASLR을 끈 것이나, 메모리 풀을 사용해서 집중된 영역에 뭔가를 배치시키는 것 자체가 지난 글에서 언급한 보안성과는 전혀 상관없는 내용이다. 하지만 현실 세계에서는 응당 안정성이 보안성에 우선한다. 일단 게임을 할 수 있어야 핵을 잡든 말든 중요한 것 아니겠는가?&lt;/p&gt;
&lt;p&gt;대규모 토목 공사인 줄 알았지만 그렇게 많이 고칠 필요는 없었다. 덩어리 메모리를 사용하는 곳이 크게 많지는 않았기 때문이다. 토목 공사가 끝날 즈음에 난 초기 풀 크기로 통크게 100메가 바이트를 지정했다. 풀은 두개를 사용했다. 그러니 시작과 동시에 할당은 아니더라도 메모리 공간은 200메가 바이트를 깔고 들어가는 셈이었다. 물론 우리가 그 정도로 많은 메모리를 사용하지는 않지만 어떤 경우에도 게임 내 단편화 현상에 영향을 주고 싶지는 않았기에 느낌대로 크게 잡아 버렸다. 이때까지만 해도 난 단편화 문제라 보고 받았기 때문에 이는 현명한 선택이라 생각했다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이 대규모 토목 공사도 새로 출시한 핫한 게임을 만족시키기엔 부족했다. 이 시점부터 난 게임 프로그래머와 직접 대화할 수 있었고 실질적인 문제가 단편화가 아니라는 사실을 알게 되었다. 게임 자체가 2기가 바이트에서 거의 간당 간당하게 돌아가기 때문에 서드 파티 프로그램이 너무 많은 공간을 사용하면 문제가 된다는 것이었다. 64메가 바이트 정도 안쪽으로 공간이 집중될 수 있었으면 좋겠다는 이야기를 했다. 즉, 문제는 단편화도 단편화지만 메모리 공간 자체가 많이 부족하다는 의미였다.&lt;/p&gt;
&lt;p&gt;메모리가 이리도 싼 세상에, 심지어 핸드폰도 2기가 넘는 메모리를 탑재하는 시대에 메모리 타령이라니 조금 이상하게 들릴지도 모르겠다. 우리가 여기서 이야기하는 메모리 한계는 실제 물리 메모리가 아니다. 거의 대부분 주소 공간에 관한 이야기다. 주소 공간이란 한 프로그램이 한번에 사용할 수 있는 메모리 공간이라고 생각하면 된다. 16기가 바이트의 메모리를 탑재하고 있다고 16기가 바이트를 다 쓸 수 있는게 아니기 때문이다. 64비트 CPU, 64 운영체제, 64 응용 프로그램이라면 가능하겠지만 게임은 아직 그런 환경을 고려하기란 쉽지 않다. 어쨌든 32비트를 고려해야 하기 때문에 결국은 32비트 응용 프로그램에서 발목이 잡힌다. 윈도우 환경에서 일반적으로 32비트 응용 프로그램이 사용할 수 있는 주소 공간은 2기가 바이트로 제한된다.&lt;/p&gt;
&lt;p&gt;이런 상황에서 주소 공간을 낭비하는 가장 대표적인 형태는 VirtualAlloc의 잘못된 사용에서 발생한다. 32비트 환경에서 윈도우는 할당 단위로 64KB(0x10000)를 사용하고, 페이지 크기로 4KB(0x1000)을 사용한다. 할당 단위가 64KB이기 때문에 VirtualAlloc을 64KB의 배수가 아닌 다른 값으로 사용하면 쓸 수 없는 주소 공간, 슬랙이 생겨버린다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;PVOID ptr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;VirtualAlloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x8000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MEM_COMMIT &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; MEM_RESERVE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PAGE_READWRITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위와 같은 간단한 할당 코드를 살펴보자. 32KB를 한번에 할당하기 위해서 VirtualAlloc을 호출했다. 메모리가 있다면 위 호출은 정상적으로 실행돼서 ptr에 어떤 값을 반환할 것이다. 보통 이런 호출은 어떠한 문제도 없다. 하지만 공간이 모자란 경우에는 이런 호출 조차도 사치가 된다. 앞서도 이야기 했지만 윈도우는 64KB 할당 단위를 사용하기 때문에 위와 같이 호출해 버리면 ptr 다음의 32KB는 사용할 수 없는 공간, 죽은 메모리 공간이 되기 때문이다. 슬랙을 없애기 위해서는 아래와 같은 형태로 메모리를 꼼꼼하게 사용해야 한다. 아래 코드는 64KB 영역을 예약하고 32KB만 물리 메모리를 할당하는 것을 의미한다. 나중에 32KB가 더 필요하면 ptr 뒤쪽의 32KB를 할당해서 사용할 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;PVOID ptr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;VirtualAlloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x10000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MEM_RESERVE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PAGE_READWRITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;VirtualAlloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ptr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x8000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MEM_COMMIT&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PAGE_READWRITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이런 것들을 완전히 꼼꼼하게 관리하기 위해서는 별도의 풀 메모리 매니저 API를 만들어야 한다. 단지 읽고/쓰기 위한 공간을 할당하기 위한 목적이라면 그냥 힙 관련 API를 사용하는 것이 바람직하다. 힙 API도 내부적으로 큰 덩어리들에 대해서는 VirtualAlloc을 사용하기 때문에 보통 프로그래머들이 생각하는 것처럼 속도 저하가 그리 심하지는 않다. 뭐 직접 메모리 매니저를 구현하는 비용 생각하면 그놈이 그놈인 경우가 다반사다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#4&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;풀 크기야 일부러 크게 잡아둔 것이었기 때문에 100MB라고 된 부분을 그냥 10MB로 바꿔버리면 된다. 우리에게 적합한 최소 크기에서 조금의 마진이 있는 형태로 풀 크기를 조정하는 작업을 진행하면서, 게임 프로그래머의 고민을 조금이나마 도와 주기 위해서 게임 메모리 공간을 살펴보기로 했다. 내가 제일 먼저 한 일은 게임이 더 이상 진행 불가가 된 상황의 메모리 맵을 추출하는 일이었다. 다행이도 꼼꼼한 게임 프로그래머는 우리에게 풀 덤프 파일을 제공해 주었고 거기나 난 아래와 같은 거대한 메모리 맵을 손쉽게 추출할 수 있었다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;  BaseAddr EndAddr+1 RgnSize     Type       State      Protect       Usage
-------------------------------------------------------------------------------------------
*        0    10000    10000             MEM_FREE    PAGE_NOACCESS   Free 
*    10000    20000    10000 MEM_MAPPED  MEM_COMMIT  PAGE_READWRITE   
\* 20000 21000 1000 MEM\_PRIVATE MEM\_COMMIT PAGE\_READWRITE  
\* 21000 30000 f000 MEM\_FREE PAGE\_NOACCESS Free 
\* 30000 34000 4000 MEM\_MAPPED MEM\_COMMIT PAGE\_READONLY ActivationContextData 
\* 34000 40000 c000 MEM\_FREE PAGE\_NOACCESS Free 
\* 40000 42000 2000 MEM\_MAPPED MEM\_COMMIT PAGE\_READONLY ActivationContextData 
\* 42000 50000 e000 MEM\_FREE PAGE\_NOACCESS Free 

...

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;엄청난 분량의 로그가 출력됐다. 게임이 정말 많은 메모리를 사용하고 있다는 것을 알 수 있었다. 그 로그 중에서 진짜 할당이 실패했는지 조사하기 위해서 비어 있는 영역만 따로 모아서 크기 순으로 정렬을 해서 살펴보았다. 그랬더니 아래 나와 있는 것처럼 가장 큰 덩어리가 0xF0000 크기의 영역이었다. 15MB 정도를 한번에 할당할 수 있는 영역이다. 하지만 게임이 할당한 것으로 보이는 메모리 중에는 20MB 가까운 메모리도 있었기에 그정도 크기를 요청했다면 실패했을 수도 있겠다는 생각이 들었다.&lt;/p&gt;
&lt;p&gt;게임 프로그래머의 이야기처럼 여기저기 단편화된 메모리 조각들도 있었다. 아래 리스트에서도 연한 글씨로 표시된 6d10c000, 4df31000 영역은 조각난 메모리 영역으로 공간은 비어있지만 실제로 그 메모리의 앞쪽 영역은 사용할 수 없는 부분이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;**\* 7b320000 7c220000 f00000 MEM\_FREE PAGE\_NOACCESS Free 
\* 712f6000 72180000 e8a000 MEM\_FREE PAGE\_NOACCESS Free 
\* 7e1c0000 7f030000 e70000 MEM\_FREE PAGE\_NOACCESS Free** 

* 6d10c000 6def0000   de4000             MEM_FREE    PAGE_NOACCESS     Free 
* 4df31000 4ed00000   dcf000             MEM_FREE    PAGE_NOACCESS     Free 

**\* 4baf1000 4c560000 a6f000 MEM\_FREE PAGE\_NOACCESS Free 
\* 67570000 67d40000 7d0000 MEM\_FREE PAGE\_NOACCESS Free** 

...

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;다음으로 할당된 영역만 따로 뽑아서 살펴보았다. 메모리가 그렇게나 많이 필요한 상황은 아니라고 생각했기에 할당 단위의 문제라 생각했다. 앞서 설명한 것과 같이 VirtualAlloc의 사용 방법을 변경하면 상당히 많은 메모리를 절약할 수 있을거라는 믿음이 있었다. 로그의 출력 결과는 나의 이론을 뒷받침하는 것처럼 보였다. 0x12000, 0x11000 등의 크기로 할당된 무수히 많은 메모리 공간들이 보였다. 빙고~ 이 영역들을 없애면 게임이 훨씬 더 많은 공간을 가용 메모리로 사용할 수 있겠다는 생각이 들었다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;* 584d0000 5998a000  14ba000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE      
|-568c2000 57500000 c3e000 MEM\_PRIVATE MEM\_COMMIT PAGE\_READWRITE  
\* 5e3b0000 5ee5c000 aac000 MEM\_PRIVATE MEM\_COMMIT PAGE\_READWRITE  

...

\* 440b0000 440c2000 12000 MEM\_PRIVATE MEM\_COMMIT PAGE\_READWRITE  
\* dda0000 ddb1000 11000 MEM\_PRIVATE MEM\_COMMIT PAGE\_READWRITE  
\* dde0000 ddf1000 11000 MEM\_PRIVATE MEM\_COMMIT PAGE\_READWRITE  
\* de20000 de31000 11000 MEM\_PRIVATE MEM\_COMMIT PAGE\_READWRITE  
\* de40000 de51000 11000 MEM\_PRIVATE MEM\_COMMIT PAGE\_READWRITE  
\* de60000 de71000 11000 MEM\_PRIVATE MEM\_COMMIT PAGE\_READWRITE  

...

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;#5&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;시간만 있었다면 이 단계에서 성급하게 증명하려 들었을 것 같다. 메모리 매니저 API까지 제공하는 보안 솔루션 하면 간지 나니깐. 하지만 중요한 외부 미팅이 있었기에 생각은 여기서 멈출 수 밖에 없었다. 결과론적으로 그게 나를 구했다.&lt;/p&gt;
&lt;p&gt;오늘 출근해서는 메모리 매니저 API를 구현하려고 연습장을 꺼내 들고는 끄적거리는데 생각보다 복잡했다. 우리 풀 매니저를 그냥 게임 API에 연결해서 사용하면 되는데 문제는 VirtualAlloc 따위를 후킹했을 때 훅 함수에서 다시 VirtualAlloc이 호출되는 불상사를 없애야 한다는 점이었다. 모든 동적 할당을 봉쇄한 코드를 새로 작성해야 해서 성가신 작업이었다. 그렇다고 검증도 안된 것을 게임사에 적용해 달라고 하기도 무리수.&lt;/p&gt;
&lt;p&gt;어떡하지? 어떡하지? 하고 있는데 좋은 생각이 떠올랐다. 이게 진짜 의미있는 짓인지 알아보자는 생각이었다. 과연 내가 이 변경을 통해서 얼마나 많은 슬랙 공간을 확보할 수 있을까? 뭐, 이 이론적인 가능성이 괜찮다면 게임사에다 이야기 할수도 있겠다는 생각이었다. 이 작업을 하기 위해서 할당된 메모리 크기 별로 카운트를 추출했다. 게임사에서 32KB 이상의 메모리 할당에 VirtualAlloc을 사용한다 했으니 우리의 관심 영역인 32KB(0x8000) 이상 128KB(0x20000) 이하의 메모리에 대해서 먼저 조사를 했다. 이 영역에 사용된 크기별 카운트는 아래 목록에 나와 있는 것과 같다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;00008000: 30
00009000: 39
0000a000: 33
0000b000: 11
0000c000: 35
0000d000: 20
0000e000: 51
0000f000: 240
00010000: 4996
00011000: 403
00012000: 16
00013000: 10
00014000: 8
00015000: 12
00016000: 4
00017000: 5
00018000: 6
00019000: 3
0001a000: 4
0001b000: 4
0001c000: 4
0001d000: 6
0001e000: 1
0001f000: 12
00020000: 7
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 목록에 대해서 완벽한 메모리 풀을 만들었다면 얼마나 많은 슬랙 공안을 확보할 수 있을까? 0x11000으로 할당된 403개의 공간이 나를 향해 빵긋 웃는듯이 보였다. 하지만 이내 그건 초심자의 행운 같은 것임을 깨달았다. 계산 결과는 생각과 달랐기 때문이다. 위 메모리 할당에 사용되는 총 공간은 404MB인데 슬랙으로 낭비는되는 공간은 단지 27MB였다. 헐~ 물론 404MB대비 27MB는 작은 비율은 아니다. 비율에 희망을 걸면서 전체 메모리 할당 내역을 상대로 계산을 확장했다. 그랬더니 할당에 사용된 총 공간은 1331MB였는데 슬랙으로 낭비되는 공간은 꼴랑 40MB에 불과했다. 맙.소.사~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#6&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;엄마가 그랬다. 얘야 되도록 파이썬을 사용하렴. 성급한 최적화만큼 멍청한 일도 없단다. CPU 보다는 네 시간이 항상 더 소중하다는걸 기억해야지. 그렇다. 성급하게 일을 안 벌리길 잘한것 같다는 생각 ㅋ~&lt;/p&gt;
&lt;p&gt;40MB가 작은 메모리가 아닐수도 있다. 마치 티핑 포인트 같은 지점일수도 있다. 단지 20MB만 더 있으면 다시 해제/할당의 사이클을 반복하면서 게임이 계속 진행됐을 수도 있다. 하지만 이는 너무 억척스러운 가정이라는게 함정.&lt;/p&gt;
&lt;p&gt;이슈가 끝날 즈음 그런 생각이 들었다. 64비트 시대가 멀지 않았구나. 1MB의 제약을 벗어나려 32비트의 세계가 도래한 것처럼 2GB도 어느새 너무 좁은 공간이 되어 버렸다. 뭐 맛폰 CPU가 64비트로 가는 세상이니 말 다했지.&lt;/p&gt;
&lt;p&gt;한집 살림을 위한 안정성은 어느 정도 확보했으니 다시 보안성을 위해서 풀을 쪼개고 할당을 랜덤화할 차례… 뫼비우스의 띠 위를 걷고 있는 듯한 이 느낌은 뭐지. 하앍~&lt;/p&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/_Wn31YK0VSM?si=J9vgANHe8KOHaxN8&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;center&gt;
&lt;p&gt;&lt;strong&gt;이 글을 끝까지 읽었다면 이제 커피 한잔의 여유를 가져 보아요…&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;사실 슬랙이 그리 나쁜 건 아니랍니다. 버퍼 오버런을 우아하게 허용해주는 관대함을 가졌죠 ㅋ~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;메모리도 인생도 그렇게 조금은 여백이 필요합니다.&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;</content:encoded></item><item><title><![CDATA[[소고] 게임 보안: 하드닝에 관하여…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/12520</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12520</guid><pubDate>Thu, 21 Nov 2013 23:59:24 GMT</pubDate><content:encoded>&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_하드닝에_관하여.md_0.png&apos; data-alt=&apos;인터넷에 이런 기사가 떠돌 땐 그저 남 일인 줄 알았다…&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 345px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ab7764cef08d3d0b87fe0f243ce534b9/fa8f5/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 115.78947368421053%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAXCAIAAACEf/j0AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAFM0lEQVR42n1TaVBTVxi9LtixQCWBJAqo0Iph0ehEZCmCVSpCFcEaZV9UbMWxLVVQIyEDRYuKEjYbbFVcsBYtAyiEAgEXEoKBhFUQqwUCSci+kIUEkvSGmf7pdHreed878y3n3bl3Lng9MkpraXvBYNXUN3L7BujPO1rbX7zq5jC7umGS0zvQ1NpGa6Z3c/tqnzY9e8lsam1ve874g/5MJpeDSb4ANjFYbPqzjnd/jXH7Bwdfj/Rw+9mcXjg5NPwGukM9LRJPTE6NT/DGeZNjE7yxcZ5WqwNv3r77va4Bll8wOqF9YzP9VQ+3ue1556tuFrunoZkOfQ1Go8ViMZst/wJQqWcE0xKJTCFTqKRylUgig1quVMnkSqmVKrFELhBJoBaKJFBDIZLIDQarHZjR6gRSpUyuksgVYolMMA2DQiiSiqVysVQBNV8onhZLYR6Ozc+b5ubn5+bmzQvLAFKRaGyge0YtVWsMCtWsQqWd0WjU6hkY4atSq+fmjNZ+K4yGf2A0Gs1mE+jt6qopu8ab4vMEYqFwGvYZZ2d1+ln4aLUaSB386qzU6bR6nW5Wr4cupnnrz8GUVC+bMRoslhElrGmGxUq+UmMyzBr1s/+5SRDzZovJbDGbTKCd0dfcQBsZ7mFLxLDQMS57L9dBoVfyh/uZnG5GD4fZP9DJ4TKH+rr6uayxEa5i8vUwlyHk80H97ZK0QFReDL6KHN/5tNIyJxkb6mp9RC0hRsdGO4XtRgQGfbhps40ndlG4HzI1dC0xDvfm3vFzBM/qh3dB3c3ib0JWXUkOjPVakeBtR4zF+7rb+6CAD9om2MshJNAe77/cx9NmtTPwdF8W7Y8pSQ+ZqDmbl4B7/Nsd0FBZmhW29seEgEgPh+hNGKyLnb8XKjvetyB5664NmDAcav8B5+goDG79cvzH9rHbXG6cCld1lF79Kqju8T3QRXt0PT08N8bf33GJD3Jp2u51TUUxLcXxLYUH85L8IvEueeQt6Rkeu8Mc9wVj8uN8aUVHzO/qqJlf1D66C6qrKjMTI+6cT0nCOcXiEN9Ged86sycvOSjroG9tfhT50NZCkl/qMffEWNdTie4lSZvbr6YY39ZVkaPp9fdBWSkF64rMOxJZEOV9eT/28A63gni/RvKXjbkx3T8fY1JSvo9fHxnqeCJiVXkslnrA7eHRzYO3T1CTcKyGB6DierHdErB9PTpjm3PpYf8n2ZGUxIDKjKjyk/se5hMY5SknQ9fux9nmhKEr4rwpcdjmCwRN771bXwe+rLkLqKVF9ovBjnXIDH9U5k7XfIJXRtRG6tE9NzIOXDuzt/aHqPQIry3uDunBq64nbLhzBN9ZdlQ78OuttK2s2vugoozi+AHY5YHI3oYhhbqc3b6SfGjjpZTt5VmE9JgAIsEH64Z0QDm4uDgFb1pTnIhnl6XKmVRqIo795AEopRQuByDQ2TYvAFka4XolFFMY7nxir3dqxIbknWtCcGh7Bzs0egXK6SOko32YrxvjWhK/8WIJAcuurwLMluqLxz97kA/PJrGdcphVcby1KMkVYxvkg8J7IFcgbDErkWgMAoNGYDBIlKNddcmpOR5ttK1YOt4P+IO0m8Qd5LRPOTWZQ82X378sGG3P/WQ1AgCwCGIxWLIULLWxxmXLFsPk3s9xOkGTSdViMgiBaHyooij39Onv+jtqtIopjUqsk43+8tOlzKxMEukciUTMIWcv8DyZfJ6UQ7x4IUfM45i0f5qMKqDR6ERCiUqhVig0UFuv4QL/B+aFq2q2WP4G1d5MhPV9nIgAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;인터넷에 이런 기사가 떠돌 땐 그저 남 일인 줄 알았다…&apos; title=&apos;&apos; src=&apos;/static/ab7764cef08d3d0b87fe0f243ce534b9/fa8f5/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_0.png&apos; srcset=&apos;/static/ab7764cef08d3d0b87fe0f243ce534b9/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_0.png 190w,
/static/ab7764cef08d3d0b87fe0f243ce534b9/fa8f5/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_0.png 345w&apos; sizes=&apos;(max-width: 345px) 100vw, 345px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;인터넷에 이런 기사가 떠돌 땐 그저 남 일인 줄 알았다…&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;아침에 눈을 떴는데 이상한 느낌이 들었다. 말을 하려고 하는데 목소리가 나오지 않는 기이한 현상이 벌어진 것이다. 침 삼킬 때 따끔 거리는 일은 있었어도 목소리가 아예 나오지 않는 이런 경우는 첨이라 어이가 없었다. 조금 이러다 말겠지 했는데 생각보다 오래간다. 래리 페이지가 목소리를 잃었다며 두문불출할 때만 했었어도 그냥 먼 산 불구경 하듯 딴나라 이야기라 생각했는데, 막상 내가 당해 보니 이게 보통 일이 아니다. 단 한 차례도 말하는 걸 특별하다 생각하지 않았는데 말이 나오지 않으니 일상 생활이 거의 불가능할 지경, A부터 Z까지 되는 게 하나도 없다. 멘붕 ㅠㅜ~&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;이 모든 사단의 발단은 요상한 해킹툴 하나에 있다. 그 녀석이 정체를 드러낸 것은 지난 주였다. 해킹툴이 잔뜩 올라오는 사이트에 우리 보안 제품이 적용된 게임의 해킹툴도 올라왔다. 평소에 그냥 왜 다른 업체들이 그 해킹툴을 안 막을까 너무 궁금했던 차였다. 왜냐하면 파일도 구하기 쉬우니 그냥 패턴으로라도 막으면 될텐데 왜 저렇게 버젓이 운영되도록 놔둘까하는 호기심이 있었다. 사이트가 너무 많아서 관심의 사각지대에 있나 보다라고 혼자 생각해보기도 했었다.&lt;/p&gt;
&lt;p&gt;평소 생각처럼 패턴 차단을 먼저 시도했는데, 그 다음이 가관이었다. 그 해킹툴이 전혀 다른 모습으로 돌아온 것이다. 그것도 2시간만에. 그때 진실을 마주하게 되었다. 다른 업체들이 안 막는 게 아니라 못 막는 거였구나. 다시 패치를 했다. 또 2시간. 또 패치를 했다. 또 2시간. 그맘때쯤 녀석이 그리 호락호락한 놈은 아니라는 사실을 인지하게 되었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_하드닝에_관하여.md_1.png&apos; data-alt=&apos;해킹툴의 바지런한 업데이트. 너도 힘들지? 죽겠지? ㅋㅋㅋ&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 295px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/0a8937754a3803ffb3bd03f9de4af25a/60cc9/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 62.63157894736842%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABiElEQVR42l3SWY/iQAwE4Pz/vwZoJQ4t983AQggJtxCQ+Yg187B+6FS73VUud5Jtmh2yLM/zLMt2u91yuZxMJtb9fr9YLObzuTWSs9lsOp0Oh8PD4SBzPp+TvCiOxyOUV+H+er3ebrdFUWw2m39V2Eo6StMUvt1u8Ol0SvZp6g4dB6FATRcEXZNZrVbj8dipC5L9fr/ZbEqWZZmQvVwuaAAUiNXBVu0FKRYFugu66OL5fCY+iqIfmqPRiDFbWBGfAJ/KFOD6+xP3+z1Beb1esQLBogLOfqYYyVAWX1WoeTweCb6Ys5boDAYDDqOLTqfDoV6s3W6X1Var5aYjzX88I/tVjsnhCkwQDtshEEOOeL1eCcGYk4fhNqRsjT3mLElWWa/XY/VPFZLv9/uj7N0MHPC2YRK2HqsI57qLGvnQ/1+ZGvpQtrLHG3GDcCF+r0ajUavVgI8yPsphmzJiUpJF9efBMr/KMQuVHvmjjD5+SQ4ptNttDm1h/m3N3Jz1YmvaZOv1OtmyLL8BnHbGlrJbkCkAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;해킹툴의 바지런한 업데이트. 너도 힘들지? 죽겠지? ㅋㅋㅋ&apos; title=&apos;&apos; src=&apos;/static/0a8937754a3803ffb3bd03f9de4af25a/60cc9/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_1.png&apos; srcset=&apos;/static/0a8937754a3803ffb3bd03f9de4af25a/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_1.png 190w,
/static/0a8937754a3803ffb3bd03f9de4af25a/60cc9/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_1.png 295w&apos; sizes=&apos;(max-width: 295px) 100vw, 295px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;해킹툴의 바지런한 업데이트. 너도 힘들지? 죽겠지? ㅋㅋㅋ&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;어쨌든 그때부터 개발팀은 무한분석, 불꽃코딩, 밤샘, 지원팀은 매일같은 업데이트를 하게 되었다. 물론 업체 측에서도 해킹툴 척결의 의지가 있었기에 업데이트를 상당히 우호적으로 적용해 주었고 일정 수준 이상의 성과를 보이고 있다. 오늘이 꼭 10일째 되는 날인데, 우리는 그 사이에 무려 7번의 업데이트를 했다. 사실 주말 빼고는 매일 업데이트를 했다고 할 수 있다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;이번 해킹툴 차단에 결정적 기여를 한 사람은 다름아닌 막내였다. 녀석과 2시간 짜리 공방을 벌이던 때 면역 체계 이론에 빠삭한 막내가 HIV(에이즈 바이러스)에 대응하는 전략에서 가져온 새로운 아이디어를 제안했다. 평소 나도 생명체에서 답을 찾아야 한다는 생각이 강했던터라 귀담아 듣게 되었는데 생각보다 좋은 전략이었다. 그래서 막내의 아이디어를 당장 구현했다. 사실 크게 구현이 어려운 부분은 없는 아이디어라 다음날 구현할 수 있었고 패치에 적용했다.&lt;/p&gt;
&lt;p&gt;내심 막내도 나도 기대했다. 난 6시간만 버티면 좋겠다고 했는데 결국 그날은 10시간을 버텼다. 물론 대박은 그 시간이 아니었다. 녀석의 실수를 끌어낸 것이다. 지속적인 패치로 피로도가 누적됐는지 해커가 핵심 구성 모듈 중의 하나를 날것 그대로 방출한 것이다. 이 또한 막내가 발견했다. 막내의 발견 이후에도 난 다른 작업 때문에 바빠서 그 모듈을 분석하지 않고 있었는데 막내가 그 모듈의 핵심적인 기능 대부분을 분석해서 알려주었다. 막내가 분석하지 못한 내용은 같이 앉아서 분석을 했는데 우리는 그날 야근을 하면서 녀석의 수법을 모두 알아낼 수 있었다. 몇가지 참신한 기법도 있었지만 역시나 리버싱엔 능하지만 코딩은 잘 못하는 전형적인 해커였다.&lt;/p&gt;
&lt;p&gt;지피지기면 백전백승이라고 했던가? 녀석의 수법을 회피할 수 있도록 전체적인 구조를 재구성 하는 작업을 했다. 이건 생각보다 빡쎈 작업이라 다소 시간이 걸렸다. 그리고 그 주 주말엔 XIGNCODE3의 가장 강력한 기능 중에 하나를 준비했다. 4년 만이었다. 여기까지 기어온 네오는 녀석이 두 번째. 그 패치는 14일 적용됐고, 해커는 아직도 47.5차원 어디쯤에서 방황하는 중이다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;해커의 주된 공격 방식은 코드 조작(tampering)이다. 우리 코드를 제멋대로 패치해서 정상적으로 기능들이 동작하지 않도록 만드는 것이다. 이런 작업은 주로 패치할 대상 주소가 몇 개나 되는지에 의존하는데 우리는 다년간 이런 공격을 많이 받았기 때문에 폭탄을 제거하기 위해서는 여기저기 잘라야 하는 선들이 상당히 많다. 하지만 리버싱에 능한 그 녀석은 그 모든 선을 다 찾아서 잘라 버렸다. 이러면 VM 코드니, CRC 체크니 말하는데 그냥 그런 것들을 수행하는 부분 모두가 세트 메뉴로 다 패치됐다고 생각하는 게 속 편하다. 우리가 날것 그대로 방출된 모듈을 분석하기 전까지는 정말이지 발가벗고 녀석과 대적하는 느낌이었다. 그 정도로 녀석의 리버싱 능력은 탁월했다. 우리는 그 능력을 봉쇄하기 위해 다양한 하드닝 전략을 생각했는데 여기에 10개 정도만 추려서 소개해보면 다음과 같다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;필요한 코드는 필요한 시점에 로드되야 한다. 보통 프로그램은 실행과 동시에 모든 필요한 코드가 로딩된다. 이래서는 문제가 있다. 한번에 패치 대상 주소를 모두 확보할 수 있기 때문이다. 핵심 코드는 그 코드가 필요한 그 순간에만 존재하도록 만들어야 한다.&lt;/li&gt;
&lt;/ol&gt;
  &lt;br&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;모든 코드는 언제든지 재기동 될 수 있어야 한다. 우리 몸의 세포는 매일 새롭게 태어난다. 심지어 뼈도 매일 조금씩 변화해서 10년이 지나면 완전 새로운 뼈로 태어난다. 이것과 마찬가지로 모든 구성 요소는 필요한 시점에 언제든지 새롭게 재기동 될 수 있어야 한다. 재기동 시키면 지속적으로 해당 컴포넌트들에 가해진 패치를 무력화 시킬 수 있다. 마치 드래곤볼의 피콜로 처럼 팔이 잘리면 조금 있다 다시 팔이 살아나는 것과 같은 시스템을 만들어야 한다.&lt;/li&gt;
&lt;/ol&gt;
  &lt;br&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;해커에게 동일한 형태로 표출되는 코드가 다른 동작을 수행할 수 있도록 구성해야 한다. 세포가 동일한 구조로 되어 있지만 눈과 코와 귀와 입처럼 다른 기관으로 분화되는 것과 같은 이치다. 해커에겐 표면적으로 동일하게 보여지지만 실제로는 다른 동작을 하도록 만들어야 한다는 말이다.&lt;/li&gt;
&lt;/ol&gt;
  &lt;br&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;코드 변조 여부를 스스로 인지할 수 있어야 한다. 보통은 CRC 체크 코드 등을 별도의 작업 단위로 구성하는 경우가 많다. 이런 건 그냥 소용없는 짓이다. 마치 그 코드가 원래 수행하려고 했던 일 자체가 CRC 체크인 것처럼 만들어야 한다. CRC 체크 코드와 원래 수행하는 코드 사이의 결합도를 아주 높여야 한다는 것이다. 샴쌍둥이들처럼 떼는 것 자체가 불가능하도록 만들어야 한다.&lt;/li&gt;
&lt;/ol&gt;
  &lt;br&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;때로는 느슨한 랜덤 시드가 효과적이다. 하이엔트로피 짱짱맨을 외치는 사람들이 많다. 하지만 몇몇 부분에 있어서는 해커에게 그건 변하지 않는다는 것을 인식시키는 것이 훨씬 효과적이다. 변하지 않는다고 생각하고 내 PC에서 잘 되니까 릴리즈 했는데 그 순간 변해버린다면 제 아무리 날고기는 해커도 당황할 수 밖에 없다. 그래서 아주 느슨한 랜덤 시드를 섞어 쓰는 것이 효과적이다.&lt;/li&gt;
&lt;/ol&gt;
  &lt;br&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;스레드 경계, 예외 경계, IPC 경계, 운영체제 콜백 경계를 활용해야 한다. 보통 코드는 직렬화된 순서로 진행된다. 이런 구조는 아주 쉽게 트레이스되고 분석된다. 그 트레이스 흐름을 끊을 수 있는 것들이 이런 장치들이다. 코드 내에서 이런 장치가 지속적으로 자주 등장하도록 만들어야 한다.&lt;/li&gt;
&lt;/ol&gt;
  &lt;br&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;전체 코드가 메모리 상의 특정 영역에 집중돼 있으면 곤란하다. 분산 배치시켜야 한다. 이는 관련 코드를 스캔하는 속도를 떨어뜨리고 더 찾기 어렵게 만든다.&lt;/li&gt;
&lt;/ol&gt;
  &lt;br&gt;
&lt;ol start=&quot;8&quot;&gt;
&lt;li&gt;리버싱을 어렵게 만드는 방법 보다는 분석을 다 한 다음에도 프로그래밍을 어렵게 만드는 방법이 효과적이다. 탐지 기반 설계보다는 회피 기반 설계가 더 효과적이라는 의미다.&lt;/li&gt;
&lt;/ol&gt;
  &lt;br&gt;
&lt;ol start=&quot;9&quot;&gt;
&lt;li&gt;탐지와 보고의 거리는 멀수록 효과적이다. 둘이 가깝다는 건 그냥 그 루틴은 쓸모가 없다는 것과 같다. 최대한 멀게 만들어라.&lt;/li&gt;
&lt;/ol&gt;
  &lt;br&gt;
&lt;ol start=&quot;10&quot;&gt;
&lt;li&gt;포인터 전역 변수는 피해라. 모든 데이터는 아주 은밀한 방식으로 숨겨야 한다. 전역 변수는 고양이에게 생선을 던져주는 것과 같은 형태다. 인코딩 같은 건 소용도 없으니 아주 은밀한 데이터 저장 방식을 고려해야 한다. 7번과 같은 이치다. 코드 뿐만 아니라 데이터도 분산 배치되어야 한다는 것을 의미한다.&lt;/li&gt;
&lt;/ol&gt;
  &lt;br&gt;
&lt;/blockquote&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;실무를 주로 하다보면 이론적인 부분이 취약해지기 마련이다. 앞서 우리가 생각한 방법들도 사실 경험적인 추론에 의한 것들이지 수학적으로 코드 조작에 대응할 수 있는 방법들은 아니다. 잘 알겠지만 가장 효과적인 방법은 모든 코드를 알고, 그 원리를 알더라도 공격하기가 힘든 수학적인 근간이 있는 방법들이다. 이런 점에서 이번 싸움을 하면서 난 anti tampering이라든가 tamper proofing 같은 기법들에 관심이 생기기 시작했다. 그 과정중에 2009년에 발간된 기념비적인 책을 하나 찾게 되었는데 바로 Surreptitious Software란 책이다. 조작 방지에 관한 내용만 전문적으로 다루고 있는 책인데 실무적인 지식 보다는 이론적인 부분에 포커스가 있다. 사실 뭐 반반 짬뽕이라고 보면 된다. 나같은 사람이 보기에 편하게 쓰여진 책인 것 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_하드닝에_관하여.md_2.jpg&apos; data-alt=&apos;올해의 꿀통: Surreptitious Software&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 300px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ef82d3ad1b36ef89abea87152ef1e3e7/0cdb7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_2.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAIDBQT/xAAVAQEBAAAAAAAAAAAAAAAAAAABAP/aAAwDAQACEAMQAAAB2a4QHQCU0hdgb//EABsQAAICAwEAAAAAAAAAAAAAAAECAxIABBAR/9oACAEBAAEFAneuX5tE0jm9fJVDKqjn/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwEf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAGxAAAgIDAQAAAAAAAAAAAAAAAAECEBFBUXH/2gAIAQEABj8CN0vRRadYZF8r/8QAGxABAAIDAQEAAAAAAAAAAAAAAQARECExQZH/2gAIAQEAAT8hPubd+YFAXcIAFO0qCL7y8CuN3GWdOsf/2gAMAwEAAgADAAAAEIjH/P/EABYRAQEBAAAAAAAAAAAAAAAAAAEQEf/aAAgBAwEBPxAyE//EABURAQEAAAAAAAAAAAAAAAAAAAEg/9oACAECAQE/EGP/xAAeEAEAAQQCAwAAAAAAAAAAAAABEQAhMUEQUaGx8P/aAAgBAQABPxAkg3i9o8ua1g+lMokES7pDaQkGILZ+tTDFBKxdh1PBaKDAcoNACko3WuP/2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;올해의 꿀통: Surreptitious Software&apos; title=&apos;&apos; src=&apos;/static/ef82d3ad1b36ef89abea87152ef1e3e7/0cdb7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_2.jpg&apos; srcset=&apos;/static/ef82d3ad1b36ef89abea87152ef1e3e7/8ccab/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_2.jpg 190w,
/static/ef82d3ad1b36ef89abea87152ef1e3e7/0cdb7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_2.jpg 300w&apos; sizes=&apos;(max-width: 300px) 100vw, 300px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;올해의 꿀통: Surreptitious Software&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;중간에 Arxan 이야기도 잠시 나와서 나름 반가웠다. 내가 그토록 애타게 찾아 헤맸던 수학적인 근간이 있는 알고리즘도 몇 개 발견할 수 있었다. 대박~ 대부분의 수학적인 기반의 코드들이 그렇듯이 결과론적으론 아주 심플한데 해커 입장에서는 구토를 유발케하는 그런 코드들이다. 알고리즘이 궁금한 분들은 책을 사서 읽어보도록 하자. 여기 공간이 협소해서 알고리즘을 다 소개하기에는 무리가 따를 것 같다. 당연한 소리겠지만 여러분이 코드 보안에 신경써야 하는 분야에서 일하고 있다면 100만원을 주고 사도 돈이 아깝지 않은 책이다. 너무 싼가? ㅋ~&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_하드닝에_관하여.md_3.png&apos; data-alt=&apos;알고리즘 하나로 회사를 차리기도 한다. 반가워요, Arxan&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 494px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/defb18abe219856dbe4f09488b4294fd/7f4de/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 45.78947368421053%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABT0lEQVR42j1R2W6DMBDk/z8q5OAKeaJKC9jY65NQE5HmB0InRu1ILHvNeL1OlmWx1nZd1zQNY0wr1fe9lPLzeh0Azlnf3263dV1fr9caf+sfknmex3FEWUeABi3ExjnrvbF2CmGcJmS+59nDhoCMde7n+UyQ7TkbpBRELQ7ljAshhVD1pU337JRRWQ150aX7dpfywxGWHY7dLh2bj2T+amWWy7xQZUVFac61qy+mOpuy0nnhzjWdMp3ltm2h6LQWjMFqojBNCT4pBsG5d84ohUsqKeEoItzfGgxujdYIMSpYAnMRDUJMIM/3u7YW8bvLOc45gQNCTCqtY9qB470HGbJwcD8sK3k8HsYY1FDYHHRDAgTC4bEbGRDgYP3o2UrYcRJCoIg4KW2DAWhCiOVvdmPqOAhCOJB7k+FBBnr/h7xfKwI+8iYCIUS3NthlWX4BLPXYesU4jcoAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;알고리즘 하나로 회사를 차리기도 한다. 반가워요, Arxan&apos; title=&apos;&apos; src=&apos;/static/defb18abe219856dbe4f09488b4294fd/7f4de/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_3.png&apos; srcset=&apos;/static/defb18abe219856dbe4f09488b4294fd/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_3.png 190w,
/static/defb18abe219856dbe4f09488b4294fd/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_3.png 380w,
/static/defb18abe219856dbe4f09488b4294fd/7f4de/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_3.png 494w&apos; sizes=&apos;(max-width: 494px) 100vw, 494px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;알고리즘 하나로 회사를 차리기도 한다. 반가워요, Arxan&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_하드닝에_관하여.md_4.png&apos; data-alt=&apos;그럴듯해 보이지만 결국은 그냥 여기저기서 크로스로 체크하겠다는 말&lt;br&gt;&lt;br&gt;때로는 포장이 더 중요할 때도 ㅋㅋㅋ~&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 513px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/468985f72f1048c7e3a8bf1a7f334cea/7fe11/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 62.63157894736842%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABNklEQVR42oWS246CQBBE+f+PQzEEEwiXBA2CgNxBgWWPtDtx9YF+mNA9VdXVPWjLVvz8xfeVtkmepsl13TAMv/nau/x3T5jjONZ13XXdtIbABP8ip2nqeR4IReMchiGOY67meUbitMbj8fjsjPb5fAbx0XxYo6qqpmk4RR1wURSovMhJkhyPR3CS5nnOkLfbDUIQBHCQBnC/3/u+930fC3TSyEGAQyzLMvh4lilIy7K8Xq8UoyhibW3bUuEUC5phGJZlyZC2bR8OBxyqsQEhKup8IwSTCv2fZErSjaCqJiflCntUSC+Xy263YwRWyCkN/r2z4zi6rr/vXD0SDfimP7bZCPt/ktULczI/OwT6rohDijhnqUhgW+11+w/DobwwNNM09/s9H9Jsm4xD+DSXKWCK52VZfgEwNfBN1dkumQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그럴듯해 보이지만 결국은 그냥 여기저기서 크로스로 체크하겠다는 말&lt;br&gt;&lt;br&gt;때로는 포장이 더 중요할 때도 ㅋㅋㅋ~&apos; title=&apos;&apos; src=&apos;/static/468985f72f1048c7e3a8bf1a7f334cea/7fe11/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_4.png&apos; srcset=&apos;/static/468985f72f1048c7e3a8bf1a7f334cea/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_4.png 190w,
/static/468985f72f1048c7e3a8bf1a7f334cea/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_4.png 380w,
/static/468985f72f1048c7e3a8bf1a7f334cea/7fe11/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_4.png 513w&apos; sizes=&apos;(max-width: 513px) 100vw, 513px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그럴듯해 보이지만 결국은 그냥 여기저기서 크로스로 체크하겠다는 말&lt;br&gt;&lt;br&gt;때로는 포장이 더 중요할 때도 ㅋㅋㅋ~&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h3&gt;#4&lt;/h3&gt;
&lt;p&gt;보안 코드들이 다 그렇지만 우리 코드도 점점 더 필요한 기능을 수행하는 코드보다 메타 코드가 늘어나고 있다. 주로 매크로 기능을 하는 코드들인데 더미 코드를 삽입한다거나 코드 구조를 변경한다거나 CRC 체크를 한다거나 하는 코드들이다. 메타 코드가 늘어날수록 원본 코드의 가독성은 떨어지고 버그는 코드 속에 더 은밀하게 숨겨진다. 요즘은 이런 것들을 매크로가 아닌 다른 방법으로 할 수 없을까 궁리중이다. 코드 위빙(code weaving)이라 불리는 기법들인데 C/C++같은 저급 언어의 컴파일 타임 내지는 컴파일된 결과물에 수행하기에는 다소 어려움이 있는 것 같다. 노가다가 답인가? ㅠㅜ~&lt;/p&gt;
&lt;h3&gt;#5&lt;/h3&gt;
&lt;p&gt;어쨌든 그놈 덕분에 우리는 훨씬 더 강력한 기능들을 많이 추가할 수 있었다. 고맙긴 하지만 그래도 이젠 우리가 헤어져야 할 시간. 겁나 디버깅 중인 것 같은데 너도 ROE를 생각해야 하지 않겠니? 단언컨대 그 시간에 다른 게임 디버깅 하면 훨씬 수월할거야. 그럼 이제 바이, 짜이찌엔, 그리고 사요나라 ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_하드닝에_관하여.md_5.png&apos; data-alt=&apos;사실 해커에게 이런 소리 듣는 안티 치트 솔루션은 흔치 않습니다. ㅋ~&lt;br&gt;&lt;br&gt;최선을 다해서 싸워드리겠습니다. 느낌 아니까~&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 602px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5314ee1ec51c9ea326ed7be0b9037fe4/d1b94/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_5.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 23.684210526315788%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAIAAADKYVtkAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAsUlEQVR42j1OUQ6FIAzjIoIQE80DhQEbcP+LvYKJ/SBd15UqYclEMaVaS8m5lFJrTXPk1lrOFGOEyMwglAh7EHiu61JEBOs98Tz3PR1EPnjr7HEc1tp9352zbgHjS7DCqxCPVGS33kUEl1zrGINnk1kFosDUhBdyziyzFL5RY/RS4WB4cIMTVAKHTxb43S3ae0f6OyNFoav3vxBQO3gfgPM8oXx4YoSoP2ybNtoYo7X+A0pZNskJ1GtpAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;사실 해커에게 이런 소리 듣는 안티 치트 솔루션은 흔치 않습니다. ㅋ~&lt;br&gt;&lt;br&gt;최선을 다해서 싸워드리겠습니다. 느낌 아니까~&apos; title=&apos;&apos; src=&apos;/static/5314ee1ec51c9ea326ed7be0b9037fe4/d1b94/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_5.png&apos; srcset=&apos;/static/5314ee1ec51c9ea326ed7be0b9037fe4/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_5.png 190w,
/static/5314ee1ec51c9ea326ed7be0b9037fe4/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_5.png 380w,
/static/5314ee1ec51c9ea326ed7be0b9037fe4/d1b94/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_5.png 602w&apos; sizes=&apos;(max-width: 602px) 100vw, 602px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;사실 해커에게 이런 소리 듣는 안티 치트 솔루션은 흔치 않습니다. ㅋ~&lt;br&gt;&lt;br&gt;최선을 다해서 싸워드리겠습니다. 느낌 아니까~&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_하드닝에_관하여.md_6.png&apos; data-alt=&apos;보다 유쾌한 게임 경험을 제공하기 위해 항상 노력하겠습니다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/38220aea1fcc0dc1e11709f1c7f4dd57/984b6/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_6.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 52.10526315789474%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAB60lEQVR42k1S2ZLaMBD0/39UUkVtEqjF+JKRbfkG37DAYhbIS2dmSKXy0DWWZHX39MiKoxgqCJGmGYxJkZoMVbVD07RIYoMkMiiLCnGUIM8K1NUeRV6hbXp0bY++G9B1Iwaqx+MJVkhky+UKWkdQKoTvK2xsF7btCLlhgbJG23ZEMGAcJ1Qk4Kx9+E6AwFVw3j1au9jVDSxWyEwu6mVe4nj4oMs9Ak9hG2iEvoZySchRdDmAiTPoMHoRrT3qIMXj8cT9/hBYTBTpGFlawCSptBtpg8W3BX4ufuHt+w8s31awVxvYSxueHSDeGrT7VhyN4wF3IhRSglUTAWdUl1Qpm/JvPkM/oqPKrWacHV3m/abpJLfz5YLz+RPTeMQ4TIKJyC1uN6bgCyLlsJmcB9LsGgmdBXgwWkUSg7TrhVAEf6OQUgT8754EexK39rwg+0JCkOCHA7mgyZEq43y64HQ6S77s4kD1MH3QZCfMty88n7+l5RM5tlzbg+v4iLYxYp1IljmhyEqa5k4Gxs7TpJDBZUkmyOm8oCGWRU3rnM4zehU5LL3V8t44L3Zy+bziep0F83z7r97+7V/n195Me+zwRt+3+Uu6sHTIzgwppOKQ8+TpsTtxSW+QXfB3Xe4l61Lyfrljp6+OCqzfN/gDJPDWfMLvRmMAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;보다 유쾌한 게임 경험을 제공하기 위해 항상 노력하겠습니다.&apos; title=&apos;&apos; src=&apos;/static/38220aea1fcc0dc1e11709f1c7f4dd57/984b6/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_6.png&apos; srcset=&apos;/static/38220aea1fcc0dc1e11709f1c7f4dd57/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_6.png 190w,
/static/38220aea1fcc0dc1e11709f1c7f4dd57/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_6.png 380w,
/static/38220aea1fcc0dc1e11709f1c7f4dd57/984b6/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%95%98%EB%93%9C%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%98%EC%97%AC.md_6.png 630w&apos; sizes=&apos;(max-width: 630px) 100vw, 630px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;보다 유쾌한 게임 경험을 제공하기 위해 항상 노력하겠습니다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 마소 30주년에 부쳐…]]></title><description><![CDATA[9…]]></description><link>https://jiniya.net/wp/archives/12561</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12561</guid><pubDate>Tue, 19 Nov 2013 23:59:23 GMT</pubDate><content:encoded>&lt;p&gt;96년 초여름. 생일 선물로 뭘 받고 싶은지 물어보는 친구 녀석에게 난 겁 없이 마이크로소프트웨어라는 잡지를 말했다. 중학생이라 큰 돈이 없었던 친구 녀석은 고맙게도 용돈을 탈탈 털어서 마소를 선물해줬다.. 그게 내 인생 첫 번째 마소였다. 친구의 선물이기도 했고 너무 신기하기도 했기에 난 마소를 신주단지 모시듯이 두고는 심심할 때마다 펼쳐서 읽었던 기억이 난다. 물론 내가 그 당시 마소에 실린 글 중에 이해하는 글은 단 하나도 없었다. 시쳇말로 흰 건 여백이고, 검은 건 글인 수준이었다. 하지만 난 마소를 읽고, 또 읽으면서 막연하게 내가 어른이 된다면 여기 글을 쓴 아저씨들과 비슷한 일을 하는 사람이 될지도 모르겠다는 생각을 했었던 것 같다.&lt;/p&gt;
&lt;h3&gt;마소, 그리고 프로그래머&lt;/h3&gt;
&lt;p&gt;고등학교 시절부터는 상황이 조금 나아졌다. 동아리에서 회비로 정기 구독을 했기에 언제나 최신 마소를 마음껏 볼 수 있었다. 대학생 때에는 도서관에서 이번 달 마소를 모두 공짜로 볼 수 있었지만 국내 유일의 프로그래밍 잡지가 폐간되지 않기를 간절히 바라는 마음으로 정기 구독을 하기도 했었다 (그시절 프로그램 세계라는 프로그래밍 잡지가 폐간 됐었다). 마소 필자가 된 이후로는 지금까지 증정본을 받아서 보는 호사를 누리고 있다. 결국 난생처음 생일 선물로 마소를 받은 다음 거의 17년 동안 마소를 끼고 살았던 셈이다.&lt;/p&gt;
&lt;p&gt;17년을 함께한 마소를 돌아보면 역설적이게도 기술 보다는 사람이 더 많이 기억에 남는다. 비베 관련 글을 많이 쓰시던 신승근님의 비베 책만 몇 천 권 읽었다는 글을 보면서는 대학교 연구 도서관에 있는 전공 관련 서적을 모조리 다 읽어 버리겠다는 패기에 불타 오르기도 했었고, 나성언님의 인터페이스 저널을 통해서 선배 프로그래머들은 일상에서 어떤 생각을 하는지 조금이나마 훔쳐볼 수 있었다. 안윤호님의 칼럼은 늘 동경의 대상이었다. 저분의 내공은 얼마나 깊을까라는 생각을 하면서 매번 연재되는 글들을 기다렸던 기억이 난다. 주니어 코너에 있었던 황헌주님의 초보 개발자의 일기장을 보면서는 나도 막연하게 직업 프로그래머로 생활하게 된다면 저런 일상을 보낼까라는 생각을 하기도 했었고, 터보 C 정복의 저자로 유명하신 임인건님 같은 대가의 짤막한 인터뷰라도 실리는 날에는 그 글을 끼고 다니면서 나도 먼 훗날 반드시 훌륭한 프로그래머가 되고야 말겠다는 꿈을 키웠다. 일면식도 없는 김성우님은 가장 훌륭한 글쓰기 선생님이었다. 엔지니어에게 글쓰기가 왜 중요한지, 재미있는 글을 쓰기 위해서는 어떤 과정들을 거쳐야 하는지에 대해서 길잡이가 되어준 고마운 글들을 많이 써주셨다.&lt;/p&gt;
&lt;p&gt;또한 마소는 나에게 세상에 나 같은 사람이 또 있다는 사실을 발견하게 해 준 잡지이기도 했다. 어린 시절 주변에는 나와 같은 생각을 하는 친구들이 흔치 않았다. 대부분의 친구 녀석들은 메모리를 최적화 시켜서 19금 게임을 실행시키는 정도의 컴퓨터 지식으로 만족했다. 그 프로그램들이 어떤 원리로 동작하는지, 그것들을 만들기 위해서는 무엇을 배워야 하는지에 대해서 궁금해 하는 친구들은 없었다. 물론 학교 선생님들은 더 몰랐다. 호기심을 해결할 창구도 없었고, 같은 주제를 가지고 열띤 토론을 할만한 친구도 전무했다. 외딴 섬에 혼자 떨어져 있는 느낌이었던 나에게 마소는 세상에 나 같은 사람이 수도 없이 많이 있다는 사실을 알려준 고마운 존재였다.&lt;/p&gt;
&lt;p&gt;학생 시절 나는 마소를 통해서 먼저 이 길을 걸어간 선배 프로그래머들의 주옥 같은 조언을 들을 수 있었다. 직업 프로그래머로 일하는 동안에 마소는 동시대를 살아가는 다른 프로그래머들의 다양한 고민과 생각을 엿볼 수 있는 창문과도 같은 역할을 해주었다. 마소는 항상 나에게 가장 기술적인 잡지인 동시에 가장 사람 냄새 나는 잡지였다.&lt;/p&gt;
&lt;h3&gt;전업 프로그래머를 꿈꾸는 후배들에게&lt;/h3&gt;
&lt;p&gt;나를 포함한 대부분의 프로그래머가 그렇지만 처음 시작할 때에는 누구나 위대한 프로그래머를 꿈꾼다. 몇 일 은둔해서는 새로운 구조의 그래픽 엔진을 뚝딱 만들어내는 존 카맥, 겨울 방학에 심심해서 만들기 시작한 운영체제가 전세계에서 가장 잘 나가는 오픈소스 운영체제가 된 리누스 토발즈, 크리스마스 휴가 기간에 심심해서 만든 파이썬이 NASA에서도 사용하는 프로그래밍 언어가 된 귀도 반 로섬 같은 전설의 프로그래머를 상상하는 것이다. 설상가상으로 거의 대부분의 프로그래머들은 열심이만 하면 자신도 그런 위대한 프로그래머가 될 수 있다는 환상을 가진다.&lt;/p&gt;
&lt;p&gt;처음 시작하던 시절 나 또한 그런 생각이 있었다. 노력하면 위대한 프로그래머가 될 수 있다는 생각과, 내가 제법 똑똑한 프로그래머라는 착각에 빠져 있었다. 물론 그런 착각은 그리 오래가지 않았다. 10년 정도가 지난 지금 내가 업계에서 배운 한 가지 사실은 나는 그냥 철저하게 평범한 지적 수준을 가진 보통 프로그래머라는 것이다. 이런 사실을 깨달았을 때 난 굉장히 심각한 자괴감에 빠졌었다. 갑자기 방향을 잃은 느낌이었다. 아마 프로그래머란 직업에 더 강한 열망을 가진 독자일수록 먼 훗날 나와 같은 상황에 봉착할 확률이 많을 것 같다는 생각이다. 난 방황의 과정 속에서 두 가지 중요한 사실을 발견했다. 부족한 내가 지금까지 직업 프로그래머로 살아가는데 든든한 버팀목이 되고 있기에 잠깐 소개해볼까 한다.&lt;/p&gt;
&lt;p&gt;내가 알게 된 첫 번째 사실은 세상에는 다양한 사람들만큼이나 다양한 문제가 있다는 점이다. 위대한 프로그래머가 반드시 필요한 아주 복잡하고 어려운 문제도 있지만, 평범한 프로그래머도 풀 수 있는 가벼운 문제들도 산재해 있다. 당연히 천재 프로그래머 몇 명이 모두 해결할 수는 없는 노릇이다. 세상에 존재하는 조만가지의 문제를 모두 해결하기 위해서는 보통 수준의 프로그래머도 아주 많이 필요하다. 결국 우리가 모두 다 리누스 토발즈나 존 카맥처럼 되겠다는 생각을 가질 필요도 없고, 그렇게 될 필요도 없다는 것을 의미한다.&lt;/p&gt;
&lt;p&gt;두 번째는 사람을 이해하는 프로그래머가 되는 것이 중요하다는 점이다. 10년이란 기간 동안 다양한 프로그래머들을 만났다. 창업을 한 이후에는 개발사에 SDK를 공급하는 업무적 특성 때문에 상대적으로 외부 개발자들과 협업할 기회가 많았다. 그렇게 많은 프로그래머들을 만났는데 사람을 이해하는 프로그래머는 정말 드물었다. 기계와 친숙하고 코딩에 능숙하지만 사람과의 의사 소통에는 젬병인 프로그래머가 비일비재했다. 물론 전문 지식은 다소 부족하지만 사람을 이해하는 능력이 뛰어난 프로그래머도 간혹 있었다. 협업이란 측면에서는 당연히 후자 쪽이 훨씬 일하기 수월했다. 이는 의사 소통 능력이 뛰어나다는 점만으로도 아주 특별한 프로그래머가 될 수 있다는 것을 의미한다.&lt;/p&gt;
&lt;p&gt;의사소통 능력을 키우려면 어떻게 해야 할까? 당연한 이야기겠지만 그 답은 기계나 전공 서적에 있지 않다. 바로 인문학에 있다. 인문학은 나와 다른 사람들이 이 세상에 존재하는 것을 인식하고, 그 차이를 인정하는 것에서 출발한다. 따라서 인문학을 공부한다는 것은 나와 다른 생각을 가진 수많은 사람들을 포용하는 능력을 키울 수 있다는 것을 의미하기도 한다. 프로그래머가 철학과 고전을 읽어야 하는 이유가 바로 여기에 있다. 고전과 철학 책이 재미 없는 독자라면 연애를 적극 권장해 주고 싶다. 자신과 다른 타인을 이해하고 자신의 바닥을 경험하는데 연애만큼 좋은 수단도 없기 때문이다.&lt;/p&gt;
&lt;h3&gt;60살의 마소를 꿈꾸며&lt;/h3&gt;
&lt;p&gt;많은 사람들이 마소가 최신 트렌드를 충분히 반영하는 잡지가 되기를, 인터넷에서 찾을 수 없는 고급 지식이 실리는 잡지가 되기를 희망한다. 그런데 난 여기에 조금 회의적이다. 활자화돼서 인쇄되는 시간에 벌써 트렌드는 넘어가기 마련이다. 그 정도로 요즘은 빠르다. 인터넷에 없는 고급 지식이 담기길 소망하는 것은 더욱 힘든 일이다. 요즘은 스택오버플로우에 없다면 아직까지 궁금해 한 사람이 단 한 명도 없다는 것을, 구글에 없다면 이 세상에는 없는 지식이라는 말이 나올 정도로 인터넷과 커뮤니티가 발달했다. 사실 우리가 상상할 수 있는 거의 모든 지식이 인터넷에 있다고 해도 과언이 아니라는 이야기다. 특히나 IT쪽 정보는 그 정도가 더 심하다. 그러니 거기에도 없는 정보를 담는다는 말은 조금 어폐가 있는 것 같다.&lt;/p&gt;
&lt;p&gt;나는 마소가 동시대를 살아가는 다양한 프로그래머의 이야기를 담는 잡지가 되기를 소망한다. 앞서간 선배 프로그래머의 조언, 우리 시대 프로그래머의 생각, 그리고 프로그래머를 꿈꾸는 학생들의 고민을 충실하게 담고 있는 잡지가 됐으면 하는 바램이다. 우리가 닿을 수 없는 넘사벽 개발자들의 이야기는 인터넷에도 책에도 얼마든지 있다. 하지만 2013년 대한민국을 함께 살아가는 프로그래머들의 이야기를 담을 수 있는 잡지는 단 하나 마소 밖에는 없다. 마소가 더 많은 프로그래머들에게 사람 냄새 풍기는 잡지로 다가가기를 희망해 본다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[전 우주적 게임 보안 솔루션, XIGNCODE3 프로젝트에 참여할 프로그래머를 찾고 있습니다.]]></title><description><![CDATA[XIGNCODE3 개발 프로젝트에 참여할 C/C++ 윈도우 시스템 프로그래머를 찾고 있습니다. 영어 읽기는 기본, C/C…]]></description><link>https://jiniya.net/wp/archives/12367</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12367</guid><pubDate>Wed, 25 Sep 2013 23:59:22 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://www.wellbia.com&quot;&gt;XIGNCODE3 개발 프로젝트에 참여할 C/C++ 윈도우 시스템 프로그래머를 찾고 있습니다.&lt;/a&gt; 영어 읽기는 기본, C/C++을 잘하면 좋고, 윈도우 시스템에 대한 이해가 있으면 더 좋고, 파이썬을 다룰 줄 알면 금상첨화, 유닉스 계통 운영체제를 다뤄봤으면 완벽하죠. 새로운 코드를 작성할 수 있을 정도로 능력자라면 정말 땡큐겠지만, 그냥 저냥 있는 코드 보면서 이해할 수 있고, printf 넣어가면서 디버깅 해서 문제점을 찾을 수 있는 정도의 능력만 가져도 감사할 따름입니다.&lt;/p&gt;
&lt;p&gt;“저는 웹 프로그래머 입니다. 저는 드라이버 개발만 하는데요. 저는 C/C++ 프로그래머라 루아나 파이썬은 모릅니다.”와 같이 지나치게 편협한 수준의 범주에 자신을 국한시키는 프로그래머, 투덜이 스머프형 프로그래머는 정중히 사양하겠습니다. 새로운 명령 체계를 가진 CPU, 새로운 아키텍처의 컴퓨터가 주어지더라도 매뉴얼만 있다면 주소록 정도는 간단하게 작성할 수 있는 수준의 사고력을 가지신 분들을 환영합니다. 모르는 건 죄가 아니지만 배우겠다는 의지가 없거나 배우는 속도가 너무 더디면 함께 일하기 힘들기 때문입니다. 일정 수준 이상의 수학적 사고 회로를 뇌에 탑재하신 분이면 좋겠다는 욕심도 초큼 있습니다.&lt;/p&gt;
&lt;p&gt;끝으로 게임 보안 이라는 분야에 관심이 있었던 분, 내지는 안드로메다 해커도 놀랄만큼 위대한 게임 보안 솔루션을 진짜 한번 만들어보고 싶다, 라는 당찬 포부를 가지신 분들이면 최고겠지요. 이런 연유로 스스로 동기부여가 확실하게 되는 분이었으면 좋겠다는 바램도 눈꼽만큼 있습니다.&lt;/p&gt;
&lt;p&gt;개발팀 분위기는 조용하게 혼자 연구하고 뭔가 속닥속닥 만드는 거 좋아하시는 분이라면 편하게 일할 수 있는 환경입니다. 물론 좀 액티브하고 토론하는거 좋아하고 하는 분이면 더 좋을 것 같지만 그런 분들은 흔치 않지요. 대체적으로 거의 모든 일을 스스로 알아서 잘해야 합니다. 누가 이거저거 일일이 정해주고 시키고 해야지 일을 할 수 있는 분이라면 안타깝지만 우리와는 잘 맞지 않을 것 같네요. 스스로 일을 만들고, 계획을 세우고, 결국에는 해내는 주도적인 성향을 가지신 분을 선호합니다.&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;최고 근무 환경 -&gt; 최고 프로그래머들 -&gt; 최고 소프트웨어 -&gt; 수익 -&gt; 최고 근무 환경&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;– 조엘의 피드백 루프: 어디서 시작하든 상관은 없다. 어디든 진입이 힘들다는 건 함정.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;우리는 조엘의 피드백 루프를 믿습니다. &lt;a href=&quot;http://www.jiniya.net/wp/archives/831&quot;&gt;최고의 프로그래머가 얼마나 희소한지, 얼마나 중요한지 뼈저리게 알고 있습니다.&lt;/a&gt; 따라서 자금이 허락하는 한도 내에서 최고의 근무 환경을 만들기 위해서 노력하고 있습니다. 물론 자금이 허락하는 한도가 부족하다는 함정이 있긴 합니다.&lt;/p&gt;
&lt;p&gt;소프트웨어 개발에서 가장 중요한 요소는 &lt;a href=&quot;http://sangminpark.wordpress.com/2011/09/13/%EC%98%81%EC%9B%85-%EC%97%86%EB%8A%94-%EB%82%98%EB%9D%BC/&quot;&gt;개념의 일관성(conceptual integrity)&lt;/a&gt; 이라고 생각합니다. 소수 정예로 설계하고 만드는 것이 좀 더 효율적이라고 생각합니다. 우리가 만드는 소프트웨어가 그리 크지 않기 때문이기도 하구요. 어중이 떠중이 머리수만 늘리면 된다는 생각을 혐오합니다.&lt;/p&gt;
&lt;p&gt;그 프로젝트에 참여하는 프로그래머는 몇 명인가요, 라는 질문보다는 그 프로젝트엔 누가 참여하나요, 라는 질문을 더 좋아합니다. 네. 맞습니다. 사람 중요한지 아는 회사입니다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;모든 프로그래머는 두 개의 모니터를 가져야 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;모든 프로그래머는 빠른 컴퓨터를 가져야 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;모든 프로그래머는 자신이 선택할 수 있는 마우스와 키보드를 가져야 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;모든 프로그래머는 편안한 의자를 가져야 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;모든 프로그래머는 빠른 인터넷 접속 환경을 가져야 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;모든 프로그래머는 정숙한 작업 환경을 가져야 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
  &lt;br&gt;
&lt;p&gt;-- &lt;a href=&quot;http://www.codinghorror.com/blog/2006/08/the-programmers-bill-of-rights.html&quot;&gt;프로그래머 권리장전, Jeff Atwood&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;center&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; margin-bottom: 16px;&apos; data-url=&apos;./전_우주적_게임_보안_솔루션,_XIGNCODE3_프로젝트에_참여할_프로그래머를_찾고_있습니다_.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/506608767fefc9fc467df7cbc3882c6a/7fbea/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAUC/8QAFgEBAQEAAAAAAAAAAAAAAAAAAQAC/9oADAMBAAIQAxAAAAHaNiK6YNf/xAAaEAADAQEBAQAAAAAAAAAAAAAAAgMBEhEi/9oACAEBAAEFApt6I/ctppSnRjsp9Mf/xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPwFH/8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQIBAT8BV//EABoQAAIDAQEAAAAAAAAAAAAAAAABESExQVH/2gAIAQEABj8C1KPSU1XGXBhRJ//EABoQAQADAAMAAAAAAAAAAAAAAAEAESFBUZH/2gAIAQEAAT8h3lPk5aEa7GGbRvdlkoATYdMRfE//2gAMAwEAAgADAAAAEHwP/8QAFhEBAQEAAAAAAAAAAAAAAAAAABFR/9oACAEDAQE/EIvH/8QAFhEBAQEAAAAAAAAAAAAAAAAAABEh/9oACAECAQE/EMiH/8QAHhABAQACAQUBAAAAAAAAAAAAAREAITFBUWFxkaH/2gAIAQEAAT8QoOzsobdZsfytDG6L1y5SQHKfcYwJR5W93JE48IJ+42JfB0T3n//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                 XIGNCODE3                           md 0&apos; title=&apos;&apos; src=&apos;/static/506608767fefc9fc467df7cbc3882c6a/7fbea/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_0.jpg&apos; srcset=&apos;/static/506608767fefc9fc467df7cbc3882c6a/8ccab/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_0.jpg 190w,
/static/506608767fefc9fc467df7cbc3882c6a/ea4c8/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_0.jpg 380w,
/static/506608767fefc9fc467df7cbc3882c6a/7fbea/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_0.jpg 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;strong&gt;프로그래머라면 응당 최고급 컴퓨터를 써야 한다고 생각합니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;우린 CPU 보다는 소중한 존재니까염 ㅋ~&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;  
&lt;h3&gt;#2&lt;/h3&gt;
&lt;center&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; margin-bottom: 16px;&apos; data-url=&apos;./전_우주적_게임_보안_솔루션,_XIGNCODE3_프로젝트에_참여할_프로그래머를_찾고_있습니다_.md_1.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ce4f0a6e0b0ee0d7371845b33e345c4b/7fbea/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 74.73684210526315%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAEDBAX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAABaKhoEZL/AP/EABsQAAIDAAMAAAAAAAAAAAAAAAISAQMRACIx/9oACAEBAAEFAmjjdYswVMp8KrU//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFhEBAQEAAAAAAAAAAAAAAAAAARAh/9oACAECAQE/AQyf/8QAHxAAAQQABwAAAAAAAAAAAAAAAAECESESIjIzgZKh/9oACAEBAAY/Atodk9E1diJHJNFYeUP/xAAcEAACAgIDAAAAAAAAAAAAAAABEQAhQWExUXH/2gAIAQEAAT8hL26uKSOmV0h3MAai3gAKrcKsHBnyNDFtn//aAAwDAQACAAMAAAAQIx//xAAXEQEAAwAAAAAAAAAAAAAAAAAAASEx/9oACAEDAQE/EJ1T/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAEhcf/aAAgBAgEBPxBiwU//xAAdEAEBAAICAwEAAAAAAAAAAAABEQAhMUFRcZGh/9oACAEBAAE/ENNvrgEDn5lxckpHWh+3DMJeoceOvWUXXsQsGrmoHCo7jrDfEAITsO5n/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                 XIGNCODE3                           md 1&apos; title=&apos;&apos; src=&apos;/static/ce4f0a6e0b0ee0d7371845b33e345c4b/7fbea/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_1.jpg&apos; srcset=&apos;/static/ce4f0a6e0b0ee0d7371845b33e345c4b/8ccab/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_1.jpg 190w,
/static/ce4f0a6e0b0ee0d7371845b33e345c4b/ea4c8/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_1.jpg 380w,
/static/ce4f0a6e0b0ee0d7371845b33e345c4b/7fbea/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_1.jpg 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;strong&gt;도서비 따위 아끼지 않습니다. 느낌 아니까…&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;  
&lt;br&gt;
&lt;p&gt;저는 거의 대부분의 컴퓨터 지식을 책을 통해 배웠습니다. 지금도 책은 지식을 습득할 수 있는 가장 저렴하고 효과적인 수단이라고 믿고 있습니다. 요즘은 인터넷 검색이면 충분하다는 생각을 가지신 분들도 많은데, 인터넷에 존재하는 파편화된 지식은 절대로 책이 제공하는 총체적인 지식을 대체할 순 없다는 생각입니다. 책을 통해 틀을 세우고, 틀 사이에 존재하는 간극을 인터넷 검색과 토론을 통해서 메우는 것이 맞다는 생각입니다. 그런고로 도서비는 아끼지 않습니다. 보고 싶은 책이나 자료는 모두 구비해 드립니다. 일년에 책을 12권 보다 적게 읽고, 인터넷 검색이면 충분하다고 생각하시는 프로그래머라면 알러지가 생길지도 모르겠습니다. 적어도 한번쯤은 기술 서적을 읽으면서 가슴 벅차 본 느낌이 있는 분들을 사랑합니다.&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;카맥은 거창한 수사 같은 것은 혐오했지만, 다그쳐 물으면 적어도 나름대로 한 가지 의견을 피력하곤 했다. “정보화 시대에 장벽이란 없다. 장벽은 자기가 만드는 것이다. 새롭고 원대한 것을 계획하고 개발하는 데 수백만 달러의 자본이 필요치 않다. 냉장고에 채울 피자와 다이어트 코크, 작업에 쓸 값싼 PC, 그리고 해내겠다는 의지만 있으면 된다. 우리는 바닥에서도 잤다. 물이 불은 강도 걸어서 건넜다.”&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;– 둠, 데이비드 커시너&lt;/p&gt;
&lt;/blockquote&gt;
&lt;center&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 520px; margin-bottom: 16px;&apos; data-url=&apos;./전_우주적_게임_보안_솔루션,_XIGNCODE3_프로젝트에_참여할_프로그래머를_찾고_있습니다_.md_2.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/4064179dfc214c65c5cbb3715bcd89f7/95cb2/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_2.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 62.10526315789474%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIDAf/EABYBAQEBAAAAAAAAAAAAAAAAAAEAAv/aAAwDAQACEAMQAAAByTrlqXI//8QAGxAAAwACAwAAAAAAAAAAAAAAAQIDABESITL/2gAIAQEAAQUC2q5YmiSTSDye0ko4f//EABYRAQEBAAAAAAAAAAAAAAAAAAEQIf/aAAgBAwEBPwFMn//EABURAQEAAAAAAAAAAAAAAAAAAAAR/9oACAECAQE/AVf/xAAdEAABAgcAAAAAAAAAAAAAAAAAARACESExQYGh/9oACAEBAAY/AqCTwW40Wm//xAAcEAEBAQABBQAAAAAAAAAAAAABEQBBITFhgaH/2gAIAQEAAT8hQAi+FukJa4NEOr0yUXdw4Y+6TSu//9oADAMBAAIAAwAAABCXL//EABcRAAMBAAAAAAAAAAAAAAAAAAABEVH/2gAIAQMBAT8QjRHp/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAERUf/aAAgBAgEBPxCxk4f/xAAbEAEAAwEBAQEAAAAAAAAAAAABABEhMUGRsf/aAAgBAQABPxBzW/WfiXIW2K2e/Joij1iK6RAa2nyDcTmMPSwbVe/J/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                 XIGNCODE3                           md 2&apos; title=&apos;&apos; src=&apos;/static/4064179dfc214c65c5cbb3715bcd89f7/95cb2/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_2.jpg&apos; srcset=&apos;/static/4064179dfc214c65c5cbb3715bcd89f7/8ccab/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_2.jpg 190w,
/static/4064179dfc214c65c5cbb3715bcd89f7/ea4c8/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_2.jpg 380w,
/static/4064179dfc214c65c5cbb3715bcd89f7/95cb2/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_2.jpg 520w&apos; sizes=&apos;(max-width: 520px) 100vw, 520px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;strong&gt;버닝하는 여러분을 위해 에너지 드링크와 컵라면은 상시 제공됩니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;참이슬 후레시와 헛개 컨디션은 흔치 않은 아이템 ㅋㅋ~&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;  
&lt;h3&gt;#4&lt;/h3&gt;
&lt;center&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; margin-bottom: 16px;&apos; data-url=&apos;./전_우주적_게임_보안_솔루션,_XIGNCODE3_프로젝트에_참여할_프로그래머를_찾고_있습니다_.md_3.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/fd18960eb894e21c53c1b77d862d893e/7fbea/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_3.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIEA//EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAUeXQCcP/8QAGRAAAgMBAAAAAAAAAAAAAAAAAQIAEiER/9oACAEBAAEFAg4lQ0I1VzpCXM//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAYEAEAAwEAAAAAAAAAAAAAAAAAARAhMf/aAAgBAQAGPwKsQ6yX/8QAGxAAAwACAwAAAAAAAAAAAAAAAAERMVEhYXH/2gAIAQEAAT8hyklytGVM6Gpk8S7HPyKkiUs3SU//2gAMAwEAAgADAAAAENPP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQIBAT8Qqv/EABwQAQEBAAIDAQAAAAAAAAAAAAERAHGxITFB4f/aAAgBAQABPxAiFoW1fGlWA4usv9Uj+c6L7HWpETBOcs6i+b//2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                 XIGNCODE3                           md 3&apos; title=&apos;&apos; src=&apos;/static/fd18960eb894e21c53c1b77d862d893e/7fbea/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_3.jpg&apos; srcset=&apos;/static/fd18960eb894e21c53c1b77d862d893e/8ccab/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_3.jpg 190w,
/static/fd18960eb894e21c53c1b77d862d893e/ea4c8/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_3.jpg 380w,
/static/fd18960eb894e21c53c1b77d862d893e/7fbea/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_3.jpg 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;strong&gt;열린 환경을 지향합니다. 신입이 뭘 알아, 따위의 소리는 하지 않습니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;모든 걸 볼 수 있고, 모든 걸 바꿀 수 있습니다.&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;&lt;br&gt;  
&lt;p&gt;소스 코드에 겹겹이 접근 제한을 걸고, 개발 PC 인터넷을 끊고, 안그래도 사양이 떨어지는 개발 PC에 복잡한 보안 소프트웨어 설치를 강요하고, USB를 포함한 저장 장치는 들고 들어갈 수도 없고, 개발 PC가 있는 방에 들어가기 전에 소지품 검사를 하고, 모든 소지품은 사물함에 보관한 다음에 개발 PC에 접근할 수 있는 회사들이 많이 있습니다. 사람을 믿지 못하는거죠. 프로그래머도 사람이니까요. 근데 이런 곳에서 무슨 창조성이 발휘 되겠습니까? 그리고 그리 한들 잘될까요? 의문입니다.&lt;/p&gt;
&lt;p&gt;기본적으로 우리는 함께 일하는 사람을 신뢰합니다. 자신의 PC 보안은 알아서 잘 지킬 수 있다고 판단합니다. 소스 코드에 대한 접근 제한도 없습니다. 모든 걸 볼 수 있고, 모든 걸 바꿀 수 있습니다. 큰 회사에서 일하면서 도대체 이놈에 모듈은 어떻게 만든건지도 모른체 갑갑함 속에서 개발했다면 모든 것을 통제할 수 있는 상태에 있는 여기가 바로 천국일지도 모르겠네요. ㅋ~&lt;/p&gt;
&lt;p&gt;그러다 사고나면 어쩌냐구요? 소스 코드 유출이 큰 문제라는 생각은 하지않습니다. 우리가 판매하는 것은 300만 라인의 오픈 소스와 30만 라인의 소스 코드가 컴파일된 바이너리 파일도, 10만개가 넘는 패턴 오브젝트를 포함한 데이터베이스 파일도 아닌 해킹툴을 차단할 수 있는 우리의 능력이라고 생각하기 때문입니다.&lt;/p&gt;
&lt;p&gt;물론 현재 버전의 코드가 유출되더라도 내일의 XIGNCODE3는 그때의 기술과는 다른 버전이 될 거라는 자신감이 있기 때문이기도 합니다. 우리는 코드를 설명하는 장황한 매뉴얼을 만들지 않습니다. 언제나 코드와 매뉴얼 사이에는 불일치가 있다고 생각하기 때문에 최대한 코드를 이해하기 쉽게 쓰고, 그런 코드만 보고도 매뉴얼 수준의 이해를 할 수 있는 사람과 함께 일하기를 희망합니다. 코드 작성할 시간도 없는데 앉아서 MSDN 만들고 있을 수는 없잖아요. — 조엘 아저씨가 말했듯 MSDN이 친절한 이유는 윈도우가 소스 코드를 제공하지 않기 때문입니다. — 그리고 더 중요한 건 그 매뉴얼을 만드는 사이 전체 코드는 열두번도 더 바뀌기 때문에 언제나 매뉴얼은 틀릴 수 밖에 없다는 맹점을 가지고 있기도 하구요.&lt;/p&gt;
&lt;p&gt;이랬든 저랬든 한 가지 확실한 사실은 우리는 프로그래머 여러분들에게 실오라기 하나 걸치지 않은 아주 투명한 환경을 제공한다는 것입니다.&lt;/p&gt;
&lt;h3&gt;#5&lt;/h3&gt;
&lt;p&gt;최고의 실력자를 뽑을 수 없다는 것 누구보다 잘 알고 있습니다. 그래서 염치없이 최고로 잘하는 사람을 뽑습니다, 라는 소리 따윈 하지 않습니다. 현실적인 수준에서 우리와 같이 일할 수 있는 사람을 찾고 있습니다. 앞서도 말했듯이 당장은 관련 지식이 좀 부족하더라도 빠르게 배울 수 있는 분들을 더 환영합니다. 특히 이쪽 분야에 진지하게 관심이 있고, 정말 제대로 된 제품 한번 만들어 보겠다는 의지가 있는 분들이었으면 좋겠습니다.&lt;/p&gt;
&lt;p&gt;구구절절 떠들었는데 지원은 어떻게 하냐구요? codewiz 앳 wellbia 닷 com으로 메일 주시면 됩니다. 이력서와 간단한 자기소개서를 보내 주셔도 되고, 지속적으로 관리하는 자신의 블로그나 인터넷 사이트가 있는 경우에는 해당 사이트 주소만 보내주셔도 됩니다.&lt;/p&gt;
&lt;center&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 497px; margin-bottom: 16px;&apos; data-url=&apos;./전_우주적_게임_보안_솔루션,_XIGNCODE3_프로젝트에_참여할_프로그래머를_찾고_있습니다_.md_4.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/1a76c050422bb5ec3444bd9f613d3681/c8b0d/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 28.421052631578945%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABMElEQVR42lWRh27CMBCGef8XKyqlhFJCGRkkZHiRCLIgJn/PTlSplizd8uf/7mago/ULeZridDjS9RD6PoIgRNd1qKsKbdugrms0TWNjbdva+yDbxO73ymAw92rMjPHse3jHE+L4As45WM6g1BVKSqRJCikEWJaDM44rxU0N5wJlUdhcluZEGTD3J6DWGoefPfb7AyRBBBVflSSgGsFCIUkS65vPyrJEQfGyKMHok+7xtArfvGoE9r22CndbFzk9MAqUUqMaxq1vlKQ0FgOUBsyojgnrcyGnlifgMABHUrdzd9h+bbD8WGK9crD9drEh3/lcwVk6cFbr0abc4n2BLGMkpkfTdv+BZimXKLKLiM8xovAM7+RNM0zI9hGdI6q5IPADO+sojHC7jcvQr+Gv5V9hbMBkJdhfUwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                 XIGNCODE3                           md 4&apos; title=&apos;&apos; src=&apos;/static/1a76c050422bb5ec3444bd9f613d3681/c8b0d/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_4.png&apos; srcset=&apos;/static/1a76c050422bb5ec3444bd9f613d3681/08678/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_4.png 190w,
/static/1a76c050422bb5ec3444bd9f613d3681/2edd7/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_4.png 380w,
/static/1a76c050422bb5ec3444bd9f613d3681/c8b0d/%EC%A0%84_%EC%9A%B0%EC%A3%BC%EC%A0%81_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98%2C_XIGNCODE3_%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90_%EC%B0%B8%EC%97%AC%ED%95%A0_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EB%A5%BC_%EC%B0%BE%EA%B3%A0_%EC%9E%88%EC%8A%B5%EB%8B%88%EB%8B%A4_.md_4.png 497w&apos; sizes=&apos;(max-width: 497px) 100vw, 497px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;strong&gt;건방진 중2병 해커의 허세…&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;해커들에게 보안이 뭔지 따끔하게 가르쳐 줄 수 있는 실.력.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;그리고 정말 제대로 된 게임 보안 솔루션을 만들어 보고 싶다는 열.정.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;이 두 가지를 가지고 있다면 지금 바로 지원하세요.&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;</content:encoded></item><item><title><![CDATA[서비스 지원의 품격]]></title><description><![CDATA[얼마 전 모 업체 대표님과 저녁에 술을 마셨습니다. 바(BAR…]]></description><link>https://jiniya.net/wp/archives/12338</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12338</guid><pubDate>Fri, 13 Sep 2013 23:59:21 GMT</pubDate><content:encoded>&lt;p&gt;얼마 전 모 업체 대표님과 저녁에 술을 마셨습니다. 바(BAR)를 갔는데, 그 바 주인 아줌마가 아침에는 광고 일을 하는 분이었어요. 같이 술을 마시던 대표님이 원래 광고 쪽에서 유명하셨던 분이라 클라이언트가 누구냐는 질문을 했습니다. 주인 아줌마는 뻘쭘해 하며 별로 유명하지 않다고 얼버무렸습니다. 재차 이어진 대표님의 질문. 주인 아주머니는 자신은 하청의 하청이라며 자신의 클라이언트도 아니라는 식으로 부끄러워 하면서 업체명을 이야기 했습니다. 그때 질문을 했던 대표님께서 그러셨습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;광고쟁이가 클라이언트를 부끄러워하면 그건 자격이 없는 사람이다. 광고 쟁이는 자신의 고객이 유명하거나 유명하지 않거나, 또는 돈을 많이 주거나 적게 주거나 상관 없이 그 업체가 세상에서 최고의 제품을 만든다는 생각으로 광고를 만들어야 한다. 한치라도 클라이언트에 대해서 부끄럽다거나 별로라는 생각을 가지는 순간 그 쟁이는 아웃이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;술도 제법 마셨고, 너무 늦은 시간까지 이어진 술 자리라 피곤하기도 해서 정확한 문구가 기억나진 않지만 대략적인 뉘앙스는 비슷했던 것 같습니다. 저 이야기를 듣고는 저도 조금은 부끄러운 생각이 들었습니다. 그리곤 저 정도 생각을 하니까 한 업체의 대표를 하고 있고, 또 그 회사가 성공하고 있는 거구나, 라는 생각이 들었습니다.&lt;/p&gt;
&lt;p&gt;최근에 저희 회사도 고객이 제법 생겼습니다. 동시 접속자가 많은 게임도 있고, 적은 게임도 있습니다. 매출 순위에서 1위를 하는 게임도 있고, 목록에 오르지도 못하는 게임도 있습니다. 상대적으로 계약 금액이 높은 게임도 있고, 낮은 게임도 있습니다. 잘 만든 게임도 있고, 그렇지 않은 게임도 있습니다. 유명한 게임도 있고, 아무도 모르는 게임도 있습니다.&lt;/p&gt;
&lt;p&gt;이렇게 모두 다 다른 게임들이지만 한 가지 공통점이 있다면 모두 우리가 만든 보안 솔루션을 사용하기로 결정한 게임이라는 점입니다. 그러니 우리에겐 다 같은 게임이고, 모두 다 최고의 게임입니다. 하지만 마음 한 켠에서는 그렇지 않은 생각도 있었던 것이 사실입니다. 유명세에 따라 그들의 요구사항에 차등을 두려는 저질스런 생각이 있었던 것이죠.&lt;/p&gt;
&lt;p&gt;그날 술자리를 파하고 집으로 돌아오면서 그런 생각이 들었습니다. 우리가 만든 XIGNCODE3라는 솔루션을 탑재하고 서비스가 되고 있는 게임이라면, 단 한 명의 사용자만 그 게임을 즐긴다 할지라도 그 게임이 우리의 얼굴이라는 생각입니다. 그러니 우리는 그 게임의 표면적인 지표와는 상관없이 그 게임이 해킹으로 피해를 입지 않도록 최선을 다해서 서비스를 제공할 의무가 있고, 반대로 그 업체는 최고의 서비스를 받을 권리가 있는 겁니다.&lt;/p&gt;
&lt;p&gt;웰비아닷컴에서 단 하루만 서비스를 받은 고객일지라도 그 회사 참 친절하다, 고맙다, 라는 생각이 드는 그런 회사였으면 좋겠습니다. 사내에 있는 모든 사람이 고객에게 항상 가난한 마음가짐을 가지고 있는 회사였으면 하는 바램입니다. 서비스 지원의 품격을 아는 센스 있는 사람들이 모여있는 회사이길 소망해 봅니다. 느낌 아니까…&lt;/p&gt;
&lt;p&gt; 18
 152&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[원 데이 (One Day)]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/12317</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12317</guid><pubDate>Fri, 13 Sep 2013 23:59:20 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; margin-bottom: 16px;&apos; data-url=&apos;./원_데이_(One_Day).md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ae515f573e373dfbba4d0b74fc3f0b4c/56d4e/%EC%9B%90_%EB%8D%B0%EC%9D%B4_(One_Day).md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 66.31578947368422%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIEBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAC/9oADAMBAAIQAxAAAAGVU1JRFAf/xAAbEAABBAMAAAAAAAAAAAAAAAACAAEREwMxQf/aAAgBAQABBQIYXaiWnoZFiKf/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAaEAADAAMBAAAAAAAAAAAAAAAAARESMjNh/9oACAEBAAY/AvSQ1EzKtM6M/8QAGhABAAMBAQEAAAAAAAAAAAAAAQARIWExQf/aAAgBAQABPyGtBu3xiGFlandOpsvQexkRqP8A/9oADAMBAAIAAwAAABAEz//EABYRAAMAAAAAAAAAAAAAAAAAAAEQMf/aAAgBAwEBPxAxf//EABYRAQEBAAAAAAAAAAAAAAAAAAARIf/aAAgBAgEBPxCRj//EABsQAQADAQADAAAAAAAAAAAAAAEAESExQXHh/9oACAEBAAE/EHbVKsoY43hG73IBjcd5C7NocfMHTuFcalpV7Ps//9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;      One Day  md 0&apos; title=&apos;&apos; src=&apos;/static/ae515f573e373dfbba4d0b74fc3f0b4c/56d4e/%EC%9B%90_%EB%8D%B0%EC%9D%B4_(One_Day).md_0.jpg&apos; srcset=&apos;/static/ae515f573e373dfbba4d0b74fc3f0b4c/8ccab/%EC%9B%90_%EB%8D%B0%EC%9D%B4_(One_Day).md_0.jpg 190w,
/static/ae515f573e373dfbba4d0b74fc3f0b4c/ea4c8/%EC%9B%90_%EB%8D%B0%EC%9D%B4_(One_Day).md_0.jpg 380w,
/static/ae515f573e373dfbba4d0b74fc3f0b4c/56d4e/%EC%9B%90_%EB%8D%B0%EC%9D%B4_(One_Day).md_0.jpg 640w&apos; sizes=&apos;(max-width: 640px) 100vw, 640px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;사랑을 부르는 낭만의 도시, 파리~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;영화 ‘클래식’을 재미있게 봤다던 친구 녀석이 추천해줘서 ‘원 데이’란 영화를 보게 되었습니다. 앤 해서웨이가 나오는 영환데, 전 정말 앤 해서웨이가 이렇게 예쁜 배우라는 사실을 처음 알았습니다. 그녀의 딱딱한 영국식 억양 마저도 귀여워 보이게 만드는 묘한 매력이 있더군요.&lt;/p&gt;
&lt;p&gt;영화는 사랑하는 한 남자를 멀리서 지켜보는 한 여자에 관한 이야깁니다. 이 영화를 보면 딱 두 가지 사실에 놀랄 겁니다. 아름다운 영상에 한번 놀라고, 앤 해서웨이의 미모에 또 한번 놀랄 거예요. 물론 덱스터 역을 맡은 배우도 토나오게 잘생겼습니다. 수려하게 이어지는 영상에 고요하게 물 흐르듯 흐르는 스토리는 가슴을 짠하게 만듭니다. 특히나 마지막 회상 장면을 볼 때에는 정말이지 가슴이 먹먹해 지더군요.&lt;/p&gt;
&lt;p&gt;영화 후반부에 나오는 이안의 대사가 참 가슴에 와 닿았습니다. 진짜 사랑이란 어쩌면 이런게 아닐까, 라는 생각…&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ian: She made you decent, and in return you made her so happy, so happy.&lt;/p&gt;
&lt;p&gt;이안: 그녀는 너를 훌륭하게 만들어 줬어. 그리고 너는 그녀를 웃게 만들어줬지. 정말 기쁘게.&lt;/p&gt;
&lt;p&gt;– One Day, 2011&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Emma: Whatever happens tomorrow, we had today.&lt;/p&gt;
&lt;p&gt;엠마: 내일 무슨 일이 있든지간에 우린 오늘 하루를 살았어.&lt;/p&gt;
&lt;p&gt;– One Day, 2011&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; 21
 1&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[건축학개론]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/5882</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5882</guid><pubDate>Thu, 12 Sep 2013 23:59:19 GMT</pubDate><content:encoded>&lt;p&gt;주말에 정말 오랜만에 영화관에서 영화를 봤다. 우연찮게 서점에 갔다가 영화나 볼까하는 생각이 들어서 즉흥적으로 윗층에 있는 영화관으로 향했다. 오랜만에 가는 영화관이라 그랬을까? 실패하고 싶지 않다는 생각에 아이뻐 앱을 가지고 평점도 보고, 소감도 보고 이러면서 뭘 볼지를 한참을 고민했다. 첨에는 화차를 보려고 했었다. 접때 화차 감독님이 나온 두드림 방송이 퍽이나 감동적이었기 때문이었다. 근데 나의 손가락은 벌써 건축학개론을 선택하고 있었다. 이유야 머 단순하다. 후훗. 수지짱에 가인느님까지… 이거야 뭐, 영화가 똥망이라 하더라도 눈은 즐겁지 않겠냐는 생각이었다.&lt;/p&gt;
&lt;p&gt;그런데 영화는 생각보다 대박이었다. 특히 그 납뜩이 역할이 진짜 제대로였다. 조금 지루할라치면 한번씩 등장해서는 빵빵 터트려줬다. 주인공이 손목 때리는거 보통 사이에서는 하는거 아니지 않냐는 택도 아닌 질문을 했을 때 납뜩이의 받아치는 대사, “그럼 뭐할까? 아구창이라도 날릴까?” 여기서 진짜 쓰러질뻔 했다. ㅋ~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이 영화를 보고 나온 남자들의 98%는 SNS에 xxx 개론의 누구 누구가 떠오른다는 글을 남긴다고 한다. 영화를 보고 나오는 그때, 나도 제일 처음 떠오른 생각은 컴퓨터 개론 수업이었다. 물론 안타깝게도 나는 개론의 그녀가 떠올라서 생각났다기 보다는 그냥 나는 무얼 들었나 하는 생각에서였다.&lt;/p&gt;
&lt;p&gt;내가 들었던 컴퓨터 개론은 정말 생각하기도 싫을 만큼 끔찍한 수업이었다. 교수님은 수면제 그 자체였고, 강의실은 지하였으며, 강의실 크기에 비해서 수강한 학생이 너무도 많아서 들어가기만해도 갑갑했다. 거기다 공대 수업 아니겠는가? ㅋㅋ~ 한 2-3번 듣다가 그 담부터는 전부 여친 수업을 듣거나 학교 앞 CNN(만화방)에서 죽치고 있었던 것 같다.&lt;/p&gt;
&lt;p&gt;그 수면제 교수님은 학점 깐깐하게 주기로 유명했기에 난 당연히 F를 받았다. 복학해서 그 수업을 재수강 했는데, 개론 수업이 없어져서 Visual Basic을 대체 과목으로 들어야 했다. 정말 속으로는 감사합니다를 한 백 번 외쳤던 것 같다. ㅋㅋㅋ&lt;/p&gt;
&lt;p&gt;Visual Basic은 1학낸 때의 개론 수업보다는 좀 나았다. 일단 수업이 지상이었고, 학생도 딱 숨어서 수업 듣기 좋을 정도로 있었고, 거기다 Visual Basic은 그냥 땅짚고 헤엄치기 ㅋㅋ~ 재수강이 아닌 1학년들이 조금 불쌍하게 보였다. 나 말고도 재수강을 하는 사람이 부지기수였고, 병특을 마치고 온 사람들도 더러 있었기 때문이었다. 복학한 시점에 들은 수업이라 수업은 정말 꼬박꼬박 들어갔었던 것 같다. 그 수업엔 그래도 공대 치고는 괜찮은 여학생들이 더러 있었는데 풋풋한 감정을 느끼기엔 너무 닳고 닳은 나이가 아니었나라는 생각…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;영화 전체를 관통하는 플롯인 첫사랑을 15년 만에 만난다는 설정은 정말 공감갔다. 누구나 한 번쯤 가지는 경험 아닐까? 물론 영화처럼 내가 건축가가 됐는데 첫사랑이 집 지어 달라고 오는 경우는 쉽지 않겠지만 말이다. 나한테 첫사랑이 찾아와서는 대뜸 이런 저런 프로그램을 짜달라고 하는 일은 더 없겠지? 여튼 보통 사람이라면 이런 식으로 첫사랑을 다시 대면하는 경우는 거의 없을 것이다. 대부분 머 뻔한 동창회를 통해서 다시 만나곤 한다.&lt;/p&gt;
&lt;p&gt;나도 동창회에서 그런 경험을 한 적이 있는데 정말 욱겼다. 그 아이는 진짜 첫사랑이었는데, 내 인생에 있어서 처음이자 마지막인 짝사랑이었다. 여튼 그 초등학교 동창을 10년이 훌쩍 지나 대학생 때 알럽스쿨이라는 불륜 제조기를 통해서 다시 만나게 됐다. 시간이 많이 지났고 어떻게 변했을지 무척 궁금해 했던 기억이 난다. 설레이는 마음으로 모임을 나갔는데. 하앍~ 여전히 너무 아름다운 것이 아닌가? ㅋㅋ~ 깜짝 놀랐다. 10년이 훌쩍 지나서 만났는데도 난 그 아이 앞에서 한 번도 제대로 이야기를 하지 못했던 것 같다. 첫사랑은 첫사랑이더라는 ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;건축학개론이 밋밋한 스토리에도 불구하고 퍽이나 감동적인 이유는 아마도 이 영화가 큰 억지를 가지고 있지 않기 때문인 것 같다. 영화 속의 모든 소재가 실제로 누구에게나 있을 법한 그런 것들이다. 개론 수업에서 만난 첫사랑, 돈많은 선배, 연애 상담해 주는 친구, 실타래처럼 엉켜버린 관계, 그리고 첫사랑을 한참만에 만난다는 설정까지. 누구나 흔히 겪어 봄직한 이야기라 많은 사람들의 공감을 사는 것 같다는 생각이 든다.&lt;/p&gt;
&lt;p&gt;몇 년 전이긴 한데 19살 꼬맹이하고 소개팅을 했던 적이 한 번 있었다. 사람들이 다 미쳤다고 하기는 하는데 그 소개팅 느낌이란 마치 사촌동생 밥사주고 커피사주고, 고민 상담해주는 느낌이었다. 그때 그런 생각이 들었다. 아, 내가 만약 이 애랑 만난다면 그건 진짜 범죄 행위가 될수도 있겠다. 그 친구가 평생 한 번 경험할 수 있는 풋풋한 사랑을 할 기회를 내가 박탈할지도 모른다는 생각이 들었기 때문이다.&lt;/p&gt;
&lt;p&gt;뭐든지 시기가 있다는 말을 많이 한다. 난 풋풋한 사랑을 할 수 있는 결정적 시기가 그리 길지 않다고 생각한다. 나이 들어서도 얼마든지 열정적이고 격렬한 사랑을 할 수도 있다. 하지만 절대로 풋풋한 사랑을 다시 할 수는 없다. 왜냐하면 처음이 아니기 때문이다.&lt;/p&gt;
&lt;p&gt;풋풋함이란 처음에만 느낄 수 있는 감정이다. 그래서 그런 풋내나는 사랑은 영원히 추억할 수 밖에는 없다. 영화 보는 내내 좋았던 그 시간들이 생각났다. 걱정도 없었고, 생각도 없었고, 그냥 막 살아도 뭔가 될 것 같은 가능성만 있었던 그런 시기에 했던 풋풋한 사랑이란…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;일단 우리가 어떤 경험을 하고 나면, 다시는 그 경험을 하기 이전처럼 세상을 볼 수 없게 된다는 것이다. 우리가 어떤 경험을 하는 순간부터 그 경험은 과거, 현재, 그리고 미래를 보는 렌즈의 일부가 되어 우리가 보는 것들을 조성하고 왜곡한다. 이 렌즈는 안경처럼 밤에 벗어서 침대 곁 탁자에 놓아둘 수 있는 것이 아니다. 이 렌즈는 마치 강력접착제로 우리의 눈동자에 영원히 붙여 놓은 콘택트렌즈와 같다.&lt;/p&gt;
&lt;p&gt;– 행복에 걸려 비틀거리다, 대니얼 길버트&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[연기 (緣起) …]]></title><description><![CDATA[벤자민 버튼의 시간은 거꾸로 간다, 200…]]></description><link>https://jiniya.net/wp/archives/12269</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12269</guid><pubDate>Wed, 11 Sep 2013 23:59:18 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;벤자민 버튼의 시간은 거꾸로 간다, 2008&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;가끔 생각해보면 정말 그 모든 일들이 기적만 같습니다. 그 모든 과정에 아주 사소한 일 하나만 달랐어도 아마 지금 저는 어떻게 됐을지 모르니깐 말입니다. 물론 더 잘됐겠죠? ㅋㅋㅋ~ 이런 걸 보면 불교의 ‘연기’라는 말이 실감납니다. 우리가 지금 이렇게 존재하고 있다는 건, 그 자체로도 이미 말도 안되는 기적같은 일들이 모두 맞아 떨어진 결과입니다. 아마 태엽을 감아서 다시 지금처럼 만들어 보라고한다면 우린 절대 성공할 수 없을 겁니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;인터넷 수업을 듣지 않았다면,&lt;/p&gt;
&lt;p&gt;인터넷 수업 레포트로 홈페이지 만드는 과제가 나오지 않았다면,&lt;/p&gt;
&lt;p&gt;내가 과제를 무시했다면,&lt;/p&gt;
&lt;p&gt;그 회사 사장이 약속을 지켰다면,&lt;/p&gt;
&lt;p&gt;빡쳐서 그 회사를 때려치지 않았다면,&lt;/p&gt;
&lt;p&gt;그 회사 사장이 전력선 통신에 미치지 않았다면,&lt;/p&gt;
&lt;p&gt;그 회사 사장이 엉뚱한 회장을 섭외하지 않았다면,&lt;/p&gt;
&lt;p&gt;그 회장이 회사를 말아먹지 않았다면,&lt;/p&gt;
&lt;p&gt;회사가 망하는 과정에 병무청에 아는 사람이 없었다면,&lt;/p&gt;
&lt;p&gt;교수님 아들이 같은 학번의 동창이 아니었다면,&lt;/p&gt;
&lt;p&gt;홈페이지 과제를 내주신 교수님이 소개해 준 다른 회사가 정상적인 회사였다면,&lt;/p&gt;
&lt;p&gt;그 회사에 다단계에 미친 실장만 없었다면,&lt;/p&gt;
&lt;p&gt;그 당시 잉여로운 시간이 없었다면,&lt;/p&gt;
&lt;p&gt;객기에 그 회사를 뛰쳐나오지 않았더라면,&lt;/p&gt;
&lt;p&gt;그 팀장이 내 이력서를 그냥 흘려 보냈더라면,&lt;/p&gt;
&lt;p&gt;그 채용 담당자가 전화를 받지 않는다고 두 번 전화하지 않았다면,&lt;/p&gt;
&lt;p&gt;회사 이름만 듣고 홈페이지를 들어가보지 않았다면,&lt;/p&gt;
&lt;p&gt;먼저 면접 본 회사에서 나를 그렇게 무시하지 않았더라면,&lt;/p&gt;
&lt;p&gt;그 회사에 동향에 동성을 가진 실장님이 안계셨다면,&lt;/p&gt;
&lt;p&gt;그 날 DOM 모임에 참석하지 않았더라면,&lt;/p&gt;
&lt;p&gt;내가 술을 안마셨다면,&lt;/p&gt;
&lt;p&gt;그때 팀원이 나를 좋게 소개해 주지 않았더라면,&lt;/p&gt;
&lt;p&gt;그때 내가 시건방진 미친 소리를 안했더라면,&lt;/p&gt;
&lt;p&gt;내가 잉여 시간에 인터넷 활동을 안했더라면,&lt;/p&gt;
&lt;p&gt;그 회사 사장이 미쳐서 우리를 다 자르지 않았더라면,&lt;/p&gt;
&lt;p&gt;…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;살면서 우리는 다양한 사건 속에 놓이고 그 사건들에 대한 반응은 피드백되서 우리에게 새로운 사건으로 또 주어집니다. 결국 우리는 무수히 많은 상호작용 속에서 존재하는 것이죠. 이러한 상호작용의 결과가 지금의 ‘나’를 만들고 있는 겁니다. 운명이라는 것이 있다면 사건에 대한 우리의 반응, 내지는 선택의 모음이 아닌가라는 생각을 해봅니다.&lt;/p&gt;
&lt;p&gt;당신은 오늘 어떤 선택을 하셨나요?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Life is C between B and D.&lt;/p&gt;
&lt;p&gt;인생은 태어남(Birth)과 죽음(Death) 사이에 있는 선택(Choice)이다.&lt;/p&gt;
&lt;p&gt;– Jean Paul Sartre&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; 1
 17&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[모바일 게임 보안 솔루션: XIGNCODE3 for Android]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/12153</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12153</guid><pubDate>Thu, 29 Aug 2013 23:59:17 GMT</pubDate><content:encoded>&lt;p&gt;모바일 게임 보안 솔루션 분야에 &lt;a href=&quot;http://www.jiniya.net/wp/archives/9960&quot;&gt;출사표를&lt;/a&gt; 던진지도 제법 시간이 지났습니다. 관련 제품이 전무한 상태이고, 저희 쪽에서도 직접적으로 광고를 하고 있지는 않은 상태라 아직도 많은 분들께서 모바일 게임 쪽에는 안티 해킹 솔루션이 없다고 알고 계신 경우가 많은 것 같습니다. 이런 안타까운 현실을 조금 개선하고자 요즘 가장 핫한 모바일 게임 보안 솔루션인 &lt;a href=&quot;http://www.wellbia.com/dp/&quot;&gt;XIGNCODE3 for Android&lt;/a&gt;의 기능에 대해서 잠깐 소개를 해보는 시간을 가져볼까 합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;역사는 반복된다고 했던가요? 모바일 시장을 보고 있으면 온라인 게임 보안 시장의 예전 모습을 보는 듯한 느낌이 많이 들곤 합니다. 온라인 게임 보안의 초기 시장의 경우에도 많은 게임 업체에서 외부 솔루션 업체는 믿지 못한다는 생각으로 직접 하겠다고 덤빈 경우가 많았습니다. 물론 안타깝게도 대부분 결과가 좋지 않았습니다. 그런 과도기를 거친 후에는 매출이 일정 수준 이상인 게임들은 통상적으로 게임 보안 솔루션을 필수적으로 탑재하는 시대가 오게 되었습니다.&lt;/p&gt;
&lt;p&gt;시간이 흘러 흘러 최근에는 게임 출시 전에 사용자들이 제일 먼저 묻는 질문 중에 하나가 이런 것들이 되었습니다. 안티치트 솔루션이 무엇이냐? 해킹 방지 대책이 무엇이냐? 이런 현상을 반영하듯 요즘은 외부 솔루션 업체만으론 힘에 부치기에 게임사 내부에도 별도의 보안팀을 두어서 외부 솔루션 업체가 특화시키지 못하는 — 외부 솔루션 업체는 특성상 범용적인 보안을 할 수 밖에는 없답니다. — 게임의 세부 사항들에 대한 보안을 강화해 나가는 추세입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;center&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 483px; margin-bottom: 16px;&apos; data-url=&apos;./모바일_게임_보안_솔루션_XIGNCODE3_for_Android.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/01d7f6960a7eb81af52937ab32af2118/a3f7c/%EB%AA%A8%EB%B0%94%EC%9D%BC_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_XIGNCODE3_for_Android.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 52.63157894736842%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACDklEQVR42l2S22/TMBjF82dy0QK9sNJudB20WkFsCNax0o2LeBgIiZeBNCREeRkPvEwwgQTtGKs0LhJT2zhJO9auceI4aeMbzloVxEnsHB9/v/h7sAKhHQQB55wxNp7/NUMRRikLRRkdbgkhFAc5rutKRymVEaWjvfEynEOScsGtAHrMkyFhJIRt23bxX5gNxcMjTpbywwQXdb/pUDTfuv3CKofFPPyXghDCGP8HSzOggQyPSGfAA3lO4XD1YedxAsxmzGtbzvYO/hrCEMGuezyGOeOYepDY0shw/XijQ7rv0IfTjXhEm5oEGflONC+qWnLf/6EYvdZWd1vWBTQgnMgON+HbhfZyFe3+7P+6at58cPQoZ85fAOmUfiUBMkl9dkrPxsD0J1wN2y4079UDTWLykbrVLqlaKqZdmjHyCZBTtek4uHweZKMgG9GyEZCLh+HMDt5TXORcb85lW/kveK8+aLyGm2e0aBQkY3pSBZMpEEnqibQeWTLO5nV1wZhYNNQ5/VwanKrgz4rve1XwpGzcWGsUnukra83F51qxbN59CZbetO6/N4ofW8WKeWffLNXaqzVj+Xt7ZdcsVczCb6+myBviub7suI+wYCLwiIcPsVd3eujAP+hZlut4to2Q6xPCIXQDIhzH6/epRBQRig8Hl7QQTvBNg68s6D3trnecjmXZlg3FyZUaVY68+AOpwDM9uDQbGwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;              XIGNCODE3 for Android md 0&apos; title=&apos;&apos; src=&apos;/static/01d7f6960a7eb81af52937ab32af2118/a3f7c/%EB%AA%A8%EB%B0%94%EC%9D%BC_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_XIGNCODE3_for_Android.md_0.png&apos; srcset=&apos;/static/01d7f6960a7eb81af52937ab32af2118/08678/%EB%AA%A8%EB%B0%94%EC%9D%BC_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_XIGNCODE3_for_Android.md_0.png 190w,
/static/01d7f6960a7eb81af52937ab32af2118/2edd7/%EB%AA%A8%EB%B0%94%EC%9D%BC_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_XIGNCODE3_for_Android.md_0.png 380w,
/static/01d7f6960a7eb81af52937ab32af2118/a3f7c/%EB%AA%A8%EB%B0%94%EC%9D%BC_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_XIGNCODE3_for_Android.md_0.png 483w&apos; sizes=&apos;(max-width: 483px) 100vw, 483px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;모바일 핵 탐지 카운트. 모바일 해킹, 온라인 못지 않습니다. 자바는 거들뿐…&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;먼저 모든 솔루션이 그렇겠지만 과연 이게 필요한가, 과연 그 조악한 모바일 디바이스에서 해킹을 시도하는 사용자가 당췌 얼마나 될까라는 의문을 가질 수 있습니다. 우선 그 질문에 대한 답변을 먼저 하자면, 단언컨대 모바일 환경의 해킹 시도는 온라인의 그것 못지 않게 심각합니다.&lt;/p&gt;
&lt;p&gt;아직 블랙마켓이 형성되기 전이라 전문 프로그래머들이 진출하진 않았습니다. 바야흐로 초딩의 시대죠. 하지만 만만하게 볼 초딩이 아닙니다. 상상력 하나는 끝짱이거든요. 몇몇 메모리 조작 도구들이 개발되었고 초딩들은 그것들을 하염없이 개조해고, 개조하고, 또 개조해서 우회 엔진이라 말하며 웹사이트에 올립니다. 거기서 끝이 아니죠. 그 올려진 도구를 사용해서 밤새도록 끊임없이 앱의 메모리를 염탐하고 조작하고 있습니다. 이런 초딩 인구가 집계가 되지 않을 정도로 많다는 카더라 통신도 있습니다.&lt;/p&gt;
&lt;p&gt;더 심각한 상황은 엄마가 컴퓨터는 끄라고 하지만 핸드폰을 끄라는 소리는 하지 않기 때문에 핸드폰이라는 디바이스는 초딩들에게 24시간 열려있습니다. 이런 연유로 초보 해커인 초딩들은 오늘도 밤새도록 이불 밑에서 앱 메모리를 탐색하면서 어딘가 허점은 없을까? 아이템을 공짜로 훔칠순 없을까? 연구하고 또 연구하고 있습니다. 여기다 초딩의 영웅심이 더해지면 해킹툴 유포 속도는 빛의 속도에 근접하게 됩니다. 인정받고 싶어하는 그들의 욕구 때문에 절대로 알아낸 지식을 혼자만 알고 끝내는 법이 없지요. 어떻게는 짜투리 지식도 공유하고 또 공유합니다. 집단 지성 풀이 만들어지는 겁니다. 특히나 요즘 초딩들은 조기 교육 덕분에 영어 리소스에 손쉽게 접근할 수 있습니다. 이런 사실은 그들이 아주 고급스런 인터넷 정보에 접근할 수 있음을 의미하지요. 더불어 더 이상 그들이 초딩의 지식 한계에 머무르지는 않는다는 것을 의미하기도 합니다. 이쯤되면 메이저 업체에서 만든 앱들도 난자 당하는 건 시간 문제라는 걸 알 수 있습니다.&lt;/p&gt;
&lt;p&gt;게임이 인기를 끌면 끌수록 모여드는 초딩은 늘어나고 게임은 더 많은 해킹 위협에 노출됩니다. 컨텐츠 개발에 힘써야 할 게임 프로그래머들이 변수 오프셋을 변경하고 값을 암호화 시키는 작업에 더 많은 시간을 투자하게 됩니다. A를 A라 저장하지 못하는 그야말로 난감한 상황이 됩니다. 게이머들의 컨텐츠 소모 속도는 빨라지고, 게임 프로그래머의 개발 속도는 더뎌집니다. 결국 개발한 앱은 컨텐츠 경쟁력에서 뒤쳐질 수 밖에 없습니다. 심지어는 실컷 만들어 놓고, 사용자도 많은데 매출은 없는 기형적인 구조가 되기도 합니다.&lt;/p&gt;
&lt;p&gt;이쯤되면 아 뭔가, 우리를 대신해서 이 초딩 집단을 컨트롤해 줄 현자가 필요하겠구나, 라는 생각이 듭니다. 안드로이드 시스템에 해박한 지식을 가진, 리눅스를 적어도 커널 1.2 때부터는 사용해 왔던, X윈도우 커서 앞에서 눈물을 한번쯤 흘려 본 똑똑한 시스템 프로그래머가 필요한 시점인거죠.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;안드로이드의 가장 큰 홀은 다름 아닌 자바입니다. 자바는 그냥 게이머들에게 소스 코드를 던져주는 것과 똑같습니다. 변수값을 암호화해도 암호화 키나 시드 값을 알아내기가 정말 쉽습니다. 자바 코드는 너무 쉽게 디컴파일이 되고, 그걸 다시 컴파일해서 리패키징 하는 작업은 ‘식은 죽 먹기’입니다. 해킹 앱을 변조해서 새로 만들어내는 방법은 이미 튜토리얼 수준으로 공개돼 있어서 컴퓨터에 접근할 수 있는 초딩이라면 누구나 30분 내에 자신만의 독자적인 신규 해킹 앱을 제조해 낼 수 있는 수준입니다.&lt;/p&gt;
&lt;p&gt;주먹구구 식으로 해킹 앱 패키지명 몇 개를 추가하는 것으로는 공격의 속도를 감당할 수 없습니다. 마치 UCC 처럼 해킹 앱을 제작해서 배포하는 수준이기 때문에 기존의 해시 시스템으로도 대응하기가 힘든 속도입니다.&lt;/p&gt;
&lt;p&gt;XIGNCODE3 for Android는 온라인에서 검증된 우수한 패턴 처리 시스템과 백엔드 시스템을 사용해서 이렇게 초딩들이 마구잡이로 만들어내는 변종 앱들을 신속하게 처리할 수 있는 구조를 가지고 있습니다. 더욱이 저희는 Android 환경의 APK 전용 패턴 시스템을 별도로 제작했습니다. 이 방식을 통해서 초딩들이 허구헌날 새로 만들어내는 변종 앱들에 대해서도 패턴 변경 없이 놀라울 정도로 높은 수준의 진단율을 유지할 수 있는 구조를 가지고 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;아주 잘 다듬어진 패턴 시스템이지만 무력화 시키는 것이 불가능하지는 않습니다. 그 벽을 뚫고 넘어온 친구들에게 우리는 루팅 체크라는 아름다운 선물을 제공해 주고 있습니다. 안드로이드 환경에서 다른 앱 메모리를 변조하기 위해서는 루트 권한 획득이 필수적이기 때문에 해킹 앱들은 필수적으로 루트 권한을 획득해야 합니다.&lt;/p&gt;
&lt;p&gt;한가지 안타까운 점은 기존의 잘못된 상식 때문에 이 기능의 효용 가치가 너무나 심각하게 훼손 됐다는 점입니다. 기존 앱들, 심지어 금융앱에서도 루팅 체크를 su나 supersu의 존재를 체크하거나 특정 경로의 존재 유무를 체크하는 방식을 사용하고 있습니다. 잘 아시겠지만 이 방식을 우회하는 것은 정말 쉽습니다. 요즘 루팅 앱에서는 임시 언루팅이라는 이름으로 그러한 기능을 제공해 주고 있습니다. 반대로 이 방식의 치명적인 단점은 루팅 됐다는 사실 만으로 앱 실행을 차단한다는 점입니다. 루팅이란 자신의 돈으로 산 디바이스의 주인 권리를 찾겠다는 말인데 이걸 찾았다고 앱 실행을 제한한다는 것은 조금 이상합니다. 특히 금융 앱이 아닌 앱들에서는 이러한 허들은 앱을 사용하는 접속자를 늘리는데 도움이 안 되는 방식임에 틀림없습니다.&lt;/p&gt;
&lt;p&gt;당연히 저희는 기존의 파일, 경로 체크와 같은 조악한 방식의 루팅 체크를 사용하지 않습니다. 우리는 진짜 시스템 프로그래머잖아요. 직접 프로세스에 접근해서 관련 조사를 수행합니다. 이 방식을 우회하기 위해서는 리눅스 커널을 새로 디자인하거나 시스템 전체의 동작 방식을 변경하는 아주 복잡한 작업이 필요합니다. 그래서 우회하기가 쉽지 않죠. 더불어 루팅 됐다는 사실만으로는 차단 하지 않기 때문에 동접 건전성을 유지할 수 있습니다.&lt;/p&gt;
&lt;p&gt;루팅 앱을 체크하는 문제가 쉽게 느껴질 수 있습니다. 하지만 생각보다 쉬운 문제는 아닙니다. 바로 권한 페널티가 있기 때문입니다. 안드로이드 환경은 기본적으로 루팅을 불법으로 간주하고 있습니다. 따라서 정상 어플리케이션이 루트 권한을 요구하기란 쉽지 않습니다. 물론 루팅 단말에서만 권한을 요구할 수 있지만 그것 또한 정상적인 운영체제 경험을 위배하기 때문에 좋은 전략이라고 볼 수는 없습니다.&lt;/p&gt;
&lt;p&gt;이런 연유로 안드로이드 환경에서는 통상적으로 해킹툴은 모든 권한을 가지고 있고, 보안 제품은 제한된 권한을 가질 수 밖에는 없습니다. 이렇게 권한 차이가 발생하는 것을 두고 우리는 권한 페널티가 존재한다고 이야기합니다. 결국 낮은 권한을 가진 프로그램이 높은 권한을 가진 프로그램을 탐지해야 하는 문제라는 것이죠. 이 이야기를 쉽게 말하면 다른 우주에 있는 범죄자를 잡는 것과 똑같다고 생각하시면 됩니다. 우주 끝이 어딘지도 모르는데 우주 밖에 있는 범죄자를 잡아야 한다뉘 욱기죠. 그래서 어려운 문제입니다.&lt;/p&gt;
&lt;p&gt;XIGNCODE3 개발 팀은 다년간 이런 환경에서 작업을 해 왔고 권한 페널티에 있어서는 누구보다 전문가 입니다. 모두가 드라이버 설치를 강제할 때 그걸 옵션으로 했고, 모두가 64비트 프로세스를 띄울 때 WoW64에서 모든 것을 처리하도록 만들었습니다. 단언컨대 권한 페널티에 있어서 우리보다 전문가는 없다고 자부합니다. 우리는 낮은 권한에서 높은 권한을 가진 오브젝트를 검사하는 다양한 전략과 전술을 알고 있습니다. 이런 온라인 보안에서의 실전 경험은 모바일 보안에서도 당연히 진가를 발휘할 수 밖에 없습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#4&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;완벽한 보안 솔루션이란 없습니다. 물론 저희도 완벽하진 않습니다. 다만 빛의 속도로 완벽해지는 것을 추구하는 한 솔루션입니다. 여러분의 게임을 서버 기반으로 디자인 했기 때문에 안전하다고 생각하실지도 모르겠습니다. 하지만 여전히 자동 플레이는 큰 문제이며, 오픈 플랫폼인 안드로이드의 취약점을 공격하는 것에 대해서는 속수무책일 수 밖에 없습니다. 알려진 공격루트를 허용하는 것과 차단하는 것 사이에는 하늘과 땅만큼의 차이가 있다는 점을 꼭 기억할 필요가 있습니다.&lt;/p&gt;
&lt;p&gt;모바일 게임 보안, 이제 선택이 아닌 필수입니다.&lt;/p&gt;
&lt;center&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 483px; margin-bottom: 16px;&apos; data-url=&apos;./모바일_게임_보안_솔루션_XIGNCODE3_for_Android.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/01d7f6960a7eb81af52937ab32af2118/a3f7c/%EB%AA%A8%EB%B0%94%EC%9D%BC_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_XIGNCODE3_for_Android.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 52.63157894736842%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACDklEQVR42l2S22/TMBjF82dy0QK9sNJudB20WkFsCNax0o2LeBgIiZeBNCREeRkPvEwwgQTtGKs0LhJT2zhJO9auceI4aeMbzloVxEnsHB9/v/h7sAKhHQQB55wxNp7/NUMRRikLRRkdbgkhFAc5rutKRymVEaWjvfEynEOScsGtAHrMkyFhJIRt23bxX5gNxcMjTpbywwQXdb/pUDTfuv3CKofFPPyXghDCGP8HSzOggQyPSGfAA3lO4XD1YedxAsxmzGtbzvYO/hrCEMGuezyGOeOYepDY0shw/XijQ7rv0IfTjXhEm5oEGflONC+qWnLf/6EYvdZWd1vWBTQgnMgON+HbhfZyFe3+7P+6at58cPQoZ85fAOmUfiUBMkl9dkrPxsD0J1wN2y4079UDTWLykbrVLqlaKqZdmjHyCZBTtek4uHweZKMgG9GyEZCLh+HMDt5TXORcb85lW/kveK8+aLyGm2e0aBQkY3pSBZMpEEnqibQeWTLO5nV1wZhYNNQ5/VwanKrgz4rve1XwpGzcWGsUnukra83F51qxbN59CZbetO6/N4ofW8WKeWffLNXaqzVj+Xt7ZdcsVczCb6+myBviub7suI+wYCLwiIcPsVd3eujAP+hZlut4to2Q6xPCIXQDIhzH6/epRBQRig8Hl7QQTvBNg68s6D3trnecjmXZlg3FyZUaVY68+AOpwDM9uDQbGwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;              XIGNCODE3 for Android md 0&apos; title=&apos;&apos; src=&apos;/static/01d7f6960a7eb81af52937ab32af2118/a3f7c/%EB%AA%A8%EB%B0%94%EC%9D%BC_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_XIGNCODE3_for_Android.md_0.png&apos; srcset=&apos;/static/01d7f6960a7eb81af52937ab32af2118/08678/%EB%AA%A8%EB%B0%94%EC%9D%BC_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_XIGNCODE3_for_Android.md_0.png 190w,
/static/01d7f6960a7eb81af52937ab32af2118/2edd7/%EB%AA%A8%EB%B0%94%EC%9D%BC_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_XIGNCODE3_for_Android.md_0.png 380w,
/static/01d7f6960a7eb81af52937ab32af2118/a3f7c/%EB%AA%A8%EB%B0%94%EC%9D%BC_%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_XIGNCODE3_for_Android.md_0.png 483w&apos; sizes=&apos;(max-width: 483px) 100vw, 483px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;약은 약사에게 진료는 의사에게, 보안은 XIGNCODE3가 하는 걸로 ㅋ~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://www.wellbia.com/dp/&quot;&gt;XIGNCODE3 for Android&lt;/a&gt;는 검증된 유일한 모바일 게임 보안 솔루션입니다.&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;</content:encoded></item><item><title><![CDATA[어느 택시 기사 아저씨의 조언]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/12120</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12120</guid><pubDate>Thu, 22 Aug 2013 23:59:16 GMT</pubDate><content:encoded>&lt;p&gt;강남에서 저녁 먹고, 술을 한 잔 하고는 집에 오는데 피곤해서 택시를 탔다. 친구 녀석이 같은 방향이라 떨궈주고 가려고 같이 탔는데, 가는 길에 기사 아저씨와 친구 사이에 약간 실랑이가 있었다. 기사 아저씨가 실수로 길을 조금 돌아간 것이다. 결국 공은 나에게 왔고, 난 피곤해서 그냥 가자고 했다.&lt;/p&gt;
&lt;p&gt;그 일 때문에 친구가 내리고 택시 기사 아저씨와 이런 저런 이야기를 하게 됐다. 대기업에서 28년 근무하시고는 얼마 전에 정년 퇴직 하셨다는 아저씨. 몇 마디 안에 그 아저씨의 지식이나 철학적 사유의 깊이가 범상치 않음을 느낄 수 있었다. 그래서 나도 모르게 이런저런 이야기를 털어놓게 됐는데, 의외로 생면부지의 택시 기사 아저씨에게 뜻깊은 조언을 들을 수 있었다.&lt;/p&gt;
&lt;p&gt;물론 뭐 뻔하다면 뻔한 이야기이긴 하다. 하지만 그날 난 쉬운 길을 택하며 자기 합리화를 한 껏 하고 있던 시점이라 아저씨의 이런 이야기는 나에게 의미있는 일침이 되었고, 내가 저지를 뻔 한 더 큰 실수를 막아주었다.&lt;/p&gt;
&lt;p&gt;나 자신도 내 맘에 안 드는데, 남이 내 맘에 들기가 어디 쉽겠는가. 욕심을 버리자. 마음을 비우고.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;당신과 직장 상사와 부하 직원으로 만나는 그 사람들도 사실 직장 내 관계라는 그 사소한 조건 하나만 떼고 나면 당신과 하나도 다를 것이 없는 사람입니다. 그들을 내치는 것은 쉽습니다. 그것보다 그들에게 기회를 주고 방향을 제시하는 것이 리더의 역할입니다. 물론 경우에 따라서는 많은 기회를 제공했음에도 조직 내에서 함께 일하기엔 정말 힘든 사람들도 있을겁니다. 그런 경우에도 마지막 말은 꼭 아껴두세요. 헤어질 때 여운을 조금 남겨 놓는 편이 당신 인생에 큰 도움이 될 겁니다. 인생이란 정말 신비로워서 나중에 그 사람을 어떤 장소, 어떤 위치에서 어떻게 만나게 될지 절대로 알 수 없답니다.&lt;/p&gt;
&lt;p&gt;만약 당신이 그 사람들에게 존중받길 원한다면 반대로 그 사람들을 먼저 존중하는 습관을 가지는 것이 중요합니다. 화를 내고, 욕을 하고, 재떨이를 던지는 일은 누구나 할 수 있는 일입니다. 하지만 상대를 진심으로 이해하고 존중하는 일은 그 누구도 쉽게 하지 못한다는 점을 꼭 기억하세요.&lt;/p&gt;
&lt;p&gt;– 하계에 거주하신다는 어느 택시 기사님의 말씀&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;나는 문관이고 상대는 무관이라 하여 그를 괄시해서는 안 되며, 나는 세력이 강하고 상대는 힘이 약하다 하여 교만하게 대해서는 안 되며, 나는 현명하고 그는 어리석다 하여 그를 무시해서는 안 되며, 나는 늙었는데 그는 젊다 하여 서글퍼 해서도 안 된다. 엄숙하고 공손하고 겸손하고 온순하여 예의를 잃지 않으며, 화평하게 하여 뒤틀리고 막힘이 없게 하면 정과 뜻이 서로 통할 것이다.&lt;/p&gt;
&lt;p&gt;– 목민심서, 정약용&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; 153
 32&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[인생은 불공평한 것~]]></title><description><![CDATA[there is always inequity in life. Some men are killed in a war and some men are wounded, and some men never leave the country, and some men…]]></description><link>https://jiniya.net/wp/archives/12095</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12095</guid><pubDate>Tue, 06 Aug 2013 23:59:15 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;there is always inequity in life. Some men are killed in a war and some men are wounded, and some men never leave the country, and some men are stationed in the Antarctic and some are stationed in San Francisco. It’s very hard in military or in personal life to assure complete equality. Life is unfair.&lt;/p&gt;
&lt;p&gt;삶에는 언제나 불공평한 점들이 존재합니다. 어떤 사람은 전쟁에서 죽고, 어떤 사람은 부상을 입고, 어떤 사람은 절대로 해외로 나갈 수 없고, 어떤 사람은 남극에 주둔하고, 어떤 사람은 샌프란시스코에 주둔합니다. 군대나 개인의 삶을 100% 공평하도록 보장하는 것은 매우 힘든 일입니다. 인생은 불공평합니다.&lt;/p&gt;
&lt;p&gt;– John F. Kennedy: “The President’s News Conference,” March 21, 1962.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;기회는 평등하겠지만 결과는 결코 평등할 수 없다. 결과가 공평하다는 건 어느 누군가에게는 평등하지 않다는 것이기 때문에 말 자체가 넌센스 같기도 하다. A는 휴가 일수가 20일인데, 난 왜 10일이지, B는 인센티브를 100원 받았는데 난 왜 없지, C는 쉐프가 요리해 준다는데 난 왜 쉐프가 없지, 수영장은, 바리스타는, … 이 모든 것에 대한 대답을 딱 한마디로 해주면 당신은 그걸 받을 만큼 뛰어나지 않기 때문이다.&lt;/p&gt;
&lt;p&gt;회사는 직원을 채용하면서 모든 직원이 다 뛰어나길 기대하진 않는다. 잘하는 사람도 있고, 못하는 사람도 있다. 소녀시대같은 슈퍼스타가 필요한 부분도 있고, 묵묵히 그 뒤에서 그들의 치장을 도와줄 아티스트들이 필요한 경우도 있다. 그런데 아티스트들이 왜 우리는 소녀시대 같지 않냐고 한다면 뭐라고 대답해야 할까? 거울을 보라고 해야 할까? 반대로 생각해보자. 돌려서 회사에서 당신은 왜 소녀시대 같지 않냐고 묻는다면 뭐라고 대답할 건가? 그 미칠듯이 많은 사람들이 소녀시대는 줄서서 보려고 기다리면서 왜 당신은 기다리지 않은 것일까?&lt;/p&gt;
&lt;p&gt;누구도 당신의 능력이 타인과 동등해야 한다고 요구하지 않았다. 그러니 당신도 이제 세상을 향해서 결과가 공평해야 한다는 주장은 좀 접도록 하자. 이마트에서 3000원에 파는 한라봉을 재래시장에서 5000원에 판다고 상인에게 따져 무엇하겠는가? 이마트에 가서 사 먹든가, 한라봉을 먹지 말든가해야지.&lt;/p&gt;
&lt;p&gt; 10
 5&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[토속촌 기행]]></title><description><![CDATA[#0    고 노무현 전대통령이 맛있다고 해서 일약 스타덤에 오른 삼계탕집이 있으니 바로 종로에 있는 토속촌이다. 이 삼계탕집이 얼마나 유명하냐면 일개 삼계탕 집임에도 국세청의 세무조사까지 받았었다. MB…]]></description><link>https://jiniya.net/wp/archives/12001</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12001</guid><pubDate>Tue, 06 Aug 2013 23:59:14 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 315px; margin-bottom: 16px;&apos; data-url=&apos;./토속촌_기행.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/e47f0bbe78b96e458018751c07a5991a/ba98e/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 133.1578947368421%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABAADAf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHTYRhcaHnR2MLaP//EABsQAAIDAAMAAAAAAAAAAAAAAAECAAMREhMg/9oACAEBAAEFApghsUQclDa06FmDDXhLnx//xAAWEQEBAQAAAAAAAAAAAAAAAAARABD/2gAIAQMBAT8BI3//xAAWEQEBAQAAAAAAAAAAAAAAAAARABD/2gAIAQIBAT8BZ3//xAAfEAACAQIHAAAAAAAAAAAAAAAAAgEQIRESIDJBgdH/2gAIAQEABj8CLthSOS7dG9aZlI80f//EAB0QAQEBAAICAwAAAAAAAAAAAAERACExEEFRYbH/2gAIAQEAAT8hG+8qU3chLdFDX7g9krefRjWtEyF2nr50kBZz9sef/9oADAMBAAIAAwAAABCA1r7/xAAXEQADAQAAAAAAAAAAAAAAAAAAARAR/9oACAEDAQE/EEMX/8QAFREBAQAAAAAAAAAAAAAAAAAAASD/2gAIAQIBAT8QYP/EAB0QAQEAAwEAAwEAAAAAAAAAAAERADFBIRBhcZH/2gAIAQEAAT8QJF2S4hWlBPJcXsx3wv8AXHRNpm18j0xeqop+35kZb9nsxUxHmMrH3KfTFROm1s3nw6mAOf/Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 0&apos; title=&apos;&apos; src=&apos;/static/e47f0bbe78b96e458018751c07a5991a/ba98e/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_0.jpg&apos; srcset=&apos;/static/e47f0bbe78b96e458018751c07a5991a/8ccab/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_0.jpg 190w,
/static/e47f0bbe78b96e458018751c07a5991a/ba98e/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_0.jpg 315w&apos; sizes=&apos;(max-width: 315px) 100vw, 315px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;  &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; margin-bottom: 16px;&apos; data-url=&apos;./토속촌_기행.md_1.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/79ea7b100038ff93e6575e6e9591c182/7fbea/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAEFAgT/xAAWAQEBAQAAAAAAAAAAAAAAAAABAgP/2gAMAwEAAhADEAAAAU9zM7pnKJ//xAAaEAEBAQADAQAAAAAAAAAAAAACAQMABBES/9oACAEBAAEFAtIfk+DOdX2aNI3C8NQn/8QAFREBAQAAAAAAAAAAAAAAAAAAACH/2gAIAQMBAT8BV//EABYRAQEBAAAAAAAAAAAAAAAAAAARIf/aAAgBAgEBPwGsf//EAB0QAAICAQUAAAAAAAAAAAAAAAABAhFhEiExQYH/2gAIAQEABj8C3XpVpxeS41WTT0clKbR//8QAGhABAQEAAwEAAAAAAAAAAAAAAREAITFBUf/aAAgBAQABPyGzFPimDTyBOmQVuUrInB9hqONkZHg7/9oADAMBAAIAAwAAABDD/wD/xAAWEQEBAQAAAAAAAAAAAAAAAAABEDH/2gAIAQMBAT8QRTI//8QAFhEBAQEAAAAAAAAAAAAAAAAAAREQ/9oACAECAQE/EADLj//EAB0QAQADAAEFAAAAAAAAAAAAAAEAESExQVFhcbH/2gAIAQEAAT8QpiZFHTssHKulp83zK1FchvoqMVRFja+QCQR3SF+ug1P/2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 1&apos; title=&apos;&apos; src=&apos;/static/79ea7b100038ff93e6575e6e9591c182/7fbea/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_1.jpg&apos; srcset=&apos;/static/79ea7b100038ff93e6575e6e9591c182/8ccab/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_1.jpg 190w,
/static/79ea7b100038ff93e6575e6e9591c182/ea4c8/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_1.jpg 380w,
/static/79ea7b100038ff93e6575e6e9591c182/7fbea/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_1.jpg 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;고 노무현 전대통령이 맛있다고 해서 일약 스타덤에 오른 삼계탕집이 있으니 바로 종로에 있는 토속촌이다. 이 삼계탕집이 얼마나 유명하냐면 일개 삼계탕 집임에도 &lt;a href=&quot;http://www.joseilbo.com/news/htmls/2013/02/20130214171660.html&quot;&gt;국세청의 세무조사&lt;/a&gt;까지 받았었다. MB가 그렇게 꼼꼼하게 털어주시는 바람에 더 유명해졌는지도 모르겠다. 어쨌든 매번 가보자는 말만 하다가 이번 주말에 첨으로 가보게 되었다.&lt;/p&gt;
&lt;p&gt;12시에 보기로 했는데 너무 과한 시간이었다. 1시간 늦춰서 한시에 삼계탕 집엘 갔다. 실제로는 더 늦은 시간이었는데도 사람들이 빼곡히 줄을 서 있었다. 헐. 무슨 삼계탕을 줄서서 먹지, 라고 생각했는데 여기까지 왔으니 줄을 일단 서고 봤다. 저 뒤에 주차장까지 한 50미터는 줄을 서 있었다. 그 줄에서 약간 기대를 가졌다. 진짜 맛있나? 이러면서… 그런데 실제로 삼계탕을 받아들고 먹으면서는 맛은 개인의 취향이니 다 다를 수 있다는 생각을 했다. 소문난 잔치에 먹을 것 없다는 속담을 떠올리면서 ㅋㅋ~&lt;/p&gt;
&lt;p&gt;국물은 보통 삼계탕 집보다는 조금 더 진한 수준이었는데 닭이 무슨 돌닭이 나오는 느낌이었다. 단단해도 너.무. 단단했다. 심지어 해체가 잘 안 될 지경, 큭~ 잘 익었음에도 딱딱했다. 그냥저냥 먹을만한 삼계탕이었는데, 줄서서 막 찾아가서 먹고 싶을 정도의 삼계탕은 아니라는 생각이 들었다.&lt;/p&gt;
&lt;p&gt;개인적으로 서울에서 가 본 삼계탕 집 중에서는 &lt;a href=&quot;http://www.xn--989ar29a23aj97a5kg.com/index.php?mid=map_hq&quot;&gt;호수 삼계탕&lt;/a&gt;이란 곳이 제일 괜찮았다. 예전에 고등학교 친구가 놀러와서 데리고 간 적이 한 번 있었는데, 이번에도 놀러와서는 그 집에 가자는 이야기를 했었다. 그 시크한 놈이 그런 말을 하기에 어지간히 괜찮았나 보다 라고 속으로 생각만 했다. 멀어서 그냥 족발 사줬는데 족발이 어쩌고 저쩌고 어찌나 궁시렁 되던지 ㅠㅜ~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;난 서울이 참 사람 살기에 좋은 곳은 아니라는 생각을 많이 한다. 가장 주된 이유는 사람이 많아도 너무 많기 때문이다. 잘 싸돌아 뎅기지도 않지만 가끔 어디 나갈 일이 있어서 지하철을 한번씩 타보면 정말 숨이 탁탁 막힌다. 물론 지하철 뿐만이 아니다. 어딜 가나 사람이 토나올 정도로 많다. 그런데 진짜 역설적인 사실은 그렇게 싫어하는 이유 넘버원이 바로 나를 서울에 살 수 밖에 없게 만드는 이유라는 점이다. 죄다 서울에 있으니 다른 곳에 있으면 결국 매번 서울로 와야 하는 것이다. 실제로 이날 만났던 후배 녀석도 부산에서 사업을 하다 일주일에 서울을 2-3번씩 와야 하는 어처구니 없음에 결국 서울로 왔다.&lt;/p&gt;
&lt;p&gt;어쨌든 이렇게 사람 많은 서울도 한가지 장점은 있는데 바로 볼 게 많다는 점이다. 어딜가나 뭐가 많다. 그리고 세미나든 뭐든 죄다 일단 서울은 하고 본다. 그러니 보고 싶은 게 많고 구경하는 거 좋아하는 사람들한테는 참 좋은 곳이기도 하다. 이날도 삼계탕 집에서 나와서는 광화문 쪽으로 가다 &lt;a href=&quot;http://www.much.go.kr/MuPageLink.do&quot;&gt;대한민국 역사 박물관&lt;/a&gt; 이란 곳이 있어서 들어가 보게 되었다. 그런데 생각보다 재밌었다. 다음에 시간 나면 설명할 때 정주행을 한 번 하고 싶을 정도였다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 240px; margin-bottom: 16px;&apos; data-url=&apos;./토속촌_기행.md_2.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/db0545e7eb07cf92120990a28b27b5c9/6e1d3/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_2.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 133.1578947368421%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAIDBAX/xAAWAQEBAQAAAAAAAAAAAAAAAAAAAQL/2gAMAwEAAhADEAAAAbqQUMXcIgkTRbTLLxH/xAAeEAABAwQDAAAAAAAAAAAAAAABAAIRAxIhMQQQMv/aAAgBAQABBQKVdlXYE3N0aDYHGaF5QHR3/8QAFREBAQAAAAAAAAAAAAAAAAAAEBH/2gAIAQMBAT8BKf/EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EABkQAAIDAQAAAAAAAAAAAAAAAAARASAhUf/aAAgBAQAGPwITrknRTlP/xAAcEAADAAIDAQAAAAAAAAAAAAAAAREhMRBBUWH/2gAIAQEAAT8h1JmF8KNm0x4Sq6Y1VmPZcGWjC+kuhE1wqeiP/9oADAMBAAIAAwAAABDM6wD/xAAWEQEBAQAAAAAAAAAAAAAAAAAAEQH/2gAIAQMBAT8QzEUr/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAEREP/aAAgBAgEBPxDIiH//xAAeEAACAgICAwAAAAAAAAAAAAABEQAhMUEQcVGhsf/aAAgBAQABPxCljHsDbXL3DnYMm3WYQDM7cKS2JlkIWdB+O/UKETjaJQf2UqBBHTSgoFHweMnYn//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 2&apos; title=&apos;&apos; src=&apos;/static/db0545e7eb07cf92120990a28b27b5c9/6e1d3/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_2.jpg&apos; srcset=&apos;/static/db0545e7eb07cf92120990a28b27b5c9/8ccab/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_2.jpg 190w,
/static/db0545e7eb07cf92120990a28b27b5c9/6e1d3/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_2.jpg 240w&apos; sizes=&apos;(max-width: 240px) 100vw, 240px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;학교 추첨하는 뺑뺑이 기계, 실제로 뺑뺑이를 돌렸다는 사실이 조금 충격적이었다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;하기야 후세 아이들은 어떻게 의사 난수 생성 함수로 뺑뺑이를 돌렸지 하면서 웃을지도 모를일이다 ㅋ~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 520px; margin-bottom: 16px;&apos; data-url=&apos;./토속촌_기행.md_3.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/1699f310f9d8403db8aebf731e42ba34/95cb2/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_3.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAMEAQX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAABjZjo5haV/8QAGhABAAIDAQAAAAAAAAAAAAAAAQACAwQRIf/aAAgBAQABBQIwkdclqcsWeqk8Z//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABgQAAMBAQAAAAAAAAAAAAAAAAABMSAh/9oACAEBAAY/AqyvHT//xAAbEAADAAIDAAAAAAAAAAAAAAAAAREhQVFxkf/aAAgBAQABPyGwJ7QexIf08L2VOh25n//aAAwDAQACAAMAAAAQvM//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAbEAEAAwEAAwAAAAAAAAAAAAABABEhMUFR8P/aAAgBAQABPxCuxXtMwrq8s5oHtgAE21D1hDXy4b2zmE//2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 3&apos; title=&apos;&apos; src=&apos;/static/1699f310f9d8403db8aebf731e42ba34/95cb2/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_3.jpg&apos; srcset=&apos;/static/1699f310f9d8403db8aebf731e42ba34/8ccab/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_3.jpg 190w,
/static/1699f310f9d8403db8aebf731e42ba34/ea4c8/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_3.jpg 380w,
/static/1699f310f9d8403db8aebf731e42ba34/95cb2/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_3.jpg 520w&apos; sizes=&apos;(max-width: 520px) 100vw, 520px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./토속촌_기행.md_4.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/6ae697bae50cc6ac50682467b5099410/dface/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 71.57894736842105%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAD3klEQVR42iWT2U/UdxTFf+mDfaiJTdqnvvShSWOhaWwjFS2yBKWIVVutS8EBGYZt2JRV2QQEAUeQbRbmB8OswMAwwsAg0IEBBQoFgoCA2ipptEnT+D98+oU+fHMfvrnnnnPPudLtvFRUsT+RnZpKUY6agiwV11OuknjlAj9ERXEiNIyTx0OJOPYdwYe/JSw4mLCjwURHhBP42ad8dOAAAQcD2f/Bft6TJKSivALaWzS0tnbS0NCG2WLGbrVgMso03tNQWV5FWXEFRTcKyExJJ1WZglqVRnpSMheijvPJxx9yKvIkh776GmkX8HZ5GQ2au9Tf12OyOfF4XXgnPPT29dDwQEtF+R0K80tQp18n/qqK2CsJxF5S8OPZS8REhBAU+DlxvySgVKp5f98+JI2mGr1ei6nbg29+idWtBZ79scja5gy+mXFM9l40jQaKiirJyswnQaFCpUwn7so1zkRHcyL4EIkKJZnpN/ji4JdIZouOji4bdrefkalFfl9bYfvPFda2F3j5ao7HsxOM+cbpNNuoqKgjO7NAAKoF2yQunLtI6DcBnD99mgwBePHnq0gWm0zvwAgO9xTt1hH8iyv8+26Vd39P82bDxes5mZ11N5P+URrbzFRWN6FW56OIU3HuzGVOhYcQFXIEVWIaWRn5gqHNQlf3MCaLi0HvJHPLq+zsLPHPX9O83Rrm7bMBttZ9eP1PsPUN0aS3U17ZSHb2LbG3TJSKeMIPB6CIjSdZmYZkdTh4oHXQZBigd3ge3+JzlrZ3ePriOS/fvGbj1QuWt7ZYe7HBtBg2+dsSnfZBauq13CyuofRWCZejg4XsGDLVeUgGo4myKgN1zU6a5SE6nVMM+jfoH1/GO7vBo/lNxubWmV/fZmppk4fjgqlrjDa5j9p7OvJyy/ZyHBMaJPaYi6TV6alv6qVF9mDu92Ny+hmeXkfu8eEYnGFgfBHrwAyusQXabaPozB7aLYO0GR00t8qUlNwhLyOZqCMBwnlhSrvchaV/Srj8eK/xoe8p7l9XBUtRfau4J5bpHZnbA+72zGITaegZ9NFld/OgyUBtTR1lNwu59P1RzkZFIhk7Hcj2MTrs4xjMo1j6/FgFuHtiBbOQ3+XcZfqEnqHZvSQ0G5zoO4VcTTvl5bXU3qkWl1RKctx5Ig4HIumNVvRdHgE2LBwcENVLh8NH99C8iJGXto4hjEKqqfsRLYYetEbxdFY097Xcrb5H6c1i8nNyUCclEBl0UJgi99Aqu9B2uMR0F7JtQjCbxibk7w5pMfbTanT+/69z0Krrpqm5g4b7LVRV1FBceIvcrByy0lLFbR/jP/V54wyUIdUIAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 4&apos; title=&apos;&apos; src=&apos;/static/6ae697bae50cc6ac50682467b5099410/dface/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_4.png&apos; srcset=&apos;/static/6ae697bae50cc6ac50682467b5099410/08678/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_4.png 190w,
/static/6ae697bae50cc6ac50682467b5099410/2edd7/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_4.png 380w,
/static/6ae697bae50cc6ac50682467b5099410/dface/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_4.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;한 파독 광부의 일기, 1964.11.10 맑음, 하나님은 나를 이러한 곳까지 인도하여 주시었다…&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;100년 뒤엔 한 프로그래머의 애환이 담긴 일기가 전시될지도, 미리미리 일기 써두자 ㅋ~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;전시된 한 파독 광부의 일기는 정말이지 굉장히 인상적이었다. 날짜며 내용을 한참을 들여다 봤다. 특히나 일기 중앙에 있는 ‘생’과 ‘사’란 글자는 이 일기의 백미였다. ‘생’이란 글자는 빗금 채우기를 했고, ‘사’라는 글자는 빨간색으로 적으면서 이 일기의 작성자의 예술적 감각을 한눈에 알 수 있게 했다. 아마 전시하는 측에서도 그런 글자의 임팩트를 생각해서 이 페이지를 펼쳐둔 게 아닐까라는 막연한 추측을 해봤다. 물론 다른 한편으론 그가 그곳에서 느꼈을 고통, 외로움, 생경함 등으로 얼마나 힘들었을지를 단적으로 보여주는 것 같아 조금은 씁쓸했다. 이런 분들이 있었기에 우리가 이제는 이만큼 살 수 있게 된 게 아닐까? 넘겨가며 뒷페이지를 조금 더 들여다보고 싶었으나 전시물이라 이 페이지만 볼 수 있다는 사실이 조금 안타까웠다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;광화문 교보문고를 가는 길에 세종대왕 동상이 있는 곳에서 무료 가훈 써주기 행사를 하고 있었다. 줄이 길지 않아 우리도 쓰자고 했다. 후배 녀석이 논어에 나오는 한 구절을 고르기에 나도 똑같은 내용으로 골랐다. 한땀한땀 정성스레 화선지에 쓴 글자를 받아드는데 필체가 제법 마음에 들었다. 개발팀 한 귀퉁이에 걸어 놓고는 압박해야 겠다는 생각과 함께… ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 550px; margin-bottom: 16px;&apos; data-url=&apos;./토속촌_기행.md_5.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/bccbd145d6cbde081e00f68dfa111d34/8c3ad/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_5.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 59.47368421052632%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAAA7DAAAOwwHHb6hkAAADC0lEQVR42iWT228TZxDF9z9qKqVSCVIFEkU8VOkTL6FpSwGRligBVYACxAGaQu4327G9Xl921058I3ES3x07tmPHN+JcoPTP+XW8fRitvm92zpwzZz7l28FBBr4aYHDga64PXeWHmze4e2eEe6OjTIyN8ffbt6zNvcP0qaT2kiTMIPsfYiRjEUzVhd+rMvvqBVOT44zfv4cydGWIG999z/CPtxkZ/Y2798f4/dEE06//YnZukVW7Ey2oE4kn2E+lyeYLZHN5DtIZErt7+HWTpTU7T55O8fjP5yjPp6ZZnp1HUz3o4RA7wiKVSVEsFajWjqgdV2i26jQaNTrdJq12g+7HphWNk5qVq1RKLCwusrRqR3n67AUuX5CgaRIwTHYFMJ1NC5sDykcl6o2qBXrSanD5qcfH0za9sy4XF6d0On3QYwE9plwusubYRHn85BlOj4ZbVXF7NbKFHKXyIYflEifNOmdS2I/qcZXLz+dcfDrj/KLHP18uhWXLYt2V6Kvp1ysPH46zvqnyaGKSn37+hemZGd69n2PmzRsM08DhdGCEDN7Pz+MP+AmFTevs82lofg3b6xk+7MSJRiMEQ1soI3d+Zd3pYW3DzivbDBsOJ75ggJc2myU/Go8QEUddHrcABnBsOsnkMpgCapg6S8tL6HoAl3iwFY2jDA/fZmV9U7qGxMm4uJfmqHokbubFmEOZWYd2t02t0eDLv59F7hnNdouz81O6vQ49GUer2xIj05hbEZRbt4aZX94QVkFxOcx2LEa+WCCVzYgxKXKFAvWTujBN4HS58Pal+nx45Bt0OtmTzSgkd8kdFv8HvH7tJrMLq3gNg4A4HY5EyEvyIJMRt7PkBLxcrbB3cMB2NGqNIZZIWOfkzg5ZaVopFS0S4UgU5crVa9hkdbTVFby6IYMOWD9HpCghBf31SWWy7MsoCtKoKO73G/UBshJ76ZTcFyx1fiOEMvjNEJMP/mDhpQ27qrEiW+9W+5LEAJdqvQQ9vI3q1/EGdHkdSQyRpukhzO2Y5MPooTB2tyovyuQ/wsazwACYJpgAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 5&apos; title=&apos;&apos; src=&apos;/static/bccbd145d6cbde081e00f68dfa111d34/8c3ad/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_5.png&apos; srcset=&apos;/static/bccbd145d6cbde081e00f68dfa111d34/08678/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_5.png 190w,
/static/bccbd145d6cbde081e00f68dfa111d34/2edd7/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_5.png 380w,
/static/bccbd145d6cbde081e00f68dfa111d34/8c3ad/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_5.png 550w&apos; sizes=&apos;(max-width: 550px) 100vw, 550px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;사실 이 날 후배를 만난 이유는 “코딩호러의 이펙티브 프로그래밍”이란 책을 선물하려는 생각에서였다. 그냥 보내줘도 되지만 만난지도 오래돼서 얼굴이나 볼 겸 만났다. 올해 읽은 책 중에 “코딩호러의 이펙티브 프로그래밍”은 “페르시아 왕자 개발일지”만큼 흥미진진한 책이었다. 지지난주 였나? 주말 저녁에 &lt;a href=&quot;http://www.benjaminlog.com/entry/effective-programming&quot;&gt;김재호님께서 올리신 서평&lt;/a&gt;을 보고는 12시간을 못참고 강남까지 한달음에 달려가 책을 샀다. 나도 3번 넘게 읽는 책은 “조엘 온 소프트웨어”, “모어 조엘 온 소프트웨어”, “해커와 화가” 였기 때문이라 더 기대가 됐다. 교보문고는 너무 더워서 그 옆 조용한 커피숍에서 그 내용을 들이켰는데 정말이지 감동적이었다. 더러는 평소 생각하는 바와 일치하는 부분이 있어서 반갑기도 했다.&lt;/p&gt;
&lt;p&gt;책 내용이 너무 좋아서 개발팀 애들에게 한권씩 돌려야 겠다는 생각을 했다. 그래서 다음날 책을 들고 가서는 한 녀석에게 정말 감동적인 책이었다고 보여줬는데, 그 녀석이 그랬다. 이런 책이 진짜 도움이 돼요? 흠,… 핡~ 아무리 좋은 보석이 있어도 그걸 볼 준비가 돼 있어야 보이는구나 싶었다. 어쩌면 아직 이 친구들에게는 WOW64에서 시스템 리다이렉션이 어떤 부분에서 발생하는지, PEB가 왜 듀얼 구성이 되는지와 같은 테크니컬한 내용을 하나씩 차례차례 설명해 주는 책들이 더 갚어치가 있을수도 있겠다는 생각이 들었다. 그래서 주변에 읽을만한 사람들에게 선물해야 겠다고 맘을 바꿨다.&lt;/p&gt;
&lt;p&gt;후배 녀석도 책을 한 권 사줬는데, 하루키의 신작 “색채가 없는 다자키 스쿠루와 그가 순례를 떠난 해”였다. 전반부 조금 읽었는데 하루키 소설의 전형적인 도입부를 보는 듯한 느낌이었지만 재미는 있다는 생각이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#4&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 480px; margin-bottom: 16px;&apos; data-url=&apos;토속촌_기행.md_6.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/769cd6d2ada0565bf1116ea6d455a3f4/9aebd/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_6.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 177.89473684210526%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAkCAIAAAAGkY33AAAACXBIWXMAARlAAAEZQAGA43XUAAAHgElEQVR42oWQeVRT2RnA3/89PTNF6zgeQSBsypCEzYUlLAkveSGLsiciRBYhLAETAREXhkEHa6mOoI4DKFswkEAAsTPT1krVGRUZlmNLCKuDHgEhhCUhC8m7vYGejqenPf3O733nd7/7fe/ddxEXgqu7p8t2h18fOnjQzcvLi0jg0n5lZ/fxRx/bws7OztXN3c3NzX73nn1EJ+Kh3zo7uTg67nFycrK3t0cUinZFu7ylrVkOo12hVMq/7aqXbkZzs7SpWdrV0S5vlUlbWnu+U3Y/bGiRylpbZW1tbTKZDAH/L9YBMP1HZX19ZmbGbDYjln/FxtZj3oBsQKC/WzP9+fVq9ZCmalDTN6sf1RgG53WrZuvbNzO9vb1arfaXL3dN6RpUq7KxNZjrVaudU7qOSV3TqK1yf1rXM21bto2vfT+jBwA3Gm2n+WV4YME4vGAcXDA9eWd4tWhSLZla1GvPZw3KKV3dyAp8y4s5w8M363+a0VtxfGvkv/zz1o7Jglf8tFTwdPHCC035y6Xyl5prQ9q/vV1XTKzZejbnEQsOttiwboIDsxVYcWC04MLe95yed1eHtLdeLVcOasv6llIezj96C2/Q1gNH/udtW3D89Yr5/bpli4V1y7x+Y8Vk/bAH6Zxc6ZpcgVkJ84RN/s0fp1cfTK9+mLunVpQTtjaFalGuWkDQB3Oh3e9oPXPYg7mIntmInjl0i80lrWeWen+Wdt8mMNt2H8wHy6f9mlQHpWqEqXyd1KFmKcaFj2bzH89xet5gXTPM7hmYIZHdM8zO1/T2CVQ+RpONovJxevskKlPFKMfC740gofXDOW1D7MYhftd4as8Er3OM3znO6xwX3J841j0e26FmyFQQWvMrSl0/tXE4rHGY1jDAV7yi3OlH9t8bJTf+w0+qCmwdC2xVB7eNBbepQxVj4YpxilwNK/4to7DHt3mEeHd4/z3bklg/7FHzk2fdAFJ65sbnZ2+Vltw8X3zjQ84VV8N8obgaNpRuyrnC61BKT1efL6oqKbxecuorBGAoCKMAlGoTegRgoDagM+kA24S5CYbijAgLNRREhANaGAilQEfMLPZCUfFacjJISsazc/C0NFwoxGNirBiGs1g4m21hMk0YZsCYega2itJXIlADh2MUCOASMbAiZxsatHkiwEsAaSkgRQCyMsFRPhAkW/k8S3ycns/TxUYb6BEGJraOMQwY3cTlmASCNTQCwakcE4VpDWeDyDiAxdjg8nFmrJmdoKdHrdO4Oka0gRFtomDagHADBTWHRS4HRCz4UgwhGLIioegLqPqCML0kRCcJWZNQtHmBSxBRgEYUsJwftJgToBUFzucFjgiDx7JCFnKD5nMPvcsNWBQFIvgkCUzuxSe9oOATRKsNknUcug0oG6NEmJf7PJ7cdnl0w232sSuYIlnUnhujJMQy/NnsX0LWnvnoX3gaB0hg1BuoyJtsyggZf0XeGCYbnn/2cxPhdT1h5YknGPEzDoWbB0mI7pnbdL/i/TOe/oXz2guyaYhkHiIZB0lQTMMky9/JxgGyaZAMi8tPvSDr/UTTkL9ukGUcJCJgkgh+jgZTQUC9D4x64SOeYIwIBai9wJgXmIBnIQI1EUwQwTgRqDa3VJ5gdC+sIM/lB/oUPs/lfi87AvraD/Z3Bj6W+fwg9/+x1f8Hme/TFr/eJp/eRp9nrQeeSP3/Wu/9ROo30BXc1x74Y+sBhHs4KjEpJSMzOz09Mzs790hUrCQrt/5yZdnZc6L8fCaTk5qalpOTg2GsuLgEoVBYVl5WWFSYeCw5OjoeYUUyEuJjCgrEv79SUXmlQnzqZM3lS2++/+725YunCk9eOF+ccSK14svPGxu/qa2thnK6SHIskc/lsA5z2QjGYPJ5R4tPn7lypfLqH65drvhdeWnZtUsVkvxTAkFK6vHUkpLikpIzpRfOFxUUXK64lJmRmSXMys4SRjJZSCQHPZ5+rKhEIi4UQcq/vAA9LStFJM6moiEYC71y9YvkVH4YlcJLjC0szo9NOJKTl5FwNCZREI8cP1yQl/RFFu98alRRXlLZidgzOYml4uMXj7FOJtCzuZTU1KhCIe8sjyESJpwVp1yMDs+MR7N59Fw+lod8w9Z9jelvYqvXUc1V6vxX1PdXw+crQ2evUReq6dpr4QtV6NL1CM1NxsqtyOVqugZSRV+sQjW32atII9daG6ep5egVaUCZCTogGaA9HSiFoE2AKzNAjwh8KwbtSeBeFGiNBU1c/A4Lb44DdUwcyQttPi2qzubektBkebSm7NA7WaF1ovD6PFpDRnCNMKRGzJBKsBZh8N30/XdyQ1pygqQZATVibm3mobuIvftuySF2nF/Qp4Sdn9rvoDJC/QN8d+zatn2XHZNLPxLL+WT39m07f8OOwuISoz6x3wahUAOYHPquPTsQgrNrNyouD+TvdHR0sHfkcg+zWBx7+z0QgeC4SJTv5OTi4OB0Ij3jZL54y6OjY9PS0p2dXRACwdXPnUhy83QiEBydnL19fEhkb4c9jh5793n7+JK9fTw89sK6q6u7m7sHFGeCCxF2+Pi6uXv8Exjx+50eLF/fAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 6&apos; title=&apos;&apos; src=&apos;/static/769cd6d2ada0565bf1116ea6d455a3f4/9aebd/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_6.png&apos; srcset=&apos;/static/769cd6d2ada0565bf1116ea6d455a3f4/08678/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_6.png 190w,
/static/769cd6d2ada0565bf1116ea6d455a3f4/2edd7/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_6.png 380w,
/static/769cd6d2ada0565bf1116ea6d455a3f4/9aebd/%ED%86%A0%EC%86%8D%EC%B4%8C_%EA%B8%B0%ED%96%89.md_6.png 480w&apos; sizes=&apos;(max-width: 480px) 100vw, 480px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;후배 녀석이 개발한 프로그램, 에브리싱.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;커피 마시면서 녀석이 요즘 개발하는 프로그램 이야기를 들었다. 에브리싱이라는 노래방 프로그램을 개발하고 있는데 사운드 처리하는 부분에서 조금 애를 먹었다고 했다. 도중에 오픈 소스 프로그램을 안드로이드 환경으로 포팅하는 과정에 실패해서 다른 방법을 선택했다는 이야기도 했다. 그 오픈소스가 조금 복잡한 라이센스였는데, 난 오픈소스를 가져다 쓸때는 라이센스 문제를 항상 꼼꼼하게 체크해야 한다는 이야기를 해줬다. 그 외에도 후배 녀석이 XIGNCODE에 적용하면 좋을만한 여러가지 요즘 트렌드한 내용들을 이야기 해줬다. 난 정말 상상도 못했던 엄청난 이야기들이라 정말 기뻤다.&lt;/p&gt;
&lt;p&gt;대학시절 프로그래밍 과제를 한다고 주위 사람들의 소스 코드를 크게 참고한 적은 없었다. 물론 인터넷 소스는 무지하게 참고했다. 간혹 소스 코드를 봐 달라는 이야기를 하는 친구들도 있었는데 그렇게 흥미로운 소스는 없었다. 그러다 한 날 레드 블랙 트리 과제를 하고 있는데, 녀석이 와서는 자기는 벌써 다했다는 이야기를 했다. 그래서 잠깐 녀석의 소스 코드를 봤는데 깜짝 놀랐다. 정말 잘 짰기 때문이었다. 처세에는 조금 둔한 친구긴 한데, 그래도 그 프로그래밍 실력만큼 잘 됐으면 좋겠다는 생각이 든다.&lt;/p&gt;
&lt;p&gt;대한민국 역사 박물관에서 SM엔터테인먼트에 있는 연예인들이 나오는 스크린이 있었다. 보아가 나오는데 녀석이 그랬다. 우와 보아 이사님이네요. 보아 이사님이라… 우리가 생각하는 NO.1 부르던 꼬꼬마 권보아도 회사라는 조직 속에서 만나면 보아 이사님이 될수도 있다는 생각이 들었다. 그래도 보아 이사님이라뉘. 나름 신선한 충격 ㅋ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[안윤호님 칼럼 소개를 빙자한 자랑질 ㅋㅋ~]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/12040</link><guid isPermaLink="false">https://jiniya.net/wp/archives/12040</guid><pubDate>Tue, 06 Aug 2013 23:59:13 GMT</pubDate><content:encoded>&lt;p&gt;대학시절 &lt;a href=&quot;http://www.jiniya.net/wp/archives/1208&quot;&gt;나성언님의 칼럼&lt;/a&gt;과 안윤호님의 마소 칼럼을 즐겨 읽었습니다. 나성언 님의 칼럼은 에세이 스타일에 일상에서 느낀 점들을 기술과 연관시켜 풀어내는 글들이 많았던 반면 아마추어 커널 해커라고 소개된 안윤호님의 칼럼은 상당히 테크니컬한 내용들을 많이 담고 있었습니다. 때로는 시대를 앞서 나가기도 하고, 때로는 과거를 꿰뚫는 철학적 통찰을 담기도 하는 등 정말 흥미진진한 내용들이 많았습니다. 막연하게 나도 나중에 글을 쓴다면 그런 글을 쓰고 싶다는 생각을 많이 했었습니다. (&amp;#x3C;- 마음만 먹는다고 되는 건 아니지요 ㅋ~)&lt;/p&gt;
&lt;p&gt;그랬던 꼬꼬마 프로그래머인 저도 마소에 소소한 글을 쓰면서 언젠가 한번은 &lt;a href=&quot;http://www.imaso.co.kr/?doc=bbs/gnuboard.php&amp;#x26;bo_table=article&amp;#x26;page=569&amp;#x26;wr_id=32050&quot;&gt;안윤호님&lt;/a&gt;에 대해서 물었던 기억이 있습니다. 그.런.데. 놀라운 일이 몇일전 제가 &lt;a href=&quot;http://www.jiniya.net/wp/archives/11877&quot;&gt;“국내 프로그래머 블로그”&lt;/a&gt;란 글을 올리고 벌어지게 되었습니다 ㅋㅋㅋ~ 바로 존경해 마지않는 안윤호님과 페친이 된 것입니다. 사실 전 뭐 페북을 별로 안 해서 페친된 걸 자랑질 하는 건 아니구요. 어린 시절 저의 우상이었던 분께 제가 발견되었다는 기쁨을 좀 자랑질하고 싶었습니다 ㅋㅋㅋ~&lt;/p&gt;
&lt;center&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 523px; margin-bottom: 16px;&apos; data-url=&apos;./안윤호님_칼럼_소개를_빙자한_자랑질_ㅋㅋ~.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/c90c18b0fc3a7f52c7f8c45a1d5581af/c53f8/%EC%95%88%EC%9C%A4%ED%98%B8%EB%8B%98_%EC%B9%BC%EB%9F%BC_%EC%86%8C%EA%B0%9C%EB%A5%BC_%EB%B9%99%EC%9E%90%ED%95%9C_%EC%9E%90%EB%9E%91%EC%A7%88_%E3%85%8B%E3%85%8B~.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 88.94736842105263%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAIAAADUsmlHAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACk0lEQVR42o1UO2tUQRS+f8BC0FpQIQhWQoISwSqFYBe0thB/hqWNnaCg+QFiEoyFYNQtUgjaGpKYZDe7bu7e57xfd+5z45m7mkRIgoePwxmY7zznjBcmaLM7oExwaYQ0ShswtHaGNlmeF0VRnghjrPdmcfnho8e7vUEQM0S4ziyTGdCAbDLbNM3BKVKUldftdjudDmPc2hykVfnBf0gJZKW0H8SjMIbge4PhYOj7o5ALKYSilNd1fRYZMpRSWWuzzEKixiUMJRuoNbN2fHrajkyl6oexn6AQ05Cywf7I1R/GnEuID42Be+MxYDzR/0ZOsPixwzZ24o1NvL6tuSzKcpKCkKrIi8PbEybopnEG+PXowlJ8YXZz6s7PS7PJ9Xvpem+faER036cR0kLZXwFLsB6M6H7IhyHT5o87qMujr96G56Y3Lt/uXZwJrszJ7b6uakipKKqyBKMsQFd1XlQTVHUNkUFa8sJieP6mf3Vu99pcMD3Pt3pUG0JYiikgSTEmDIAIBWDKQaeYQEfBr0deLw6n7vo35kcz94e3HuidvipKxgTjAhpmMvdapNIAaAHlnDJOKIe+OLLe2pPLn8T7L3xplb/7XApVH4xhvI1rTFMfw5GM3dHmhYdkhm1F84pkJc+rhGrnta6gurLFoXEcVV3BK/CE0JJrRhjFPE1cnbAk4LVq+c7RGWQooz/0YdgxAg8iQThOkVAKHnlbF3T7BEDPHXltrfPs6ZOEGj9MEcZRjIIoiRIUIw5Dtrm756Rpqr/6KPLXb9+XVlYQFQHkTFiUpMCHkYQJDmIUQUpKQXsJhcUTMCfGZVtUG/nDx9XnL16mhI8i5AaLSd9PhVtm2Gr4EmBxrJr8DVkmtVbGwAcxIf8GYgDiEXIXgtIAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                        md 0&apos; title=&apos;&apos; src=&apos;/static/c90c18b0fc3a7f52c7f8c45a1d5581af/c53f8/%EC%95%88%EC%9C%A4%ED%98%B8%EB%8B%98_%EC%B9%BC%EB%9F%BC_%EC%86%8C%EA%B0%9C%EB%A5%BC_%EB%B9%99%EC%9E%90%ED%95%9C_%EC%9E%90%EB%9E%91%EC%A7%88_%E3%85%8B%E3%85%8B~.md_0.png&apos; srcset=&apos;/static/c90c18b0fc3a7f52c7f8c45a1d5581af/08678/%EC%95%88%EC%9C%A4%ED%98%B8%EB%8B%98_%EC%B9%BC%EB%9F%BC_%EC%86%8C%EA%B0%9C%EB%A5%BC_%EB%B9%99%EC%9E%90%ED%95%9C_%EC%9E%90%EB%9E%91%EC%A7%88_%E3%85%8B%E3%85%8B~.md_0.png 190w,
/static/c90c18b0fc3a7f52c7f8c45a1d5581af/2edd7/%EC%95%88%EC%9C%A4%ED%98%B8%EB%8B%98_%EC%B9%BC%EB%9F%BC_%EC%86%8C%EA%B0%9C%EB%A5%BC_%EB%B9%99%EC%9E%90%ED%95%9C_%EC%9E%90%EB%9E%91%EC%A7%88_%E3%85%8B%E3%85%8B~.md_0.png 380w,
/static/c90c18b0fc3a7f52c7f8c45a1d5581af/c53f8/%EC%95%88%EC%9C%A4%ED%98%B8%EB%8B%98_%EC%B9%BC%EB%9F%BC_%EC%86%8C%EA%B0%9C%EB%A5%BC_%EB%B9%99%EC%9E%90%ED%95%9C_%EC%9E%90%EB%9E%91%EC%A7%88_%E3%85%8B%E3%85%8B~.md_0.png 523w&apos; sizes=&apos;(max-width: 523px) 100vw, 523px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;선생님 제가 영광입니다. 눈물 좀 닦고 ㅠㅜ 저도 자랑질 좀 ㅋㅋ~&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;예전 &lt;a href=&quot;http://www.jiniya.net/wp/archives/831&quot;&gt;“고음내기”&lt;/a&gt;라는 글에서 소개했었지만 안윤호님의 칼럼 중에서도 &lt;a href=&quot;http://www.zdnet.co.kr/news/news_view.asp?artice_id=00000039129985&amp;#x26;type=det&quot;&gt;“기술 유전자”&lt;/a&gt;라는 표현과 함께 데이비드 커틀러를 소개한 내용은 그때나 지금이나 저에게는 굉장히 인상적이었습니다. 개인적으로 소프트웨어 개발에서 가장 중요한 부분은 &lt;a href=&quot;http://sangminpark.wordpress.com/2011/09/13/%EC%98%81%EC%9B%85-%EC%97%86%EB%8A%94-%EB%82%98%EB%9D%BC/&quot;&gt;“개념의 일관성(conceptual integrity)”&lt;/a&gt;이라고 생각하는데요. 큰 소프트웨어에서 그런 것들을 홀로 설계할 수 있는 사람들은 그리 많지 않다는 게 제 생각입니다. 그래서 “기술 유전자”라는 게 존재할 수 밖에 없지 않을까라는 생각을 하기도 하구요.&lt;/p&gt;
&lt;p&gt;어쨌든 안윤호님의 칼럼은 지금 읽어보아도 큰 도움이 될 것 같습니다. 아마 이쯤되면 대부분 아 그거 어떻게 구해서 읽지?!, 라며 궁금해 하실 것 같은데요. 제가 한땀한땀 폼 서치 변수를 입력해서 모아 보았습니다. 한번에 모.두. 즐기세요 ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://search2.zdnet.co.kr/search.asp?pageNum=1&amp;#x26;frmdate_year=2001&amp;#x26;frmdate_month=1&amp;#x26;frmdate_day=1&amp;#x26;todate_year=2013&amp;#x26;todate_month=08&amp;#x26;todate_day=13&amp;#x26;code_idx=all&amp;#x26;kwd=%EC%95%88%EC%9C%A4%ED%98%B8&quot;&gt;안윤호님 칼럼 보기&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[국내 IT 블로그]]></title><description><![CDATA[양질의 IT 정보가 올라오는 블로그도 한 번 모아 보았습니다. 즐찾, RSS 추가는 필수랍니다. http://kwang82.hankyung.com/ http://archvista.net/ http://goodhyun.com/ http://mrpyo…]]></description><link>https://jiniya.net/wp/archives/11897</link><guid isPermaLink="false">https://jiniya.net/wp/archives/11897</guid><pubDate>Fri, 02 Aug 2013 23:59:12 GMT</pubDate><content:encoded>&lt;p&gt;양질의 IT 정보가 올라오는 블로그도 한 번 모아 보았습니다.&lt;/p&gt;
&lt;p&gt;즐찾, RSS 추가는 필수랍니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://kwang82.hankyung.com/&quot;&gt;http://kwang82.hankyung.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://archvista.net/&quot;&gt;http://archvista.net/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://goodhyun.com/&quot;&gt;http://goodhyun.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://mrpyo.com/&quot;&gt;http://mrpyo.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sungmooncho.com/&quot;&gt;http://sungmooncho.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.dongpyo.com/blog/&quot;&gt;http://www.dongpyo.com/blog/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://vcnc.tistory.com/&quot;&gt;http://vcnc.tistory.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sanbaek.com/&quot;&gt;http://sanbaek.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://wangsy.com/blog/&quot;&gt;http://wangsy.com/blog/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://interpiler.com/&quot;&gt;http://interpiler.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://estima.wordpress.com/&quot;&gt;http://estima.wordpress.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jimmyrim.com/&quot;&gt;http://www.jimmyrim.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.mickeykim.com/&quot;&gt;http://www.mickeykim.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://subokim.wordpress.com/&quot;&gt;http://subokim.wordpress.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.iamday.net/&quot;&gt;http://www.iamday.net/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://xenix.kr/&quot;&gt;http://xenix.kr/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://trendinsight.biz/&quot;&gt;http://trendinsight.biz/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://lovesera.tistory.com/&quot;&gt;http://lovesera.tistory.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; 1
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[국내 프로그래머 블로그]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/11877</link><guid isPermaLink="false">https://jiniya.net/wp/archives/11877</guid><pubDate>Thu, 01 Aug 2013 23:59:11 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://jiniya.net/tt/440&quot;&gt;예전에도 한 번 프로그래머 블로그 목록을 올린 적이 있었는데요.&lt;/a&gt; 살펴보니 그사이 정말 많은 블로그들이 역사의 뒤안길로 사라진 것 같습니다. 안타까운 현실입니다 ㅠㅜ~ 구글 리더 서비스 종료에 발맞춰서 아직까지 비콘 시그널이 전송되는 블로그를 한 번 정리해 봤습니다. 항상 저에게 큰 통찰을 주시는 고마운 분들이기도 합니다. 실제로 프로그래머가 아닌 분도 몇 분 계신데 제 생각에 프로그래머 만큼이나 이 바닥 사람들에게 큰 통찰을 제공하신다는 생각이 들어서 포함시켜 보았습니다. 즐찾, RSS 추가는 필수랍니다 ㅋ~&lt;/p&gt;
&lt;p&gt;**자, 이제 그러면 여러분의 꿀통을 공개해 볼까요?&lt;/p&gt;
&lt;p&gt;나만 알고 있기엔 너무나 안타까운 초강추 블로그가 있다면 제보해 주세요 !!!**&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://whiteship.me/&quot;&gt;http://whiteship.me/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://moogi.new21.org/tc/&quot;&gt;http://moogi.new21.org/tc/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://zetlos.tistory.com/&quot;&gt;http://zetlos.tistory.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://hongyver.pe.kr/&quot;&gt;http://hongyver.pe.kr/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.naver.com/gloryo/&quot;&gt;http://blog.naver.com/gloryo/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://greemate.tistory.com/&quot;&gt;http://greemate.tistory.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.pyrasis.com/main/&quot;&gt;http://www.pyrasis.com/main/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.naver.com/delmadang&quot;&gt;http://blog.naver.com/delmadang&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://toyfab.tistory.com/&quot;&gt;http://toyfab.tistory.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://kippler.tistory.com/&quot;&gt;http://kippler.tistory.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.rkttu.com/&quot;&gt;http://www.rkttu.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://lunapiece.net/&quot;&gt;http://lunapiece.net/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.sysnet.pe.kr/&quot;&gt;http://www.sysnet.pe.kr/&lt;/a&gt; &lt;a href=&quot;http://blog.naver.com/techshare&quot;&gt;http://blog.naver.com/techshare&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://agile.egloos.com/&quot;&gt;http://agile.egloos.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.daum.net/gdocument&quot;&gt;http://blog.daum.net/gdocument&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://gleamynode.net/articles/&quot;&gt;http://gleamynode.net/articles/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.naver.com/drvoss&quot;&gt;http://blog.naver.com/drvoss&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.talk-with-hani.com/&quot;&gt;http://www.talk-with-hani.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://minjang.egloos.com/&quot;&gt;http://minjang.egloos.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jamestic.egloos.com/&quot;&gt;http://jamestic.egloos.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.benjaminlog.com/&quot;&gt;http://www.benjaminlog.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jacking.tistory.com/&quot;&gt;http://jacking.tistory.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sangminpark.wordpress.com/&quot;&gt;http://sangminpark.wordpress.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://youngrok.com/Home&quot;&gt;http://youngrok.com/Home&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://rein.kr/blog/&quot;&gt;http://rein.kr/blog/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.dahlia.kr/&quot;&gt;http://blog.dahlia.kr/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://micingamja.egloos.com/&quot;&gt;http://micingamja.egloos.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://zextor.tistory.com/&quot;&gt;http://zextor.tistory.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://j.mearie.org/&quot;&gt;http://j.mearie.org/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://parkpd.egloos.com/&quot;&gt;http://parkpd.egloos.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://arload.wordpress.com/&quot;&gt;http://arload.wordpress.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://freesearch.pe.kr/&quot;&gt;http://freesearch.pe.kr/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.gsong.pe.kr/wp/&quot;&gt;http://www.gsong.pe.kr/wp/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://kkamagui.tistory.com/&quot;&gt;http://kkamagui.tistory.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://naggingmachine.tistory.com/&quot;&gt;http://naggingmachine.tistory.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://npcode.com/blog/&quot;&gt;http://npcode.com/blog/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://xrath.com/&quot;&gt;http://xrath.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://bugsfixed.blogspot.kr/&quot;&gt;http://bugsfixed.blogspot.kr/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://madchick.egloos.com/&quot;&gt;http://madchick.egloos.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://eslife.tistory.com/&quot;&gt;http://eslife.tistory.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://khmirage.tistory.com/&quot;&gt;http://khmirage.tistory.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.devgrapher.com/&quot;&gt;http://blog.devgrapher.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://pragmaticstory.com/&quot;&gt;http://pragmaticstory.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://anyflow.net/&quot;&gt;http://anyflow.net/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.doortts.com/&quot;&gt;http://blog.doortts.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://kingori.egloos.com/&quot;&gt;http://kingori.egloos.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jhrogue.blogspot.kr/&quot;&gt;http://jhrogue.blogspot.kr/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jz.pe.kr/&quot;&gt;http://jz.pe.kr/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://dishdev.me/&quot;&gt;http://dishdev.me/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sirini.net/&quot;&gt;http://sirini.net/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://npteam.net/&quot;&gt;http://npteam.net/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://rhea.pe.kr/&quot;&gt;http://rhea.pe.kr/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.naver.com/agebreak&quot;&gt;http://blog.naver.com/agebreak&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://charsyam.wordpress.com/&quot;&gt;http://charsyam.wordpress.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://kblog.popekim.com/&quot;&gt;http://kblog.popekim.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://zpacket.blogspot.kr/&quot;&gt;http://zpacket.blogspot.kr/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.gamedevforever.com/&quot;&gt;http://www.gamedevforever.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://bomjun.tistory.com/&quot;&gt;http://bomjun.tistory.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://forensic-proof.com/&quot;&gt;http://forensic-proof.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://iam-hs.com/&quot;&gt;http://iam-hs.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://window31.com/&quot;&gt;http://window31.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; 3832
 2367&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[좌.절.금.지]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/11906</link><guid isPermaLink="false">https://jiniya.net/wp/archives/11906</guid><pubDate>Tue, 30 Jul 2013 23:59:10 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;당시 아인슈타인이 친구에게 보낸 편지를 보면 그가 얼마나 깊은 절망에 빠져 있었는지를 쉽게 짐작할 수 있다. “우리 부모님은 나 때문에 행복한 적이 거의 없었어. 특히 내 학비를 대기 위해 정말 어려운 생활을 해오셨지. … 지금의 나는 무위도식하면서 부모님과 친척들에게 짐만 될 뿐이야. … 이렇게 사느니 차라리 죽어버리는 게 낫다는 생각이 들어……”&lt;/p&gt;
&lt;p&gt;– 평행 우주, 미치오 카쿠&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;전 인류를 통틀어 가장 똑똑하다고 일컬어지는 아인슈타인도 취직을 못해서 힘들었던 적이 있었다. 이런 불세출의 천재도 그런데, 하물며 보통의 사람은 어떻겠는가… 그러니 절망하거나 좌절하지 말자. 아인슈타인도 취직을 못해서 고생한 적이 있었다. 다시 적어 놓고 봐도 욱기긴 하다. 아인슈타인이 취직을 못했다니 ㅠㅜ~&lt;/p&gt;
&lt;p&gt;당신이 겪고 있는 그 엄청나게 지랄맞고 당신을 미츄어 버리게 만드는 그 짜증나는 일도 언젠간 다 지나가고 추억이 될 날이 올 것이다.&lt;/p&gt;
&lt;p&gt;그러니 어쨌든 좌.절.금.지.&lt;/p&gt;
&lt;p&gt; 54
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[F# 101]]></title><description><![CDATA[F# 인트로덕션: 강연 하시는 분이 유머 감각이 좀 있으십니다. 욱겨요 ㅋ~ 학부 전공이 컴퓨터 공학이었습니다.…]]></description><link>https://jiniya.net/wp/archives/11592</link><guid isPermaLink="false">https://jiniya.net/wp/archives/11592</guid><pubDate>Wed, 24 Jul 2013 23:59:09 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;F# 인트로덕션: 강연 하시는 분이 유머 감각이 좀 있으십니다. 욱겨요 ㅋ~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;학부 전공이 컴퓨터 공학이었습니다. 4년을 다녔는데 항상 아쉬웠던 점은 함수형 언어에 관한 수업을 듣지 않은 것이라는 생각이 많았습니다. 학교에 함수형 언어 수업이 있었는지는 잘 모르겠네요. 어쨌든 MIT의 “컴퓨터 프로그램의 구조와 해석” 같은 책들을 보면서 전 항상 프로그래머로써 촌스럽다는 생각을 많이 했었습니다.&lt;/p&gt;
&lt;p&gt;그럼 졸압하고 혼자 공부하면 됐지 않냐구요? 네. 옳은 말씀입니다. 하지만 항상 함수형 언어들은 한가지 맹점을 가지고 있었는데 제가 사용하기에 그다지 실용적이지 않다는 점이었습니다. 심지어 임베딩을 해서 쓰기에도 적합한 타겟을 물색하기가 쉽지 않았죠. 그렇게 시간은 하염없이 흘러갔습니다.&lt;/p&gt;
&lt;p&gt;시대가 많이 변했죠. CPU는 하나라고 가정되던 세상에서 핸드폰 속에도 쿼드코어가 들어가는 시대가 됐습니다. 멀티 스레드 프로그래밍은 이제 일반적인 화두가 돼 버렀죠. 구글을 기점으로 마치 새로운 기법인마냥 “맵-리듀스”란 용어가 한때 업계를 휘젓기도 했습니다. 바야흐로 함수형 언어가 다시 각광을 받을 수 있는 시대가 된 것이죠.&lt;/p&gt;
&lt;p&gt;함수형 언어는 기본적으로 사이드 이펙트에서 자유롭기 때문에 명령형 언어(C,C++,Python, …)에 비해서 병렬화를 하기가 엄청 수월하다는 장점이 있습니다. 더불어 위 인트로덕션 동영상에도 나오지만 함수형 언어를 이용한 문제 해결 과정은 정말이지 문제 자체에만 집중할 수 있게 해준다는 느낌이 강하죠. 문제를 풀기위한 구질구질한 작업들은 잠시 잊어도 되는 것입니다. 당연히 생산성이 향상될 수 밖에 없겠죠.&lt;/p&gt;
&lt;p&gt;이런 시대적 흐름에 발맞춰 MS에서는 F#이라는 .NET용 함수형 언어를 개발했습니다. MS가 개발한 언어답게 Real-World에서 바로 사용할 수 있을 정도로 실용성이 강조됐습니다. 기존 .NET 프레임워크를 잘 활용할 수 있도록 구성돼 있죠. 특히나 제가 느낀 인상은 MS가 상당히 공을 들이고 있다는 점입니다. &lt;a href=&quot;http://msdn.microsoft.com/en-us/vstudio/hh388569.aspx&quot;&gt;F# 배우기&lt;/a&gt; 페이자만 보더라도 정말 토나오죠. MVP 리드도 F# MVP를 간절하게 찾고 있는 모양이예요. 이러니 저리니 해도 일자리를 구한다는 의미라면 사실 F#이란 언어가 크게 시장성이 있지는 않을 겁니다. 그래도 배워두면 여러분의 강력한 무기 중에 하나가 될 거라는 점은 장담할 수 있을 것 같아요.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 577px; margin-bottom: 16px;&apos; data-url=&apos;./fs0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ed48662f94a64fd9613d68ab9825be3e/32e64/fs0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 39.473684210526315%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAA7UlEQVR42pVQ2ZKEIBDz//9xdjxQR7kvlUPZoE/7tkOlqKQhpJvmuq5SypsPo55BHvnP1aSUQ8jSmy1u1Vy+MSvtOkKN3XM6Y8zfBJdm34NUjjK9rFIqCxljCiFhP0Ks5Oa1eMSczz9maBiEtADjeqGKi0oguTDglXAjhMXrxm73mCnEVM1IIyMlE+0Jfb3neeZdv5CJQQ4jbfulJ6zt19fP1A5rN6xt90Fx/AilXGPttlIltWOspn0WQZlhzHCuKTc4UtrfQym08wDX0C/Q5PM8jmis18ZrXXFz90h8B8z4VEhjvPM7YiDReSnlFwHyzEz31AupAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;fs0&apos; title=&apos;&apos; src=&apos;/static/ed48662f94a64fd9613d68ab9825be3e/32e64/fs0.png&apos; srcset=&apos;/static/ed48662f94a64fd9613d68ab9825be3e/08678/fs0.png 190w,
/static/ed48662f94a64fd9613d68ab9825be3e/2edd7/fs0.png 380w,
/static/ed48662f94a64fd9613d68ab9825be3e/32e64/fs0.png 577w&apos; sizes=&apos;(max-width: 577px) 100vw, 577px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;MVP 계의 블루오션 F#, 지금 시작하세요 ㅋ~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;함수형 언어는 리그 오브 레전드 리그와 비슷한 특징을 하나 더 가지고 있는데요. 게임 방송을 보면 와 저렇게 하면 쉽게 되겠구나 라고 생각되는데 막상 직접 해보면 생각처럼 잘되지 않습니다. 함수형 언어도 남들이 풀어놓은 솔루션을 볼 때면 와 이거 정말 쉽네, 저렇게 간단하게 되는구나, 라고 생각되는데, 막상 스크래치해서 처음부터 만들어 내려면 하나부터 열까지 생각이 탁탁 막히는 느낌이 들겁니다. 바로 명령형 언어에 너무 익숙해져버린 뇌 때문이죠. 함수형 언어를 배울 때 가장 먼저 익혀야 하는 것은 함수형 시각으로 문제를 생각하는 방식입니다. 최근에 “Real-World Functional Programming”이란 책을 한 권 구입했습니다. 서문에 이런 저의 생각이 잘 나와 있더군요 ㅋ~ 물론 본문은 아직 시작을 못했습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.amazon.com/Real-World-Functional-Programming-With-Examples/dp/1933988924/ref=sr_1_1?ie=UTF8&amp;#x26;qid=1374631648&amp;#x26;sr=8-1&amp;#x26;keywords=practical+functional+f%23&quot;&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 300px; margin-bottom: 16px;&apos; data-url=&apos;./fs1.jpg&apos;&gt;
      &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAQBBQP/xAAVAQEBAAAAAAAAAAAAAAAAAAABAv/aAAwDAQACEAMQAAABu9YMY7bRfGtGLAX/AP/EABwQAAMAAgMBAAAAAAAAAAAAAAECAwAEESMxM//aAAgBAQABBQK1nSknL4PNsdyAhs2vrFeZZ//EABcRAQEBAQAAAAAAAAAAAAAAAAEQITH/2gAIAQMBAT8BHYdn/8QAFhEBAQEAAAAAAAAAAAAAAAAAARAx/9oACAECAQE/AWOT/8QAHBAAAgICAwAAAAAAAAAAAAAAARECEAADMWGB/9oACAEBAAY/AlFYBLlOvM1Hq4Gv/8QAHRABAAEEAwEAAAAAAAAAAAAAAQAQESExQWFxwf/aAAgBAQABPyHWpbkmlCzDvMFrL3gO3CC9Xp7qgy8Ibi4PtP/aAAwDAQACAAMAAAAQh8+8/8QAFxEBAAMAAAAAAAAAAAAAAAAAEAERMf/aAAgBAwEBPxCSxuf/xAAXEQADAQAAAAAAAAAAAAAAAAABECEx/9oACAECAQE/EAgWC//EAB8QAQABAwQDAAAAAAAAAAAAAAERACExEEFRwWGBkf/aAAgBAQABPxBoVu5GWfNGoSgEyDBm0H2kJJG7vV5weCeaOlYIBzn2F0JTc7qKQbANrS60/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;fs1&apos; title=&apos;&apos; src=&apos;/static/558bd4a3bfd497fe8031b3c84200b31d/0cdb7/fs1.jpg&apos; srcset=&apos;/static/558bd4a3bfd497fe8031b3c84200b31d/8ccab/fs1.jpg 190w,
/static/558bd4a3bfd497fe8031b3c84200b31d/0cdb7/fs1.jpg 300w&apos; sizes=&apos;(max-width: 300px) 100vw, 300px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
    &lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This book is different from many other programming books available today. It doesn’t focus only on a specific programming language or library. Instead, it use the presented languages and libraries to explain &lt;strong&gt;a way of thinking&lt;/strong&gt; — a way of thinking that becoming increasingly important and has influenced many recent technologies.&lt;/p&gt;
&lt;p&gt;– Real-World Functional Programming, Tomas Petricek &amp;#x26; Jon Skeet&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;최근에 우리는 .NET 환경을 적극 활용하는 방향으로 전환했습니다. 전 F#으로 패턴 스캐닝 엔진을 새롭게 쓰는 작업을 하고 있습니다. .NET이 일반화된 환경이기도 하고, MONO 같은 오픈 소소를 활용하면 손쉽게 멀티 플랫폼의 장점을 누릴수도 있기 때문입니다. 보안적인 측면에서도 네이티브와 듀얼 구성을 한다면 다양성 측면에서는 오히려 보안이 한층 더 강화된다고 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;감히 예측컨데 앞으로는 함수형 언어로 생각을 할 수 있는 프로그래머와 그렇지 않은 프로그래머로 나뉘는 시대가 올 겁니다. 미리미리 함수형 사고 회로를 뇌에다 설치하는 작업을 해 두도록 합시다. 설령 그런 시대가 오지 않아도 손해 보진 않을 거예요 ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt; 1
 1&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[나이는 정말 숫자에 불과합니다…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/11796</link><guid isPermaLink="false">https://jiniya.net/wp/archives/11796</guid><pubDate>Tue, 23 Jul 2013 23:59:08 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./나이는_정말_숫자에_불과합니다.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ce8c357cda465dab8832273de3d5d724/dface/%EB%82%98%EC%9D%B4%EB%8A%94_%EC%A0%95%EB%A7%90_%EC%88%AB%EC%9E%90%EC%97%90_%EB%B6%88%EA%B3%BC%ED%95%A9%EB%8B%88%EB%8B%A4.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAAAsSAAALEgHS3X78AAACr0lEQVR42mVU2W7aUBT0//9EIzVSQ18ihT40C9AoDgQS9h0DYQcDZjMGA5GmZw6QVu3D6HJ9uXPmzBnbsOoWXl5iCIdDeH42kctl0W630el2MBgOYNsjjMdjzGYOttsNfN8XbPX32nOxdl0sFnNMJhOFUalUEImEUa1WUa/X0em0MRoN5XCMqTPFdDoRshnm8xlWq9X/pOs1lsulFlTCTDaj6prNphJWqxX0el2s3BU2G0/Bi8Rut8PhcBDssd/vZe/D80i4gCOF7bENIxaLasuDwUDUdYS4gaG0yopUZ9u2trRaLfUiFZ1VLRYLhSOd2KORcPRhhEIh5LJZ9Pt9tFotWXuYTo5tOo4j7Y/0kud5cMWv9doVtdtPsP3NZqPPWdS4vf2p/vV6PVXY7XaVgApIQNA7quLKM5Kwdbbt+7uTl2fCu1tYVg3NRkM9rNWqqtYT79T8ra8XzzgTnfE34ZKEpmlqTOhVV6JCMnpIRcdJbk9TPYKD+Re+/IfDcWWQRiIR1wlXJT5cORySM3uMgSuV9/vDp7qPj4/TpI+gf2x1Lp4zs8brawLlcklhWRbaMhiSDodDJaRn8/lcPXV08lN9znMOzJn+ySr3RiqVQrFYRKlUUtRqNUWpVFRP6/WGnjfEY+aTw2NBWsNV4yWxIdlAighhEplMBslkEolEAvl8XonK5bJa0Gq15fJRMWP1/t7SNFDZUnM413ySlFYZUQl2TILN1qmkUCjg7e0N0WgUj4+PeHoykU6nhehd4lWTQpVjVk9tUiVVszBFGA8PD/IuR5AQwkIhD079RzCI+/s78Mw0n1Q9u6A97CCdTiEWi+meAiqV8rGYDNYIymUi8isi73QY3wMBBAJXuLz8iouLL7q/vr7G1dU3BG9uYMoXiR+TeDwu5Dmxx1L1BC35DbYkSEHnf7fpAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                 md 0&apos; title=&apos;&apos; src=&apos;/static/ce8c357cda465dab8832273de3d5d724/dface/%EB%82%98%EC%9D%B4%EB%8A%94_%EC%A0%95%EB%A7%90_%EC%88%AB%EC%9E%90%EC%97%90_%EB%B6%88%EA%B3%BC%ED%95%A9%EB%8B%88%EB%8B%A4.md_0.png&apos; srcset=&apos;/static/ce8c357cda465dab8832273de3d5d724/08678/%EB%82%98%EC%9D%B4%EB%8A%94_%EC%A0%95%EB%A7%90_%EC%88%AB%EC%9E%90%EC%97%90_%EB%B6%88%EA%B3%BC%ED%95%A9%EB%8B%88%EB%8B%A4.md_0.png 190w,
/static/ce8c357cda465dab8832273de3d5d724/2edd7/%EB%82%98%EC%9D%B4%EB%8A%94_%EC%A0%95%EB%A7%90_%EC%88%AB%EC%9E%90%EC%97%90_%EB%B6%88%EA%B3%BC%ED%95%A9%EB%8B%88%EB%8B%A4.md_0.png 380w,
/static/ce8c357cda465dab8832273de3d5d724/dface/%EB%82%98%EC%9D%B4%EB%8A%94_%EC%A0%95%EB%A7%90_%EC%88%AB%EC%9E%90%EC%97%90_%EB%B6%88%EA%B3%BC%ED%95%A9%EB%8B%88%EB%8B%A4.md_0.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;환갑의 나이에도 이렇게 불꽃코딩하시면 저희는 부끄럽지요 ㅠㅜ~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;어제부터 아주 성가신 문제를 하나 보고 있었습니다. 사실 중요한 부분도 아닌데 엔지니어의 지적 호기심이랄까요? ㅎㅎ~ 여튼 반쯤만 해결된 상태입니다. 오늘 문제를 좀 집중해서 보려고 윈도우 소스 코드를 좀 뒤적거렸습니다. 모니터로 보니 당췌 산만해서 중요한 부분이고 몇 줄 안 되는 것 같아서 출력 버튼을 눌렀지요. 근데 무려 52페이지가 출력돼 버려서 적잖게 당황스러웠습니다. 거기까진 생각보다 파일 내용이 많았구나 이러면서 그러려니 했는데… 파일 위쪽 주석에 적힌 이름이 저를 멘탈붕괴 상태로 만들어 버렸습니다. 선명하게 적힌 Dave N. Cutler, 그 옆에 날짜는 절 더 당황스럽게 만들었지요. 26-Oct-2000.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 419px; margin-bottom: 16px;&apos; data-url=&apos;./나이는_정말_숫자에_불과합니다.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/887e56bffa84ccffa5f82ac7d37736c1/96e9b/%EB%82%98%EC%9D%B4%EB%8A%94_%EC%A0%95%EB%A7%90_%EC%88%AB%EC%9E%90%EC%97%90_%EB%B6%88%EA%B3%BC%ED%95%A9%EB%8B%88%EB%8B%A4.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 20%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAjUlEQVR42o2ODQ7DIAiFe/9j2mmNsbY61Ip/e113gBFC3oN8wKK1llKOPgyZ1a9nPscc879YlFJCiN47DHd22fnLR46xxCMfEKGEPe2JEzGFK0DAcuMbfn2jtQZTe8WYCoHJNWMLKqxLDiQ0pkh894OttcaY53JpRZPG4u29ySABQCDBo4kOMNiHnHN+ACQT5jSd+CPGAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                 md 1&apos; title=&apos;&apos; src=&apos;/static/887e56bffa84ccffa5f82ac7d37736c1/96e9b/%EB%82%98%EC%9D%B4%EB%8A%94_%EC%A0%95%EB%A7%90_%EC%88%AB%EC%9E%90%EC%97%90_%EB%B6%88%EA%B3%BC%ED%95%A9%EB%8B%88%EB%8B%A4.md_1.png&apos; srcset=&apos;/static/887e56bffa84ccffa5f82ac7d37736c1/08678/%EB%82%98%EC%9D%B4%EB%8A%94_%EC%A0%95%EB%A7%90_%EC%88%AB%EC%9E%90%EC%97%90_%EB%B6%88%EA%B3%BC%ED%95%A9%EB%8B%88%EB%8B%A4.md_1.png 190w,
/static/887e56bffa84ccffa5f82ac7d37736c1/2edd7/%EB%82%98%EC%9D%B4%EB%8A%94_%EC%A0%95%EB%A7%90_%EC%88%AB%EC%9E%90%EC%97%90_%EB%B6%88%EA%B3%BC%ED%95%A9%EB%8B%88%EB%8B%A4.md_1.png 380w,
/static/887e56bffa84ccffa5f82ac7d37736c1/96e9b/%EB%82%98%EC%9D%B4%EB%8A%94_%EC%A0%95%EB%A7%90_%EC%88%AB%EC%9E%90%EC%97%90_%EB%B6%88%EA%B3%BC%ED%95%A9%EB%8B%88%EB%8B%A4.md_1.png 419w&apos; sizes=&apos;(max-width: 419px) 100vw, 419px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;&lt;a href=&quot;http://www.jiniya.net/wp/archives/289&quot;&gt;요즘은 내가 대세… 17년만에 소스 코드 물려 받았지요 ㅋ&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;네. 그렇죠. 그렇게 밑에 똑똑하고 코딩 잘하는 애들 줄줄이 비엔나처럼 있겠지만 중요한 부분 코딩 맡기시려니 미덥지 않으셨던 거 이해합니다. 그래도 환갑의 나이에 이건 좀 지나치신 건 아니신지. 너무 부끄럽잖아요. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;제가 오늘 본 부분이 AMD64로의 주요한 포팅 작업이었던 것 같군요. 다 확인은 안 해 보았지만 2002년까지 그의 작업이 확인됐습니다. 큭~ 이후 윈도우 애저를 만드시고, 무려 2013년 현재에도 칠순의 나이에 Xbox One 디벨로퍼로 활약하시는 당신은 진짜 초큼 어이가 없습니다. 진정 초사기 캐릭이신거죠? ㅋㅋㅋ~ 분발해야겠습니다. 칠순의 할아버님도 이렇게 열심히 코딩하시는데…&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Windows NT&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;Cutler left Digital for Microsoft in &lt;strong&gt;October 1988 and led the development of Windows NT.&lt;/strong&gt; Later, he worked on targeting Windows NT to Digital’s 64-bit Alpha architecture (itself based on the Prism design),[citation needed] then on Windows 2000. After the demise of Windows on Alpha (and the demise of DEC), &lt;strong&gt;Cutler was instrumental in porting Windows to AMD’s new 64-bit AMD64 architecture.&lt;/strong&gt; He was officially involved with the Windows XP Pro 64-bit and Windows Server 2003 SP1 64-bit releases. He moved to working on Microsoft’s Live Platform in August 2006. Dave Cutler was awarded the prestigious status of Senior Technical Fellow at Microsoft.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Windows Azure&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;At the 2008&lt;/strong&gt; Professional Developers Conference, Microsoft announced Azure Services Platform, a cloud-based operating system which Microsoft is developing. During the conference keynote, &lt;strong&gt;Cutler was mentioned as a lead developer&lt;/strong&gt; on the project, along with Amitabh Srivastava.[5]&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Xbox&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;As of January 2012, a spokesperson for Microsoft has confirmed that Cutler is no longer working on Windows Azure, and has since joined the Xbox team.[6] No further information was provided as to what Cutler’s role was, nor what he was working on within the team.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In May 2013&lt;/strong&gt;, Microsoft announced the Xbox One console, and Cutler was mentioned as having worked in the development of host OS portion of the system running inside the new gaming device. &lt;strong&gt;Apparently Cutler’s work was focused in creating an optimized version of Microsoft’s Hyper-V Host OS specifically designed for Xbox One.&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;– &lt;a href=&quot;http://en.wikipedia.org/wiki/Dave_Cutler#Windows_NT&quot;&gt;http://en.wikipedia.org/wiki/Dave_Cutler#Windows_NT&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[boost 라이브러리 집중 분석]]></title><description><![CDATA[시쳇말로 C 언어는 2시간 배워서 20년 써먹고, C++은 20년 배워서 2시간 써먹는다는 이야기가 있다. 그만큼 C 언어는 간결하고 핵심적인 기능만 포함한 언어인 반면, C++은 복잡하고 다양한 기능이 포함돼 있다. 나는 C 언어를 배운지는 2…]]></description><link>https://jiniya.net/wp/archives/11769</link><guid isPermaLink="false">https://jiniya.net/wp/archives/11769</guid><pubDate>Tue, 23 Jul 2013 23:59:07 GMT</pubDate><content:encoded>&lt;p&gt;시쳇말로 C 언어는 2시간 배워서 20년 써먹고, C++은 20년 배워서 2시간 써먹는다는 이야기가 있다. 그만큼 C 언어는 간결하고 핵심적인 기능만 포함한 언어인 반면, C++은 복잡하고 다양한 기능이 포함돼 있다. 나는 C 언어를 배운지는 20년, C++은 13년 정도 됐다. 그간 주로 일했던 도메인이 보안이라 성능 이슈가 주요하고 네이티브 코드를 많이 작성해야 했기에 주력 프로그래밍 언어는 언제나 C++이었다. 그렇게 오래 함께한 언어임에도 C++은 여전히 어려운 언어이고, 지금까지도 항상 공부해야 하는 언어다. 물론 이런 현상은 단지 내가 멍청하기 때문만은 아닌 것 같다. 실제로 C 언어의 창시자인 Brian Kernighan 할아버지도 그런 의견을 피력했던 적이 있었기 때문이다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;때때로 나는 C 대신 C++을 사용해서 프로그램을 작성합니다. 제가 생각하기에 C++은 모든 기능을 내장하기 때문이라고 하더라도 매우 큰 언어입니다. 어떤 크기의 C 프로그램을 작성하든지 저는 75, 80, 90% 정도의 언어 기능을 사용합니다. 다시 말하면 어떤 종류의 프로그램이든 간에 대부분의 C 언어 기능이 유용하다는 점 입니다. 이와는 대조적으로 제가 C++을 사용한다면 언어의 10% 정도도 사용하지 못합니다. 그리고 나머지 90%는 제가 이해하고 있다고 생각하지 않습니다. 이러한 점들에서 전 C++은 너무 크다고 말합니다. 그러나 C++은 큰 프로그램을 작성하는데 필요한 많은 기능들을 제공합니다. 객체를 만드는 것이 가능하며, 내부적인 정보의 표현을 보호할 수 있습니다. 그래서 결국 내부를 보지 못하게 만드는 훌륭한 외관을 표현할 수 있습니다. C++은 제가 생각하기에 아주 방대한 양의 유용한 메카니즘을 가지고 있습니다. 그리고 그것은 C 언어가 당신에게 주지 못하는 점 입니다.&lt;/p&gt;
&lt;p&gt;– &lt;a href=&quot;http://www.cs.cmu.edu/~mihaib/kernighan-interview/&quot;&gt;Brian Kernighan, 2000&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;기존의 C++이란 언어 자체도 방대한 기능으로 무장한 언어였지만 모던 C++로 불리는 C++11과 C++13, C++14로 불리며 지금 계속 개정 작업이 진행되고 있는 신규 표준은 훨씬 더 방대한 내용을 담고 있다. 상당히 최신 기술들이기 때문에 아직까지도 골수 C++ 프로그래머들도 이러한 기능을 잘 모르는 경우가 많다. 기능을 지원하는 컴파일러들이 제한적이기 때문에 실용성이 없다고 주장하는 입장도 많이 있다. boost는 이런 간극을 메워줄 수 있는 주요한 라이브러리다. 표준에 채택된 기능을 상당수 포함하고 있고, 추후 표준에도 적극적으로 라이브러리 기능들이 제안되고 있기 때문이다. 더불어 C++11을 지원하는 새로운 컴파일러를 사용하지 않더라도 boost를 사용하면 새로운 표준 라이브러리 기능들을 사용할 수 있기 때문에 더욱 효과적이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;왜 boost인가?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;boost의 주요 기능을 소개하기에 앞서서 왜 이런 복잡한 형태의 라이브러리를 사용해야 하는지에 대해서 먼저 알아보는 것이 중요한 것 같다. 왜냐하면 인식이 조금씩 바뀌고 있지만 여전히 boost와 같은 형태의 복잡하고 거대한 라이브러리를 사용하는 것에 대해서 회의적인 프로그래머들이 상당수 있기 때문이기도 하고, 무엇을 공부함에 있어서 그 필요성을 절감하고 공부하는 것과 단지 다른 사람들이 쓴다고 하니까 배우는 것에는 큰 차이가 있기 때문이기도 하다.&lt;/p&gt;
&lt;p&gt;반대하는 쪽 주장의 면면을 살펴보면 이렇다. 1) 버그가 있다. 2) 너무 복잡하다. 3) 내가 만드는 걸 선호한다.&lt;/p&gt;
&lt;p&gt;이 중에서 버그 이야기를 먼저 해보자. 결론만 먼저 말하면 사실 이런 주장을 하는 프로그래머치고 boost의 버그를 정확하고 명백하게 보여주는 프로그래머는 없었다. 대부분 그들이 도입하면서 겪었던 일부 문제들을 가지고 boost의 버그로 말하는 경향이 있는데 여기에는 boost 라이브러리의 사용법을 명확하게 몰라서 생긴 문제가 거의 대다수였다. 즉, 돌려 말하면 윈도우 API를 잘못 사용해서 잘못된 결과를 얻어놓고서는 윈도우 API의 버그라고 말하는 경우와 동일한 경우가 대부분이라는 점이다. 백 번 양보해서 제대로 된 버그를 발견했다고 치더라도 그걸 고쳐서 오픈소스 커뮤니티에 기여하면 된다. boost와 같은 라이브러리의 경우 전세계 수많은 개발자들이 지켜보고 있기 때문에 그 어떤 프로젝트보다도 결함이 신속하고 빠르게 고쳐진다. 적어도 버그 문제에 있어서는 직접 작성하는 것보다 훨씬 고품질의 결과를 얻을 수 있다는 점은 인정하자.&lt;/p&gt;
&lt;p&gt;너무 복잡하다. 맞다. boost 라이브러리는 영문 정식 명칭이 library가 아닌 libraries로 돼 있을 만큼 정말 엄청나게 다양한 라이브러리의 묶음이다. 걔 중에는 유용한 것들도 있지만 당연히 사용하는 쪽 입장에서는 불필요한 부분도 많이 있다. 하지만 이는 다시 생각해보면 복잡해서 잘 모르는 부분은 사용하지 않으면 그만이다. boost를 사용한다고 해서 거기 있는 모든 라이브러리를 몽땅 써야 하는 것은 아니다. 더욱이 boost의 경우에 템플릿 기반의 라이브러리라 대다수 코드들은 헤더를 포함하지 않으면 그 어떤 코드도 우리 프로젝트에 영향을 미치지 않는다.&lt;/p&gt;
&lt;p&gt;끝으로 꼭 직접 만든 것만 믿는 프로그래머들이 있다. 하지만 이건 정말이지 바보 같은 생각이다. 왜냐하면 조금만 시각을 달리하면 직접 만든 건 결국 하나도 없기 때문에다. 심지어 C++이란 언어 자체도 직접 만든 것은 아니다. 컴파일러도 마찬가지다. 그러니 직접 만든 것만 쓰겠다는 생각은 자신의 시야를 너무 좁은 곳에 두는 관점이라는 걸 명심하자.&lt;/p&gt;
&lt;p&gt;자 그럼 이제 반박을 떠나서 boost와 같은 외부 라이브러리 사용의 긍정적인 측면을 살펴보도록 하자. 버그의 정반대 측면인 안정성을 들 수 있다. boost와 같은 검증된 라이브러리는 수많은 프로그램에서 사용되고, 전세계에 분포한 다양한 개발자들이 프로젝트에 참여하고 있다. 보는 눈이 많은 만큼 훨씬 더 안정적일 수 밖에 없다. 혹여 사용하다가 결정적인 버그를 발견했다손 치더라도 오픈 소스이기 때문에 수정해서 사용할 수 있고, 커뮤니티에 기여하는 경우에는 다음부터는 유사한 문제를 겪는 프로그래머가 없도록 도와 줄 수도 있다.&lt;/p&gt;
&lt;p&gt;다음은 멀티 플랫폼이다. 요즘 컴퓨팅 환경의 트렌드를 한 마디로 요약하자면 멀티 플랫폼이다. 컴퓨터가 들어가지 않은 디바이스를 찾기 힘들 지경이다. 자동차, 세탁기, 냉장고, TV, 핸드폰, 손목시계, 안경 등 우리가 상상할 수 있는 모든 곳에는 컴퓨터가 탑재되고 있다. 그만큼 프로그래머들은 고달픈 시대다. 한가지 플랫폼만 했어도 충분했는데 이제는 이쪽 저쪽을 다 신경 써야 하기 때문이다. 이럴 때 가장 좋은 것이 이식성이 있는 소스 코드다. boost의 경우 다양한 환경에 대한 추상화 계층을 사용하기 때문에 boost::asio와 같은 비동기 입출력 라이브러리를 사용한다면 우리는 Windows, BSD, Linux 등과 같은 플랫폼에 상관 없이 그 플랫폼에 얼추 최적화된 구현을 바로 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;끝으로 가장 결정적인 이유는 좋은 라이브러리를 써봐야 좋은 라이브러리를 만들 수 있기 때문이다. 컴퓨터 공학을 가르치는 대학의 경우 대부분 소스 코드 베끼기가 실력 향상에 좋지 않다는 이유로 소스 코드 보는 행위를 장려하지 않고 있다. 안타깝게도 이런 현상 때문에 제대로 된 코드를 쓸 줄 아는 프로그래머가 그렇게도 드문 것 같다. 다른 사람이 만든 소스 코드, 또는 선배 프로그래머들이 만든 소스 코드를 봐야지 아 이런 식으로 짜는 구나를 알 수 있다. 파서를 strstr로 짜고 있는 프로그래머, 함수 포인터를 몰라서 switch/case를 일일이 열거하고 있는 프로그래머를 보면 정말이지 어디서부터 이야기를 해야 할지 답이 안 나오는 지경이다. 직접 만들더라도 많은 사람들이 사용하는 좋은 구조에 대해서는 알아두는 것이 도움이 된다는 점을 꼭 기억하자.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;shared_ptr&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;아마도 boost 라이브러리를 접했던 프로그래머의 절반 이상이 shared_ptr 이라는 스마트 포인터 하나를 사용하기 위해서 접했다고 해도 과언이 아닐 만큼 boost 보다 더 유명한 클래스다. 이제는 C++11에 포함돼 있기 때문에 std::shared_ptr 형태로 사용할 수 있다. 하지만 아직 C++11을 지원하는 컴파일러를 사용할 수 없는 환경이라면 boost는 여전히 강력한 대안이다.&lt;/p&gt;
&lt;p&gt;C++11 이전의 표준에 포함됐던 유일한 스마트 포인터 클래스는 auto_ptr 클래스였다. auto_ptr의 경우 소유권 이전에 대해서 다소 난해한 정책을 가지고 있어서 스마트 포인터를 처음 접하는 프로그래머에게 좋지 않은 인상을 남기는 허들 역할을 톡톡히 했다. &amp;#x3C;리스트 1&gt;에는 전형적인 auto_ptr의 잘못된 사용을 보여주고 있다. auto_ptr의 경우에는 복사 시에 소유권이 이전되는 데 이게 상황에 따라서 상당히 미묘한 많은 문제를 일으킨다. 더욱이 이런 특징 때문에 결정적으로 STL 컨테이너와는 전혀 연동을 할 수 없기 때문에 반쪽 짜리 스마트 포인터라는 오명을 가지기도 했었다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 1 auto_ptr의 소유권 이전 문제를 보여주는 전형적인 예제&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;memory&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;iostream&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;namespace&lt;/span&gt; std&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Value&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; val_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Value ctor&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Value dtor&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;auto_ptr&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Value&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; param&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    param&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;val_ &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_tmain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; argc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _TCHAR&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; argv&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    auto_ptr&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Value&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pa&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; Value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    pa&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;val_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;pa val_ = &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; pa&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;val_ &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;fn 호출 시작&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pa&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;fn 호출 끝&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;pa val_ = &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; pa&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;val_ &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;auto_ptr의 소유권 이전 문제를 개선한 것이 boost의 shared_ptr이다. shared_ptr은 내부적으로 레퍼런스 카운팅을 사용하기 때문에 복사하더라도 해당 객체를 참조하는 포인터가 모두 사라지는 경우에만 실질적으로 객체 파괴 작업이 일어난다. 복사 시에 레퍼런스 카운트를 증가시키고, 파괴 시에는 레퍼런스 카운트를 감소시켜 0이 되는 경우에 실제로 객체를 파괴하도록 만들어져 있기 때문이다. 이런 장점 때문에 auto_ptr과 달리 STL 컨테이너에 넣어도 안전하다.&lt;/p&gt;
&lt;p&gt;shared_ptr은 레퍼런스 카운팅이라는 기본적인 장점에 추가적으로 커스텀 파괴자를 지원하기 때문에 스마트 포인터의 활용도를 한층 더 높일 수 있다는 장점도 있다. &amp;#x3C;리스트 2&gt;에는 세 개의 파일 리소스를 사용해서 처리를 하는 일반적인 루틴을 보여주고 있다. 이 경우에 사용하는 리소스가 추가될 때마다 인덴트 깊이가 깊어져서 코드가 보기 힘들어지는 경향이 있다. 실제로 스마트 포인터가 없는 COM 코드에서는 이러한 코드가 일반적이다.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;리스트 2&gt;의 코드를 가독성이 좋도록 개선한 버전이 &amp;#x3C;리스트 3&gt;에 나와 있다. 변경된 코드에서는 실패 시에 바로 함수 실행을 리턴하도록 만들었다. 하지만 이렇게 할 때에도 매 실패 시점마다 프로그래머가 현재 획득한 리소스와 해제해야 할 리소스 목록을 알고 있어야 한다는 단점이 있다.&lt;/p&gt;
&lt;p&gt;이런 코드의 경우 가장 깔끔한 해결 방법은 기존의 레거시 파일 처리 루틴을 사용하지 않고 RAII(Resource Acquisition Is Initialization) 형태로 설계된 파일 클래스를 사용하는 것이 정답이다. 하지만 현실 세계에 존재하는 수많은 레거시 코드를 일일이 그런 형태로 래핑하는 것은 너무 이상적인 이야기일 수 밖에 없다. 이런 경우에 중간 단계의 절충안으로 shared_ptr을 사용할 수 있다. &amp;#x3C;리스트 4&gt;에는 shared_ptr의 커스텀 파괴자를 사용해서 자원을 관리하는 코드가 나와 있다. shared_ptr이 파괴될 때 fclose가 호출되기 때문에 파일 포인터 자원이 자동적으로 소거된다. 이 코드에서 프로그래머는 자원 생성 시에만 파괴 루틴을 등록하고 이후에는 해당 자원에 대해서는 신경 쓰지 않아도 되기 때문에 실수할 가능성이 줄어들고 그만큼 자원 관련 버그도 줄여준다. 예외 발생 시에도 자원을 안전하게 파괴할 수 있다는 것은 추가적인 장점이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 2 파일 포인터 자원 3개를 사용하는 일반적인 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;MergeFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPCSTR dst&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCSTR src1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCSTR src2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    FILE &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;dfp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    FILE &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;sfp1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    FILE &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;sfp2&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    dfp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fopen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dst&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;wb&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dfp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        sfp1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fopen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;src1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;rb&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sfp1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            sfp2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fopen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;src2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;rb&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sfp2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token comment&quot;&gt;// 실제 처리할 작업&lt;/span&gt;

                &lt;span class=&quot;token function&quot;&gt;fclose&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sfp2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;token function&quot;&gt;fclose&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sfp1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token function&quot;&gt;fclose&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dfp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 3 실패시 리턴 방식을 사용한 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;MergeFile2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPCSTR dst&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCSTR src1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCSTR src2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    FILE &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;dfp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    FILE &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;sfp1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    FILE &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;sfp2&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    dfp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fopen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dst&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;wb&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;dfp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    sfp1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fopen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;src1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;rb&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;sfp1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;fclose&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dfp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    sfp2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fopen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;src2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;rb&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;sfp2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;fclose&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sfp1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;fclose&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dfp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// 실제 처리할 작업&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;fclose&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sfp2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;fclose&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sfp1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;fclose&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dfp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 4 shared_ptr을 사용하여 자원 관리를 하는 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;boost/shared_ptr.hpp&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; boost&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;shared_pt&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; vsptr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;MergeFile3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPCSTR dst&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCSTR src1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCSTR src2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    FILE &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;dfp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    FILE &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;sfp1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    FILE &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;sfp2&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    dfp &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fopen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dst&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;wb&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;dfp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    vsptr &lt;span class=&quot;token function&quot;&gt;dfp_closer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dfp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fclose&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    sfp1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fopen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;src1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;rb&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;sfp1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    vsptr &lt;span class=&quot;token function&quot;&gt;sfp1_closer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sfp1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fclose&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    sfp2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fopen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;src2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;rb&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;sfp2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    vsptr &lt;span class=&quot;token function&quot;&gt;sfp2_closer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sfp2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fclose&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// 실제 처리할 작업&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;bind&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;boost에서 shared_ptr 다음으로 유명한 것을 들자면 단연코 bind가 될 것이다. 유연하게 설계된 클래스가 얼마나 효율적으로 기존 시스템과 마찰 없이 잘 결합될 수 있는지를 단적으로 보여주는 클래스라고 할 수 있다.&lt;/p&gt;
&lt;p&gt;bind은 기본적으로 함수 호출 객체를 만들어주는 역할을 한다. &amp;#x3C;리스트 5&gt;에는 기본적인 사용 방법이 나와 있다. fn이라는 기존 함수에 a, b, c, d, e 파라미터로 1, 2, 3, 4, 5를 전달해서 호출하는 함수 객체를 만드는 것을 보여주고 있다. 해당 함수 객체를 호출하면 결과 값은 15가 출력된다.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;리스트 6&gt;에는 플레이스홀더를 사용해서 bind 객체를 생성하는 것을 보여준다. _1로 표시된 자리에 해당 함수 객체를 호출할 첫 번째 파라미터가 들어간다는 의미다. 따라서 이 함수 객체를 호출할 때에는 _1 자리에 들어갈 파라미터를 넣어주어야 한다. 예제에서는 10을 넣어주었다. 따라서 이 객체는 최종적으로 fn(1, 2, 10, 4, 5)를 호출하는 결과를 보여준다.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;리스트 7&gt;에는 플레이스홀더를 두 개 사용한 예제가 나와 있다. _1에는 첫번째 파라미터가, _2에는 두번째 파라미터가 들어간다. 따라서 이 함수 객체를 사용할 때에는 2개의 파라미터를 넣어주어야 정상적으로 호출된다. 예제 코드의 bind는 최종적으로 fn(1, 11, 10, 4, 5)를 호출하는 것과 동일한 기능을 한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 5 기본적인 bind 예제&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;boost/bind.hpp&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; d&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a = %d, b = %d, c = %d, d = %d, e = %d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; d &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; c &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; d &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; boost&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 6 bind 플레이스홀더 사용 예제 1&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; boost&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 7 bind 플레이스홀더 사용 예제 2&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; boost&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fn&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;boost::bind의 경우 클래스 멤버 함수에도 동일하게 적용할 수 있다. &amp;#x3C;리스트 8&gt;에는 멤버 함수에 bind를 적용한 코드가 나와 있다. 이 코드에 나와 있는 두 bind 호출은 모두 최종적으로 bob.Say(“Hello”)를 호출하는 역할을 한다. boost::bind는 파라미터를 지정하는 경우 값을 복사하는 형태로 동작하기 때문에 내부 동작을 보여주기 위해서 생성자, 복사 생성자, 소멸자에 각각 printf를 추가해 놓았다.. 출력된 내용을 살펴보면 첫 번째 bind의 경우에는 지속적으로 객체가 복사되고 있음을 확인할 수 있다. 이를 제거하기 위해서는 boost::ref를 사용하면 된다. 첫 번째 bind 코드를 boost::bind(&amp;#x26;Man::Say, boost::ref(bob), “Hello”)()와 같이 고쳐서 테스트를 해보면 값이 복사되지 않는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 8 멤버 함수에 bind 적용 예제&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;stdio.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;boost/bind.hpp&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Man&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string name_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;Man&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        name_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%s ctor\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name_&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;c_str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;Man&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Man &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;r&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        name_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; r&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%s cctor\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name_&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;c_str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Man&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%s dtor\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name_&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;c_str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Say&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%s: %s\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name_&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;c_str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    Man &lt;span class=&quot;token function&quot;&gt;bob&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Bob&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    boost&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;Man&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;Say&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bob&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    boost&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;Man&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;Say&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bob&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;bind의 객체가 복사된다는 특징은 shared_ptr과 같은 스마트 포인터와 결합하면 좀 더 유연한 동작을 가능하게 한다. &amp;#x3C;리스트 9&gt;에는 shared_ptr 객체를 참조하는 bind 예제가 나와 있다. bind가 객체를 복사해 두었기 때문에 bob.reset 이후에도 객체가 파괴되지 않고 살아있어서 정상적으로 멤버 함수 호출이 이루어진다. 실질적인 bob 객체는 bind 함수 객체를 담고 있는 function 객체가 사라질 때 같이 소멸된다.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;리스트 9&gt;의 코드에서 객체를 복사하지 않고 boost::ref를 사용해서 직접 참조했다면 bob.reset 시점에 객체가 사라지고 이후 호출되는 fn(“Hello”)는 사라진 객체를 참조하게 되기 때문에 크래시가 발생하는 문제점이 생긴다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 9 shared_ptr 객체의 멤버 함수를 참조하는 bind 예제&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;stdio.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;boost/shared_ptr.hpp&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;boost/bind.hpp&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;boost/function.hpp&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;namespace&lt;/span&gt; boost&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    shared_ptr&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Man&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bob&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Man&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Bob&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    function&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; fn &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;Man&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;Say&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bob&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    bob&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&amp;#x3C;리스트 9&gt;의 코드에도 잠깐 등장하지만 bind 결과 함수 객체를 저장해놓고 함수 포인터와 같이 지속적으로 사용하기 위해서는 boost::function 클래스를 사용하면 된다. function 클래스의 템플릿 파라미터로 함수 원형을 넣어주면 된다. &amp;#x3C;리스트 9&gt;의 예제 코드의 fn은 반환값이 없으며(void), 파라미터로 문자열을(const char *) 가지는 함수 객체를 만들겠다는 것을 의미한다.&lt;/p&gt;
&lt;p&gt;C++에 익숙하지 않은 프로그래머의 경우에는 여기까지만 이야기하면 이걸 도대체 어디에다 사용하겠다는 건지 의아해 하는 경우가 많다. 그런 경우라면 &amp;#x3C;리스트 10&gt;에 나와 있는 것과 같은 코드가 도움이 된다. 예제 코드에서는 벡터 멤버를 출력하기 위해서 이터레이터를 만들고 printf를 사용해서 벡터 멤버를 출력하고 있다. 하지만 이를 boost::bind를 사용하면 &amp;#x3C;리스트 11&gt;에 나와 있는 것과 같이 간단하게 한 줄로 해결할 수 있다. 코드가 짧다는 것을 실수할 가능성은 줄어들고, 가독성은 좋아진다는 것을 의미한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 10 이터레이터를 사용해서 벡터 멤버를 출력하는 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;stdio.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;vector&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;namespace&lt;/span&gt; std&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    vector&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; ints&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    vector&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;iterator it &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 vector&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;iterator end &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;it &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; end&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; \&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;it&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;it&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 11 boost::bind를 사용해서 벡터 멤버를 출력하는 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;stdio.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;vector&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;algorithm&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;boost/bind.hpp&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;namespace&lt;/span&gt; std&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;namespace&lt;/span&gt; boost&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    vector&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; ints&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;for_each&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;begin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ints&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;printf&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;%d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; \_1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;thread&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;멀티스레드란 환경이 이제는 표준적인 프로그래밍 환경으로 자리잡은 것 같다. 하지만 스레드를 플랫폼마다 지원하는 방식의 차이가 있어서 표준적인 방식으로 사용하기에는 아직 문제가 많다. 이런 경우에는 boost::thread를 사용하면 손쉽게 멀티 플랫폼을 지원하는 스레드 코드를 작성할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;리스트 12&gt;에는 간단한 스레드 작성 코드가 나와 있다. 기존의 윈도우 스레드 구조와 크게 다르지 않은 코드다. boost::thread 생성자로 스레드 함수 포인터와 파라미터를 전달해서 스레드를 생성시키고 있는 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;윈도우 프로그래밍을 하면 게시판에 올라오는 흔한 질문 중에 하나가 클래스 멤버 함수를 스레드로 구동시키는 방법에 관한 것이다. 컨텍스트에 관한 개념이 없어서 하는 질문인데 기존 윈도우 코드로만 해결하려면 정적 메소드를 만들고 파라미터로 객체 인스턴스를 전달하는 복잡한 과정을 거쳐야 한다. 하지만 boost에서는 boost::bind를 이용하면 손쉽게 클래스 멤버 함수도 스레드로 호출할 수 있다. &amp;#x3C;리스트 13&gt;에는 boost::bind를 사용해서 클래스 멤버 함수를 스레드로 호출하는 예제가 나와 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 12 boost::thread 예제&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;stdio.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;boost/thread.hpp&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ThreadProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%s\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    boost&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;thread &lt;span class=&quot;token function&quot;&gt;th1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ThreadProc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Mark&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    boost&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;thread &lt;span class=&quot;token function&quot;&gt;th2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ThreadProc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Bob&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    th1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    th2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 13 클래스 멤버 함수를 스레드로 호출하는 예제&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;stdio.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;string&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;boost/thread.hpp&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;boost/bind.hpp&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Man&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
 std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;string name\_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

 &lt;span class=&quot;token function&quot;&gt;Man&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; \&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 name\_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

 &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Say&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; \&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;[%d] %s: %s\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetCurrentThreadId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name\_&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;c\&lt;span class=&quot;token function&quot;&gt;_str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
 Man &lt;span class=&quot;token function&quot;&gt;bob&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Bob&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 Man &lt;span class=&quot;token function&quot;&gt;mark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Mark&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 
 boost&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;thread &lt;span class=&quot;token function&quot;&gt;th1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;boost&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;Man&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;Say&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bob&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 boost&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;thread &lt;span class=&quot;token function&quot;&gt;th2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;boost&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;Man&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;Say&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mark&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Bye~&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

 th1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 th2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;언어를 넘어서&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;최근에는 C/C++의 영향력이 급격하게 줄어들고 있는 모양새다. 다양한 요인이 있겠지만 아무래도 첫 번째 요인은 컴퓨팅 파워가 놀랍도록 좋아진 점을 들 수 있을 것 같다. 이제는 더 이상 몇 바이트, 몇 나노초를 계산해가면서 프로그래밍하지 않아도 되는 세상이다. 또 다른 요인으로는 과거와는 다르게 프로그램에 기대하는 요구사항이 폭발적으로 증가했다는 점도 들 수 있다. 고객의 요구사항은 시시각각 변하고, 살아남는 프로그램이 되기 위해서는 그러한 요구사항의 변화를 빠른 속도로 대처해야 한다. 그런 점에서 정적인 언어인 C++은 다소 불리할 수 밖에 없었다.&lt;/p&gt;
&lt;p&gt;모던 C++은 이러한 생산성에 관한 취약점을 극복하기 위해서 다양한 기능들을 추가했다. boost 라이브러리 같은 것들을 사용하면 기존 C++ 컴파일러를 사용해서도 제한적이나마 편리한 신규 기능들을 체험해 볼 수 있다. 하지만 이 모든 사실 이전에 반드시 기억해야 할 것은 C++이 항상 우리에게 주어진 문제를 푸는 최선의 도구는 아니라는 점이다.&lt;/p&gt;
&lt;p&gt;C++ 언어를 사용하는 프로그래머의 경우 포인터를 다룬다는 점에서 나름 자부심이 많이 있는 편이다. 그래서 그런지 언어에 대한 자부심도 남다른 편인 것 같다. 하지만 모든 문제를 C++로 풀 필요는 없다. 주어진 문제를 해결하는데 적합한 도구를 사용하면 된다. C++로도 풀 수 있는 것이지 다른 대안 언어만큼 쉽게 풀 수 있는 것은 절대로 아니다. 그러니 C++ 언어의 새로운 기능을 꾸준히 탐색하는 것만큼이나 C++이란 언어의 도그마에 빠지지 않도록 각별히 주의해야 할 것 같다. 세상에 주어진 다양한 문제만큼이나 그 문제들을 독창적으로 해결할 수 있는 언어도 많다. 우리는 단지 적절한 도구를 사용해서 그 문제들을 풀기만 하면 되는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;boost 기능에 대해서 정리가 잘 된 슬라이드~ 백문이 불여일슬라이드 ㅋ~&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[치킨 게임]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/11731</link><guid isPermaLink="false">https://jiniya.net/wp/archives/11731</guid><pubDate>Mon, 22 Jul 2013 23:59:06 GMT</pubDate><content:encoded>&lt;p&gt;흔하게 시장 지배 기업이 신규 진입자를 제거하기 위해서 사용하는 전략 중에 하나가 &lt;a href=&quot;http://rigvedawiki.net/r1/wiki.php/%EC%B9%98%ED%82%A8%20%EA%B2%8C%EC%9E%84&quot;&gt;치킨 게임&lt;/a&gt;입니다. 가격을 내려서 출혈 경쟁을 하고 경쟁자가 사라지면 독점의 이익을 누리겠다는 것이죠. 그래서들 보.통.은. 누군가 새롭게 등장만 하면 와~ 치킨 게임으로 쟤들 죽여버리자, 라고들 단순하게 생각을 많이 하는데요. 이게 치킨 게임이 통하는 분야가 있고 안 통하는 분야가 있습니다. 그러니 스킬을 시전하기 전에는 충분히 생각을 잘 해보는 것이 중요합니다. 자승자박 할 수가 있거든요.&lt;/p&gt;
&lt;p&gt;흔한 세탁소를 한다고 생각해봅시다. 복잡한 세탁이 아닌 정말 단순한 원룸 총각의 각종 빨래물을 세탁하는 세탁소입니다. 이 경우에 기존에 시장을 장악하고 있는 세탁소에서는 신규 세탁소를 가격으로 제압할 수 있습니다. 왜일까요? 여기에는 서비스 품질이 크게 중요한 요소가 아니기 때문입니다. 이놈이나 저놈이나 비슷비슷하기 때문에 가격이 싸면 장땡인거죠. 그리고 주요 고객층인 원룸 총각은 세탁물을 조금 더 반짝반짝하게 하는데 더 많은 비용을 지불할 의사가 없습니다. 자신이 하기엔 귀찮고 누군가 대신 해준다면 가장 싼데가 장땡이라고 생각하기 때문에 이런 전략이 통할 수가 있습니다.&lt;/p&gt;
&lt;p&gt;반대의 경우를 생각해 봅시다. 우리 동네에 베스킨라빈스 알스크림 가게가 새로 들어왔습니다. 기존에 마트를 하던 사장님께서 뿔났습니다. 알스크림 가격 50% 할인. 베스킨라빈스 망할때까지. 이랬습니다. 통했을까요? 아마 50% 할인한 사장님만 죽어났을 겁니다. 왜일까요? 본질적으로 차이가 나기 때문입니다. 베스킨라빈스와 죠스바 사이에는 가격으로 메울수 없는 본질적인 차이가 있기 때문이죠. 가격이 10배나 비싸지만 조금 더 맛있는 알스크림을 먹고 싶은 사람들은 그 가격을 지불하고 베스킨라빈스 알스크림을 사먹을 의사가 있기 때문에 여기엔 치킨 게임이 통할 수가 없는 겁니다.&lt;/p&gt;
&lt;p&gt;이론적으로 맛있는 알스크림을 먹기 위해 충분한 비용을 지불할 의사가 있는 고객으로부터 알스크림 가게를 유지하기 위한 비용 이상만 수익을 창출할 수 있다면 상대방이 가격을 0으로 만든다고 하더라도 가게를 영.원.히. 운영할 수 있습니다. 반대로 50% 할인 정책을 내세운 마트 사장님 입장에서는 가격을 0으로 내린다고 하더라도 베스킨라빈스 고객은 영원히 죠스바를 사먹으로 가게에 오는 일은 없을 겁니다. 그러니 베스킨라빈스 고객을 유치할 순 없고, 기존 고객에게 가격만 내리는 꼴이 됐으니 손해는 결국 마트 사장님만 보게 되는 셈이죠.&lt;/p&gt;
&lt;p&gt;자본주의 사회에서 가격은 가장 강력한 무기입니다.&lt;/p&gt;
&lt;p&gt;하지만 가장 강력한 무기라고 해서 그게 또 전부라는 말은 아닌거죠.&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;이건 좀 다르긴 한데, 이야기를 조금 더 확장하면 동일한 내용이 채용 시장에서도 통용됩니다. 보통의 입사 지원자들은 자신의 연봉을 낮게 부르는 것이 가장 강력한 무기라고 생각합니다. 하지만 이 또한 앞선 치킨 게임과 마찬가지로 통용되는 분야가 있고, 아닌 분야가 있는 것이죠. 실질적으로 개인이 생산할 수 있는 부가가치가 뻥튀기 될 수 있는 시장일수록 사실 연봉과 같은 가격은 중요한 요소가 되지 않습니다. 반대로 세탁소같은 구조의 분야에서 일하면서 자신의 연봉을 고고하게 책정하고 있다면 그 또한 경쟁력이 없는 셈이겠죠. 중요한 요소는 여러분이 하려고 하는 일이 부가가치 뻥튀기가 되는 분야(중력에 자유로운 직업)인지 아닌지가 중요한 요소라는 점이죠.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[광고: 애플, 우리의 서명]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/11651</link><guid isPermaLink="false">https://jiniya.net/wp/archives/11651</guid><pubDate>Mon, 15 Jul 2013 23:59:05 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;초큼 멋진 애플의 이미지 광고&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;그렇습니다.&lt;/p&gt;
&lt;p&gt;중요한 건 바로 제품이 주는 경험.&lt;/p&gt;
&lt;p&gt;사람들이 어떻게 느낄까?&lt;/p&gt;
&lt;p&gt;삶이 더 좋아질까?&lt;/p&gt;
&lt;p&gt;존재할 만한 이유가 있는걸까?&lt;/p&gt;
&lt;p&gt;단 몇개의 위대한 것을 얻기 위해&lt;/p&gt;
&lt;p&gt;그 몇 배의 시간동안 우리는 노력합니다.&lt;/p&gt;
&lt;p&gt;우리의 손길이 닿는 모든 아이디어가 사람들의 삶에 닿을 수 있을 때까지&lt;/p&gt;
&lt;p&gt;당신은 무심코 지나칠 수도 있겠지만 언제나 느낄 것입니다.&lt;/p&gt;
&lt;p&gt;이것이 우리의 서명&lt;/p&gt;
&lt;p&gt;그리고 이것은 우리의 전부입니다.&lt;/p&gt;
&lt;p&gt;– 애플, 우리의 서명&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 게임 보안: 난독화는 만병통치약인가요?]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/11516</link><guid isPermaLink="false">https://jiniya.net/wp/archives/11516</guid><pubDate>Mon, 15 Jul 2013 23:59:04 GMT</pubDate><content:encoded>&lt;p&gt;“난독화”란 용어가 보안 업계에 들불처럼 퍼지고 있습니다. 이 단어를 누가 처음 꺼냈는지는 모르겠지만 요즘은 마치 이 녀석을 빼고는 보안을 말할 수 없다는 분위기가 돼 가는 것 같아서 안타깝기 그지 없는 실정입니다. 그 가운데는 너무 많은 약장수들이 있는 것도 한 몫 하는 것 같습니다. 할머니들을 모아놓고 약을 파는 약장수나 컴퓨터를 사용하는 업계 전반의 공포심을 상대로 장난치는 그들이나 본질적으로 다른 점은 없지 않나라는 생각이 듭니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_난독화는_만병통치약인가요.md_0.png&apos; data-alt=&apos;약장수가 너무 많아요. UPX 들고 와서 난독화라고 팔기 부끄럽지 않나요?&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 409px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/4ac858a23e13f1053e9736130fe90d0a/ff023/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%82%9C%EB%8F%85%ED%99%94%EB%8A%94_%EB%A7%8C%EB%B3%91%ED%86%B5%EC%B9%98%EC%95%BD%EC%9D%B8%EA%B0%80%EC%9A%94.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 74.21052631578947%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAC/ElEQVR42j1Ry27bRhTlH/YHmmVRoOi2XaZAkTbJOinSOkEKtEUS1U5kPaxYokRTkSmKskjOkMMZkuJDfIiUaD5kyXbTXUdG4cFd3Jl7zr33nGHq9Q+HR7Xa4dvOSfPv2uH7Rr03YOv1erPVaLXbtXdvfv/zjx7b/XBcb7Wb7VazVns3OBve3t6UZckYBmodt9/+dcj3R4PesNvhRmdir8Nx7LDf47sn/dOTwYgXz4cSx34anPLdzkAYTaNFkixXTJFXb35hXz5p/fZz4+Bx89ef6i8evX/41cF3Xz57+PWrl09br540nv1w9OLHo4PHDQp79O3r7x88/+aLp0ev+0ye52Nudno8PDsRuI/isCtpM1v6pE14OGJl/uOE6wgirwLJVERDEfGEB8JAOe/JFnKZTVV5jqPMZAcT08QmxmGwCH0/TZfVpjARfTHcub3ZVjefr69vt7efb/75dx+76y1DdbumiwGxkU0gXswDz/YX9sKz/MAJCTQxwLQUU5Fheh/LIFmvMqYqS1lQJE4a98eTs4mpmqZqYdkM7MhF7pgVJW6iSXpoR7G7jJ3/I7CiNFztyXAC5XNlyk8pWR2r6AIBAbjEdwxHYAWJnwrsOZgAfYaACPULZMyQDeereL0n062QigwVazMt9KIiK/N1cZnmkR8hGcELzTGdOZ5jSAgklm7TfGEHl+ucqarKJha4UAxg6EAjyEjSNA6jNE2z9Rqpug6g53hX26vdzW57vdvuaHZFr2VV3k3GliZrRDOJhvcJMjG8MymIDdUgOtEVLfDCJEqWUZKtLrNVlqVZfpkzZVFYmkXFINkgClZEsLCCVbhOg5WHPSABDE3quSzKEi9RR2IviZw4nEd7zfSfiY6BqulANzTDsZ2yKGnXqqzSeHknBBNELHNuajjwA4ov8pyOpLEnU4Q8U4GiAgBd16UuFEWx2WySKFZlBUGdro0QUqayMlWyLKOA8u4wm7KivVUFQhVCSvb9e/J+MtRpFWsYGQaUwTJe3jPLsvwPb8XkCcD0HkoAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;약장수가 너무 많아요. UPX 들고 와서 난독화라고 팔기 부끄럽지 않나요?&apos; title=&apos;&apos; src=&apos;/static/4ac858a23e13f1053e9736130fe90d0a/ff023/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%82%9C%EB%8F%85%ED%99%94%EB%8A%94_%EB%A7%8C%EB%B3%91%ED%86%B5%EC%B9%98%EC%95%BD%EC%9D%B8%EA%B0%80%EC%9A%94.md_0.png&apos; srcset=&apos;/static/4ac858a23e13f1053e9736130fe90d0a/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%82%9C%EB%8F%85%ED%99%94%EB%8A%94_%EB%A7%8C%EB%B3%91%ED%86%B5%EC%B9%98%EC%95%BD%EC%9D%B8%EA%B0%80%EC%9A%94.md_0.png 190w,
/static/4ac858a23e13f1053e9736130fe90d0a/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%82%9C%EB%8F%85%ED%99%94%EB%8A%94_%EB%A7%8C%EB%B3%91%ED%86%B5%EC%B9%98%EC%95%BD%EC%9D%B8%EA%B0%80%EC%9A%94.md_0.png 380w,
/static/4ac858a23e13f1053e9736130fe90d0a/ff023/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%82%9C%EB%8F%85%ED%99%94%EB%8A%94_%EB%A7%8C%EB%B3%91%ED%86%B5%EC%B9%98%EC%95%BD%EC%9D%B8%EA%B0%80%EC%9A%94.md_0.png 409w&apos; sizes=&apos;(max-width: 409px) 100vw, 409px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;약장수가 너무 많아요. UPX 들고 와서 난독화라고 팔기 부끄럽지 않나요?&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;약장수들은 항상 그렇습니다. 애꾸눈이예요. 무슨 이야기냐구요? 한쪽만 본다는 것이죠. 문제의 본질을 총체적으로 보지 않고 지엽적인 부분만 집중해서 봅니다. 그리곤 그 지엽적인 부분을 전체 문제와 동일시 하는 과정을 거치죠. 결국 그 지엽적인 문제만 해결하는 방법을 가지고 와서 원래 문제를 다 해결할 수 있다고 광고를 합니다. 잘 아시겠지만 보안에서는 말이죠. 완벽이란 없습니다. 그러니 만병통치약도 없지요. 여러분에게 누군가 찾아와서 다 막습니다, 완벽합니다, 이거 하나로 모든 걸 차단할 수 있는 완벽한 솔루션입니다, 그런 이야기를 한다면 일단 의심하고 보는게 맞습니다.&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;난독화란 기술은 크게 폴리모픽과 메타모픽이라는 테크닉에 기반해서 구현 됩니다. 두 가지 기술의 차이는 아래 글에 상세하게 나와 있습니다. 여러분이 일단 난독화의 진실을 제대로 이해하려면 이 두가지 기술의 차이를 정확하게 하는 게 중요합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;변이(mutation)는 바이러스 제작자에게는 참 오래된 화두다. 바이러스 제작자들은 백신을 피하기 위해서 바이러스의 다양한 부분들이 변형되도록 연구했다. 이름을 바꾸었고, 내부에서 사용하는 문자열을 변경했다. 그리고 최근에는 백신의 감시를 피하기 위해서 바이러스 코드를 직접 변형하는 기법들을 사용한다. 변이는 바이러스의 출발점부터 지금까지 존재하는 가장 근본적이면서도 가장 강력한 기술이다. 이렇게 음지에서 연구된 ‘변이’라는 기법이 요즘은 난독화라는 이름으로 속속 바이러스가 아닌 일반 프로그램을 보호하는 용도로도 사용되고 있다. 이런 현상을 보면 정말 극과 극은 통한다는 말이 실감나기도 한다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;프로그램 변형 기법을 설명할 때 흔히 등장하는 용어로 메타모픽(metamorphic)과 폴리모픽(polymorphic)이 있다. 이 둘은 모두 morphic이란 어미에서 볼 수 있듯이 원본 프로그램을 변형시켜 새로운 ‘변이’를 만들어내는 방법을 의미한다. 용어 자체가 워낙 비슷하게 생긴 까닭에 용어의 비슷함만큼이나 그 차이가 불분명하게 여기저기 많이 사용되는 경향이 있다. 잠깐 둘의 차이점을 살펴보고 넘어가도록 하자.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;이 두 변형 기법의 가장 근본적인 차이는 원본 회귀 가능성에 있다. 변형 함수를 M, 원본 바이너리를 S, 변형된 바이너리를 D라고 할 때, 이 사이에서는 D = M(S)라는 관계가 성립한다. 여기까지는 메타모픽과 폴리모픽 모두 동일하다. 둘의 차이는 생성된 D에 있다. 만약에 생성된 D로부터 원본 S로 돌아갈 수 있는 역함수 M-1가 존재한다면 이 변형함수 M은 폴리모픽 함수라 하고, 역함수가 존재하지 않는 변형함수라면 메타모픽 함수라 부른다. 즉, 변형된 바이너리에서 원본을 추출하는 것이 가능하다면 폴리모픽, 불가능하다면 메타모픽이란 이야기다. 메타모픽이 폴리모픽보다는 좀 더 상위의 변형 기법임을 알 수 있다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;– 메타모픽 엔진의 핵심, 코드 교환의 원리, 신영진&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;글에도 나와 있는 것처럼 메타모픽이 변형으로써는 좀 더 상위의 개념입니다. 그런데 시중에 나와 있는 거의 대부분의 난독화 솔루션이라 불리는 것들은 대부분 폴리모픽이란 메커니즘에 기반하고 있는 경우가 많습니다. 이 경우에는 사실 upx와 크게 차이가 없습니다. 패커죠. 메모리 상에서 원본이 드러나기 때문입니다. 물론 그보다 더 조악한 수준의 심벌을 숨겨주는 프로그램을 난독화라고 파는 경우도 많이 있습니다.&lt;/p&gt;
&lt;p&gt;반면 메타모픽 쯤 되면 사실 해커들이 말하는 어레이 몇 개 찾아가지고서는 공략하기 힘든 수준이 됩니다. 하지만 PC 기반의 시중에 출시되어 있는 난독화 솔루션 중에서도 메타모픽이란 기술에 근간을 둔 제품은 거의 없습니다. 제품엔 메타모픽이라고 그럴싸하게 적어놓고 있지만 그렇지 않은 경우가 많습니다. 물론 거기에도 속깊은 사정이 있답니다. 그건 조금 있다가 살펴보기로 합시다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;역사를 아는 것이 중요합니다. 과거를 알아야 미래를 예측할 수 있기 때문이지요. PC 기반 플랫폼에서는 난독화라는 기술은 바이러스 제작자들 사이에서 연구가 됐지만 나중에는 일반 프로그램에도 상당수 차용됐습니다. 이렇게 일반 프로그램에서 사용하게 된 계기는 바로 크랙을 막기 위함이었습니다. 크랙이란 건 주로 실행 파일을 리버싱해서 주요 코드를 바꾼 다음 실행하는 방법을 말합니다. 이런 행위를 막기 위해서 난독화가 도입된 것이죠. 실행 파일 단계에서의 정적 분석을 어렵게 만들기 위한 장치였습니다. 여기까지 들으면 요즘 다른 분야에서 벌어지는 시츄에이션과 얼추 비슷하죠?&lt;/p&gt;
&lt;p&gt;네. 그렇게 초기 수준의 난독화를 도입하자 크랙이 사라졌을까요? 천만의 말씀. 만만의 콩떡이죠 ㅋ~ 크랙하는 사람들은 금방 방법을 찾았습니다. 굳이 실행 파일을 패치하지 않고, 메모리 상의 코드를 직접 패치해도 똑같은 결과가 나온다는 걸 알아내 버린것이죠. 그 전 세대에 개발된 난독화라는 기법이 폴리모픽이란 메커니즘에 기반해서 메모리 상에는 원본이 그대로 드러나는 문제점이 있었기 때문이죠. 이게 이제 다음에 벌어질 일입니다. 어레이라고 불리는 것들이 몇 개 돌아다닐 겁니다. 그런 어레이 몇 개만 입수하면 부산시에 사는 초등학생도 크랙을 할 수 있게 되는 것이죠.&lt;/p&gt;
&lt;p&gt;메모리 패칭에 난독화가 속수 무책이자 보안 업계 사람들은 크게 세 가지 길로 나뉘게 됐습니다. 첫번째 사람들은 난독화를 독자적으로 더 깊게 연구한 사람들입니다. 메타모픽 수준으로 진화한 것이죠. 메모리 상에도 원본 코드가 드러나지 않을 뿐더러 실행할 때마다 바뀌기 때문에 해커 입장에서 패치하기가 곤란하게 만든 것입니다. 그 다음으로는 정적 체크를 선택한 사람들이 있습니다. 파일 뿐만 아니라 메모리 상의 코드가 변경됐는지를 체크하는 코드를 삽입한 겁니다. 끝으로는 동적 방어 메커니즘을 무장한 사람들이 나오게 됐습니다. 메모리 보안이라 불리는 기술이죠. 운영체제를 패칭해서 우리 프로그램이 디버깅 당하거나 메모리가 불법적으로 조작되는 행위를 하지 못하도록 방어하는 것을 말합니다.&lt;/p&gt;
&lt;p&gt;어떻게 됐을까요? 누가 가장 성공했을까요? 물론 여기엔 완벽한 방법도 없고, 또 어떤 한가지가 가장 뛰어나지도 않습니다. 모든 방법을 적절하게 잘 버무려 써야겠지요. 그래도 어쨌든 오늘은 난독화 이야기를 하기로 했으니 메타모픽 쪽으로 선회한 사람들에 대해서만 알아보도록 합시다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;메타모픽으로 선회한 사람들은 어떻게 됐을까요? 과연 그들의 생각처럼 어떤 해커도 그들의 코드를 해독하지 못했을까요? 당연히 아니겠지요. 안타깝게도 그들은 해커의 공격을 받기도 전에 스스로 붕괴할 수 밖에 없었습니다. 너무 큰 문제에 봉착해 버렸거든요. 우리의 튜링옹께서 1936년에 증명을 끝내버린 정지 문제였습니다. 정지 문제란 간단히 말하면 프로그램 P가 주어졌을 때 그 프로그램이 정지할지 하지 않을지 판단하는 프로그램은 작성할 수 없다는 것을 의미합니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;계산 복잡도 이론에서 정지문제(停止問題, halting problem)는 판정 문제의 일종으로 다음과 같이 요약할 수 있다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;프로그램을 설명한 것과 처음 입력값이 주어졌을 때, 이 프로그램에 입력값을 넣고 실행한다면 이 프로그램이 계산을 끝내고 멈출지 아니면 영원히 계속 계산할지 판정하라.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;1936년에 앨런 튜링이 모든 가능한 입력값에 대해 정지문제를 풀 수 있는 일반적인 알고리즘 은 존재하지 않는다는 것을 증명했다. 그러므로 ‘정지문제는 튜링 기계에서 판정할 수 없다’고 한다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;– &lt;a href=&quot;http://ko.wikipedia.org/wiki/%EC%A0%95%EC%A7%80_%EB%AC%B8%EC%A0%9C&quot;&gt;http://ko.wikipedia.org/wiki/%EC%A0%95%EC%A7%80_%EB%AC%B8%EC%A0%9C&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이게 왜 메타모픽이랑 연관이 될지 궁금할 겁니다. 바로 메타모픽의 얼굴이 너무 많다는 겁니다. 실제로 진짜 메타모픽 엔진은 실행할 때마다 모든 코드가 예측할 수 없는 순서로 재배열, 재구조화되는 과정을 거칩니다. 그런 모든 변종이 정상적으로 동작한다는 것을 보장할 수가 없습니다. 즉, 메타모픽을 적용한 프로그램이 어떤 고객의 PC에서 멈추더라도 그건 전혀 이상한 현상이 아니라는 것이지요. 왜냐하면 그 변종에 대해서는 누구도 검증을 하지 못했거든요. 메타모픽 엔진은 본질적으로 안전성을 검증할 수가 없습니다.&lt;/p&gt;
&lt;p&gt;이쯤에서 JIT 컴파일을 반론으로 들고 나오는 사람들이 있습니다. JIT 컴파일은 메타모픽이랑은 완전 다른 기술입니다. JIT 컴파일은 서로 다른 CPU의 종류에 대해서만 한정적으로 서로 다른 컴파일 결과를 만들어내는 기술이지 동일한 CPU에서 매번 다른 코드를 만들어내는 기술이 아닙니다. 어쨌든, 최고의 메타모픽 엔진은 튜링옹께서 증명하셨던 것처럼 누구도 그것의 안정성에 대해서는 검증할 방법이 없습니다.&lt;/p&gt;
&lt;p&gt;물론 정지 문제만 있었던 것이 아닙니다. 다른 문제도 있었습니다. 바로 자신의 얼굴이 너무 많아서 자신 조차도 이게 정상인지 아닌지를 판단할 방법이 없어진다는 겁니다. 코드가 매번 바뀌기 때문에 진짜 메타모픽 엔진은 변형된 코드에 대해서 예측할 수 없습니다. 따라서 현재 실행되는 코드만 보고 나 스스로 이 코드가 원래 나의 코드인지 아니면 해커가 변형한 코드인지를 분간해 낼 방법이 없어진다는 점입니다. 최고의 메타모픽 엔진으로 보호된 프로그램은 아주 사소한 프로그램 변조도 본질적으로 그 공격을 판단할 방법이 없어지는 묘한 현상이 발생합니다. 자가당착적인 구조죠. 성형에 중독된 여성들이 진짜 자기 얼굴이 어땠는지 까먹는 것과 비슷한 문제라고 보셔도 되겠습니다.&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://github.int13h.com/webgldoom/doom.html#e1m1&quot;&gt;HTML5를 기점으로 이제 자바스크립트로 둠을 만드는 세상이 도래했습니다.&lt;/a&gt; 요즘 자바스크립트는 더 이상 예전의 자바스크립트가 아니지요. 하지만 잘 알겠지만 자바스크립트는 소스 코드가 브라우저에 그대로 다운로드 됩니다. 게임 입장에서는 쥐약입니다. 핵심 코드들이 모두 날 것 그대로 노출된다는 것이기 때문이지요. 그래서 브라우저 게임 대부분은 지금까지는 서버에서 모든 연산이 가능한 방식의 게임 밖에는 출시되고 있지 않습니다. 클라이언트 연산이 들어가는 게임이 나온다면 정말 쉽게 해킹이 가능할 것이기 때문입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How do I protect my content from pirates?&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;The “modern” open-source-based answer to this is, of course, that you shouldn’t: instead, you should architect your application or business so that the value is generated by the service you offer, not in the content delivered to the browser. However, in some cases that may well be unduly idealistic. Your best bet for under those circumstances is to look into JavaScript obfuscators.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;– &lt;a href=&quot;http://learningwebgl.com/cookbook/index.php/WebGL:_Frequently_Asked_Questions#How_do_I_protect_my_content_from_pirates.3F&quot;&gt;http://learningwebgl.com/cookbook/index.php/WebGL:_Frequently_Asked_Questions#How_do_I_protect_my_content_from_pirates.3F&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;WebGL FAQ 페이지에서 발췌한 내용입니다. 컨텐츠를 어떻게 보호할 수 있느냐는 질문입니다. 답은 아이러니하게도 난독화를 적용하는게 현실적인 수준이라는 대답입니다. 요즘 난독화가 자주 등장하는 가장 극적인 이유를 보여주는 한 장면입니다. 개발을 더 빠르고, 더 쉽게 할 수 있는 생산성이 높아지는 도구들을 잔뜩 만들었는데, 결국 사람들이 쉽게 만든다는 건 해커도 쉽게 리버싱 할 수 있는 환경을 만들어 버린 겁니다. 리플렉션 우왕 굳. 이랬는데 그 리플렉션에 사용되는 메타 데이터로 해커도 같이 꿀빨고 있었던 셈이죠.&lt;/p&gt;
&lt;p&gt;어쨌든 계속 이야기 했지만 이 싸움의 끝에는 안타깝게도 난독화가 위치할 수는 없습니다. 폴리모픽은 결국은 원본을 구할 수 있다는 말이고, 메타모픽은 여러가지 문제가 있기 때문입니다. 자바스크립트 난독화 도구도 당연히 난독화 이전 상태로 돌려놓을 수 있습니다. 변수명/함수명은 보기 힘들어지지 않냐구요? 어셈블리 코드도 C 코드 보듯이 보는 친구들입니다. 그런 문자열 몇 개 뭉개졌다고 해독하기 힘들다고 생각하는 건 너무 순진한 생각입니다.&lt;/p&gt;
&lt;p&gt;어떻게 해야 할까요? 네. 맞습니다. 사람이 이해하기 쉽도록 만든 장치를 사용해서 다시 이해하기 어렵게 만드는 우스꽝스러운 일을 해야 합니다. 이해하기 쉽게 만든 장치들을 사용해서 이해하기 어렵게 만든 내용을 해석하는 해석기를 만들어야 한다는 것이다. 자바스크립트 위에 새로운 해석기 레이어를 올려야 한다는 겁니다. 당연한 이야기겠지만 그 해석기가 해석하는 코드는 해커가 이해하기 어려운 수준으로 만들어야 겠지요. 결국은 VM 같은 구조가 되는 겁니다. 그러면 그 해석기 코드는 해커가 이해하기는 힘들기 때문에 기존과 동일한 수준, 내지는 만들기에 따라서는 더 높은 수준으로 분석하기가 힘들게 만들 수 있습니다. 그리고 자바스크립트 상에서 구동되는 코드 체계는 그 해석기가 해석하는 코드가 반드시 있어야 동작하도록 만들어 놓아야 하는 겁니다.&lt;/p&gt;
&lt;p&gt;얘가 도대체 무슨 소리를 하는 거냐고 의아해 하실 거예요. 또 좀 아는 사람들은 그게 말이냐 돼냐? 가능한 소리를 해야지, 라고들 합니다. 그럼 이제 작품 감상을 하러갈 시간이 된 것 같습니다. &lt;a href=&quot;http://bellard.org/jslinux/&quot;&gt;직접 보면 웃음 밖에는 안 나오는 프랑스 컴퓨터 사이언스계의 우주 신, Fabrice Bellard옹의 작품입니다.&lt;/a&gt; 이제 약을 팔아도 이정도는 만들어 놓고 약을 팔도록 합시다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_난독화는_만병통치약인가요.md_1.png&apos; data-alt=&apos;어서와. 이런 솔루션은 처음이지?&lt;br&gt;&lt;br&gt;애꾸눈에게 여러분의 보안을 맡기진 마세요.&lt;br&gt;&lt;br&gt;적어도 다양한 양념을 적절히 버무려 쓸 줄 아는 사람들에게 맡기세요.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a30add875aa83d9ebb3c954c66f9a0c7/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%82%9C%EB%8F%85%ED%99%94%EB%8A%94_%EB%A7%8C%EB%B3%91%ED%86%B5%EC%B9%98%EC%95%BD%EC%9D%B8%EA%B0%80%EC%9A%94.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 50%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABi0lEQVR42k1SWXaDMAz0MUigPyXBmCWQsNhA0qbt/c801cihrx96o3UkSzaXywXX6xV93yt2XYdhGBTpK8sSxbmALSyKolCbUlUV8vxdsXJOY5WrYEIIWNcV3ntQ/3h+4vn1xDxPmKZJm0yid32HpmnQ1A1c5eBKp2TtpVW01qKua5hlWZVoWRYhmQUDgo/2/b5h2zZt8HjctfG6bnEAyQ1h0TzmrOuifnO73eCFcJYJxzFOFYLXAk7tZ49BcpjHht8/39qANcyNje9aw1cZPonCZBaP44hJhGSDIJN8mCOhj0UsHoVsk4lISp315DGt7KVtW/RyBOrcRelKRVuKbuMxKNzRrvMw7nUMHmw/lmmaVpil+zSLwyJNU2RZhvR4RJqlOArSfhPJJPYXf+mUJEmQHBJFY4WVncnOK/Zdr7aTyxH1kvICfq9OhD7q9DP/dDpp051cCfUvvRKIZ/l3JHEuktFXvJ6e57nEz7oS2iT7L4aBSHLWKes67nEXp7uxOBwOKiza9d3+T/gLKXougP0LVuAAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;어서와. 이런 솔루션은 처음이지?&lt;br&gt;&lt;br&gt;애꾸눈에게 여러분의 보안을 맡기진 마세요.&lt;br&gt;&lt;br&gt;적어도 다양한 양념을 적절히 버무려 쓸 줄 아는 사람들에게 맡기세요.&apos; title=&apos;&apos; src=&apos;/static/a30add875aa83d9ebb3c954c66f9a0c7/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%82%9C%EB%8F%85%ED%99%94%EB%8A%94_%EB%A7%8C%EB%B3%91%ED%86%B5%EC%B9%98%EC%95%BD%EC%9D%B8%EA%B0%80%EC%9A%94.md_1.png&apos; srcset=&apos;/static/a30add875aa83d9ebb3c954c66f9a0c7/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%82%9C%EB%8F%85%ED%99%94%EB%8A%94_%EB%A7%8C%EB%B3%91%ED%86%B5%EC%B9%98%EC%95%BD%EC%9D%B8%EA%B0%80%EC%9A%94.md_1.png 190w,
/static/a30add875aa83d9ebb3c954c66f9a0c7/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%82%9C%EB%8F%85%ED%99%94%EB%8A%94_%EB%A7%8C%EB%B3%91%ED%86%B5%EC%B9%98%EC%95%BD%EC%9D%B8%EA%B0%80%EC%9A%94.md_1.png 380w,
/static/a30add875aa83d9ebb3c954c66f9a0c7/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%82%9C%EB%8F%85%ED%99%94%EB%8A%94_%EB%A7%8C%EB%B3%91%ED%86%B5%EC%B9%98%EC%95%BD%EC%9D%B8%EA%B0%80%EC%9A%94.md_1.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;어서와. 이런 솔루션은 처음이지?&lt;br&gt;&lt;br&gt;애꾸눈에게 여러분의 보안을 맡기진 마세요.&lt;br&gt;&lt;br&gt;적어도 다양한 양념을 적절히 버무려 쓸 줄 아는 사람들에게 맡기세요.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[게임가드 170 오류 코드 해결 방법]]></title><description><![CDATA[gg170
게임가드 170 오류 코드 화면 게임 하시면서 이런 화면을 많이 보셨을 겁니다. 게임가드 구동에 실패해서 발생하는 게임가드 17…]]></description><link>https://jiniya.net/wp/archives/11608</link><guid isPermaLink="false">https://jiniya.net/wp/archives/11608</guid><pubDate>Tue, 09 Jul 2013 23:59:03 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/wp/wp-content/uploads/2013/07/gg170.png&quot;&gt;&lt;img src=&quot;http://www.jiniya.net/wp/wp-content/uploads/2013/07/gg170.png&quot; alt=&quot;gg170&quot;&gt;&lt;/a&gt;
&lt;strong&gt;게임가드 170 오류 코드 화면&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;게임 하시면서 이런 화면을 많이 보셨을 겁니다. 게임가드 구동에 실패해서 발생하는 게임가드 170 오류 코드입니다. 오류 코드가 발생하면 상기 화면과 같이 친절한 메시지 상자를 출력해서 사용자에게 오류가 발생했음을 알려주고 있습니다. &lt;a href=&quot;http://gameguard.co.kr/list01.html&quot;&gt;그런데 안타깝게도 공식 FAQ 페이지에도 관련 오류 코드에 대한 설명이 나와 있지 않아서 전문적인 지식이 없는 분들은 문제점을 해결하기가 힘드실 것 같아요.&lt;/a&gt; 저도 오늘 게임을 하다가 이 오류 코드를 만났는데요. 검색을 해보니 저 외에도 수많은 분들이 이 오류 코드 때문에 고생하시는 것 같아서 해결 방법을 포스팅해 봅니다.&lt;/p&gt;
&lt;p&gt;우선 해당 오류 코드는 게임가드 서비스나 드라이버가 구동이 실패했을 때 발생하는 것으로 추정됩니다. 실패하는 이유는 여러가지가 있을 수 있는데요. 보통은 게임에 관리자 권한이 없거나 백신에서 해당 권한을 차단하는 경우가 있습니다.&lt;/p&gt;
&lt;p&gt;백신을 사용하시는 경우에는 해당 백신을 종료하신 다음에 게임을 실행해 보시구요. 그래서 실행된다면 백신 때문인 겁니다. 그럴 때에는 각자 사용하는 백신 옵션을 조정해서 게임가드에 관련 권한이 부여되도록 설정해 주시면 됩니다.&lt;/p&gt;
&lt;p&gt;다른 주요한 원인은 실행되는 게임에 관리자 권한이 없어서 발생하는 경우입니다. 윈도우 Vista 부터 UAC 라는 것이 생겼습니다. 관리자 권한을 요청하지 않으면 무조건 일반 권한으로 프로그램을 실행시키는 기능입니다. 이런 좋은 운영체제를 사용하면서 보안성을 취약하게 만들기 위해서 일부러 UAC 기능을 꺼두었다면 문제가 되지 않는데, 만약 켜져 있다면 게임이 별도로 관리자 권한을 요청하지 않으면 게임가드도 관리자 권한을 얻지 못해서 170 오류 코드가 발생하게 됩니다. 통상적으로 이런 경우에 게임사에 요청해서 게임 실행파일에 관리자 권한을 요청하는 매니페스트를 추가해 두면 문제가 발생하지 않는데요. 제가 실행했던 반 온라인의 경우에는 게임 실행 파일에 매니페스트가 없어서 UAC를 끄기 전까지는 170 오류 코드를 피할 수가 없었습니다.&lt;/p&gt;
&lt;p&gt;이렇게 매니페스트가 없어서 관리자 권한을 못 받는 게임인 경우에는 임시 방편으로 해당 게임을 항상 관리자 권한으로 실행하도록 옵션을 설정해 주시면 됩니다. 게임 실행 파일이 있는 폴더로 가셔서 게임 실행 파일에 우클릭해서 설정 메뉴에 보시면 아래와 같이 항상 관리자 권한으로 실행하도록 만들어주는 옵션이 있습니다. 이 옵션을 체크한 다음 게임을 실행하시면 됩니다. 그러면 게임 실행 시에 UAC 경고창이 뜨게 됩니다. YES 눌러주면 게임가드가 관리자 권한을 얻을 수 있고, 여러분도 게임을 할 수 있게 될 겁니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/wp/wp-content/uploads/2013/07/prop.png&quot;&gt;&lt;img src=&quot;http://www.jiniya.net/wp/wp-content/uploads/2013/07/prop.png&quot; alt=&quot;prop&quot;&gt;&lt;/a&gt;
&lt;strong&gt;게임 클라이언트 프로그램 등록 정보 화면&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt; 0
 4&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[마가 끼다…]]></title><description><![CDATA[리비전 그래프… 27/37, 72.97% 성공… 마가 낀게 틀림없다. (<-- 대부분의 쪼다 프로그래머들이 하는 변명 ㅠㅜ) 올들어 총 3…]]></description><link>https://jiniya.net/wp/archives/11218</link><guid isPermaLink="false">https://jiniya.net/wp/archives/11218</guid><pubDate>Wed, 26 Jun 2013 23:59:02 GMT</pubDate><content:encoded>&lt;center&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 281px; margin-bottom: 16px;&apos; data-url=&apos;./마가_끼다.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/583f907cd600d58fbfbf94edb19cebac/fa392/%EB%A7%88%EA%B0%80_%EB%81%BC%EB%8B%A4.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 177.89473684210526%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAkCAYAAACJ8xqgAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAFR0lEQVR42pVVWW8TVxjNP+tTH9rHqhXioUKiLaICIQIlLCFm6wKkShAQqVGjRC0CFZBKqGhpK0ClLdBs2GIJSRw7OI7j8TIztmff7umZJeBELMlIVzP3zp1zz/d953zTIYTAeoYf+Aiv68UL2HlnE3aOb8Id6ddoLRDxu3Bfx3oBhQgg+JFtLKOYvY9KcQJ6qwy3JMN5XoKbL8FTWxsBjEd4lSsKpFqLlHxMn9iKf7a9i8efvQP11uWNAQZBDKjLOlqSCeE6MO3jWFr+FDV1K2znj/UDBgw5jLnoljHWmELGeYKCVoJv8QDdgOfGeezYaFFu5UfQdfV97L35HiYq1+GZIygUutBspmBZ9zZeFNFaRj1zGwqHpxS49gyK/BdM4wF8X0oAgyAevo8X8/B5ZT0cbUWxbQe2F4SCgaEPorzcTYb7yPBuAgisHmvX2ubx5aOlnUddPoiavA2t1iWuGSyaRsBwY7EIMT0NMTkJIUkQCwsQExMQ6TTE7CxErRatBYYOP4rAg6ulUc7/BmXpNhyt8OLgGPDm7xBn+iFGRyHGxiAyGYihIYjBQYiRYQSj14DvhyBl0rh09WfkczkYxT7MPfgEubHNUIo/xo5h4Tqi/ISgug5hUVuGEc/De8i2Xo9DlusIs2a4Epr6FFTta9RZWdMdguP+G+UjLNzqKodAJoFUGUJrIrD0eN7ks94EGh6gXUM9vxlS9nOYlW95sJf4OFjj5bCq4YuHDHe2ACyWgTxzm5uHKITz50BBgp+/ADm9BdWJLTBmehBM3uehelsOVwCDBHD+b2jNbih6Hxr6Wa5VYCnPUc79B13RuGMcUr0H5VonNG8AQS7LaF4JmOQy+4TVzEBRjqFY2AGldhK6OgGzMYbCfAr16jEsLnbCtZ/CQzmOQNPeBDhP5ZoswDgc+xeoSj88b4rGT0NVf6Cob3B+N5JOlLt8fjVgEDgst42ALg8iwGxc7Wj7HJmm6ITdqFQO0FpqDII2AmsBxYr8V6rcBijEDBpqCrVqNy12moC1cBuH93pAy7pCHw6j1fwOts9w5xcJGGuR6GT4JdkdRaPRB9dTXkrkdYCG0Y9S6QDkehcsL0PAJcpAi5ggmIUqH4FUPoyGcgq+R5GHbTFUxIrM6Jo1DAdQraTIsAdO8AjIEdBOGCJHV3yDunoCmnmGPVFNmkSbEULftwOa5mmUy3uZq92wBRlm2AweU9w5ijp7A42pD1Ef+4D3j+HN0OfzDDE7BzE3F7ObmmJEZjvDfjLcj2ajC44zCYorDtlibPYjNKv7UCt1ollLwecfT1huXDTLioEcZ1UjJsMzkKQDTPp+amwykYWfhJxFgw2gWjvE+0l4gfIy5PZe2Q6o6+exXOphNQ+z4z6M26egNiN5zEGWj/HAFN/3UtDyqkbwqkHA01gq7uWHnWQ4nmjSS45/hjqrH+Y4tKLHKr8V0HV/IthZWOZ56myav0kV884CCn6ZVc3x5zMItTFA612ko5qJsN8AaNsjqFZPQdd6qcM0vksfx54/P8JXk92wgmeUUx9q9SO8n6RT5LcDmuYohT1E4w+TxRzg8IW2gNbSFbQa17G8PAzDmIHrVsnQTQDFmwBP0Fo7WOXtBLwXNQiP1dXM3czdNnabL8hs6a25awM8x25CazUOU4fjkbWAx1GXqVaP0ufnyE7aAKDRi1ptPz/eBdOc5WeTfD5Ibx9iGvriLrSB0RH1QjZLy5IIfJkgo6hIF8l2Meoocd6C9QPGD2FAMnveHhZhO224i2E+TcL0N8YwPj38VGU1B+iK3qT35dedt3bA/wHMeZf1oIHcEwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;      md 0&apos; title=&apos;&apos; src=&apos;/static/583f907cd600d58fbfbf94edb19cebac/fa392/%EB%A7%88%EA%B0%80_%EB%81%BC%EB%8B%A4.md_0.png&apos; srcset=&apos;/static/583f907cd600d58fbfbf94edb19cebac/08678/%EB%A7%88%EA%B0%80_%EB%81%BC%EB%8B%A4.md_0.png 190w,
/static/583f907cd600d58fbfbf94edb19cebac/fa392/%EB%A7%88%EA%B0%80_%EB%81%BC%EB%8B%A4.md_0.png 281w&apos; sizes=&apos;(max-width: 281px) 100vw, 281px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;리비전 그래프… 27/37, 72.97% 성공…&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;마가 낀게 틀림없다. (&amp;#x3C;-- 대부분의 쪼다 프로그래머들이 하는 변명 ㅠㅜ) 올들어 총 37번의 엔진 릴리즈가 있었다. 그림은 그 릴리즈 때마다 태그를 붙여둔 리비전 그래프다. 그런데 우습게도 이 중에 거의 삼분지 일에 해당하는 10번의 릴리즈가 5월 중순부터 5월 말까지 발생했고, 안타깝게도 그 릴리즈에 모두 소소한 문제가 있었다. 물론 지원팀 덕분에 그 파급 효과가 고객에게 미치지는 않았다. 단지 내부적으로 엄청난 피로도가 누적되는 과정이 있었을 뿐이다.&lt;/p&gt;
&lt;p&gt;너무 어처구니가 없어서 릴리즈 노트를 보면서 무엇이 이런 참담한 결과를 가져왔나 꼼꼼히 살펴 보았다. 그 복기 과정을 통해서 난 반드시 기억해야 할 아주 중요한 교훈 두 가지를 얻었는데 다음과 같은 것이었다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;버그 수정과 기능 추가를 한 릴리즈에 묶는 행위가 재앙을 만든 일등 공신이었다. 난 항상 별 생각 없이 기능 추가와 버그 수정이 동시에 일어난 빌드를 릴리즈 했는데 이게 말 그대로 헬 게이트를 여는 원인이 돼 버렸다. 이게 잘 될 때는 기능 추가도 되고 버그 수정도 되는 꿀빠는 일이지만 안 될때는 말 그대로 버그 수정을 했는데 신규로 추가된 기능에서 버그가 또 새롭게 잉태돼서 계속 쓰지도 못하는 코드가 릴리즈 돼 버리는 문제가 있었던 것이다. 버그 수정과 기능 추가를 분리해서 빌드 했다면 적어도 중간에 하나씩은 쓸 수 있는 빌드가 생겼을 것이다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;코딩 허세. 코딩 허세. 허세가 문제였다. 10번의 실패한 릴리즈 중에서 8번이 동일한 로직 변경 과정에서 발생했다. 린스타트업과 같은 방식으로 검증을 통해서 차근차근 접근할 수도 있는 부분이었는데 내 허세가 한 번에 완성할 수 있다는 생각을 만든 것이다. 그도 그럴것이 실제로는 아주 간단한 조건을 변경하는 것이었기에 더 쉽게 생각됐다. 하지만 그 사소한 조건의 변화가 미칠 수 있는 파급 효과는 실로 어마어마했다. 내가 무엇을 상상하던 그것보다 훨씬 더 컸다. 그 결과 릴리즈를 8번이나 날려 먹고서야 제대로 만들 수 있었다. 검증 단계를 통해서 접근 했다면 시간은 더 걸리더라도 지원팀에서 검증 작업에 이토록 애를 먹지는 않았을 것이다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이 과정 중에서도 내가 잘한 일이 하나 있다. 바로 릴리즈에 개입하지 않았다는 점이다. 회사 초기에는 내가 릴리즈를 할 때도 있었고, 지원팀에서 릴리즈를 할 때에도 내가 개입하는 경우가 많았는데 언제부턴가 본능적으로 내가 개입하지 않아야 문제가 덜 발생한다는 사실을 알게 되었다. 그래서 이런 문제점들이 고객들에겐 표출되지 않을 수 있었다.&lt;/p&gt;
&lt;p&gt;물론 본질적으로 모든 문제는 내가 집중해서 제대로 일하지 않았기 때문에 발생한 일들이다. 그 모든 잘못의 근본적인 원인의 면면을 살펴보면 결국 내가 제대로 프로그램을 만들었으면 애초에 하나도 발생하지 않았을 일들이다. 그래서 더 가슴 아프다.&lt;/p&gt;
&lt;p&gt;자원은 항상 부족하다. 정신 차리고 제대로 일하는 수 밖에는 없다. 작은 업체가 살아남는 방법은 뛰면서 쏘는 방법 밖에는 없으니까 말이다.&lt;/p&gt;
&lt;p&gt;덧) 포스의 어두운 면과 밝은 면은 항상 공존하는 것처럼 이런 참담한 결과가 나쁜 점만 있었던 건 아니었다. 테스트 코드가 훨씬 더 많이 필요하다는 인식이 생겼고, 엔진의 릴리즈 현황을 자동으로 추적할 수 있는 훌륭한 백엔드 시스템도 만들어졌다.&lt;/p&gt;
&lt;center&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 289px; margin-bottom: 16px;&apos; data-url=&apos;./마가_끼다.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/860c9e4558f8cdc84141dd395e2a0c52/3b5c2/%EB%A7%88%EA%B0%80_%EB%81%BC%EB%8B%A4.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 138.42105263157896%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAcCAIAAADuuAg3AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAFg0lEQVR42kVVV3MaVxTm5+Yhr5lJcRzFlhM7sWTLtowEQhQVmkAg2tLL0pdlYelVwCIQIETv5eYsTiYzdxhg773fOV85yxm28IcCxuQMCUIOq//oQXNqOya248h2RGwnJJpF0Ty6GRLD3SO0orerxGYUQeMIJxe7dWJ8vfqz7uaomjOUk9oF40JTOB9FizjqhuZVJyo7nyu2WslcL5kdJt7l+RvcKkCbBKeSN1JB2X1KV87oI/7rZtHSK1gM6s8XZ/tBl0QrO/h68OO44R4xTo+ZzxSx+7SewC9rWT2axzjZmHo5i9tMPJP2WKP4kKFU3Qen23JG+q4ShCITU99n9N2Gq5LRkzZRIaoatfFRCx+3vWhCcjo1Rxi/VMkOLDou99MLh/nMgfHaD26EshsoG6UbjBP6AhxYk5qzmtYXU9pFP4imJAc4aKQNWuHbX3/+Tnj6+6IX1KmOGiUz8LQehNA0miQUZu0x4KxHBHoOlSoGjBLR+dvBE87ZTslN2496BB1X04QSoZzTwve6xWidQJPI6MkLRa2GYZZ/IP8pSKSVobSi/4TPegEO2kmybuCo5U/4ZY0ChgaRbFCx6IXQkFgy7nxEhSbRbSe4zVgnjx5fUhbKKPsdHM0oDgLFpuS25UM197TjC7nEWfdVjVBXUjoodZq3ZALy8SPebjpqDxY8JbsNnPoS0ty9Hs1iLDKc304iCCULyTuN/HA5CkfDMv7Xl+CTRtXK4/6WyWruGeyMtzduecsNa6mGtR4dQMfuMFQ+JNAiRgWkHssZQqlZP5SMKCddfz5+63eK4NFiHFVJD2YdX4XBwmkllVOxOv93OAzFg9tA9pBbUs0b54MwOKeUvGOKZrRNRv3XfO7LZEjeaDvInLrTcv6PzBoYKp9G4cuqHyzQmk7NDj9bNfug6S4ltVRItuOfHHVxA3HOPNhYwtgATMgu46gXTNWsHqwDC2SAu1wYXyZ5x+SN7Yqtwzi6NQfAgGxq/MRGilejMGfQ8j7XneBKqHD2HGjdW+EwCzujLHqu4uIdWoLP8mrpe8jDY9mSpdRR33U2pQFUTp7WLoYEbj8367jlrNFiOC2kdHaMh1Dm/GRPfvGumNC2K9ZmyRJ0S0ALrfKjiP+qDkTMKU6Ovu01PdWsoZYzJQllLCir5E0R7xW4H/60G07mvUA5pbuVHwJMIaGBtEBFeVoDEnCqOeO16M9S3kSF5DR543WJIWFOiwC2wt1ZipUE9g06voBbolN9korfCrh7xdQd+JIDHYI2ufgtNMPkjIt+aDkIex3CiPdy3g2UEppvcqwGYcJ7CUI2y2awAHDEThLou1212Q2ntayx9+D024V3yo8g0noa3S7pk+OXz00PKLSZU+sxCb1AsJ8ecWARrLELxoSMBKSgAaQX0x7v730fDUhxjIfL3/s1R6SVpxK8chtO7oECjGfVn8CccRh5LDI0BiLThAIagzbgs5o1Hn96YRC/UR//Ijz6aV7Qobo1rj4sUCo6rABddqIG2UkCuyH6PocQxgCsVT8E5S0m0aLvIo1LzGaBwyKg6TvGc95K3427/n7TDWo3YVoA8gbQlnGP9Uwi2AfrB1ziK+Ef3aanGVNi569cBm4IOzVrvtS9Iqvotdsukpztq6WHpO8a8sthS51Tzw+ufEILM3zU9uLW82REsRpFaBt/RN/040rKeFwPXrZzhkbFhmm+fPjrB5dZAJN8d3gW7TfcpP8aBMtQ6noR2wzDUBEZlE2eA9nkHe4U95/861msljNAvGD0gpBsqr6RBNaPBWRg6eEj3ihiq91wrOdNGfJGdf3+Svjm5upvIBIA4PXQe/KjbYo1yTcPAM4a3ixgJjaVFDC5yykF94KwpYT235BuEpDzZS/IQo4j/wCaplGvMFXzjgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;      md 1&apos; title=&apos;&apos; src=&apos;/static/860c9e4558f8cdc84141dd395e2a0c52/3b5c2/%EB%A7%88%EA%B0%80_%EB%81%BC%EB%8B%A4.md_1.png&apos; srcset=&apos;/static/860c9e4558f8cdc84141dd395e2a0c52/08678/%EB%A7%88%EA%B0%80_%EB%81%BC%EB%8B%A4.md_1.png 190w,
/static/860c9e4558f8cdc84141dd395e2a0c52/3b5c2/%EB%A7%88%EA%B0%80_%EB%81%BC%EB%8B%A4.md_1.png 289w&apos; sizes=&apos;(max-width: 289px) 100vw, 289px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;언젠간 이런 시스템을 만들 날이 오겠지? ㅇㅇ~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;게이머들에게 공정하다는 느낌을 줄 수 있는 그날을 꿈 꿔 본다.&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;</content:encoded></item><item><title><![CDATA[레거시 코드 활용 전략~]]></title><description><![CDATA[2002년…]]></description><link>https://jiniya.net/wp/archives/11458</link><guid isPermaLink="false">https://jiniya.net/wp/archives/11458</guid><pubDate>Tue, 25 Jun 2013 23:59:01 GMT</pubDate><content:encoded>&lt;p&gt;2002년 3월, 꿈에 그리던 병역특례 회사에 첫 출근을 했다. 따뜻한 봄 날, 직업 프로그래머로써 내 생애 첫 번째 미션이 주어졌다. 사수의 서버 프로그램을 유지 보수하는 일이었다. 나에게 인수인계를 해 준 선임 프로그래머는 그 주에 회사를 그만두었고, 난 계속 죽는 서버 프로그램을 유지 보수 해야 했다. 신입 프로그래머라 실력보다는 패기가 앞섰던 시기였다. 난 지저분해 보이는 프로그램 코드를 처음부터 다시 짜야 한다고 주장했고, 실제로 그렇게 했다. 하지만 안타깝게도 내가 새로 만든 프로그램은 원래 프로그램보다 더 자주 죽었고, 현대적인 UI를 제외하고는 그다지 나아 보이지 않았다. 결과적으로 원래 프로그램을 유지 보수 하는 만큼의 시간을 더 들이고 나서야 새로운 프로그램이 정상 동작하도록 만들 수 있었다.&lt;/p&gt;
&lt;p&gt;이 이야기를 시작한 이유는 거의 대부분의 프로그래머가 2002년의 나와 똑같은 자세로 레거시 코드를 대하기 때문이다. 이 글을 쓰기 전에 주변에 있는 10명 이상의 프로그래머에게 레거시 코드에 대한 생각과 레거시 코드를 다루는 본인만의 노하우가 있는지를 물어보았다. 정말 재미있게도 그 모든 사람이 하나같이 똑같은 이야기를 했다. 새로 만들어야지. 그 중에 한 명은 레거시란 말 자체가 이미 쓸모 없다는 뉘앙스를 내포하고 있지 않냐는 말까지 덧붙였다.&lt;/p&gt;
&lt;p&gt;11년이 흘렀다. 그사이 난 레거시 코드 때문에 고생도 해보았고, 내가 만든 코드를 레거시 코드라고 부르는 사람들과 만나기도 했다. 그 과정 속에서 생각이 조금 바뀌었다. 레거시 코드를 나쁜 것, 버려야 할 것으로 보던 시각에서 점차적으로 힘들지만 함께 해야 하는 것이라 느끼게 된 것이다. 그리고 그렇게 바뀌게 된 배경에는 레거시 코드가 생겨나는 본질적인 구조에 대해서 알게 되었기 때문이었다. 우리에게 지금 절실하게 필요한 것은 레거시 코드를 리팩토링하는 몇 가지 테크니컬한 기법들이 아니라 그것을 바라보는 프레임을 바꾸는 일인지도 모르겠다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;레거시 코드의 탄생&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;레거시 코드란 오래되고 낡아서 손대기 힘든 코드를 의미한다. 그렇다면 도대체 오래되고 낡아서 손대기 힘든 코드는 어떻게 만들어지는 것일까? 단순히 오래됐기 때문일까? 아니다. 오래된 코드임에도 유지 보수하기 쉬운 코드들은 얼마든지 있다. 그렇다면 왜 어려운 것일까? 대부분의 프로그래머들은 레거시 코드가 조악하게 작성돼서 그렇다고 생각하는 경향이 있다. 하지만 이 또한 진실을 아니다. 레거시 코드는 우리가 생각했던 것과는 전혀 다른 경로로 만들어진다. 레거시 코드의 본질적인 측면을 이해하기 위해서는 이 탄생 배경을 이해하는 것이 필수적이다.&lt;/p&gt;
&lt;p&gt;현대적인 프로그램의 코드 양은 이미 상상을 초월하는 수준으로 방대하다. 이러한 많은 코드 중에서는 프로그램의 업데이트와 함께 지속적으로 변경되는 코드들도 있지만 한 번 만들어 놓은 다음에는 변경이 거의 없는 코드들도 있다. 오래된 저장소에서 작업하고 있다면 변경 이력에 관한 저장소 통계를 내보면 의외로 재미있는 결과를 마주할 수 있을 것이다. 다름아닌 자주 변경되는 부분만 계속 변경된다는 점이다. 변경의 사각 지대에 있는 코드들은 한 번 작성된 이후 몇 년 동안 단 한 줄의 수정도 없는 경우도 많다. 레거시 코드는 바로 이러한 사각 지대에서 발생한다. 오랜 기간 수정이 발생하지 않기에 그걸 아는 프로그래머가 드물어지고 그런 과정이 굳어져서 마치 화석처럼 돼 버리면 레거시 코드가 되는 것이다.&lt;/p&gt;
&lt;p&gt;여기서 생각해 보아야 할 점은 왜 몇 년간 단 한 번의 변경도 없었을까라는 점이다. 이는 두 가지를 의미한다. 하나는 그 코드가 본연의 목적은 잘 수행했다는 이야기고, 다른 하나는 그 코드가 관여한 부분에 요구 사항의 변경이 없었다는 것이다. 즉, 이는 다시 말하면 레거시 코드는 많은 프로그래머들의 생각처럼 단순히 잘못 작성되고 오래된 나쁜 코드가 아니라 오히려 안정된 코드라는 점이다.&lt;/p&gt;
&lt;p&gt;외부 업체에서 제공한 라이브러리의 경우도 크게 틀리지 않다. 외부 업체에서 제공한 라이브러리가 기능을 정상적으로 수행하지 못했거나 버그가 많았다면 레거시 코드가 되기 전에 이미 많은 사람들의 관심 속에서 다른 라이브러리로 교체가 되거나 직접 작성되는 운명을 거쳤을 것이다. 하지만 제한된 기능을 안정적으로 수행하는 라이브러리의 경우에는 프로그래머들의 사각지대에 놓이게 되고 시간이 오래 흐르면 직접 만든 코드와 마찬가지로 화석처럼 굳어져 버린다. 이 경우에 직접 만든 코드보다 상황이 더 좋지 않은 이유는 라이브러리를 개발한 업체가 더 이상 해당 라이브러리를 유지 보수 하지 않는다거나 아예 사라진 경우도 발생할 수 있기 때문이다. 어쨌든 이 경우에도 직접 만든 코드와 마찬가지로 오랜 시간 본연의 기능을 안정적으로 수행했기 때문에 레거시가 됐다는 점에는 변함이 없다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;새로 만드는 이유&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;앞서 레거시 코드는 오래되고 낡아서 손대기 힘들다는 기존의 관점이 아닌 오히려 오랜 시간 묵묵히 자신의 역할을 다했기 때문에 살아남을 수 있었던 안정된 코드라는 관점을 제시했다. 하지만 그럼에도 현실세계의 수많은 프로그래머들은 여전히 레거시 코드를 부정하며 새로 만드는 방법 밖에는 없다고 안달한다. 왜 그런 것일까?&lt;/p&gt;
&lt;p&gt;첫 번째 이유는 안정된 코드가 다루기 쉬운 코드라는 말은 아니기 때문이다. 프로그래밍 패러다임에도 일정한 흐름이 있고 유행이 있다. 구조화된 프로그래밍 기법이 알려지기 전까지 모든 프로그래머들은 goto 구문을 남발하면서 프로그래밍 하던 것을 당연하게 생각했었고, 객체지향 프로그래밍이 유행하기 전의 프로그래머들은 당연히 프로그램은 절차지향적으로 작성해야 한다고 굳게 믿고 있었다. 레거시 코드는 오랜 시간을 버텼고 그 코드를 처음 작성한 프로그래머와 지금 유지 보수를 맡은 프로그래머 사이에는 시차가 존재할 수 밖에 없다. 이러한 시차는 당연하게 유지 보수를 맡은 프로그래머에게는 거대한 장애물 역할을 하는 동시에, 새로 작성하는 것을 택하도록 만드는 인센티브 역할을 한다.&lt;/p&gt;
&lt;p&gt;두 번째 이유는 코드 리딩과 리팩토링에 익숙하지 않기 때문이다. 정말 안타까운 현실인데 대다수의 프로그래머 교육 기관에서 코드 리딩을 제대로 가르치지 않는다. 그 때문에 다른 사람의 코드를 제대로 읽을 줄 아는 프로그래머를 만나기란 정말 ‘하늘에 별 따기’다. 대부분의 프로그래머가 이야기하는 잘못 작성됐기 때문에 다시 만들어야 한다는 주장은 안타깝게도 그걸 해석하는 자신의 이해력이 부족하다는 전제를 내포하고 있다. 일년에 자기 계발서 몇 권 읽는 친구에게 두꺼운 철학책을 읽으라고 권해준다면 철학책 저자의 생각이 오롯이 친구에게 전달되기 보다는 왜곡되기가 쉬운 것과 같은 이치다. 물론 그 철학책을 접한 친구의 평을 듣고 철학책의 가치를 논하기는 더더욱 어려울 것이다.&lt;/p&gt;
&lt;p&gt;세 번째 이유는 새로 만드는 것이 기존의 코드를 유지 보수하는 작업보다 훨씬 더 재미있다는 점이다. 프로그래머들은 코드를 창조해내는 창작자들이다. 그들은 유지 보수 작업을 따분하고 지루한 작업이라고 생각한다. 새로운 코드를 써내려 가는 것을 훨씬 더 좋아한다. 유지 보수 할 수 있는 코드라고 하더라도 새로 만들고 싶어하는 또 다른 이유다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;새로 만들기의 함정&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;레거시 코드를 완전히 새롭게 만드는 일은 그 작업을 수행하는 프로그래머 입장에서는 공부도 되고 개인의 실력 발전도 되겠지만 제품 전체 내지는 조직의 이익에 비추어 본다면 잉여적인 투자라고 할 수 있기 때문에 좋은 선택이라고 보기는 힘들다. 이런 자본 논리 외에도 레거시 코드를 완전히 새롭게 작성하는 것에는 여러 가지 위험 요소가 있다.&lt;/p&gt;
&lt;p&gt;“새로 만들기”라는 과업을 수행할 프로그래머가 대부분의 경우에 레거시 코드의 모든 부분을 완전하게 이해하고 작업하는 경우는 드물다는 점이 가장 큰 위험 요소다. 실제로 앞서 인터뷰를 했던 10명의 프로그래머 모두 레거시 시스템을 완전히 새롭게 작성한 후에는 꼭 “원래 있었던 이 기능이 안 되는 것 같은데요”라는 말을 들었다고 했다. 심지어는 기존에 있었던 이스터에그가 정상적으로 동작하지 않는다는 클레임을 받았던 적도 있었다고 했다. 즉, 기존의 코드를 이용하지 않고 완전히 새롭게 만드는 경우에 기존의 코드가 가지고 있었던 모든 기능을 완전하게 충족시키기란 생각보다 쉽지 않다. 뒤에서 살펴보겠지만 심지어 어떤 경우에는 버그도 기존 코드와 동일하게 가지고 있어야 한다.&lt;/p&gt;
&lt;p&gt;새롭게 작성하는 쪽을 택하는 프로그래머의 경우 대부분 기존 코드를 보기 보다는 전체적인 기능 맥락을 보고 동일한 기능을 수행하는 새로운 코드를 작성하는 경우가 많다. 이 경우에 명세가 기존 코드의 기능을 100% 모두 충족시킨다면 상관 없겠지만 거의 대부분의 경우에 그렇지 않기 때문에 새롭게 작성한 코드는 항상 기존 코드와 100% 호환되지 않는다는 문제를 일으킨다.&lt;/p&gt;
&lt;p&gt;만약에 앞서의 전제를 뒤집어서 만약 그 프로그래머가 100% 기존 코드의 기능을 모두 이해하고 동일한 역할을 수행하는 새로운 코드를 쓴다고 한다면 이 또한 큰 낭비일 수 밖에 없다. 왜냐하면 모든 것을 완벽하게 이해했다면 그 코드를 고치는 일이 새롭게 작성하는 일보다 시간이 덜 걸릴 수 밖에 없기 때문이다.&lt;/p&gt;
&lt;p&gt;프로그래머들의 근거 없는 자신감은 “새로 만들기”라는 거대한 과업을 쉽게 보이게 만들어주는 강력한 인센티브 역할을 한다. 대부분의 프로그래머는 자신이 상대적으로 매우 똑똑하며 아주 특별한 존재라고 생각하는 경향이 강하다. 그래서 자신은 기존의 코드보다 훨씬 더 괜찮은 코드를 더 적은 시간을 투입하고 만들 수 있다는 착각에 빠진다. 하지만 이는 정말 말 그대로 착각일 뿐이다. 새롭게 만들어 보면 결국 기존의 프로그래머가 겪었던 시행착오를 모두 다 똑같이 겪으며 조건문들이 여기저기 덕지덕지 추가될 것이기 때문이다.&lt;/p&gt;
&lt;p&gt;“작은 것이 아름답다”라는 철학에 매료돼 있는 프로그래머의 경우 “새로 만들기” 증상은 더 심해진다. 그들은 항상 레거시 코드를 보면서 너무 복잡하다고 투덜거린다. 하지만 실질적으로 그들에게 완전히 새롭게 작성할 기회를 주었을 때 기존의 레거시 코드보다 더 효율적이고 간단한 구조의 결과물을 만들어내는 경우는 드물다. 왜냐하면 프로그래밍 문제의 복잡도는 어떠한 코딩 테크닉 보다는 문제 자체를 재정의하는 경우에 달성되는 것이기 때문이다. 따라서 기존 문제를 바라보는 시각을 유지한 체 코드만 새롭게 쓴다고 복잡도를 낮출 수 있다고 생각하는 것은 환상이다. 현실 세계에서는 복잡한 것은 복잡할 수 밖에 없다.&lt;/p&gt;
&lt;p&gt;물론 이런 모든 것을 뒤로할 록스타급 프로그래머를 모셔 왔다고 생각해보자. 이 경우에도 항상 새로 만들기를 적용할 수는 없다. 레거시 코드 자체가 워낙 방대한 경우도 있기 때문이다. 똑같은 내용을 동일하게 타이핑 하는 데에도 몇 년이 걸릴 정도로 방대한 레거시 코드 뭉치를 가지고 있다면 이를 새롭게 만드는 일은 프로그래머의 능력을 떠나 개인의 업무로 할 수 있는 작업은 아닐 것이기 때문이다. 그런 일이라면 “새로 만들기”는 또 다른 하나의 거대한 프로젝트가 되어야 할 것이다.&lt;/p&gt;
&lt;p&gt;이런 모든 상황을 고려해 볼 때에 결국 “새로 만들기”는 좋은 선택도 아니고 항상 사용할 수 있는 총알도 아니다. 언젠가 반드시 한번은 레거시 코드를 직접 수정해야 하는 일을 할 수 밖에는 없다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;레거시 코드의 본질적인 어려움&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;결국 피할 수 없는 숙명이라면 레거시 코드를 위해서 코드 리딩과 리팩토링만 열심히 공부를 해 둔다면 되는 것일까? 그렇지는 않다. 레거시 코드를 다루기 위한 기본적인 근간에 코드 리딩과 리팩토링이 있는 것은 사실이지만 레거시 코드는 이런 일반화된 원칙과는 다르게 추가적으로 고려해야 할 부분들이 있다. 이러한 것들이 코드 리딩에 충분히 익숙하다고 하더라도 레거시 코드를 다루는 일을 어렵게 만드는 실체적 허들 역할을 한다. 이제 갓 회사에 입사한 신입 프로그래머 K의 사례를 통해서 이러한 몇 가지 상황을 만나 보도록 하자.&lt;/p&gt;
&lt;p&gt;K는 회사에서 개발 중인 프로그램에서 사용하는 한 모듈의 유지 보수를 맡았다. 코드를 검토하던 도중 &amp;#x3C;리스트 1&gt;에 나와 있는 것과 같은 some_func라는 함수 코드를 보게 되었다. 함수 내부에서 전역 변수인 g_stage 값을 변경하는 것으로 K는 이후 fn1이나 fn2의 작업에 g_stage 값이 영향을 미칠 것이라는 사실을 예측했다. 하지만 실제로 살펴본 fn1과 fn2는 &amp;#x3C;리스트 2&gt;에 나타난 것과 같이 전혀 g_stage 값과는 상관이 없었다. K는 속으로 왜 이렇게 쓸데없는 코드를 추가했냐고 투덜거리며 g_stage 값을 변경하는 부분을 제거했다. 어떻게 됐을까? 아마 K가 예측할 수 없는 엄청난 일들이 벌어졌을 것이다.&lt;/p&gt;
&lt;p&gt;이 사례는 레거시 코드에서 흔히 나타나는 전형적인 예측 불가능한 사이드 이펙트를 보여주고 있다. some_func 호출로 g_stage의 값이 변경된다는 것을 우리는 사이드 이펙트라고 부른다. 그런데 이 코드는 거기서 g_stage 값이 변경되면 무슨 일이 벌어지는지를 보여주지 않는다. 신입 프로그래머들이 흔히 레거시 코드 작업을 하면서 필요 없는 부분이 많아서 제거했다고 하는 내용들이 대다수 이런 것들이다. 물론 교과서에 등장하는 정제된 순수한 세계 속에는 이러한 일이 없겠지만 현실 세계에서 이런 코드들이 비일비재하게 등장한다. 따라서 레거시 코드의 제거는 굉장히 신중하게 해야 한다.&lt;/p&gt;
&lt;p&gt;사이드 이펙트를 예측할 수 없는 코드를 보았을 때 K가 취할 수 있는 행동은 두 가지다. 하나는 g_stage 변수와 some_func의 g_stage 관련 조작을 동시에 제거하는 경우다. 이 경우에는 사이드 이펙트의 대상체가 같이 제거되는 것이기 때문에 동시에 제거해도 문제가 없다면 당초 K의 예측대로 이는 쓸모 없이 추가되어 있는 코드라고 할 수 있다. 이 경우에도 예외 상황은 존재하는데 만약 g_stage가 포함된 이 코드가 라이브러리의 일부 코드이며, g_stage가 외부에 노출된 변수라면 동시에 제거가 되더라도 제거하지 않는 편이 옳다. 왜냐하면 그 사이드 이펙트에 의존하는 외부 프로그램이 존재할 수 있기 때문이다.&lt;/p&gt;
&lt;p&gt;다른 한 가지 방법은 코드 내에서 g_stage가 하는 역할을 정확하게 조사한 후에 추후에 이 코드를 볼 사람은 K와 같은 의문을 가지지 않도록 g_stage 기능을 새롭게 디자인하는 것이다. 물론 이 경우에는 모든 코드를 면밀히 살펴 보아야 하기 때문에 즉석으로 리팩토링 작업을 하는 것은 좋지 않다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 1 사이드 이펙트를 예측할 수 없는 코드 1&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; g_stage&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;some_func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    g_stage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; STAGE_BEGIN&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; d &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fn1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fn2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;d&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    g_statge &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; STATE_END&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 2 사이드 이펙트를 예측할 수 없는 코드 2&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fn1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; a&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fn2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; a&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;K는 또 다른 레거시 코드 뭉치에서 &amp;#x3C;리스트 3&gt;과 같은 일반적인 문자열 복사 함수의 코드 구현을 만났다. 보안 관련 책을 열심히 공부했던 K는 이런 방식의 함수 디자인이 좋지 않다고 생각해서 함수를 &amp;#x3C;리스트 4&gt;에 나오는 코드와 같이 문자열 버퍼 크기를 전달 받도록 인터페이스를 수정했다. K는 이제 my_strcpy 함수를 호출하는 부분의 코드만 모두 변경하면 된다고 생각하고는 검색 작업을 했다. 중요한 보안 결함을 수정하는 것 같기도 해서 나름대로 뿌듯하기도 했다. 하지만 그 뿌듯함도 잠시였다. 실제로 이 작업이 그리 간단하지 않다는 것을 알 수 있었기 때문이었다. &amp;#x3C;리스트 5&gt;와 같은 코드가 문제였다.&lt;/p&gt;
&lt;p&gt;이 사례는 고착화된 인터페이스를 변경하는 일이 얼마나 어려운 일인지를 보여준다. 실제로 레거시 코드를 다룬 경험이 많이 없는 프로그래머들은 K처럼 인터페이스 변경을 단순한 코딩 테크닉의 변화로 생각하는 경향이 있다. 하지만 인터페이스라는 것은 단순한 코딩 테크닉 이상을 의미한다. 인터페이스란 그것을 설계한 프로그래머의 사상을 투영하는 성질이 있기 때문에 그걸 변경하는 것은 거대한 작업이 되는 경우가 많다. 이 경우에도 K가 레거시 코드에 대한 경험이 많았다면 버퍼 크기가 들어간 새로운 함수를 만들고 자신이 추가하는 코드에 대해서는 점진적으로 새로운 함수를 호출하도록 변경하는 구조로 가는 것이 좋았을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 3 일반적인 문자열 복사 함수&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;my_strcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;dst&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;src&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;r &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; dst&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;dst&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;src&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; r&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 4 버퍼 크기가 들어간 안전한 문자열 복사 함수&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;my_strcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;dst&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; size_t size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;src&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;r &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; dst&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;size_t i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;dst&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;src&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token char&quot;&gt;&apos;\0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; r&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;dst &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token char&quot;&gt;&apos;\0&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; r&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;    
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 5 버퍼 크기를 전달 받지 않는 일반 함수&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;some_func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 중요한 작업들 ...&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;my_strcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// 나머지 작업들 ...&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;마지막 사례를 살펴보자 K는 사내 공용 라이브러리를 유지 보수 하는 업무를 맡았다. 해당 코드를 살펴보던 중에 &amp;#x3C;리스트 6&gt;에 나와 있는 것과 같은 버그가 있는 백분율 계산 함수를 만났다. K는 코드를 보는 순간 100.0을 입력한다는 것이 10.00을 입력했다는 심증을 가졌다. 주석은 그런 K의 생각을 강화시켜주고 있었다. 자신의 존재감을 온몸으로 입증하려던 K는 과감하게 GetPercentage 함수 코드의 10.00을 100.0으로 수정했다.&lt;/p&gt;
&lt;p&gt;어떻게 됐을까? 안타깝게도 이후 상황은 K에게 좋지 않았다. K는 사실 버그를 고쳤지만 버그를 새롭게 만들어 버렸기 때문이다. 문제는 &amp;#x3C;리스트 7&gt;과 같은 코드가 문제였다. 기존의 공용 라이브러리를 사용하던 일부 프로그래머들은 자체적으로 잘못된 계산 결과를 보정해서 사용하고 있었던 것이다. 당연히 이 코드들은 K가 볼 수 없는 곳에서 제작된 것이기 때문에 K가 미라 알고 대처하기에는 힘든 점이 있었다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 6 타이핑 실수가 있는 백분율 계산 함수&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 백분율 계산 함수&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// 결과 = a / b * 100&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CalcPercentage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10.00&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 7 버그가 있는 GetPercentage 함수의 결과를 보정하는 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt; r &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetPercentage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이는 전형적인 레거시 코드의 버그 수정이 가져오는 파급 효과를 나타낸 것이다. 작위적인 것처럼 보이지만 우리 나라 회사의 소스 코드에서 흔하게 벌어지는 풍경이다. 정치가 코드에 개입해 버린 것이다. 결과를 보정해서 사용하는 프로그래머 입장에서는 결과를 보정하거나 자신만의 라이브러리를 만드는 비용보다 GetPercentage 함수를 만든 사람에게 버그 수정을 요청하는 비용이 비교도 되지 않게 높았던 것이다.&lt;/p&gt;
&lt;p&gt;그렇다면 똑똑한 K라면 어떻게 해야 했을까? 버그가 수정된 GetPercentage2 함수를 만들고 외부에 GetPercentage 버그가 수정된 GetPercenage2 함수가 만들어졌음을 알린다. 그리고 헤더에는 GetPercentage 함수는 버그가 있으니 사용하지 말라는 경고를 출력하는 안전 장치를 추가해 놓는 것이 좋겠다.&lt;/p&gt;
&lt;p&gt;결국 레거시 코드 작업이 코드 리딩과 리팩토링 이상의 경험이 필요한 이유는 부분을 통해서 전체를 유추해야 함에 있다. 레거시 코드를 다룰 때에 우리는 항상 전체를 다 볼 수 없다. 또한 레거시 코드들은 그들이 살아남은 역사만큼이나 다양한 장치들을 통해서 다른 컴포넌트들과 인터페이싱하고 있다는 점을 항상 염두에 두어야 한다. 그렇기 때문에 레거시 코드에 대한 수정은 가급적 작고 사소한 부분부터 점진적으로 이루어져야 한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;레거시 코드를 다루는 전략&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;레거시 코드를 다루는 기본 전략은 너무나 간단하다. 컴퓨터 공학에서 어려운 문제를 풀 때 항상 등장하는 분할 정복법이다. 거대한 레거시 코드를 한번에 모두 다루기는 힘들기 때문에 그걸 작은 문제들로 분할해서 점진적으로 정복해 나가는 것이다.&lt;/p&gt;
&lt;p&gt;분할 정복에서도 레거시 코드를 다룰 때에 가장 중요한 부분은 분할이다. 분할이란 결국 어떤 부분을 수정할지를 선택하는 것이고 그 문제를 거대한 레거시 코드에서 독립적인 부분으로 떼어내야 함을 의미한다. 우리가 수정할 부분이 거대한 시스템에 대해서 완전하게 독립적일 수 있도록 만드는 작업에서 시작해야 한다.&lt;/p&gt;
&lt;p&gt;예를 들어 앞선 &amp;#x3C;리스트 1&gt;에 나오는 some_func 함수의 경우에는 g_stage라는 부분이 의존적이기 때문에 바로 수정하는 것은 좋지 않다. 이 경우에 fn1과 fn2를 호출하는 로직에 변경을 가하고 싶은 경우라면 &amp;#x3C;리스트 8&gt;에 나와 있는 것과 같이 그 부분을 별도로 떼어내서 독립적으로 만든 다음 작업하는 것이 좋다. 이렇게 떼어내게 되면 some_func2 함수는 기존의 레거시 코드와는 완전히 독립적인 코드가 된다. 별도로 테스트 할 수도 있으며 기존 코드와 결과값을 비교하는 테스트를 작성할 수도 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 8 fn1, fn2 호출 로직 분리&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;some_func&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    g_stage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; STAGE_BEGIN&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;some_func2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    g_statge &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; STATE_END&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;some_func2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; d &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fn1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fn2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;d&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;앞서도 말했지만 레거시 코드에 대한 변화는 작고 사소한 부분부터 점진적으로 이루어져야 한다는 점을 반드시 기억하자. 이는 레거시 코드에 대한 변화는 없을수록 기존 동작 방식을 잘 유지할 수 있다는 것을 의미한다.&lt;/p&gt;
&lt;p&gt;예를 들어 우리가 해야 하는 일이 기존에 C로 만들어진 &amp;#x3C;리스트 9&gt;와 같은 코드를 클래스로 변환하는 작업이라고 생각해 보자. 이 경우에도 기존 코드들을 해체해서 클래스로 변환시키기 보다는 &amp;#x3C;리스트 10&gt;에 나타난 것처럼 기존 함수를 호출하는 래퍼 클래스를 만드는 것이 좋다. 기존 코드를 해체해서 새로 만드는 경우에는 수정 작업이 많은 만큼 실수할 여지도 늘어나지만 이렇게 래퍼 클래스를 만드는 경우에는 기존 코드가 하는 역할을 래퍼 클래스도 100% 동일하게 수행할 수 있기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 9 리비전 리스트를 관리하는 레거시 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HANDLE &lt;span class=&quot;token function&quot;&gt;CreateRevisionList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;CloseRevisionList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE h&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
BOOL &lt;span class=&quot;token function&quot;&gt;AddFileToRevisionList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE h&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCWSTR path&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ULONG revision&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
BOOL &lt;span class=&quot;token function&quot;&gt;DeleteFileFromRevisionList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE h&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCWSTR path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 10 리비전 리스트 래퍼 클래스&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RevisionList&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    HANDLE revlist_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CreateRevisionListError&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;RevisionList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
        revlist_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateRevisionList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;revlist_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateRevisionListError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;RevisionList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;CloseRevisionList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;revlist_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    BOOL &lt;span class=&quot;token function&quot;&gt;AddFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPCWSTR path&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ULONG revision&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AddFileToRevisionList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;revlist_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reivison&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    BOOL &lt;span class=&quot;token function&quot;&gt;DeleteFil&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPCWSTR path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DeleteFileFromRevisionList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;revlist_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;오래된 미래&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;레거시 코드란 우리가 지금 쓰고 있는 무수히 많은 코드의 오래된 미래다. 우리가 지금 쓰고 있는 코드가 오랜 시간 동안 살아 남는다면 미래의 언젠가는 똑같이 레거시 코드가 될 수 밖에 없을 것이기 때문이다. 레거시 코드가 없는 신생 프로젝트도 마찬가지다. 프로젝트 기간이 길어지고 코드가 늘어나고 하다 보면 미래의 어느 순간에는 반드시 레거시 코드가 생겨날 수 밖에 없다.&lt;/p&gt;
&lt;p&gt;‘레거시 코드는 다루기 힘들고 성가신 코드’라는 인식을 이제는 조금 바꿀 필요가 있을 것 같다. 레거시 코드는 항상 우리 주변에 있고, 다른 코드보다 조금 더 우리의 관심을 필요로 하는 코드일 뿐이다. 그러니 이제 쓰레기통에 버릴 궁리만 하기 보다는 레거시 코드를 이해하려는 마음가짐을 가지도록 하자. 어쩌면 레거시 코드를 다루는 가장 위대한 방법은 열린 마음가짐으로 그 코드를 꺼내서 읽고, 또 읽는 것에 있는지도 모른다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;내게 나무를 자를 8시간이 있다면, 나는 도끼를 가는데 6시간을 쓰겠다.&lt;/p&gt;
&lt;p&gt;– 아브라함 링컨&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[Vista 이상 시스템에 TDI 포팅 시 주의할 점]]></title><description><![CDATA[MS에서 Vista 이상부터 TDI 지원을 끊겠다고 했으나 Windows 8까지 TDI는 여전히 지원되고 있습니다. 하위호환성을 그렇게 쉽게 끊진 못하죠 ㅋ~ 몇 해 전 만들었던 TDI 클라이언트 드라이버가 Vista…]]></description><link>https://jiniya.net/wp/archives/11424</link><guid isPermaLink="false">https://jiniya.net/wp/archives/11424</guid><pubDate>Tue, 25 Jun 2013 23:59:00 GMT</pubDate><content:encoded>&lt;p&gt;MS에서 Vista 이상부터 TDI 지원을 끊겠다고 했으나 Windows 8까지 TDI는 여전히 지원되고 있습니다. 하위호환성을 그렇게 쉽게 끊진 못하죠 ㅋ~ 몇 해 전 만들었던 TDI 클라이언트 드라이버가 Vista 이상에서 동작하지 않는다고 해서 오늘 디버깅을 좀 했습니다. 별거 아닌 곳에서 삽질을 좀 해서 기록을 남겨 놓습니다. 우선 문제는 다른 건 다 잘 되는데 이상하게 TdiConnectionContext만 하면 STATUS_INVALID_PARAMETER가 떨어지는 문제였습니다. 아래와 같은 코드에서 ZwCreateFile이 성공하지 못하는 상황이었죠.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MY_KERNEL_SOCKET&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;scoket&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
NTSTATUS status&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
IO_STATUS_BLOCK iosb &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
PFILE_FULL_EA_INFORMATION ea&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

UNICODE_STRING name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
OBJECT_ATTRIBUTES oa&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;RtlInitUnicodeString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;\\Device\\Tcp&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;InitializeObjectAttributes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;oa
                              &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;name
                              &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; OBJ_CASE_INSENSITIVE &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; OBJ_KERNEL_HANDLE
                              &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
                              &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

ea &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ExAllocatePool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;ea&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; STATUS_INSUFFICIENT_RESOURCES&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

ea&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;EaNameLength &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TDI_CONNECTION_CONTEXT_LENGTH&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
ea&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;EaValueLength &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;socket&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;RtlCopyMemory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ea&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;EaName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TdiConnectionContext&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ea&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;EaNameLength&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;RtlCopyMemory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;ea&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;EaName&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ea&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;EaNameLength &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; socket&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;socket&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


status &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ZwCreateFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;cfh
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; GENERIC_READ &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; GENERIC_WRITE &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; SYNCHRONIZE
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;oa
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;iosb
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FILE_ATTRIBUTE_NORMAL
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FILE_OPEN_IF
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ea
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ea_len&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;NT_SUCCESS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;status&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 요기서 STATUS_INVALID_PARAMETER 발생&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; status&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;처음에 별거 아닌 문제로 보여서 그냥 구글링을 했는데, 저같은 이슈를 겪는 사용자가 의외로 없더군요. 질문은 올라와 있는데 그냥 해결됐다 고맙다 이런 답변만 있는… ㅠㅜ~ 삽질을 좀 하다 문제가 해결이 안 돼서 tdx.sys 드라이버 파일을 열었습니다. 그제야 답이 보이더군요. Windows XP까지는 TDI를 tcpip.sys에서 처리했으나, Vista 부터는 tdx.sys에서 처리하고 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 595px; margin-bottom: 16px;&apos; data-url=&apos;./Vista_이상_시스템에_TDI_포팅_시_주의할_점.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/0f3aab139b2cf31c9939ef779b04d17f/5acb4/Vista_%EC%9D%B4%EC%83%81_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%97%90_TDI_%ED%8F%AC%ED%8C%85_%EC%8B%9C_%EC%A3%BC%EC%9D%98%ED%95%A0_%EC%A0%90.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 16.315789473684212%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAIAAAAcOLh5AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAkUlEQVR42k3LSw6CMBSFYfa/CDehJiV1GYQIRCRcTTBp9d4CRejLdqDxH5zJyZdxfmIsF0KEEJzzcaXUbfs0xjWNLIpH3Qy3+wYQ1tWOoyIipRQiaq0zzo95fpAyYe8TRly6Dud5i7iq8ArTullj0uu+WWvjRlwzdhZi+mGid98jAJXlaxguRDuAvTFLSPnw1wf9OqbQyAlpsQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Vista         TDI            md 0&apos; title=&apos;&apos; src=&apos;/static/0f3aab139b2cf31c9939ef779b04d17f/5acb4/Vista_%EC%9D%B4%EC%83%81_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%97%90_TDI_%ED%8F%AC%ED%8C%85_%EC%8B%9C_%EC%A3%BC%EC%9D%98%ED%95%A0_%EC%A0%90.md_0.png&apos; srcset=&apos;/static/0f3aab139b2cf31c9939ef779b04d17f/08678/Vista_%EC%9D%B4%EC%83%81_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%97%90_TDI_%ED%8F%AC%ED%8C%85_%EC%8B%9C_%EC%A3%BC%EC%9D%98%ED%95%A0_%EC%A0%90.md_0.png 190w,
/static/0f3aab139b2cf31c9939ef779b04d17f/2edd7/Vista_%EC%9D%B4%EC%83%81_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%97%90_TDI_%ED%8F%AC%ED%8C%85_%EC%8B%9C_%EC%A3%BC%EC%9D%98%ED%95%A0_%EC%A0%90.md_0.png 380w,
/static/0f3aab139b2cf31c9939ef779b04d17f/5acb4/Vista_%EC%9D%B4%EC%83%81_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%97%90_TDI_%ED%8F%AC%ED%8C%85_%EC%8B%9C_%EC%A3%BC%EC%9D%98%ED%95%A0_%EC%A0%90.md_0.png 595w&apos; sizes=&apos;(max-width: 595px) 100vw, 595px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;TdiConnectionContext 인지를 검사하는 루틴&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 443px; margin-bottom: 16px;&apos; data-url=&apos;./Vista_이상_시스템에_TDI_포팅_시_주의할_점.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/192d1cbebd01be28e2bae89863bebc71/4d697/Vista_%EC%9D%B4%EC%83%81_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%97%90_TDI_%ED%8F%AC%ED%8C%85_%EC%8B%9C_%EC%A3%BC%EC%9D%98%ED%95%A0_%EC%A0%90.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 32.631578947368425%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAIAAACHqfpvAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABMUlEQVR42mWP23KCMBCGef/3ccqFqIOMGjsKxXAohIMSRSCcpGMtKHSV1ot2Z+fPv7v5ZhNOkkYISeu1rarb6dQcjfTjMcnzrCiKqjqlaVqWJZhHltCEkmUMbzUe8xxCsSxHhDiWZRFiQ0KAYmxh/GN0ncjyO0LY93aU0iAIPM9zicsNBsp4jJvm2nVd23YPvR+Ok2laDIbS0jAYlK/L0Kb0VBck2n5evmDECcLLYjFt21v3G09YVSMwh0Nlmolts8VsL2orcS9I/syK3bw4c8OhgNCyaZo/8G5XGEbSw4pydN1Mw4nqOMOlzNgZ+rdby/E8P5lM6rp+Yr0GQQnLwYRhJcshwIbOVqbNS28svvTXOFEU5/P5/83wu83m/uwo+lCU0Pdz02CaTVeal6U93H0DZMB5pFfdCoAAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Vista         TDI            md 1&apos; title=&apos;&apos; src=&apos;/static/192d1cbebd01be28e2bae89863bebc71/4d697/Vista_%EC%9D%B4%EC%83%81_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%97%90_TDI_%ED%8F%AC%ED%8C%85_%EC%8B%9C_%EC%A3%BC%EC%9D%98%ED%95%A0_%EC%A0%90.md_1.png&apos; srcset=&apos;/static/192d1cbebd01be28e2bae89863bebc71/08678/Vista_%EC%9D%B4%EC%83%81_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%97%90_TDI_%ED%8F%AC%ED%8C%85_%EC%8B%9C_%EC%A3%BC%EC%9D%98%ED%95%A0_%EC%A0%90.md_1.png 190w,
/static/192d1cbebd01be28e2bae89863bebc71/2edd7/Vista_%EC%9D%B4%EC%83%81_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%97%90_TDI_%ED%8F%AC%ED%8C%85_%EC%8B%9C_%EC%A3%BC%EC%9D%98%ED%95%A0_%EC%A0%90.md_1.png 380w,
/static/192d1cbebd01be28e2bae89863bebc71/4d697/Vista_%EC%9D%B4%EC%83%81_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%97%90_TDI_%ED%8F%AC%ED%8C%85_%EC%8B%9C_%EC%A3%BC%EC%9D%98%ED%95%A0_%EC%A0%90.md_1.png 443w&apos; sizes=&apos;(max-width: 443px) 100vw, 443px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;점프하면 이곳으로 옵니다. EaValueLength가 4인지를 검사하고 있습니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 621px; margin-bottom: 16px;&apos; data-url=&apos;./Vista_이상_시스템에_TDI_포팅_시_주의할_점.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/faa8fbf89a4c095e65dd0c57462aaaaf/41b39/Vista_%EC%9D%B4%EC%83%81_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%97%90_TDI_%ED%8F%AC%ED%8C%85_%EC%8B%9C_%EC%A3%BC%EC%9D%98%ED%95%A0_%EC%A0%90.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 26.31578947368421%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAIAAADKYVtkAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAA8ElEQVR42lWO0WqDMABF/f//aIcvYyjSNl3ZRMf2Mpib0spqNY1ZYq3GGrFJwGY+yXYeLhcuB64BADBN03GcsZRlqbUehtuYRdERwjkX2235/snihA+DzrI+SS6ct03TdF1nLBbL+fzOsmwA1nVdTzKlHYSMseH1jVN20fo2ypzrttUThus+2vb9ZrP0vCdKiVKq73ulBCEMwnNV8Sg6hV/k2gulpJRCyuuE4XkIAOS6yPfRfo/yHB2PCON8t0vjODscYBAkL370naaEEozxuE6Mt59nswfLWq9WblWxv7cxbjmXYXgKPgp4/umF0P/5BTbwCz+rAn2UAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Vista         TDI            md 2&apos; title=&apos;&apos; src=&apos;/static/faa8fbf89a4c095e65dd0c57462aaaaf/41b39/Vista_%EC%9D%B4%EC%83%81_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%97%90_TDI_%ED%8F%AC%ED%8C%85_%EC%8B%9C_%EC%A3%BC%EC%9D%98%ED%95%A0_%EC%A0%90.md_2.png&apos; srcset=&apos;/static/faa8fbf89a4c095e65dd0c57462aaaaf/08678/Vista_%EC%9D%B4%EC%83%81_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%97%90_TDI_%ED%8F%AC%ED%8C%85_%EC%8B%9C_%EC%A3%BC%EC%9D%98%ED%95%A0_%EC%A0%90.md_2.png 190w,
/static/faa8fbf89a4c095e65dd0c57462aaaaf/2edd7/Vista_%EC%9D%B4%EC%83%81_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%97%90_TDI_%ED%8F%AC%ED%8C%85_%EC%8B%9C_%EC%A3%BC%EC%9D%98%ED%95%A0_%EC%A0%90.md_2.png 380w,
/static/faa8fbf89a4c095e65dd0c57462aaaaf/41b39/Vista_%EC%9D%B4%EC%83%81_%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%97%90_TDI_%ED%8F%AC%ED%8C%85_%EC%8B%9C_%EC%A3%BC%EC%9D%98%ED%95%A0_%EC%A0%90.md_2.png 621w&apos; sizes=&apos;(max-width: 621px) 100vw, 621px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;64비트 운영체제의 tdx.sys, EaValueLength가 8인지를 검사하고 있습니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;결론만 말하면 TdiConnectionContext의 EA Value로는 항상 포인터 크기의 핸들만 전달해야 합니다. XP에서는 이런 체크가 없어서 정상적으로 동작했던 것 같네요. 헐~ 아래는 MSDN 전문입니다. 교과서를 열심히 봐야 삽질이 없습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For a connection endpoint, the EaName member is set to the system-defined constant TdiConnectionContext and &lt;strong&gt;the EA value following the EaName array is a client-supplied handle, opaque to the transport driver.&lt;/strong&gt; The transport must save this handle and subsequently pass it back to the client’s registered event handlers for this connection.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/hardware/ff565046(v=vs.85).aspx&quot;&gt;http://msdn.microsoft.com/en-us/library/windows/hardware/ff565046(v=vs.85).aspx&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이거 말고는 기존 XP 소스를 특별히 변경하지 않아도 잘 동작했습니다. 당연한 거겠지만 ㅋㅋ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[전략 서신: API 후킹을 할 때에 생각해야 할 것들…]]></title><description><![CDATA[안녕. 오늘은 너희들을 위해서 API 후킹이란 기술에 대해서 좀 써볼까 해. 물론 이 글은 API 후킹이 뭐지, 점프 코드를 어떻게 만들지, 트램펄린은 뭐지, 따위를 고민하는 초보 프로그래머를 위한 글은 아니야. 이 글은 적어도 실무에서 API…]]></description><link>https://jiniya.net/wp/archives/11276</link><guid isPermaLink="false">https://jiniya.net/wp/archives/11276</guid><pubDate>Mon, 17 Jun 2013 23:58:59 GMT</pubDate><content:encoded>&lt;p&gt;안녕.&lt;/p&gt;
&lt;p&gt;오늘은 너희들을 위해서 API 후킹이란 기술에 대해서 좀 써볼까 해. 물론 이 글은 API 후킹이 뭐지, 점프 코드를 어떻게 만들지, 트램펄린은 뭐지, 따위를 고민하는 초보 프로그래머를 위한 글은 아니야. 이 글은 적어도 실무에서 API 후킹 코드를 한번쯤은 짜 본 프로그래머를 위한 글이야. API 후킹 코드가 뭐 대단한게 있냐고? 없지. 없는데도 잘 모르는거 같아서 내가 몇 자 적어볼까 해. 니가 뭔데 이 따위 건방진 글을 쓰냐고? 그래. 맨날 버그만 만드는 내가 이런 글을 쓸 자격이 있는지 모르겠다. 그래도 훅 코드를 작성해 본 경험도 많고, 관련 검색어에 후킹도 나오고 하는걸로 봐서 한번 정도는(!?) 주제넘게 이런 이야기를 해도 되지 않을까란 생각이 들어서 감히 몇 자 끄적여 보려고 해.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 430px; margin-bottom: 16px;&apos; data-url=&apos;./전략_서신_API_후킹을_할_때에_생각해야_할_것들.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/83315f3f997fe6f225330ea2a2e22ce4/bc750/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 5.7894736842105265%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAABCAIAAABR8BlyAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAARklEQVR42g3IMQ6AIAwAQP//PEWIIK3oYKAsakpJ46A33kBEAMD82KXFTQLIdb+49xXFR8lFjWsB5cxaqv45WR5nNo7T0T96ojY7D/QZGgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;      API                    md 0&apos; title=&apos;&apos; src=&apos;/static/83315f3f997fe6f225330ea2a2e22ce4/bc750/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_0.png&apos; srcset=&apos;/static/83315f3f997fe6f225330ea2a2e22ce4/08678/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_0.png 190w,
/static/83315f3f997fe6f225330ea2a2e22ce4/2edd7/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_0.png 380w,
/static/83315f3f997fe6f225330ea2a2e22ce4/bc750/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_0.png 430w&apos; sizes=&apos;(max-width: 430px) 100vw, 430px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;시작하기에 앞서 먼저 밝히는데 이 이야기는 절.대.로. 너희에게 뭐라고 하는 건 아니니까 오해하지 않았으면 좋겠어. 너희가 무슨 죄가 있겠니. 후킹 라이브러리 하나 안 사주는 사장님이 잘못된 거지. 또 돈 안 된다고 위험한 모듈에 학교 갓 졸업한 인턴 투입하는 사장님이 잘못된 거지. 그런 악덕 사장님 덕에 나중에도 이런 위험천만한 기능을 별 생각 없이 만들 수많은 미래 보안 프로그래머를 위해서 쓰는거니까 절대 오해하지 않았으면 좋겠다. 나도 맨날 버그만 싸질러서 지원팀한테 엄청 미움받고 있어 ㅋㅋㅋ~ 돈 벌면 진짜 QA 해줄 테스트 프로그래머 한 명 뽑아야지 ㅠㅜ~ 눈물 좀 닦고, …&lt;/p&gt;
&lt;p&gt;이 이야기의 시작은 크래시 덤프에서 출발해. 오늘 크래시 덤프를 하나 받았어. 너희들도 보안 업체에서 일하니까 크래시 덤프가 얼마나 토나오는 말인지는 알지? 너네 문제가 아닌 크래시 덤프 파일을 얼마나 많이 접했니? 아마 수도 없이 많을거야. 매일 다른 업체 버그를 수정하는 코드를 만드느라 고생하는 것도 잘 알고 있어. 내가 만든 버그 수정하랴, 다른 사람 버그 수정하랴, 충돌 피하랴. 고생이 이만저만이 아니지 정말. 어쨌든 그 크래시 덤프는 원인이 이랬어.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;0:000&gt; u ntdll!ZwOpenProcess&lt;br&gt;
&lt;br&gt;
ntdll!ZwOpenProcess:&lt;br&gt;
&lt;br&gt;
7709fc00 e9bb223000 jmp 773a1ec0&lt;br&gt;
&lt;br&gt;
7709fc05 33c9 xor ecx,ecx&lt;br&gt;
&lt;br&gt;
7709fc07 8d542404 lea edx,[esp+4]&lt;br&gt;
&lt;br&gt;
7709fc0b 64ff15c0000000 call dword ptr fs:[0C0h]&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;0:000&gt; u 773a1ec0&lt;br&gt;
&lt;br&gt;
773a1ec0 ?? ???&lt;br&gt;
&lt;br&gt;
^ Memory access error in ‘u 773a1ec0′&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;너네도 알겠지만 부연 설명하면 점프 코드를 잘못 싸지른 게 원인인거지. 왜 아무도 안 건드리는 ZwOpenProcess가 저리도 어설프고 불완전하게 후킹됐을까 엄청 고민했어. 처음엔 악성 코드에 감염된 건 줄 알았어. 흔하게 중2병 학생이 코딩한 악성 코드에는 저런 버그는 수도 없이 많잖아. 그런데 안타깝게도 그 PC는 클린한 우리 테스트 PC 였거든. 물론 테스트 PC도 악성 코드에 감염될 수는 있어. 하지만 정말 아쉽게도 그 프로세스엔 다른 훅 코드가 몇 개 더 있었고, 그 모듈 정보를 통해서 난 저 훅 코드가 악성 코드가 아닌 너네가 만든 훅 코드라는 걸 알 수 있었어. 실제로 문제는 e9bb2233다음에 89가 기록돼야 하는데 89가 기록돼지 못한 것이 원인이었거든. 그 번지에 89가 기록됐으면 안전하게 너네 훅 코드로 점프가 이루어졌을거야.&lt;/p&gt;
&lt;p&gt;왜 이런 상황이 벌어졌는지 보기 위해서 본의 아니게 너네 모듈을 좀 살펴봤어. 요약하면 그 모듈은 WH_CBT 훅을 설치해서 훅 루틴에서 몇 개의 API를 후킹하는 모듈이었어. 그런데 내가 보기에 너네가 사용하는 API 훅 설치 코드에 조금 문제가 있다는 생각이 들었어. 내가 왜 그렇게 생각했는지 코드를 보면서 설명하는 시간을 조금 가져보도록 할께.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 598px; margin-bottom: 16px;&apos; data-url=&apos;./전략_서신_API_후킹을_할_때에_생각해야_할_것들.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/089db8614e37149e0b09527e04fff060/02e46/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 54.21052631578947%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABvElEQVR42mVSbW/aMBDmb+/rfsS2HzJNQiBgWRdI2o6VjlakaGQkITFxEkLs+N2eCRNl6ul0fpGfu+eec284HDqOA0CdpigIYJ63hIg8x1JJJpgxRmtt4xZWT3GUNBHEMDyEcR0DBHqe57muSwi5vEvT5iUoKBNRcmBEykqbwuQr3ZSme2Mu1huNRrYy59welFI2AoDW6wIjvviVVX9a+UMb35i10Sdg5/rfpve5M4yRTaqUOFe24LYVd3c7bxbf3+/qmpasZLLr4pLCgieTiaXN2Gt7ELYWz7l8eMjiuF4F0PeTII6EFuZ/602nru/PIfwC4ccw/FSW32yGM3+lLBctpF0MYmiPQdqkFalszFB2EmwwGIzHXw+HDaUvx+NKiByANo6PtrIlv16XTwHIihoxjFnbckwFbViDObZ+6rnf71+rnSTHn/OMULZNCsF0exCkoVGo9uCN2jc332czj9K2E0zaq7Ikm03VYvF7U9Gcy1CZSHNglD5jrwRzXef2dsYYvRIMb7c1Y3K53M/n2XJZIMSxbIR6I5jjxNPpzg7mArbfy46aEO77+fPzeLF4583eP24+UCk7yCvvv55rZULirrlpAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;      API                    md 1&apos; title=&apos;&apos; src=&apos;/static/089db8614e37149e0b09527e04fff060/02e46/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_1.png&apos; srcset=&apos;/static/089db8614e37149e0b09527e04fff060/08678/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_1.png 190w,
/static/089db8614e37149e0b09527e04fff060/2edd7/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_1.png 380w,
/static/089db8614e37149e0b09527e04fff060/02e46/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_1.png 598w&apos; sizes=&apos;(max-width: 598px) 100vw, 598px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;STEP 1: 훅 대상 코드 추적 부분, 0xe9 루프를 추적하는 루프&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;너네가 작성한 훅 설치 루틴은 크게 세 부분으로 돼 있는데 여기가 그 첫번째 부분인 훅 대상 코드 추적 부분이야. 후킹하려고 하는 NtOpenProcess에 이미 다른 훅이 설치돼 있으면 해당 주소로 점프한 곳을 계산해서 다시 그곳에 점프 코드가 있는지 점검하는 코드로 구성돼 있어. 그런데 여기서 재미난 사실은 아무 생각없이 0xe9를 찾고 있다는 점이야. 무한 루프를 추적하게되면 너네도 같이 무한 루프에 빠진다는 함정이 있어. 쉽게는 “jmp $(e9 fbffffff)” 같은 코드를 들 수 있겠지. 조금 더 영리했다면 루프를 탐지할 수 있도록 이미 스캔한 주소를 목록에 보관하고 비교를 했어야 하는게 아닌가 싶어.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 597px; margin-bottom: 16px;&apos; data-url=&apos;./전략_서신_API_후킹을_할_때에_생각해야_할_것들.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/27a43dbd86251126ac3547f4e04c4e7a/f523d/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 43.15789473684211%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABc0lEQVR42lWRb2/aMBDG8/2/ChLvhrRKtCDGpFQrVf9AlgZKDMaOQ+MkxHMSO/bNBbFmzwvrLN1Pzz133s3N9/2eMSbD8AOhQimTMKFaw2suVW06qzvdduoV4Z9L9IzQUbIoW+/KHTkRbzKZZFkGANZa93adXa1Src0GHSk7xTjfC3wok5RagkGc4NwJF3nj8Zix1FXGmAu8WJCqalFcVB8NaIAarIIogsUDUPpJ2ovAeoPBAGP8z9l5+v6h60ywyuNfMrgtf/v76I1sWPKK3jMum6aDq7zRaNQf28FPT4n7oVj9WO4eNoRxQ1NzIBrhnHPJef0Fz+fzsix7mQ0hlSsYFWsabxP8R1W8Tiudi0bC//JmsxnnvL+wx0dS13q7LY6pzHlTylMm8peo8F2KAMIQ2vYKD4dDd6j+2Ld372WuXuL1koTnHutWee/D6Bu8RXCOeIWn02nf2RgbBEcpNcaFiBs4ABCwFLIUCAUhvu4EAH8BTQ34RhQ5BR8AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;      API                    md 2&apos; title=&apos;&apos; src=&apos;/static/27a43dbd86251126ac3547f4e04c4e7a/f523d/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_2.png&apos; srcset=&apos;/static/27a43dbd86251126ac3547f4e04c4e7a/08678/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_2.png 190w,
/static/27a43dbd86251126ac3547f4e04c4e7a/2edd7/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_2.png 380w,
/static/27a43dbd86251126ac3547f4e04c4e7a/f523d/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_2.png 597w&apos; sizes=&apos;(max-width: 597px) 100vw, 597px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;STEP 2: VirtualProtect를 사용해서 대상 코드의 프로텍션 속성 변경 부분&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;다음으로 VirtualProtect를 이용해서 점프 코드를 삽입할 위치에 프로텍션 모드를 변경하는 코드야. 여기에는 큰 문제는 없어 보이는데 뒤쪽 부분과 결부하면 한가지 아쉬운 점은 VirtualProtect로 변경한 속성을 원복하지 않고 있다는 점이야. 왜 이전 프로텍션 속성으로 다시 변경을 하지 않는지 모르겠어. 다양한 환경을 접하면 알게 되겠지만 CRT에 포함된 일부 코드 중에서도 페이지 속성을 체크하는 코드도 있어. 그런 코드는 PAGE_EXECUTE_READWRITE 따위와 같이 코드에 WRITE 속성이 걸려 있으면 체크해서 오류를 토해내거든. 그러니까 변경한 속성은 꼭 다시 원복시켜 주도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 591px; margin-bottom: 16px;&apos; data-url=&apos;./전략_서신_API_후킹을_할_때에_생각해야_할_것들.md_3.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ef6a27081233d7b45b88cbe953eb4266/c1f10/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 71.05263157894737%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAIAAACgpqunAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACe0lEQVR42nVTW08TQRTeH2aMT8YC5VJU8Kf44E/gwUQfDNGYaPDBh2oADdCWdtsu7NZaeqFsC3Tpbne71+7O3rtXpywGTGRycnJm5nzfNzPnDLK9vZ3P51hWVBSHoiaq6kATRTMM47MuuOTEsaLKwJSAOtJGLBhrrsbqrGAKvMEj5XIZx3Fd1+M4jqIIelm2OU6fTqNGwzxpBY0Tv9WKaoR9NZhe9IFleteZ0MUIihZx/MgwZmA/CKAXRYOmVc/3SVKgBoAdOY4bGWZoO4FuOC5kjcNoBo+Qb9mdg/1DTQMQFoYzQoY2+j01CCICF1tNpXcux/cMZK/0HiW2BFA3AxJMT+2IpMZ1ckhozinRRpuXaHtQndgdxW2qbgd4Z5rXnoYJXYTk6VSBmasIK0fyamJVIVPhV6pipsAslbjlIruEchlUWMakVVxeq0gp1s7OoHGA/Ow/3r9MYcJzXF7HpXVCeVHmnhWZp8fSWo7K5OnlHJPOs4tFbgUVIMVqkU+x1vcb8E7/wY+Lhyg/V5UWq1Iak9NFbj7PpCriQo5+csjOo/wCXIe7mLRYEdOHwiPG+vpXGX+5X39FSpsj58vQ/My6W53xhwa9CeNS501t/LotvmvKb2viBiFsUOanofUReKfX4BApl47qv1qWZd/WWXI51vb9qEcCTtRl1VFsfWIaXuAnCbevfXCwd3yMmZYBJ0E4q/OI1c4vJBjXf4+ogdqj6SFsJ8tK1JIi34Cz2ezu7i4Ad+rMgG5Xmk6DbldMjvOv3h3lQqFQKpWS9kzAgmBeXameF/Z6Ms+bkOVa8z8ECIZhtVrNtm/vPJnYg8EEdhj8Hr4f3Ksbx38AIY3cFJFvPLEAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;      API                    md 3&apos; title=&apos;&apos; src=&apos;/static/ef6a27081233d7b45b88cbe953eb4266/c1f10/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_3.png&apos; srcset=&apos;/static/ef6a27081233d7b45b88cbe953eb4266/08678/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_3.png 190w,
/static/ef6a27081233d7b45b88cbe953eb4266/2edd7/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_3.png 380w,
/static/ef6a27081233d7b45b88cbe953eb4266/c1f10/%EC%A0%84%EB%9E%B5_%EC%84%9C%EC%8B%A0_API_%ED%9B%84%ED%82%B9%EC%9D%84_%ED%95%A0_%EB%95%8C%EC%97%90_%EC%83%9D%EA%B0%81%ED%95%B4%EC%95%BC_%ED%95%A0_%EA%B2%83%EB%93%A4.md_3.png 591w&apos; sizes=&apos;(max-width: 591px) 100vw, 591px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;STEP 3: 훅 코드를 덮어쓰는 부분&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;여기가 핵심이야. 특히 연두색으로 표시한 저 부분이 코드를 덮어쓰는 부분인데 내가 크래시 덤프에서 보았던 실패 원인이 여기에 있는 것 같기도 해. mov [eax], ecx라는 부분이 완전하게 이루어지지 못한 거지. 어떤 이유에서였든 말이야.&lt;/p&gt;
&lt;p&gt;자 이제 너네가 작성한 훅 코드를 살펴밨으니 내가 아쉬운 몇 가지 부분을 감히(?!) 언급해 보는 시간을 좀 가져볼까 해. 아마 너네가 다음번 훅 설치 루틴을 작성할 때에는 크게 도움이 될거야. 이런 복잡한 부분을 고려하기 힘들다면 그냥 상용 훅 설치 라이브러리를 사서 쓰길 바래. 그건 그래도 이런 초보적인 방식 보다는 좀 더 다양한 처리가 돼 있거든.&lt;/p&gt;
&lt;p&gt;어쨌든 한번 시작해볼께. 첫 번째는 너네는 함수 도입부가 무조건 5바이트라는 가정을 하고 있어. 왜지? 함수 코드는 너네처럼 변경하는 놈들이 아주 많을 수 있거든. 그리고 너네만 후킹하라고 만들어 놓은 부분도 아니잖니? 그런데 왜 5바이트에 꼭 맞춰져 있을거라는 가정을 하는 거지. “mov edi, edi” 같은 코드를 넣어서 윈도우가 API 도입부를 5바이트로 맞춘 것도 그리 오래되지 않았어. 핫패칭 재미를 쏠쏠하게 보기 시작하면서 넣기 시작한 거거든. 가까운 윈도우 2000만해도 그렇지 않은 함수들이 많이 있어. 그러니까 다음부터 훅 설치 루틴을 작성할 때에는 코드 길이를 계산하는 부분을 반드시 넣어 주면 좋겠어. 그러면 가변적인 코드도 안전하게 후킹할 수 있게 될거야.&lt;/p&gt;
&lt;p&gt;두 번째는 너네 훅 설치 코드에는 재배치 코드가 빠져있어. 그냥 단순히 원본을 카피하는데 그 원본에 상대주소 호출(e8), 쇼트 점프(eb) 같은 코드가 있으면 복사한 지점에서는 제대로 동작을 하지 않겠지. 왜냐하면 호출하는 지점 주소가 바꼈으니까 말이야. 그러니까 코드를 복사하고 나면 반드시 원본 코드에 상대 주소를 사용하는 부분이 있는지를 체크해서 주소를 새로 계산해 줘야해. eb 같은 경우에는 점프 주소가 변경되면 오프셋으로 사용할 공간이 모자랄수도 있거든. 그럴 경우에는 e9같은 걸로 확장시키는 방식을 써줘야 돼. 사실 너네처럼 재배치를 안 하는 코드 때문에 일부 생각있는 사람들은 단순 복사에도 안전한 6바이트 후킹(ff 25)을 더 선호하기도 해. 그런데 너네는 그마저도 5바이트로 가정을 해버려서 교양있는 사람들의 행동도 처참히 실패하게 만들어 버리곤 하지 ㅠㅜ~&lt;/p&gt;
&lt;p&gt;이제부터가 제일 중요한 거야. 프로세스 안에는 있잖아. 너네 말고도 엄청 많은 스레드가 동작하고 있어. 그 스레드들도 항상 너네와 같은 일들을 하려고 할 수도 있고, 심지어는 너네가 변경하려는 곳을 참조하려고 하기도 하거든. 간단한 예, 몇 가지만 생각해 보자. 1) mov [eax], ecx를 하는 도중에 다른 스레드가 너네 코드가 쓰려는 페이지를 VirtualProtect로 쓰지 못하도록 만들어 버리는 상황, 2) mov byte ptr [esi], 0xe9를 한 순간 다른 스레드가 NtOpenProcess를 호출해서 그 코드를 실행시켜 버리는 상황, 3) 너네가 덮어 쓰려는 데 다른 프로그램도 그 주소에 값을 덮어 쓰려는 상황, 등등. 간단한 것만 생각해도 이런데 복잡하게 들어가면 더 다양한 케이스가 있겠지?&lt;/p&gt;
&lt;p&gt;적어도 난 너네가 이런 문제에 대해서 일말의 고민이라도 했다면 InterlockedExchange 정도의 함수는 썼어야 했다고 생각해. 물론 InterlockedExchange 함수를 쓰더라도 5바이트를 덮어써야 하기 때문에 한번에 할 수는 없지. 그래도 적어도 문제가 발생할 수 있는 확률은 낮춰줄 수 있지 않겠니? 그런데 이런 고민 조차도 없다는 게 정말 안타까워. 나도 회사 다니면서 다양한 프로그래머들을 만났지만 이런 이야기들을 하면 항상 그래. 그럴 일이 없다고. 그래서 꼭 코드로 보여줘야 믿지. 아래는 내가 작성해 본 간단한 코드야. VPThread가 동작할 때, 하지 않을 때, InterlockedExchange를 썼을 때, 쓰지 않을 때, 출력되는 문장의 개수를 살펴봤으면 좋겠다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;windows.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;process.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;stdio.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tchar.h&quot;&lt;/span&gt;&lt;/span&gt;

UINT 
CALLBACK
&lt;span class=&quot;token function&quot;&gt;VPThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    HMODULE ntdll &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetModuleHandleW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;ntdll.dll&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    FARPROC ntqit &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetProcAddress&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ntdll&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NtQueryInformationThread&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        ULONG oldp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;VirtualProtect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ntqit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PAGE_EXECUTE_READ&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;oldp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

UINT
CALLBACK
&lt;span class=&quot;token function&quot;&gt;HookThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    HMODULE ntdll &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetModuleHandleW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;ntdll.dll&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    FARPROC ntop &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetProcAddress&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ntdll&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NtOpenProcess&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    PUCHAR opcode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PUCHAR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ntop&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    PULONG offset &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PULONG&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;opcode&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        __try
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            ULONG oldp&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;VirtualProtect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ntop&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PAGE_EXECUTE_READWRITE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;oldp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

            offset&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x11223344&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            offset&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x88776655&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;token comment&quot;&gt;// InterlockedExchange(offset, 0x11223344);&lt;/span&gt;
            &lt;span class=&quot;token comment&quot;&gt;// InterlockedExchange(offset, 0x88776655);&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;__except&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EXCEPTION_EXECUTE_HANDLER&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;


UINT
CALLBACK
&lt;span class=&quot;token function&quot;&gt;WatchThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    HMODULE ntdll &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetModuleHandleW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;ntdll.dll&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    FARPROC ntop &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetProcAddress&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ntdll&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NtOpenProcess&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    PUCHAR opcode &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PUCHAR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ntop&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;volatile&lt;/span&gt; PULONG offset &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;volatile&lt;/span&gt; PULONG&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;opcode&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        __try
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            ULONG k &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;InterlockedCompareExchange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;offset&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; offset&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; offset&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;k &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x88776655&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; k &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x11223344&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%p\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; k&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;__except&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EXCEPTION_EXECUTE_HANDLER&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_tmain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; argc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _TCHAR&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; argv&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    HANDLE t1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_beginthreadex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; VPThread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    HANDLE t2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_beginthreadex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HookThread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    HANDLE t3 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_beginthreadex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WatchThread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;SetThreadPriority&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; THREAD_PRIORITY_TIME_CRITICAL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;SetThreadAffinityMask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;SetThreadPriority&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; THREAD_PRIORITY_TIME_CRITICAL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;SetThreadAffinityMask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;SetThreadPriority&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; THREAD_PRIORITY_TIME_CRITICAL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;SetThreadAffinityMask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t3&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;getchar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이쯤되면 이제 내가 이야기 하려는 말을 조금은 이해할 것 같다는 생각이 들어. 다시 한번 쉽게 설명하면 너네가 문지방을 수리하려고 하는데 그 문지방을 넘나드는 수많은 사람들이 있다는 거야. 문지방을 수리하다가 그 사람들과 부딪힐 수도 있겠지? 그럼 어떻게 해야 할까? 그렇지. 문지방을 수리하는 동안에는 사람들이 넘나들지 못하게 해야 하는거야.&lt;/p&gt;
&lt;p&gt;어떻게 하냐면 있잖아. SuspendThread라는 게 있어. 이 놈이 문지방을 넘나드는 사람들을 제어할 수 있게 해주거든. 그러니까 너네가 문지방을 수리하기 전에는 저 함수를 사용해서 사람들의 통행을 제어하는 게 안전하다고 할 수 있어. 그렇다고 단순히 죄다 SuspendThread를 시켜버리면 또 무슨 문제가 있냐면 SuspendThread 시키는 시점에 딱 문지방에 걸려 있는 놈들이 있을 수 있거든. 그런 놈들은 다시 ResumeThread를 하고 조금 있다 안전한 곳으로 이동했을 때 다시 SuspendThread를 해줘야 해. 복잡하지? 엄청 복잡해. 그런데 여기서도 끝이 아니야. 이건 진짜 기본적인 것만 말한거고 더 복잡하고 고려해야 할 내용들도 많이 있어. 시간나면 FlushInstructionCache 같은 API도 같이 공부해 보면 도움이 될 것 같아. 코드 하나 바꾸는데 왜 이렇게 알아야 하는게 많냐고? 너네 프로세스가 아닌 다른 프로세스에 끼어들어서, 그 끼어든 것도 모자라 대상 프로세스의 운영체제 코드를 변경하려는 일을 하려면 이정도 복잡함은 감수해야 하는거야.&lt;/p&gt;
&lt;p&gt;다양한 생각과 함께 깊이 있는 고민을 많이 하다 보면 어느날 문득 깨닫게 될꺼야. 아 인라인 후킹이라는 게 본질적으로 안전할 수가 없구나. 그냥 확률 싸움이구나, 하는 생각 말이야. 그나마 안전한 건 4바이트를 한 번에 변경하는 테이블 후킹 밖에는 없어. 인라인 후킹을 안전하게 하려면 운영체제 스케줄러를 제어하는 수 밖에는 없지. 하지만 그런 방법은 합법적으로 존재하지 않거든. 어쨌든 불완전한 방법이지만 지금은 광범위하게 사용되고 있는 기술인만큼 고민을 많이해서 최대한 안전하게 작성하는 요령을 터득하는 게 중요할 것 같다는 생각이 들어. 그리고 항상 생각해. 이게 과연 필요한가, 이게 과연 최선인가, 다른 방법은 없는가, 라는 것들을 말이야. 후킹을 하지 않는 것이 상책 중에 상책이라는 걸 꼭 명심했으면 좋겠다.&lt;/p&gt;
&lt;p&gt;조금 어설프고 서툴러도 괜찮아. 처음이잖아. 다음 번엔 고민을 좀 더 해서 꼼꼼하게 만들었으면 좋겠어. 아니면 상용 라이브러리를 쓰던지. 아니면 사장님한테 건의해. 그 많은 프로그래머 중에 똑똑한 애 한 명 시켜서 라이브러리 하나 만들자고 말이야.&lt;/p&gt;
&lt;p&gt;잘 지내고. 고생해!&lt;/p&gt;
&lt;p&gt;2013.06.17&lt;/p&gt;</content:encoded></item><item><title><![CDATA[건투를 빈다, 김어준]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/11156</link><guid isPermaLink="false">https://jiniya.net/wp/archives/11156</guid><pubDate>Tue, 21 May 2013 23:58:58 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;나이 들어 가장 비참할 땐 결정이 잘못됐다는 걸 알았을 때가 아니라 그때 아무런 결정도 내리지 못했단 걸 깨달았을 때다.&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;한 가지는 냉정히 인정하자. 아이디어는 사업이 아니다. 사업 해보지 않은 사람들이 흔히 하는 가장 큰 착각이 바로 그거다. 아이디어가 사업이 되기 위해선 수많은 장애를 넘어야 한다. 첫 번째 장애이자 초짜 대부분을 주저앉게 만드는 건 자본. 아이디어 하나로 손쉽게 자본을 모을 거라 여기는 건 사업을 해보지 않은 자들의 공통된 착각 중 하나다.&lt;/p&gt;
&lt;p&gt;그러나 설사 자본을 마련했다고 하더라도, 그 자본도 결코 사업이 아니다. 자본은 반드시 소진된다. 처음 사업하는 사람들에게 자본이 소진되는 속도는 공포다. 언제나 예상한 것보다 비용은 더 들고 수입은 예상치를 밑돌기 마련이니까. 그게 사업의 이치다. 당연하다. 시장에 갓 등장한 신참을 누가 주목하겠나. 아무리 아이템이 좋아도 시간이 소요되기 마련이다.&lt;/p&gt;
&lt;p&gt;그러나 사실은 자본 소진을 막아줄, 계약조차 사업이 아니다. 계약과 입금은 또 다른 거다. 사업을 하게 되면 계약에서 입금까지 얼마나 먼 거리인지 알게 된다. 통장에 돈이 찍혀 출금하기 직전까진 결코 내 돈이 아니다. 그리고 그런 입금이 안정적으로 지속되게 하는 건 또 다른 문제고. 최소한 6개월은 안정적으로 입금이 찍혀야 비로소 사업이라 할 만한 게 겨우 시작된 거다.&lt;/p&gt;
&lt;p&gt;…&lt;/p&gt;
&lt;p&gt;그러니 만약 앞으로 정말 사업가가 될 생각이라면, 친구의 사업 시작을 오히려 남의 돈으로 공부 할 수 있는 절호의 기회라고 받아들이시라. 그 친구에게 부탁해 참여 기회를 잡으시라. 피해의식은 버리시라. 만약 그러는 게 고개 숙이는 것 같고 자존심 상해 도저히 못 하겠다면, 그런 마인드라면, 당신은 사업 같은 건 안 하는 게 낫겠다. 아무리 작은 사업도 그 정도 고새 숙이는 것보다 백만 배는 더 어려운 거니까.&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;더구나 단위시간 내의 생산성이나 속도로만 승부가 나지 않은 일은 앞으로 얼마든지 있다. 기죽지 말고, 스트레스 받지 말고, 감정지수, 창의력, 자신만의 복합적 문제 해결 능력을 배양하시라. 아떻게? 사회적 관계를 확대하고 시대의 맥을 놓치지 말고 인간 심리의 본질을 탐구하고 크로스컬처한 경험을 축적하시라. 그러니까 사람 두루두루 사귀고 문화 경험 많이 하고 연애 많이 하고 여행 많이 가란 소리다.&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;이번 기회에 스스로 친구를 위해 내가 손해 볼 수 있는 한계는 어디까지인지. 따져보시라. 자신의 바닥이 어딘지 가늠할 수 있게 된다.&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;당신이 지불할 수 있는 비용은 어디까진가. 어느 것도 포기할 수 없다고? 그럼 아무것도 가질 수 없는 거다. 어느 것도 포기할 수 없다고 말하는 건 삶에 대한 응석에 불과하다. 어느 것도 포기할 수 없다가 아니라 어디까지 포기할 수 있는지를 생각해야 한다.&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;자존감이란 그런 거다. 자신을 있는 그대로, 부족하고 결핍되고 미치지 못하는 것까지 모두 다 받아들인 후에도 여전히 스스로에 대한 온전한 신뢰를 굳건하게 유지하는 거. 그 지점에 도달한 후엔 더 이상 타인에게 날 입증하기 위해 쓸데없는 힘을 낭비하지 않게 된다. 누구의 승인도 기다리지 않고 그저 자신이 하고 싶고, 재밌어하는 것에만 집중하게 된다. 다른 사람 역시 어떤 왜곡 없이 있는 그대로 받아들이며.&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;사람이 나이 들어 가장 허망해질 땐, 하나도 이룬 게 없을 때가 아니라 이룬다고 이룬 것들이 자신이 원했던 게 아니란 걸 깨달았을 때다.&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;꿈이니 야망이니 거창한 단어에 주눅 들거나 현혹되거나 지배당하지 말고, 그저 자신이 죽기 전에 해보고 싶은 것들, 가보고 싶은 곳들, 만나보고 싶은 자들 따위의 리스트를 만들라. 그리고 그 리스트를 하나씩 지워가라. 사람이 왜 사느냐. 그 리스트를 지워가며 삶의 코너 코너에서 닥쳐오는 놀라움과 즐거움을 하나도 놓치지 않고 최대한 만끽하려 산다. 최소한 나는 그렇다. 건투를 빈다.&lt;/p&gt;
&lt;p&gt;– 건투를 빈다, 김어준&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[커뮤니케이션의 효율성과 따뜻함 사이 어딘가…]]></title><description><![CDATA[#…]]></description><link>https://jiniya.net/wp/archives/10554</link><guid isPermaLink="false">https://jiniya.net/wp/archives/10554</guid><pubDate>Tue, 14 May 2013 23:58:57 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;제법 오래된 일이다. 언젠가 술자리에서 한 팀장이 그랬다. 다 좋은데 제발 “그래서 결론이 뭐예요”라는 이야기는 좀 안 했다면 좋겠다는 이야기. 그 말을 들을 때마다 숨이 막히는 느낌이 든다고 그랬다. 그땐 나도 내 나름의 변명이 있었다. 말하는 사람은 한 명이지만 듣는 사람은 한 사람씩 돌아가면서 한 마디만 해도 그 양이 어마어마하다. 그래서 앞뒤는 자르고 결론이 뭔지만 궁금했던 것이다. 어쨌든 팀장의 그런 고견을 듣고 나서는 주의해야 겠다는 생각을 했다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;얼마 전이었다. 한 업체 미팅을 하는 자리였다. 그때 나와 똑같이 효율성을 중시하는 담당자를 만나게 됐다. 앞뒤 자르고 결론만 듣고 싶어하는 그 담당자에게 적잖게 당황하면서 속으로 생각했다. 아 우리 회사 직원들도 나랑 이야기하면서 어쩌면 이런 기분이 들었을지도 모르겠구나. 난 그 담당자가 제법 마음에 들었는데 그 자리에 참석한 다른 사람들은 크게 좋아하는 분위기는 아니었다.&lt;/p&gt;
&lt;p&gt;미팅을 끝내고 돌아오면서 그런 생각이 들었다. 커뮤니케이션에 있어서 지나치게 효율성을 중시하는 것은 달작지근한 맛을 없앨 수도 있겠다는 생각. 어쩌면 커뮤니케이션에도 조그만 슬랙이 필요한지도 모른다. 그 조그만 슬랙이 낭비처럼 보일지 모르지만 그 조그만 틈이 이야기를 부드럽게 만들어주고 소통을 원활하게 만드는 건지도 모르니 말이다. 이유있는 낭비랄까?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;갑을 프레임이 들불처럼 온 나라를 뒤덮고 있는 요즘이다. 그들의 오염된 관계성에서 벌어질 수 밖에 없었던 일들도 있었겠지만, 어쩌면 우리 모두가 기본적으로 지나치게 효율성만을 추구한 결과는 아닐까라는 생각을 해봤다. 효율성은 조금 버리더라도 그 사이에 약간의 여백과 따뜻함을 채운다면 어쩌면 기존 방식보다 더 효율적인 결과를 얻을지도 모른다. 그리디 메소드가 항상 옵티멀 솔루션을 보장하지 않는 것과 같은 느낌이랄까?… 기독교에서 말하는 “가난한 마음”이 우리에게 간절한 시점이 요즘이 아닌가라는 생각을 해본다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;나는 문관이고 상대는 무관이라 하여 그를 괄시해서는 안 되며, 나는 세력이 강하고 상대는 힘이 약하다 하여 교만하게 대해서는 안 되며, 나는 현명하고 그는 어리석다 하여 그를 무시해서는 안 되며, 나는 늙었는데 그는 젊다 하여 서글퍼 해서도 안 된다. 엄숙하고 공손하고 겸손하고 온순하여 예의를 잃지 않으며, 화평하게 하여 뒤틀리고 막힘이 없게 하면 정과 뜻이 서로 통할 것이다.&lt;/p&gt;
&lt;p&gt;– 목민심서, 정약용&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 게임 보안: 데이터 마이닝에 관한 소고]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/10597</link><guid isPermaLink="false">https://jiniya.net/wp/archives/10597</guid><pubDate>Mon, 29 Apr 2013 23:58:56 GMT</pubDate><content:encoded>&lt;p&gt;요즘 게임 보안 업계에 부는 바람 중에 하나가 데이터 마이닝이다. 빅데이터와 클라우드같은 요즘 가장 핫한 키워드와 어느 정도 관련성을 가지고 있기도 하고 학계에서 몇 해 전부터 꾸준히 밀고 있는 방법이기도 해서 업계의 조명을 한몸에 받고 있다.&lt;/p&gt;
&lt;p&gt;그렇다면 데이터 마이닝 과연 효과적일까? 사실 난 현재 수준의 데이터 마이닝에 대해서는 조금 회의적이다. &lt;a href=&quot;http://www.jiniya.net/wp/archives/4372&quot;&gt;지난 글&lt;/a&gt;에서도 밝힌 것처럼 지금 시도하는 내지는 주장되는 데이터 마이닝이라는 기법은 그 태생적인 한계를 가지고 있기 때문이다. 그럼에도 요즘 게임 업계에서는 마치 기존 게임 보안 솔루션보다는 데이터 마이닝 쪽의 접근이 훨씬 더 근본적인 문제 해결 방법이라는 인식을 가지는 것 같아서 몇 가지 생각을 좀 덧붙여 보려고 한다.&lt;/p&gt;
&lt;h3&gt;#0. 비용&lt;/h3&gt;
&lt;p&gt;엔씨소프트의 경우 리니지, 아이온, 블소와 같은 게임 로그 데이터가 하루에 2-3TB 가량이 쌓이고, 이를 2개월 가량 저장할 수 있는 데이터 마이닝 시스템을 구축했다고 한다. 이 시스템을 통해서 오토나 작업장 같은 부정 행위를 저지르는 사용자들을 색출해 내고 있다고 한다. 2-3TB를 60일 저장할 수 있다면 그것만해도 180TB의 저장 공간이 필요하다. 오류 등을 생각한다면 더 큰 저장 공간이 필요할 것이다. 이를 안정적으로 저장하고 관리하는 시스템을 구축하는 일만해도 보통이 아니다.&lt;/p&gt;
&lt;p&gt;하지만 문제는 데이터 저장이 아니다. 그 저장된 자료에서 의미있는 데이터를 뽑아내는 과정이 또 보통이 아니다. 오픈 소스 플랫폼을 사용해서 구축했다고 하는데 관련 분야의 인력이 부족한 실정을 고려해 본다면 결국 데이터 마이닝 시스템을 구축하는데에는 생각보다 많은 비용이 든다는 것을 알 수 있다. 게다가 아직까지는 게임 데이터를 마이닝하기 위한 맞춤형 솔루션을 제공하는 업체도 없기 때문에 바닥부터 모든 것을 직접 다 만들어야 한다.&lt;/p&gt;
&lt;p&gt;이쯤되면 결론이 나온다. 선도적인 업체에서 투자적인 목적, 내지는 훨씬 더 높은 수준의 사용자 감시 체계를 만들고 싶은 때에는 유효하겠지만 그렇지 않은 대다수 게임 업체제에서는 비용적인 측면 때문에 도입 자체가 쉽지 않다는 것이다.&lt;/p&gt;
&lt;h3&gt;#1. 속도&lt;/h3&gt;
&lt;p&gt;데이터 마이닝, 말만 들으면 뭔가 우아하고 근사해 보인다. 하지만 이 데이터 마이닝이 힘들 발휘하려면 결국 데이터가 쌓여야 한다. 데이터가 없으면 이 시스템은 그냥 깡통이다. 데이터가 쌓여야 한다는 말은 다르게 설명하면 플레이어가 시스템 기준치에 부합하는 부정 행위를 지속적으로 저질러 주어야 한다는 것을 의미한다. 이렇게 상당한 시간동안 시스템의 감시망에 부합하는 부정 행위를 저지르면 그 윤곽이 마이닝 결과를 토대로 드러나게 되고 그 사용자에 대한 제재를 할 수 있다. 현재 데이터 마이닝 시스템은 속도가 느리고, 그마저도 아주 느린 사후 대응을 할 수 밖에 없는 구조다.&lt;/p&gt;
&lt;p&gt;데이터 마이닝을 사용하는 업체들이 가지는 유일한 제재권은 계정 블럭이다. 계정 블럭도 좀 생각을 해 볼 필요가 있다. 크게 게임 결제 방식에 따라 두 가지로 나뉜다. 부분 유료화 게임과 계정비를 받는 정액제 게임이다.&lt;/p&gt;
&lt;p&gt;부분 유료화 게임의 경우 계정 블럭은 아무런 효용가치도 없다. 다시 계정을 생성하면 그만이다. 이 경우에 다시 세부적으로 나뉘게 되는데 우리 나라처럼 주민 번호라는 희소화된 식별 체계를 가진 경우에는 그나마 다행이다. 하지만 이런 체계를 가진 해외 국가는 거의 없다. 따라서 국내에서 계정 블럭을 사용할 수 있더라도 해외에서는 이를 사용하기가 쉽지는 않다. 물론 XIGNCODE3 와 같은 요즘 게임 보안 솔루션의 경우에는 이런 계정 블럭을 도와줄 수 있는 보조 수단들을 제공하고 있다. 그런 기능을 이용하면 좀 더 효과적으로 대응할 수 있지만 부정 행위를 저지르는 시점에 차단할 수 없다는 근본적인 문제점은 여전히 존재한다.&lt;/p&gt;
&lt;p&gt;다음으로 유료 게임이 있다. 유로 게임의 경우 계정 블럭이 의미하는 바는 블럭 당하는 사용자가 계정비를 날리게 되는 것을 의미한다. 즉, 그 계정비 만큼의 손해가 얼마나 큰지가 이 시스템이 유용성을 판단하는 근거가 된다고 할 수 있다. 그런데 이런 해킹 행위가 벌어지는 인기있는 유료 게임의 경우 계정비가 해킹을 시도하는 사용자 입장에서 의미있는 페널티가 되지 못한다. 실례로 부정 행위를 식별하는데 2일 정도의 시간이 필요하다고 가정 해보자. 그렇다면 이 2일의 시간동안 그 부정행위를 저지르는 사용자가 계정비 이상의 이익을 해킹을 통해서 창줄할 수 있다면 지속적으로 부정 행위를 저지를 수 있는 구조가 된다.&lt;/p&gt;
&lt;p&gt;결국 여기서 중요한 쟁점은 ROE다. 안타깝게도 부정 행위를 색출해기 위해서 걸리는 시간 동안에 작업장에서는 그 계정비를 회수하고도 남는 만큼의 부가가치를 창출할 수 있는 경우가 많다. 만약 이 부가가치를 창출할 수 없다고 판단되면 작업장이나 해커는 사라진다. 그런데 진짜 정말 안타깝게도 그들이 사라지는 이유는 데이터 마이닝 시스템이 제공하는 계정비 + 캐릭 성장 비용 때문이 아니라 해당 게임의 인기가 시들해졌거나 작업장 과다 경쟁으로 아이템 가격이 지나치게 떨어진 경우가 대부분이다.&lt;/p&gt;
&lt;h3&gt;#2. 판단 기준&lt;/h3&gt;
&lt;p&gt;한 플레이어가 게임에서 한 시간내에 연달아 100번의 승리를 하는 것이 사실상 불가능 하다고 생각해보자. 게임 업체는 이를 토대로 기준을 세운다. 마이닝 시스템에서 한 시간내에 연달아 100번의 승리를 한 사용자를 찾는 것이다. 그런데 이런 모든 기준은 정상 사용자가 우연찮게 해낼수도 있기 때문에 게임 업체는 여기에다 허용 오차를 추가한다. 즉, 초범이라던지 어쩌다 한 번인 경우는 패스시켜준다는 의미다. 그걸 넘어서 지속적으로 한 경우에는 실질적인 계정 블럭을 시킨다.&lt;/p&gt;
&lt;p&gt;말만 들으면 그럴듯 해 보인다. 하지만 말만 들었을 때 이야기다. 해커들이 어떻게 할 것 같은가? 영원히 저 룰을 못찾아서 방황하면서 모든 계정을 다 블럭당할까? 절때 아니다. 99번의 승리만 가져가면 잡히자 않는다는 것이 순식간에 퍼진다. 이걸 찾는데 아주 오랜 시간이 걸릴 것 같지만 아이러니하게도 생각보다 아주 손쉽게 발견된다. 심지어는 해커가 그걸 찾으려는 시도를 하지 않음에도 밝혀진다. 바로 사용자에 의해서 말이다. 인기있는 게임의 경우에는 해킹툴 사용자도 광범위하게 퍼져있고 그 사용자들은 제각각 다른 방식으로 해킹툴을 사용한다. 따라서 이런 집단 지성이 모이게 되면 모호할 것 같았던 게임사의 제재 룰도 연립 방정식이 풀리는 것처럼 손쉽게 단 하나의 해가 밝혀진다. 여기에 사람 심리가 더해지면 정보 공유 속도는 더 빨라진다. 해킹툴 사용자 중에 계정 블럭을 당하지 않은 사용자가 있다면 그걸 자랑하고 싶어하는 사람 심리가 생긴다. 마치 대단한 비밀을 알고 있는 것처럼 게시판에서 자랑질을 하게 되도, 그걸 또 증명하기 위해서 소수 사람들과 공유한다. 여기까지 가면 이미 모든 사람이 그 방법을 알게되는 것이나 다름 없다.&lt;/p&gt;
&lt;p&gt;다시 돌아가보자. 게임 업체가 그래서 기준을 조정했다. 90번으로 줄이고 허용 오차도 좀 더 늘리도록 했다. 이번에도 해커는 기준치를 찾는다. 다시 조정한다. 70번에 허용 오차를 왕창 늘린다. 당연히 이번에도 찾는다. 그렇게 기준을 조정하다 보면 어느 순간에는 아주 일반적인 플레이어들이 심심치 않게 해낼 수 있는 수준까지 낮아진다. 마이닝 결과에 노이즈가 너무 많이 섞이고, 결국 데이터는 쓸모없게 되는 구조다.&lt;/p&gt;
&lt;h3&gt;#3. 치명적인 마이너리티 리포트&lt;/h3&gt;
&lt;p&gt;오진은 항상 문제다. 근데 이게 데이터 마이닝에서는 더 치명적이다. 예를들어 사소한 게임 보안 제품의 오진 같은 경우에는 정상적인 사용자의 경우에 다른 컴퓨터를 사용하거나 컴퓨터를 포맷하거나 하는 형태로 플레이를 이어갈 수 있다. 하지만 데이터 마이닝의 결과로 계정 블럭을 당하게 된다면 그 페널티는 엄청나다. 물론 사용자가 소명 절차를 걸쳐서 계정을 다시 복구할 수도 있겠지만 대다수 사용자는 그렇게 하지 않는다. 여기에는 사람의 감정적인 요인이 더 많이 작용하는데 정상적인 나를 이렇게 영구정지 시킨 게임을 내가 돈내고 해야 하는 이유를 찾을 수 없다고 생각하는 사람 심리 때문이다.&lt;/p&gt;
&lt;p&gt;데이터 마이닝을 통한 계정 블럭은 진짜 최후의 수단이며 사용하지 않는 편히 오히려 게임 동접 건전성을 유지하는데 도움이 될지도 모른다. 왜냐하면 해커는 계정 블럭을 당해도 바로 새로운 계정으로 해킹을 이어갈 것이고, 정상 사용자는 사람 심리 때문에 그 게임을 떠날 것이기 때문이다. 결국 오토만 남아 있다가 그마저도 블랙 마켓이 힘을 잃는 순간 게임 속에는 아무도 없는 처참한 현실이 도래할 수 있다. 실제로 작년 하루에 2-3만 개씩의 오토 사용자를 색출해 낸다는 패기를 보여준 온라인 게임이 있었다. 하지만 패기는 패기로 끝난 것 같다. 오픈하고 얼마 지나지 않아서 인기가 시들해졌기 때문이다.&lt;/p&gt;
&lt;h3&gt;#4. 데이터 마이닝 그럼 쓸모 없을까?&lt;/h3&gt;
&lt;p&gt;약점들을 이야기 했지만 현재 수준의 데이터 마이닝도 완전히 쓸모 없지는 않다. 데이터 마이닝 시스템의 가장 큰 장점인 알려지지 않은 해킹툴에 대해서 높은 대응력을 구축할 수 있다는 점 때문이다. 마이닝 시스템을 페널티 없이 모니터링 용도로만 사용하더라도 의미가 있다는 말이다. 어느 정도의 해킹툴 사용자가 존재하는지 아는 것과 모르는 것은 천지 차이기 때문이다. 또 그 사용자의 시스템을 좀 더 집중적으로 분석 한다면 알려지지 않은 해킹툴의 실체에 대해서 판단할 수 있고, 더 나아가서는 모니터링 단계에서 색출한 사용자에 대해선 일반적인 경우와 다른 높은 수준의 보안 정책을 제공할 수도 있다.&lt;/p&gt;
&lt;p&gt;몇해전 우리가 야심차게 진행했다가 포기한 내용 중에 하나가 화이트 기반 정책이 있다. 세상의 모든 깨끗한 바이너리 파일이 웰비아닷컴을 통하도록 만들자는 계획으로 야심차게 진행했지만 게임 업체들의 이해 관계와 깨끗한 바이너리 파일이 우리가 당초 예상한 것보다 너무 많다는 이유 때문에 결국 우리는 방향을 틀었다. 하지만 제한된 환경에서는 이런 것들이 의미있을 수 있다. 일례로 최근에 우리는 서비스하고 있는 게임 퍼블리셔로부터 온라인 게임 대회 서버에만 좀 더 높은 수준의 보안 정책을 유지할 수 있냐는 질문을 받은 적이 있다. 대회 서버에는 제한된 사용자가 참여하고 악성코드와 같은 엉뚱한 것들을 허용할 필요가 없기 때문에 화이트 정책을 사용하기에 안성 맞춤이다. 마찬가지로 데이터 마이닝 시스템의 결과물을 게임 보안 솔루션에 접목한다면 좀 더 효과적인 페널티 정책과 함께 높은 수준의 게임 보안 서비스를 유지할 수 있을지도 모른다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/wp/archives/1497&quot;&gt;세상은 0.1%의 프론티어와 0.9%의 동조자들 그리고 99%의 잉여로 돌아간다고 한다.&lt;/a&gt; 그러니 쓸모에 관계없이 여유 있는 게임 업체라면 이러한 방향의 연구를 지속적으로 수행하는 것이 바람직하다. 그래야 지금의 우리는 아닐지 몰라도 우리의 자식 세대, 내지는 입는 컴퓨터를 초딩때부터 착용할 자식의 자식 세대에는 보다 유쾌하고 공정한 온라인 게임 환경을 접할 수 있을테니 말이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;덧) XIGNCODE3 개발팀에서는 기존 방식과는 다른 데이터 마이닝과 같은 대안적 게임 보안 솔루션에 대해서도 관심이 많습니다. 이런 백엔드 시스템 구축에 관심이 있거나 경험이 있는 분, 파이썬을 다룰줄 알고 웹 프로그래밍을 어느 정도 할 수 있는 분을 찾고 있습니다. 적어놓고 보니 뭐 맥가이버군요. 작은 회사들이 찾는 사람이 다 그렇겠지만 ㅠㅜ~ 어쨌든 이런 일들에 관심 있으신 분들은 codewiz at wellbia.com으로 연락 주세요.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_데이터_마이닝에_관한_소고.md_0.png&apos; data-alt=&apos;해커는 피하고 게이머는 원하는…&lt;br&gt;&lt;br&gt;평판은 하루 아침에 만들어지지 않습니다.&lt;br&gt;&lt;br&gt;XIGNCODE3는 여러분의 게임을 공정하게 만드는 가장 손쉬운 방법입니다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 610px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/73fa7017948c6db530fd6ef8d42a9475/5d5ad/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EB%A7%88%EC%9D%B4%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%9C_%EC%86%8C%EA%B3%A0.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 132.63157894736844%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAbCAIAAADzvTiPAAAACXBIWXMAAA7AAAAOwAFq1okJAAAEl0lEQVR42m1UC28bRRD2HwcJCQEl0Fag0oKKKmgFKlBKqfpI4taxz68mbtw4ceLz3T7uuXu3t/fy2T6fH2EuKa0qGI9G4939bmdnvpkKJgRj4rqOruuGYVqWZRgUwxKlIggopbZtc84Xi8X5f6QyGBx1Om0QpdlqtdoH+/v9fr+hKL3eATjlbrcLG8fHxyfDYRhFgNlsNm/Bk8kkjqK0lCRNkmmWzaZTsNNsOknT+XweCOFxDltwbJHnH9zMXFdFyPF8maRBHHMpgyjyZMiDwPV81/O4CDwpRRgxT4CfzWbvwZqun9Qbx48f9x89Hjx5MtrZIY0GqtVARzu7J0+fjbZ3wVF3q6Vu78jR6F3kFVVVO3t7/Xb7VW1PHwxcTbNGKseYgSLEMLLHmjUeO5oGDhkOGaXvbyaEQCrgfg2TMJsGEHyayjT1A+kHgZCl9YQAWzq+EIGE94NkWVYxsWVigxLTPDkb7b7E9SbaU5yDXsDg1SCQAxmIwPd9KYJQhoD2uAcC6xVYYi5jLheOyzXd05Cnl9aHFREIuArEF1JIvwxAlAFcfGVRFBWKiHqmqqfq+ExXVR3pmHHPZdyxHdu0Xdt1bccxHfi6Y9qOVS6a1LBMazabVcIwlLKMDT52oTKO40kKNU6BAmDjJImAHFF4SbLLPG8upAIAj0E1feCgazOPgXUY/GyHgw9vYeADfd1ski2Xq2WxLBbFer0us32Z9EW+MAm1qOFYtoEJ1pBJDBMZJjYtYlGETUyB8UTD+kizDLMoihI8LwrIepikPgQep1E6CaJYxgk4JeeiJEwnIVA3m8ZZBlvpPF9vyrhLcHI8QLtVXKtZStNpd9CL0rFbLfyiZioKqFFX8IuX5WKzhet11lBWvn9+8e6K7Hbx8JSONVNHlo7A2pg4mBiaZmi6TYgx1qg6JqAjFWu61NHqkmQAjpstY6+OGorV6VrtDm40cL2B6g3SUMAxWm3cUGizRRQF1fZwsyU7nRUhb8GBbY96h/rRYPzmiA5PPbhW0xjwhFCfUKYjYLgPI2GMTBUJaiSMr/4dDJXZPBdQ3jgGC8WeQC/PZnGagp3mORQ9gXpnGReRbkgAQLY27xpjxvmMsVyIVZblgSjiGPxlkhRxkoch+NNYupbObMRs3TF1k6iXatFxRXDuu24MJBMCWB8Bc3nJGOF5cQiFAmpJ4TPh83w+hYeu18v1qgBdLvNKFMMZMLEHfQM0DYLyT5zMZ9mD+/euX7t667sb39+8eePbb+78ePve3Z/v/nTn/q+/PPjjt+rOdgVeBG0DICA5dCkgp7PpPF+kIa8+vP38yZ/V7UfV5389/fv3nWcPQVv1571u7eRo37LMEuy6LiDfzQdg/AV1N8yx+q9fvTncP+x1jw4PzoaDQf/14UG333vlMadMmOM4BjVNw9KhHRHWxuOxqg0Gx9BUL6vVTz7+aOvKla0rn1/b+vKHWzevf3316ldbX3z2abvVLMHQLhhRk1qAJzolmIJjEMMue5j53PdcwZkHWfifoR/4EjrRhZMwAWDSMh/ak7kejAHoRPgE7FoGnOCbD+X8/PwfEi+dkZlFcDgAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;해커는 피하고 게이머는 원하는…&lt;br&gt;&lt;br&gt;평판은 하루 아침에 만들어지지 않습니다.&lt;br&gt;&lt;br&gt;XIGNCODE3는 여러분의 게임을 공정하게 만드는 가장 손쉬운 방법입니다.&apos; title=&apos;&apos; src=&apos;/static/73fa7017948c6db530fd6ef8d42a9475/5d5ad/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EB%A7%88%EC%9D%B4%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%9C_%EC%86%8C%EA%B3%A0.md_0.png&apos; srcset=&apos;/static/73fa7017948c6db530fd6ef8d42a9475/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EB%A7%88%EC%9D%B4%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%9C_%EC%86%8C%EA%B3%A0.md_0.png 190w,
/static/73fa7017948c6db530fd6ef8d42a9475/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EB%A7%88%EC%9D%B4%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%9C_%EC%86%8C%EA%B3%A0.md_0.png 380w,
/static/73fa7017948c6db530fd6ef8d42a9475/5d5ad/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%8D%B0%EC%9D%B4%ED%84%B0_%EB%A7%88%EC%9D%B4%EB%8B%9D%EC%97%90_%EA%B4%80%ED%95%9C_%EC%86%8C%EA%B3%A0.md_0.png 610w&apos; sizes=&apos;(max-width: 610px) 100vw, 610px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;해커는 피하고 게이머는 원하는…&lt;br&gt;&lt;br&gt;평판은 하루 아침에 만들어지지 않습니다.&lt;br&gt;&lt;br&gt;XIGNCODE3는 여러분의 게임을 공정하게 만드는 가장 손쉬운 방법입니다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[보안 프로그래머란 업에 관해서 …]]></title><description><![CDATA[최근 몇 년 사이에 해킹 사건이 부쩍 늘었다. 잊을만하면 한번씩 대규모 해킹 사건이 발생하면서 이제는 컴퓨터를 모르는 동네 아줌마들도 좀비 PC, DDoS…]]></description><link>https://jiniya.net/wp/archives/10952</link><guid isPermaLink="false">https://jiniya.net/wp/archives/10952</guid><pubDate>Tue, 23 Apr 2013 23:58:55 GMT</pubDate><content:encoded>&lt;p&gt;최근 몇 년 사이에 해킹 사건이 부쩍 늘었다. 잊을만하면 한번씩 대규모 해킹 사건이 발생하면서 이제는 컴퓨터를 모르는 동네 아줌마들도 좀비 PC, DDoS같은 용어를 자연스럽게 사용하는 세상이 돼 버렸다. 해킹이 얼마나 큰 문제인지에 대해서는 온동네 사람들이 다 알고 있다. 그림자가 있어야 빛의 존재가 부각되는 것처럼 이런 상황은 우습게도 상대적으로 보안을 더 돋보이게 만드는 흐름을 만들었다. 그래서인지 요즘 부쩍 보안 쪽 진로를 물어보는 프로그래머들이 늘었다.&lt;/p&gt;
&lt;p&gt;근 10년간 PC 보안 이라는 분야에서 프로그래머로 일하면서 내가 느낀 것은 이 분야만큼이나 성격이 적성에 많이 관여하는 곳도 없다는 생각이다. PC 보안 쪽의 진로에 대해서 약간 이나마 고민하는 사람이 있다면 자신의 성격이 여기에 나열된 것들과 맞는지 잠깐 고민하는 시간을 가져보도록 하자. 진로를 결정하는데 약간이나마 도움이 되지 않을까라는 생각을 해본다. 물론 이런 성격이 아니어도 맡은 업무를 훌륭하게 잘 할 수는 있다. 하지만 일하는 매 순간 순간이 즐겁지 않다는 데에 100원쯤은 걸 수 있을 것 같다.&lt;/p&gt;
&lt;p&gt;변화에 대한 관성이 낮은가? 보안 쪽은 변화가 굉장히 심하다. 왜냐하면 보안 관련 코드는 다양한 코드 중에서도 항상 해커의 첫 번째 공격 대상이 되기 때문이다. 취약점은 감기처럼 보안 제품을 따라 다닌다. 따라서 그 어떤 분야보다 보안 프로그램은 고칠 일이 많다. 취약점이 간단한 것이면 다행인데 어떤 경우에는 설계 전체를 뒤집어야 하는 경우도 있다. 현장에서는 설계 전체를 뒤집는 일도 대수롭지 않게 벌어진다. 그래서 변화에 대한 관성이 강하다면 이쪽 분야에서 일하는 것이 고역일 수 밖에 없다.&lt;/p&gt;
&lt;p&gt;경쟁 상황을 즐기는 편인가? 사람은 크게 경쟁에 대해서 두 가지 다른 반응이 나타난다. 한 부류는 경쟁에 내몰리면 긴장해서 평소보다 실력 발휘가 안 되는 쪽이고, 다른 한 부류는 경쟁할 때 오히려 능력이 돋보이는 집단이다. 당연한 이야기겠지만 전자인 사람들은 경쟁 상황을 본능적으로 싫어한다. 하지만 후자인 사람들은 그런 상황을 즐긴다. 보안은 해커와의 전쟁이 항상 벌어지는 곳이다. 매일 매일을 전쟁 같은 심각한 경쟁 조건 속에서 일한다. 따라서 이러한 상황 자체가 싫다면 이 쪽 일이 본질적으로 즐거울 수가 없다. 해커의 공격에 무력해진 코드를 보면서 어 그래 이번에 이 문제를 고쳐서 다시는 못 뚫게 만들어야지, 라는 생각을 해야 한다. 대신 왜 매일 이렇게 뚫리는 거지, 이 싸움은 언제쯤이면 끝날까, 라는 생각을 한다면 일이 즐거울 수가 없다.&lt;/p&gt;
&lt;p&gt;자존감이 강한가? 보안 쪽 일은 안타깝게도 고맙다는 말을 들을 일이 거의 없다. 왜냐하면 문제가 생기지 않는다면 보안 제품이 잘 막아서 문제가 없는 것이 아니라 공격이 없었다고 사람들은 생각하기 때문이다. 반면에 아주 사소한 문제라도 생긴다면 보안 제품이 왜 그런 것도 방어하지 못하냐는 클레임만 잔뜩 듣는다. 자존감이 낮다면 그런 상황을 버틸 수가 없다. 외부의 비판 속에서도 자신의 성취에 대해서 객관적인 시각을 가질 수 있는 그런 정도의 강한 멘탈이 필요하다.&lt;/p&gt;
&lt;p&gt;윤리적인 사고에 익숙한가? 보안 쪽 일을 하다 보면 옳고 그른 일의 경계가 모호해지는 경우가 많다. 당장의 당근에 눈이 멀어서 범죄를 저지르는 그런 사소한 일을 말하는 것이 아니다. 가령 2차 대전 당시에 독일군의 암호를 해독한 앨런 튜링은 옳은 일을 한 것일까? 반대로 독일군 입장에서 연합군의 암호를 해독한 엔지니어가 있다면 그 사람은 어떻게 판단해야 할까? 조국의 이익을 위해서 다른 나라를 공격하는 악성 코드를 만드는 일은 과연 옳은 일일까? 반대로 객관적인 입장에서 우리나라에 존재하는 나쁜 시설을 파괴하는 코드가 있을 때 그것을 분석해서 차단하는 것이 옳을까? 그 시설이 파괴되도록 놔두는 것이 옳을까? 보안과 악의적인 해킹은 마치 동전의 양면 정도의 차이 밖에 나지 않는 경우가 많다. 윤리적인 추상적 사고나 본인만의 뚜렷한 윤리적 입장 없이 이런 복잡하고 애매모호한 상황에 자주 놓이게 되면 어느 순간 자신이 옳은 일을 하고 있는지 아니면 범죄를 저지르고 있는지 모호해지는 경우가 한두 번이 아니다. 따라서 윤리적인 추상적 사고에 익숙하지 않다면 이 쪽 분야에서 일하는 것이 상당히 위험할 수 있다.&lt;/p&gt;
&lt;p&gt;사실 여기까지만 들으면 보안 프로그래머는 정말 못해 먹을 짓이다. 맨날 고쳐야 하고, 공격 당하고, 욕만 먹고, 게다고 범죄 행윈지 착한 짓인지 분간도 잘 되지 않으니 말이다. 하지만 프로그래머 입장에서 좋은 상황도 여럿 있다.&lt;/p&gt;
&lt;p&gt;우선은 감성적인 부분이 크지 않다는 점이 있다. 여러분이 UI를 하거나 게임을 만들거나 워드프로세서를 만들거나 심지어는 압축 프로그램을 만든다고 해도 거기엔 감성이 작용할 부분이 다분하다. 여러분은 퐌타스틱한 기능이라고 만들었는데 다른 사람들은 싫어할 수 있다는 말이다. 2픽셀 두께가 괜찮아서 그렇게 만들었는데 다른 사람들은 3픽셀을 좋아할 수도 있다. 아트적인 감성이 있는 사람이라면 이런 상황을 즐길 수도 있겠지만 논리적인 감성만 있는 사람이라면 이런 상황이 정말 헬이다. 하지만 보안 쪽 일은 이런 부분이 거의 없다. 정답이 맞고, 제대로 동작한다면 크게 딴지 걸릴 일이 없다.&lt;/p&gt;
&lt;p&gt;미션이 명확하다. 앞선 이야기의 연장선인데 대부분의 도메인에서는 특정 프로그래머의 역량을 가늠하기가 쉽지 않다. 그런데 보안 쪽은 미션이 명확하기 때문에 누가 잘하는지 못하는지가 명확하게 구분된다. 찾아내고 탐지하고 방어하고 치료하면 된다. 매우 쉽다. 그걸 해내는 사람과 그렇지 않은 사람은 눈에 띄게 차이가 난다. 이 말은 돌려 말하면 그 어떤 분야보다 손쉽게 록스타 대접을 받을 수 있다는 의미이기도 하다. 실력만 있다면 말이다. 참고로 문제는 널려 있다. 풀기가 어려워서 그렇지…&lt;/p&gt;
&lt;p&gt;유행은 돌고 돈다. 취약점도 돌고 돈다. 새로운 시스템에서 새로운 취약점이 나오기도 하지만 과거 유행했던 일들이 돌아가면서 다시 재탕되기도 한다. 이 말은 히스토리만 알고 있어도 반쯤은 먹고 들어갈 수 있다는 말이다. 또 새로운 시스템을 구성할 때에도 후배들에게 그렇게 쪼다같이 만들었다가 과거에 A, B, C란 취약점과 D, E랑 충돌나서 x고생 했다는 이야기를 해줄수도 있다. 생각보다 경험과 경력이 든든한 진입 장벽이 되어 주는 곳이기도 하다.&lt;/p&gt;
&lt;p&gt;끝으로 사족을 하나만 덧붙이지만 개인적으로 여러분이 경제적 여유를 가진 상황에 태어났다면 자선 사업을 하기를 권하고 싶다. 여러분의 돈을 나눠주는 일을 하면 우습게도 매일같이 고맙다는 말을 들을 일 뿐이고, 그렇게 골치 아프지도 않고, 실수 한번이 치명적이지도 않다. 그러다 심심해서 코딩 하고 싶은 날에는 남는 시간에 오픈 소스 작업에 기여를 하면서 다시 고맙다는 소리를 들으면 된다. 환상적이다. 물론 여러분이 남에게 나눠주고도 먹고 살 만큼의 경제적 여유를 가지고 있다면 말이다. ㅋ~&lt;/p&gt;
&lt;p&gt;남의 돈을 빌어먹는 업이란 그 자체로 본질적으로 고달픈 일이다. 업이 요구하는 자질과 자신의 성격이 잘 맞다면 그나마 과정 속에서 느끼는 고통은 좀 덜할 것 같다. 성격은 생각보다 쉬이 바뀌지 않는다. 대체적으로 업에 성격을 맞추는 것보단 자신의 성격에 어울리는 업을 찾는 것이 훨씬 더 쉽다. 그러니 다시 한 번 잘 생각해보자. 나는 어떤 사람인지 말이다.&lt;/p&gt;
&lt;p&gt; 12
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[여유를 안 가지면 시간은 언제나 없지~]]></title><description><![CDATA[인터폰 소리에 깨어난다. 이 시간에 누구지? 회사 직원이다. 자꾸 POC…]]></description><link>https://jiniya.net/wp/archives/9627</link><guid isPermaLink="false">https://jiniya.net/wp/archives/9627</guid><pubDate>Tue, 16 Apr 2013 23:58:54 GMT</pubDate><content:encoded>&lt;p&gt;인터폰 소리에 깨어난다. 이 시간에 누구지? 회사 직원이다. 자꾸 POC를 가야 한다는 말만 반복하는 그를 돌려 보내고는 씻고 금방 나가겠다고 했다. 면도도 하는 둥 마는 둥 머리에 물칠만 하고 밖으로 나갔다. 밥 먹을 시간도 없어서 서브웨이 샌드위치 하나로 택시에 올라탔다. 왜 갑자기 POC에 가야 하는지도 모른체…&lt;/p&gt;
&lt;p&gt;꼭 10년 전이었다. 그 당시 내가 일했던 회사에는 BMT가 많았다. 으레 BMT가 그렇듯 우리는 전혀 없던 기능을 전 날 무리하게 구현하거나, 크로스 해킹을 위해서 경쟁사 제품을 무력화 시키면서 밤을 보내곤 했다. 사실 BMT에는 직접 참여도 하지 않는 말단 사원이라 난 나에게 주어진 일만 열심히 하면 됐었다. 다음날 BMT 당일인데 참석해서 프리젠테이션을 해야 하는 실장님이 연락이 안 되는 상황. 급기야 아파트로 찾아 나섰다. 그 장면이 머릿속에서 오버랩 되면서… 나를 찾아 왔던 직원도 십 년 후에는 어디선가 누군가 인터폰으로 깨우는 소리에 일어날지도 모르겠다는 생각을 해봤다.&lt;/p&gt;
&lt;p&gt;얼마 전에 근처 회사에 다니는 학교 후배 녀석이 저녁에 전화를 해 왔다. 시간 있냐는 질문에 당연히 있다고 대답했는데 그 녀석이 정말 신기하다고 했다. 내가 안 바쁘다고 대답한게 한참만이라는 반응이었다. 그 때 머리를 엄청 큰 해머로 두드려 맞는 느낌이 들었다. 아, 내가 뭔가 아주 심하게 잘못 살고 있구나. 후배 녀석과 커피 한 잔 마실 여유도 없이 사는게 내가 원한 삶은 아니었는데 말이지. 무슨 일이 그렇게 중요하다고 바쁘다는 말을 입에 달고 살았지. 반성했다.&lt;/p&gt;
&lt;p&gt;POC 행사를 마치고 돌아오는 택시 안. 일정을 묻는 전화가 여기 저기서 쏟아진다. 다음주까지 해드릴께요. 다음주 수요일까지 드려도 될까요? 늦어서 죄송합니다. 다음주에 해 드리도록 하겠습니다. 그러고보니 지난 주에 다음주에 구현해 준다고 했던 기능들이 생각났다. 오늘이 금요일인데. 어쩌면 난 다음주에 살고 있었던 건 아니었을까?&lt;/p&gt;
&lt;p&gt;여유를 가지자. 조급한 마음만 가지고 일이 빨리 끝나는 건 아니니까 말이다. 어차피 잘 먹고 잘 살자고 하는 거. 냉정하게 생각해보면 그리 죽도록 중요한 일도, 미칠듯이 급한 일도 없다. 쉼표와 빈칸, 그리고 여백이 좀 필요하다. 바람처럼 왔다가 먼지처럼 가는 게 인생사 아니던가 ㅋ~&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Merovingian&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yes, of course, who has time? Who has time?&lt;/p&gt;
&lt;p&gt;But then if we do not ever take time, how can we ever have time?&lt;/p&gt;
&lt;p&gt;하지만 여유를 안 가지만 시간은 언제나 없지&lt;/p&gt;
&lt;p&gt;– 매트릭스2 리로디드, 2003&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[프로그래머, 전망보고 선택 하진 맙시다~]]></title><description><![CDATA[#0 우리가 지금 빌게이츠를 꿈꾸는 건 중세 시대에 귀족이 되는 것 만큼 어려운 일이다. 알랭 드 보통 아저씨는 말했다. 일반 사용자용 소프트웨어 세계는 철저하게 승자독식으로 돌아가는 세상이다. 이 동영상이 말하지 않는 것. #…]]></description><link>https://jiniya.net/wp/archives/10772</link><guid isPermaLink="false">https://jiniya.net/wp/archives/10772</guid><pubDate>Mon, 15 Apr 2013 23:58:53 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://www.ted.com/talks/alain_de_botton_a_kinder_gentler_philosophy_of_success.html&quot;&gt;우리가 지금 빌게이츠를 꿈꾸는 건 중세 시대에 귀족이 되는 것 만큼 어려운 일이다.&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;알랭 드 보통 아저씨는 말했다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;일반 사용자용 소프트웨어 세계는 철저하게 승자독식으로 돌아가는 세상이다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;이 동영상이 말하지 않는 것.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 610px; margin-bottom: 16px;&apos; data-url=&apos;./프로그래머,_전망보고_선택_하진_맙시다~.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/b8679ba184d4fd2deee6e4cdf7c28671/5d5ad/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%2C_%EC%A0%84%EB%A7%9D%EB%B3%B4%EA%B3%A0_%EC%84%A0%ED%83%9D_%ED%95%98%EC%A7%84_%EB%A7%99%EC%8B%9C%EB%8B%A4~.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 38.94736842105263%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAA7DAAAOwwHHb6hkAAABoElEQVR42i2QyUvDQBTG8y+KiKC41ZPL0ZOiIOihVYpKWxWpG4IriihVQVBRamsrisGFarqaZYzRNumkWSYZZxLfZR7fvOX3PqbeMBUV5j/Be0Uq8OCNK3HFck2Dmm4YpoUxNi27Ui4JovgjAwAkQZQ0VSW667oMeRzHkWXAV0qK8q1WFU3TMA2X6K5Ls2dOOjs6WTljObHm1XsqxgxCCMK6Dp0XQc6+CuwntpDrDcY2QiTJfCgd0exkMN4ZvgosZt94urZhWKSRwbTSuc1cL+ykNi5zM4mfk8eaB0WJyN/oFts6kxqKnvfPJ1vCydDhKxEL+TwBpNgN9ev6YiKxH44cPIzvFse33kHV8rlN2xmM33dFUj3RdG8s3T6XGtl8Iuu+gAQhpM1Iln8jUSUWyiytDyy/DCw9ib8G0X3suUSuefqmN3YXiKWbpm5WLwoU1TOD8U/n1+MPgY5iX/fo8FrwtOxjI0SxpWpjbJttm022BM8n99iabvtW02Zd18kYG0L+YJcLTeSOjqumQ4iJH/7NJAzbyQkaB+o2+ld8t/8AY3KcurPLDIEAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                       md 0&apos; title=&apos;&apos; src=&apos;/static/b8679ba184d4fd2deee6e4cdf7c28671/5d5ad/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%2C_%EC%A0%84%EB%A7%9D%EB%B3%B4%EA%B3%A0_%EC%84%A0%ED%83%9D_%ED%95%98%EC%A7%84_%EB%A7%99%EC%8B%9C%EB%8B%A4~.md_0.png&apos; srcset=&apos;/static/b8679ba184d4fd2deee6e4cdf7c28671/08678/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%2C_%EC%A0%84%EB%A7%9D%EB%B3%B4%EA%B3%A0_%EC%84%A0%ED%83%9D_%ED%95%98%EC%A7%84_%EB%A7%99%EC%8B%9C%EB%8B%A4~.md_0.png 190w,
/static/b8679ba184d4fd2deee6e4cdf7c28671/2edd7/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%2C_%EC%A0%84%EB%A7%9D%EB%B3%B4%EA%B3%A0_%EC%84%A0%ED%83%9D_%ED%95%98%EC%A7%84_%EB%A7%99%EC%8B%9C%EB%8B%A4~.md_0.png 380w,
/static/b8679ba184d4fd2deee6e4cdf7c28671/5d5ad/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%2C_%EC%A0%84%EB%A7%9D%EB%B3%B4%EA%B3%A0_%EC%84%A0%ED%83%9D_%ED%95%98%EC%A7%84_%EB%A7%99%EC%8B%9C%EB%8B%A4~.md_0.png 610w&apos; sizes=&apos;(max-width: 610px) 100vw, 610px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;이보다 더 승자독식인 세상이 있을까?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 294px; margin-bottom: 16px;&apos; data-url=&apos;./프로그래머,_전망보고_선택_하진_맙시다~.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/c69bd711d05ec41fd7de15d2054ddf6b/b27a5/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%2C_%EC%A0%84%EB%A7%9D%EB%B3%B4%EA%B3%A0_%EC%84%A0%ED%83%9D_%ED%95%98%EC%A7%84_%EB%A7%99%EC%8B%9C%EB%8B%A4~.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 126.31578947368422%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAZCAIAAAC+dZmEAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAC90lEQVR42l2U647aMBCF8/7v1N8rVepWoojudoFA7heSkBg7wQnQzxk2W9WyrJnxGXsux/aUsa22yozMzjih0xZB5qfdrbqfgqzdx02Qt29+WXeD16hrdTa/3pNLb2/3x3S7v27i10003e/I0+2RlerHOrTjjd1j0rz89L+9vH9fHc9q8IraHJI2SLu40Puw8qP6bZdvttnvbbI9lkmpw1wdU5WUlyhXZTMA+3Osq87GxcWbptv1apmPxyOOk6Io8jxnDYKgqiqMrFiAIff9EIZRnuVKXVCd8ziOw3AlrKY5T9OEFVkGAlv4AEO2dsTtctFchuqxp/Wl73tr7fl8TtM0juPT6TSfOGCs65pArvPglKZpiMUYg4rz4I7SWnBRFAEFgTPbrF3XcRYwZO4oyxPOSilUFzbBMBE4WGsDghDHcWKKkSkyKwGjCt5DwYHgSZVTD4cj989pP8h5NpZRFOOGjE+W5WmaGdM/C0bAHEsYCJIbZ0kVrRvE71YZAhCwx7VNU3ddi/t6vV6tVjSJmnHhZrPBnqbJdrs1RoPvexNFIQBKi+pJGpI2wSw3IFDFOQQXlgD+2XXU8MieumMlh6Ioff8QBCFMOJ0qUmbWdYOFhgDgIDDkjNeSs0sPgRS6TnE/UyygkSGGsEJUPFFdtZHoszRdWkqfsyyDLRiJkOLT2M9COpJQjidJOEecSYMNfJIkIewkidkiXUELSViROR0XR5KlYIRBYkxiEVYLMSgbYS8kmZMyT5Kgk540fS5GKi+GUrkX7F5VTYWggjwYSMJ8kgTnhSSzPAoBWaUlc4fs0qFFdSQherKC6Chw4+PjY7fbhWGAUUAY9/u9FIUVlU5CEucsN8tYLpc4hK32//G1Je+ZuluS5GH4vr+QRB5DWVbkzDtDpkhwhg/niySSD9sLPaSk0/x9SIdF/vyzXDioPAzdti0rpvknSeA9CdNkAQlt6PD8k/SAabXgXcHwkW8IHBHzhkBLhYgIetE/AEISCMd/KCT5C7WVlq2bLnSwAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                       md 1&apos; title=&apos;&apos; src=&apos;/static/c69bd711d05ec41fd7de15d2054ddf6b/b27a5/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%2C_%EC%A0%84%EB%A7%9D%EB%B3%B4%EA%B3%A0_%EC%84%A0%ED%83%9D_%ED%95%98%EC%A7%84_%EB%A7%99%EC%8B%9C%EB%8B%A4~.md_1.png&apos; srcset=&apos;/static/c69bd711d05ec41fd7de15d2054ddf6b/08678/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%2C_%EC%A0%84%EB%A7%9D%EB%B3%B4%EA%B3%A0_%EC%84%A0%ED%83%9D_%ED%95%98%EC%A7%84_%EB%A7%99%EC%8B%9C%EB%8B%A4~.md_1.png 190w,
/static/c69bd711d05ec41fd7de15d2054ddf6b/b27a5/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%2C_%EC%A0%84%EB%A7%9D%EB%B3%B4%EA%B3%A0_%EC%84%A0%ED%83%9D_%ED%95%98%EC%A7%84_%EB%A7%99%EC%8B%9C%EB%8B%A4~.md_1.png 294w&apos; sizes=&apos;(max-width: 294px) 100vw, 294px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;1위부터 10위 까지가 전체의 70%를 차지하는 세상.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;작가와 제빵사의 차이, 투기꾼과 의사의 차이, 사기꾼과 창녀의 차이를 알면 세상이 어떻게 돌아가는지를 조금 더 잘 볼 수 있게 된다. 그것이 추가적인 노동이 전혀 없이도 수입을 열 배, 백 배 늘릴 수 있는 직업과 하나를 더 얻을 때마다 그만큼의(유한한 자원인) 시간과 노력을 또 투입해야 하는 직업 — 다시 말해서 중력에 종속된 직업 — 의 차이다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;– 검은 백조, 나심 탈레브&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;압정식 사회란 극단화된 승자 독식 사회를 일컫는 말이다. 구성원에 따른 재산이나 소득을 그래프로 그렸을 때 특정 집단 내지는 특정인에게 비정상적으로 편중 현상을 보이게 되면 그 모양이 압정과 유사한 형태를 나타내기에 그렇게 부른다. 양극화의 종착역이라고 할 수 있다. 압정식 사회에서의 평균은 의미가 없다. 한 술집에 술마시는 사람들의 연소득 평균을 계산해서 그 사람들의 소득 계층을 이야기한다고 할 때 그 술집에 빌게이츠 한 명이 들어오면 평균이 전혀 의미가 없어지는 것과 같은 이치다. 결산 시즌마다 발표되는 회사들의 평균 연봉이 쓰잘때기 없이 높은 것도 이런 이유를 일부 반영한다고 할 수 있다.&lt;/p&gt;
&lt;p&gt;그렇다면 압정식 사회는 좋은 것일까 나쁜 것일까? 소득 그래프를 그려 본 사람들은 백이면 구십구는 좋지 않다고 대답할 것이다. 단 한 사람. 모든 것을 가진 사람만 유일하게 좋은 세상이라고 말할 것이다. 하지만 조금만 달리 생각해 보면 사실 도덕적으로 판단하기는 힘든 무수히 많은 압정식 사회가 존재한다. 나심 탈레브 아저씨가 “검은 백조”에서 이야기했던 극단의 왕국들이다.&lt;/p&gt;
&lt;p&gt;싸이의 강남스타일은 몇 달 전 유튜브 최다 조회수 동영상에 등극했고 지금 조회수가 무려 십억 번을 넘었다. 우리 나라 가수들 뮤비 조회수를 어지간히 합쳐도 강남스타일 조회수를 넘기란 어려워 보인다. 해리포터로 유명해진 조앤 롤링 아줌마도 빠질 수 없다. 해리 포터 시리즈는 무려 4억부 이상이 판매됐는데 이 수치는 우라 나라에서 가장 잘나가는 베스트셀러 작가들의 판매부수를 모두 합쳐도 넘기 힘든 수치다. 우리에게 좀 더 친숙한 소프트웨어 세계는 더 심각하다. 검색 엔진 시장에서 구글의 점유율은 90프로가 넘고 모바일 운영체제에서 안드로이드 점유율은 75프로가 넘는다. 데스크톱 운영체제에서 윈도우의 독주는 말하면 입이 아플 정도다.&lt;/p&gt;
&lt;p&gt;여기까지만 듣고보면 으레 사람들은 원래 세상이 승자 독식이야. 자본주의가 그렇지 뭐. 이런 식으로 반응한다. 하지만 전혀 그렇지 않은 세상도 있다. 제 아무리 뛰어난 청소부도 일반적인 청소부보다 열 배 더 많은 공간을 청소하긴 힘들다. 한계가 있다는 말이다. 치과의사도 마찬가지다. 그들이 하루에 진료할 수 있는 환자 수에는 큰 차이가 나타나지 않는다. 검사도 마찬가지다. 그들이 조사하는 사건의 개수는 제한된다. 즉 여기서 언급한 분야는 철저하게 중력이 지배하는 세상이다. 본질적인 구조상 압정식 사회가 될 수 없다는 이야기다.&lt;/p&gt;
&lt;h3&gt;#4&lt;/h3&gt;
&lt;p&gt;소프트웨어는, 특히나 일반 사용자용 소프트웨어는 철저하게 압정식 사회다. 승자독식, 약육강식이 지배하는 세상이다. 뛰어드는 모두가 부를 거머쥐는 세상이 아니라 살아남는 단 한 놈이 모두 가져가는 세상이다. 동영상에 나온 것처럼 컴퓨터 프로그래머를 해서 엄청난 부를 거머쥘 수도 있겠지만, 동시에 엄청난 시간과 노력을 투자하고도 땡전 한 푼 못 벌고는 쓸쓸하게 퇴장해야 할 수도 있다.&lt;/p&gt;
&lt;p&gt;카카오톡을 4명이서 2달 개발했다는 이야기가 나오는데 카톡을 유지시키는 데에는 어마어마한 금액이 들어갔다. 창업자가 워낙 펀딩 능력이 뛰어난 분이라 살아 남았지만 진짜 일반 벤처였다면 6달째 기근에 굶주리다 땡전 한 푼 못 벌고는 쓸쓸하게 퇴장해야 했을 수도 있다.&lt;/p&gt;
&lt;p&gt;그러니 저런 장밋빛 미래, 또는 앞으로의 수요, 내지는 전망 따위를 보고 직업을 선택하는 우를 범하진 말자. 직업 선택에는 수요와 전망 보다는 자신의 재능과 적성이 훨씬 더 중요하니까 말이다. 특히나 컴퓨터 프로그래머는 생각보다 훨씬 더 재능이나 적성이 중요한 분야다. 빌 게이츠 동영상만 봐도 그렇다. 마크 주커버그 처럼 여동생들이랑 더 재미있게 놀려고 소프트웨어를 만드는 걸 배우는 학생이 몇 명이 될까?&lt;/p&gt;
&lt;h3&gt;#5&lt;/h3&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/9bZkp7q19f0?si=xiGaYEScpgIROeLK&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;p&gt;&lt;strong&gt;그 누구도 뜨기 전까지는 성공 여부를 예측할 수 없다. 성공한 후에도 왜 떴는지 알 수 없다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;컨텐츠 산업은 그래서 더 어렵다. 소프트웨어 중에서도 게임이 더 어려운 이유.&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 게임 보안: 심리학자의 등장…]]></title><description><![CDATA[이질적인 것들의 만남이 때로는 더 환상적이기도 합니다. 최근 1년 사이에 XIGNCODE…]]></description><link>https://jiniya.net/wp/archives/10719</link><guid isPermaLink="false">https://jiniya.net/wp/archives/10719</guid><pubDate>Fri, 12 Apr 2013 23:58:52 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/Ao0e2ckFicU?si=epU8iscR1FYNF8HI&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;center&gt;
&lt;p&gt;&lt;strong&gt;이질적인 것들의 만남이 때로는 더 환상적이기도 합니다.&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;
   &lt;br&gt;
&lt;p&gt;최근 1년 사이에 XIGNCODE를 개발하면서 가장 큰 재미를 본 내용들은 대부분 사회공학적인 방법이었습니다. 결국 해커도 사람이고, 해킹툴을 사용하는 사람도 사람입니다. 이 인간이라는 한계를 넘어설 수는 없다는 게 제 생각입니다. 물론 그걸 뛰어넘는 이상한 사이코패스 같은 사람들도 있지만 그건 어디까지나 절대 다수는 아니잖아요. 이런 맥락에서 사회공학적인 기법은 심플하면서도 심오하면서도 뭔가 근원적인 매력을 가지고 있습니다. 하지만 이를 받아들이는 업체 사이에서는 아직도 갈팡질팡 하는 경향이 조금 있는 것 같습니다. 이런 전략을 아주 반기는 곳도 있고, 의구심을 품는 곳도 있고 그렇거든요. 설익은 상태죠.&lt;/p&gt;
&lt;p&gt;좀 더 재미있는 사실은 엔지니어가 많은 업체일수록 이러한 방식을 극도로 꺼려 하는 경향이 있다는 점 입니다. 사회공학적인 방법들을 사이비로 치부해 버리죠. 엔지니어들은 뭔가 어렵고, 심오하고, 복잡하고, 코딩하고 이런 걸 좋아하지만 사실 그런 것들은 웬만큼 실력이 비슷한 상대들 끼리는 뻔한 수 밖에는 안 됩니다.&lt;/p&gt;
&lt;p&gt;예전에 모 업체가 — 요즘 인터넷 기사에 줄기차게 등장하는 그 업체입니다. — 매번 보안 업체들 다 모아놓고 BMT를 시켰습니다. 마지막 관문은 크로스 해킹. 당연한 이야기겠지만 크로스 해킹을 방어하는 보안 제품은 하나도 없었습니다. 그러면서 보안 업체를 소집한 그 갑님께서는 이야기합니다. 제대로 만든 게 하나도 없으니 도입하지 않겠다. 요즘 하도 언론에 나오길래 꼬시다는 생각을 조금 했었습니다.&lt;/p&gt;
&lt;p&gt;국내 제품이 그렇지 뭐, … 라는 이야기가 여기저기서 들리는 것 같은데요. 근데 여러분이 자알 알고 계시는 외산 제품들도 똑같아요. 말만 들으면 알법한 그 엄청나게 큰 업체에서 만드는 소프트웨어들도 아주 손쉬우 방법에 당하거든요. 수십만라인 짜리 거창한 기능을 코드로 구현해 놓지만 몇 줄짜리 간단한 스크립트로 우회가 되는 경우도 부지기숩니다. 마치 괴델의 불완전성의 원리처럼 소프트웨어는 본질적으로 취약점을 가지고 태어나는지도 모릅니다. 폰 노이만식 아키텍처의 한계인지도 모르구요.&lt;/p&gt;
&lt;p&gt;마이크로소프트만 봐도 알 수 있잖아요. 취약점을 제거할 수 없기에 취약점 완화 방안을 내놓습니다. 즉, 공격은 여전히 가능한데 좀 더 어렵게 만들겠다는 거죠. 가능은 한데 경제적인 효용을 없도록 만드는 전략입니다. 이 정도가 최선입니다. ROE 따지는게 다 이유가 있는 거거든요. 어쨌든 기술이란게 좀 그렇습니다. 게임 보안 제품도 똑같거든요. 업체끼리 덤비면 사실 장난감 수준 밖에는 안 됩니다. 서로 쉬쉬하는 루프홀만 열거해도 일톤 트럭으로 옮겨야 할 지경이지 않을까 싶네요…&lt;/p&gt;
&lt;p&gt;감히 예측하건데 앞으로 사회공학적인 방법을 사용한 진단 기법들의 시대가 도래할 겁니다. 그럼 어떻게 돼냐구요? 네. 게임 보안 팀에 데이터 분석가 다음으로 심리학자가 초빙된다는 것을 의미하지요. &lt;a href=&quot;http://www.inven.co.kr/webzine/news/?news=55233&quot;&gt;똑똑한 라이엇 게임즈는 벌써 시작했군요.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;시스템 프로그래머 분들도 이제 마음을 조금 여시고 데이터 분석가와 심리학자, 그리고 뇌 과학자와 협업하는 방법을 배워야 할 때입니다. 코딩만 할 게 아니라 인문학 책도 좀 읽고, 커피숍 가서 사람들 구경도 좀 하고, 그 사람들이 도대체 왜, 그 비싼 돈을 주고 커피를 마시는 지에 관한 철학적인 생각도 좀 해 볼 때 입니다. 마음을 여세요. 프로그래밍이 전부라고 생각하는 순간 우물안 개구리 신세를 면하기 힘들거예요. 바야흐로 크로스오버, 퓨전이 대세인 시대입니다.&lt;/p&gt;
&lt;p&gt;후킹, 필터, 리버싱, 빅데이터, 클라우드, 가상화, NoSQL 같은 테크니컬한 지식 보다 깨진 유리창 이론, 2080 법칙, 나르시시즘, 플라시보 효과, 베르테르 효과, 낙인 효과 같은 이론이 훨씬 더 중요한지도 모릅니다. 결국은 다 사람이잖아요. 좀 더 넓게 생각할 필요가 있습니다. 이건 사이비가 아닙니다. 더 효과적인 방법이죠. 항상 ROE를 생각하세요. 어쨌든 아직은 자본주의로 돌아가는 세상이거든요.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 게임 보안: 0을 향한 질주…]]></title><description><![CDATA[우리도 항상 제로의 영역을 꿈꾼답니다 ㅋ~ #0 XIGNCODE…]]></description><link>https://jiniya.net/wp/archives/7777</link><guid isPermaLink="false">https://jiniya.net/wp/archives/7777</guid><pubDate>Thu, 11 Apr 2013 23:58:51 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube.com/embed/ttHpgjjVqCQ?si=sW1qujq-JGCb0Nor&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt;   &lt;/div&gt;
&lt;center&gt;
&lt;p&gt;&lt;strong&gt;우리도 항상 제로의 영역을 꿈꾼답니다 ㅋ~&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;
   &lt;br&gt;
게임은 가장 하드코어한 프로그램 중에 하나죠. 사람들이 하드웨어를 업그레이드하는 주된 원인이기도 합니다. 이런 게임과 동시에 실행돼야 하는 게임 보안 프로그램의 가장 큰 어려움 중에 하나는 게임에 영향을 주지 않아야 한다는 겁니다. 백신 검사를 시켜놓고 게임을 실행해 보세요. 게임이 얼마나 느려지는지 보시면 이 말의 의미를 금방 체감하실 수 있습니다. 게임 보안 프로그래머는 보안 프로그램이 존재 하지만 없는 것처럼 만들기 위해서 상당히 많은 공을 들여야 합니다.
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;XIGNCODE는 가장 공격적인 탐지 루틴을 사용하는 거의 유일한(?!) 게임 보안 제품입니다. 이러한 공격적인 방법을 사용하는 것은 해킹툴 억제력을 높이고 싸움에서 이길 수 있는 유일한 방법이기 때문입니다. 물론 그런다고 해킹툴이 100% 없어지는 것은 아니라는 점은 참고해 두시구요. 상대적으로 좀 더 우수한 해킹툴 제어 품질을 유지할 수 있다는 거겠죠 ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_0을_향한_질주.md_0.png&apos; data-alt=&apos;AMD 2.7GHz 싱글 코어에서의 XIGNCODE CPU 점유율&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 579px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/30697a6df719bd65020c29a8128c8d09/ff2d6/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_0%EC%9D%84_%ED%96%A5%ED%95%9C_%EC%A7%88%EC%A3%BC.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 88.94736842105263%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAIAAADUsmlHAAAACXBIWXMAAAsTAAALEwEAmpwYAAADbUlEQVR42o3SXUxTZxjA8afWxikiHz2O6I3AzIQWCnJBAgZ1GXNEs6qlFInJ1EQpIB8loCLGaRkzM3PSgC1qmG1dHC6AJUHdhjEgNrQ5pe1pgWI5PacfFAYtCsxkQyawnpeYbOrFkn+e/G7evBfPAxk1FP90MKFqOvlUkFc1kVTl51X6o05MbpDORBTNRkjfVDgTKZ2LlM6EHZ9NPj17WDFTd04Hv+lHCIfTOkwaLCNW+/AgYbYTVtxsMxIug43uJyijjTYQtNHm1ptHjXa33kIOOT20140bzUB6gmP+wJBj7PnzF/RY0OGaHKEmf58KTAcngoH/FJgaZzA1HsKr+T8o2gt2hz9r3w7WZo5aq07ds31t7Pqoj7nR/GgsgYslYlgShiVgWCIXS+IiYDEpMZzNnMJTxz2+cbAN+lI/58MmuH5T9VFaPITBKi4LPgSIRq2AixDFgL2JDWwokOZ7fRNADHlTMnmwGppVyvisuBBY61gQDrAWtYJ1CB8wYEeyAaDgmMQb+nnI6f++6aq0Stbb16fWXK49X32m9uxX8poLdaj6tyH/pvZMrayj846L9sCwc7xFozlb960Rx5U/tHzXfKXpVsONHxu0rQ2aUHfR/Be0Pytuai8/NXSRLhoMJrqkLFFyBFTXGtN2xYqLoOAkK7cE8oqZRAhiBAmCuJS97yg03BK7KB/0GahGBe9GM6iUjXsOxVfUQ5mcXVK3quJrppNoliPIEMrqOdJzoLmXR7p8YLK6ckVJKamgUjWVn98qk0PlRU7pxdUy1AoqECoRyuVrimpA0y4hXV4YHvV1PehuUbc5n9l7jA9/1Xc8NuhwQmdCvQsT0Wk0t1He/mdOEqyDVO6Xwrj0uNZWbbYkJy5tW2KGgL8zmZ+JykJzB0IGA8HulC2C+OoLlRTtBgtBCj5NgI2gVCp4WdthDbAiWMw9hKNWsAFhPQM2xuw5/5iIdnvAbCMFGbzQASivKfi70//nkeQfQY8tg3RpWfEnOTmduvbqS/IDh/OFoi+EEqEwF/UG+yXCg2LhwTyhqODAZ3uzrygujYb2TNL08nJgaXF6/k//4sL08tLce1t8Pff3Xy+ZXs0tLbxcnH8xSjqg7b6l5+lAd8/A4yfmR72m7h783R714l3d+G2dSd2Bt/9ivtupv3Ov7yed6R/RYALBMQZfsgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;AMD 2.7GHz 싱글 코어에서의 XIGNCODE CPU 점유율&apos; title=&apos;&apos; src=&apos;/static/30697a6df719bd65020c29a8128c8d09/ff2d6/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_0%EC%9D%84_%ED%96%A5%ED%95%9C_%EC%A7%88%EC%A3%BC.md_0.png&apos; srcset=&apos;/static/30697a6df719bd65020c29a8128c8d09/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_0%EC%9D%84_%ED%96%A5%ED%95%9C_%EC%A7%88%EC%A3%BC.md_0.png 190w,
/static/30697a6df719bd65020c29a8128c8d09/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_0%EC%9D%84_%ED%96%A5%ED%95%9C_%EC%A7%88%EC%A3%BC.md_0.png 380w,
/static/30697a6df719bd65020c29a8128c8d09/ff2d6/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_0%EC%9D%84_%ED%96%A5%ED%95%9C_%EC%A7%88%EC%A3%BC.md_0.png 579w&apos; sizes=&apos;(max-width: 579px) 100vw, 579px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;AMD 2.7GHz 싱글 코어에서의 XIGNCODE CPU 점유율&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;공격적인 방법이란 달리 말하면 더 많은 연산을 의미하고, 더 많은 연산이란 더 많은 CPU 자원을 의미합니다. 하지만 게임과 동시에 실행되는 게임 보안 제품의 경우는 솔루션의 특성상 CPU 자원을 굉장히 아낄 수 밖에 없습니다. 그래서 우리는 공격적인 방법을 사용하돼 가급적 게임 구동 중에는 CPU 점유율을 거의 제로에 가깝게 유지하려고 애를 씁니다. “0%니까 어 그럼 CPU를 사용하지 않는다는 건가?”라고 생각하면 오산입니다. 0.0001%, 0.00001%씩 사용한다는 말이거든요. 그 1앞에 있는 0을 한없이 늘리기 위한 노력을 불출주야 쉬지 않고 노력 한다는 의미죠.&lt;/p&gt;
&lt;p&gt;일반적으로 싱글코어에서 실행되는 게임에 있어서 2% 이상의 순간 CPU 점유율을 게임 보안 제품이 가져가면 민감한 사용자들이 순간 랙을 체감합니다. 3% 이상의 순간 점유율을 가져가면 조금 둔한 사용자가 끊김을 체감하고, 5% 이상의 점유율을 가져가면 모든 사용자가 랙을 호소합니다. 최소 사양 기준으로 말이죠.&lt;/p&gt;
&lt;p&gt;그래서 어떤 경우에도 순간적으로 CPU 점유율을 과도하게 사용하지 않아야 합니다. 이게 말로만 들으면 굉장히 쉽습니다. 아, 그냥 CPU를 덜 사용하면 되겠구나라고 말이죠. 하지만 사실 윈도우 환경에서 스레드 별로 CPU 쿼터를 지정하는 방법이 공식적으로는 존재하지 않기 때문에 정확하게 게임 보안 제품이 가져가는 CPU 점유율을 제한하는 일은 생각처럼 그리 쉽진 않습니다.&lt;/p&gt;
&lt;p&gt;윈도우 스케줄러가 아닌 선점형 스케줄러를 직접 구현하는 것이 가능하다면 문제가 조금 간단한데 윈도우 환경에서 유저모드에서 그런 스케줄러를 구현하기가 쉽지는 않습니다. 파이버가 비선점형으로 구현된 것만 봐도 알 수 있죠. 물론 커널 스케줄러를 대체하는 방법이 있긴 한데 이는 문서화된 방법도 아닐 뿐더러 시스템 전체적으로 굉장히 리스크가 큰 방법이라 상용 제품에 사용하기엔 힘든 실정입니다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;뭐 천천히 실행하면 되는 걸 가지고 왜 그렇게 호들갑을 떠냐구요. 맞습니다. 하지만 여기엔 다른 쪽에서 우리를 압박하는 요소가 있습니다. 바로 마의 시간입니다. CPU 점유율을 낮추기 위해서 탐지 코드가 무한대로 느려져서는 안 된다는 것을 의미하는 말이죠. 게임 특성에 따라 다르긴 하지만 통상적으로 게임 보안에서 3분과 5분은 굉장히 의미있는 탐지 시간입니다.&lt;/p&gt;
&lt;p&gt;3분 내 탐지가 이루어지면 유료 핵툴인 경우에는 제작자가 핵툴이 패치 됐다는 공지를 올리고 핵툴에 대한 업데이트를 진행합니다. 아주 악성 사용자들의 경우에도 이 시간 내에 탐지가 이루어지면 해킹툴 사용을 보류하는 경향이 높습니다.&lt;/p&gt;
&lt;p&gt;5분 언저리에서 진단이 되거나 이 시간보다 진단이 지연되게 되면 해킹툴 제작자는 패치 됐다는 공지를 하지 않습니다. 사용자들은 이를 하나의 페널티로 인식하지요. 공격적인 사용자의 경우에는 지속적으로 해킹툴을 사용합니다. 5분 내에 탐지되지만 게임 핵툴을 사용하는 사용자가 계속 존재하기 때문에 게이머들은 지속적으로 게임 내에서 해킹툴 사용자를 마주치게 되고 해킹툴이 많다는 인상을 받게 됩니다.&lt;/p&gt;
&lt;p&gt;즉, 마의 시간이란 아무리 늦어도 3분 내에는 해킹툴이 차단이 되어야 하고, 아주 최악의 경우에도 5분 내에는 사용자가 지속적으로 게임 플레이를 할 수 없도록 만들어야 한다는 것을 의미합니다. 이렇게 만들기 위해서는 당.연.한 이야기겠지만 CPU를 쓸 수 밖에는 없죠. 따라서 CPU 자원과 해킹툴 탐지 속도가 사이의 최적값을 찾는 것이 중요합니다. 그래야 CPU 자원을 최소한으로 사용하면서도 탐지 속도도 일정 수준 이상으로 끌어 올릴 수 있거든요.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;이런 이유로 XIGNCODE는 조금은 특이한 디스패칭 전략을 사용합니다. 우리 전략의 핵심은 시점입니다. 우리는 크게 이 시점을 네 가지 기준으로 분류합니다. 첫 번째는 게임이 시작하는 S 시점입니다. 게임의 각종 데이터가 로딩되기를 사용자가 기다리는 시점이죠. 다음으로는 시점은 게임이 시작돼서 사용자가 게임을 즐기는 P 시점이 있습니다. 또 게임을 사용자가 즐기다 게임을 일시 중단한 상태로 다른 작업을 수행하는 L 시점이 있습니다. 윈도우 환경이라면 게임이 액티브 프로세스가 아닌 시점을 의미하겠지요. 끝으로 해킹툴이 탐지된 X 시점이 있습니다. 똑똑한 분들이라면 버얼써 눈치채셨겠지만 이렇게 시점을 구분한 이유는 동일한 루틴도 어떤 시점에 실행되느냐에 따라서 CPU 자원 소모량을 다르게 만들기 위함입니다.&lt;/p&gt;
&lt;p&gt;S 시점은 게임 데이터를 로딩하기 위해서 사용자가 어차피 기다리는 시점이기 때문에 이 시점에 스케줄링 되는 루틴들은 모든 CPU 자원을 활용하는 형태로 구동됩니다. P 시점은 사용자가 실제로 게임을 즐기는 시점이기 때문에 최소한의 CPU를 사용할 수 있도록 스케줄링 됩니다. 또한 뒤에서 살펴보겠지만 점감 프리미엄을 받도록 설계돼 있습니다.&lt;/p&gt;
&lt;p&gt;L 시점의 경우에는 조금 애매합니다. L 시점이 됐다고 바로 모든 CPU 자원 소모가 들어가는 작업을 수행한다면 바로 다시 게임으로 돌아오는 경우에 랙을 체감할 수 있기 때문이죠. 떠난 시간이 일정 수준을 넘어서면 모든 검사 루틴들이 시작 시점과 동일하게 CPU 자원을 많이 소모하는 형태로 동작합니다. 다른 프로세스에게는 미안한 일이지만 어쨌든 게임 플레이라는 입장에서 봤을 때에 페널티가 발생하지는 않기 때문이죠. 마지막으로 X 시점입니다. 이 시점은 우리가 똥을 싸질러도 되는 시점이지요. 가장 아름다운 순간입니다. 크래시 따위도 전혀 무섭지 않은 무적 상태랍니다 ㅋㅋ~&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;XIGNCODE는 랙을 줄이기 위해서 사회공학적인 기법들이 사용하기도 합니다. 바로 검사 루틴들의 스케줄링 정책입니다. XIGNCODE의 모든 검사 루틴들은 기본적으로 리타르단도 방식으로 스케줄링됩니다. 리타르단도가 뭐냐구요? 점점 느려진다는 말이죠. 왜 점점 느려지게 만들었을까요? 정상 사용자들에게 최대한 피해를 주지 않기 위해서 입니다.&lt;/p&gt;
&lt;p&gt;일반적으로 해킹툴 사용자의 경우 게임 시작과 동시에 해킹툴을 사용하는 경향이 매우 높고, 모든 해킹툴 탐지의 80%는 20% 악성 사용자에게서 발생하는 경향이 있습니다. 신기하지만 2080 법칙은 어디에나 통용되는 것 같아요. 어쨌든 사회공학적으로 착하게 플레이를 하는 사용자들은 지속적으로 착하게 플레이할 가능성이 높다는 거죠. 그래서 XIGNCODE의 모든 검사 루틴은 점감 효과를 받도록 스케줄링됩니다. 게임 시작 후에 일정 시간이 지나면 거의 모든 검사 루틴들이 마치 죽은듯이 동작한다는 의미입니다. 물론 그렇게 되더라도 앞서 말한 3분내 탐지는 가능할 정도 수준으로 동작은 해야겠지요.&lt;/p&gt;
&lt;p&gt;윈도우 사용자라면 윈도우를 사용하면 할수록 빨라진다는 느낌을 받았을 겁니다. 또 어떤 프로그램을 설치해서 처음 실행했을 때 보다는 자주 실행했을 때 그 프로그램의 수행 속도가 더 빨라지는 현상도 느꼈을 텐데요. 운영체제에서 이런 것들을 가능하게 해주는 캐싱 시스템이 존재하기 때문입니다. 대단한 건 아니고 여러분이 자주 요청했던 리소스를 미리 캐싱해놨다가 사용자가 요청하는 시점에 니가 이걸 요청할 줄 알았다하고는 바로 내주는 것이죠. 이 시스템이 재미난 건 대부분의 사용자가 쓰는 프로그램을 반복적으로 사용하기 때문에 굉장히 히트율이 높다는 겁니다. XIGNCODE 개발팀에는 최근에 이런 점에 착안해서 스케줄링 정책에 이런 캐싱 시스템을 도입하려고 하고 있습니다. 즉, 여러분이 게임을 지속적으로 착하게 플레이 하면 할수록 보안 제품으로 인한 성능 페널티는 점점 더 없어지고, 여러분이 해킹툴을 사용하고 뻘짓을 하면 할 수록 여러분의 시스템을 박박 긁는 것이죠.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_0을_향한_질주.md_1.png&apos; data-alt=&apos;안타깝게도 여기에 은탄환(Silver Bullet)은 없습니다.&lt;br&gt;&lt;br&gt;물론 그렇다고 너무 아쉬워할 필요는 없습니다.&lt;br&gt;&lt;br&gt;최상급 수제 에픽 탄환인 XIGNCODE가 있잖아요.&lt;br&gt;&lt;br&gt;딜이 안 될 때에는 탄환을 먼저 체크해 보세요. 미터기는 저희가 찢어 드리겠습니다.&lt;br&gt;&lt;br&gt;뉴요커 냥꾼이는 앵벌 할 때에도 에픽 탄환을 쓴다는 점. 꼭 기억하세요 ㅋ~&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/40e890bd5b52e78e1bac3a11ccffd975/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_0%EC%9D%84_%ED%96%A5%ED%95%9C_%EC%A7%88%EC%A3%BC.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 66.84210526315789%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACS0lEQVR42mVSy04UQRTthcHERHwlhigLjZGVJoyEjfAH/ocmLDSGXxGF6FJMXLgybtSViUuVgRGkZ6anu+td1e83r8HTEN1QfXP7VPe9dc89t6y+3Ye5rusMHdu2fc8LTMAZT5Lk+P8aj1sfBPtC1EpX0mT9H2NBrCzNAx0ZZSRTRgUAoYm0NACcScEEZwK+19v5/vHrt/UPn9+++7L+/tPaK//XT0srQ3zOKPNGvu/6rgNPgV3H84bABNu6rpceP719ozMzPTt54eq1S1MT5yZXVlatOIoZFcznxKNGB1VVl2VVnvoTK8rq8OBw+dnzuc7c4sOFzuz81PVbl89feb26ZhVFG1qViEaBpm6a1uPV7DX/8OHR0fKTpQdT04/udxbu3pu/eWdm4uKbFy+tKIiIT6WQjDAUp4RzwhkBEUJcTzBJfYamuhvd7e5mb2Oz1+3+2dn5vbUFXa04jBEqhaqrJgpjREMtJbWGqmUJ8aRUOC4OkyKvsqzI06LIy/GJ/laW5BA8y3J8yuHyAjqDgu9RcGkFGxHgkeMNdocDewhd4ijZa/ba5NCEggotNedScoXKjAjqc4oWPEZJewSogTz+go7Bo4LmNBlpGM/QHqCI4Nrp95jfi8IUI4QZEyA60EGaZsdnlpXEieBKcqkEvJbcT2OVo4WsQDtpnLUgy5F8sH9wNjklLsXdAquWXstZgDPuBvHYaOB6jucMRrvbNiUMDbd0YADaWBgjlMySDMpBCRCBYZsmaRKlJyoIpHHKiU+U0KCAerA4Sv4C24Oea1Ci4zIAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;안타깝게도 여기에 은탄환(Silver Bullet)은 없습니다.&lt;br&gt;&lt;br&gt;물론 그렇다고 너무 아쉬워할 필요는 없습니다.&lt;br&gt;&lt;br&gt;최상급 수제 에픽 탄환인 XIGNCODE가 있잖아요.&lt;br&gt;&lt;br&gt;딜이 안 될 때에는 탄환을 먼저 체크해 보세요. 미터기는 저희가 찢어 드리겠습니다.&lt;br&gt;&lt;br&gt;뉴요커 냥꾼이는 앵벌 할 때에도 에픽 탄환을 쓴다는 점. 꼭 기억하세요 ㅋ~&apos; title=&apos;&apos; src=&apos;/static/40e890bd5b52e78e1bac3a11ccffd975/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_0%EC%9D%84_%ED%96%A5%ED%95%9C_%EC%A7%88%EC%A3%BC.md_1.png&apos; srcset=&apos;/static/40e890bd5b52e78e1bac3a11ccffd975/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_0%EC%9D%84_%ED%96%A5%ED%95%9C_%EC%A7%88%EC%A3%BC.md_1.png 190w,
/static/40e890bd5b52e78e1bac3a11ccffd975/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_0%EC%9D%84_%ED%96%A5%ED%95%9C_%EC%A7%88%EC%A3%BC.md_1.png 380w,
/static/40e890bd5b52e78e1bac3a11ccffd975/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_0%EC%9D%84_%ED%96%A5%ED%95%9C_%EC%A7%88%EC%A3%BC.md_1.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;안타깝게도 여기에 은탄환(Silver Bullet)은 없습니다.&lt;br&gt;&lt;br&gt;물론 그렇다고 너무 아쉬워할 필요는 없습니다.&lt;br&gt;&lt;br&gt;최상급 수제 에픽 탄환인 XIGNCODE가 있잖아요.&lt;br&gt;&lt;br&gt;딜이 안 될 때에는 탄환을 먼저 체크해 보세요. 미터기는 저희가 찢어 드리겠습니다.&lt;br&gt;&lt;br&gt;뉴요커 냥꾼이는 앵벌 할 때에도 에픽 탄환을 쓴다는 점. 꼭 기억하세요 ㅋ~&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[좀비 프로세스를 찾아서…]]></title><description><![CDATA[일반적으로 fork…]]></description><link>https://jiniya.net/wp/archives/10585</link><guid isPermaLink="false">https://jiniya.net/wp/archives/10585</guid><pubDate>Thu, 04 Apr 2013 23:58:50 GMT</pubDate><content:encoded>&lt;p&gt;일반적으로 fork 계열을 사용하는 유닉스 운영체제에서는 좀비 프로세스라는 말이 자주 등장합니다. 스티븐스 아저씨의 역작인 유닉스 프로그래밍 책에도 좀비 프로세스에 대한 소개가 여러 차례 등장하지요. 하지만 윈도우 운영체제에서는 좀비 프로세스라는 용어는 생경합니다. 이런 현상을 반영하듯이 스티븐스 아저씨에 필적하는 제프리 리처 아저씨의 역작 “Windows via C/C++”에도 좀비 프로세스라는 용어는 등장하지 않습니다.&lt;/p&gt;
&lt;p&gt;그렇다면 윈도우에는 좀비 프로세스가 없는 걸까요? 결론부터 말하면 그건 아닙니다. 근데 왤케 낯선 걸까요? 그 가장 큰 이유는 윈도우 운영체제가 좀비 프로세스에 대한 정보를 꽁꽁 숨겨 두었기 때문입니다. 작업 관리자에서 좀비라고 표시되는 프로세스나 죽은 프로세스 임에도 죽지 않고 버젓이 표시되는 것을 본 적이 있으신가요? 없을 겁니다. Toolhelp나 PSAPI를 사용해서 프로세스를 열거할 때에 죽은 프로세스가 나타나는 것을 보신 적이 있으신가요? 없을 겁니다. 이는 NT 네이티브 API를 사용해도 똑같습니다.&lt;/p&gt;
&lt;p&gt;그렇다면 이렇게 운영체제가 꽁꽁 숨겨놨는데 무슨 근거로 존재한다고 주장하는 걸까요? 나타나지도 않는데 무슨 근거로 있다고 하는 겁니까, 라고 물어볼지도 모르겠습니다. 당.연.히 일반적이지 않은 방법을 사용해야 그 존재를 찾을 수 있습니다. 좀비를 만나게 되는 경우는 크게 두 가지 경우가 있는데요. 하나는 PID 브루트포스라는 방법으로 무작위 PID를 대입해서 프로세스가 존재하는지를 검사할 때에 이 좀비가 나타나게 됩니다. 다른 하나는 커널 레벨에서 EPROCESS 구조체를 직접 열거하면 만날 수 있습니다.&lt;/p&gt;
&lt;p&gt;뭐 어쨌든 좀비 좀비 거렸는데 그러면 일단 그 좀비 프로세스의 실체를 한 번 살펴볼까요? 아래는 간단하게 notepad를 좀비로 만들고 그 결과를 관찰한 windbg 출력입니다. 이 내용을 보면 좀비 프로세스가 무엇인지 명확하게 알 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;kd&gt; !process 0 0 notepad.exe
PROCESS fffffa8002236b30
    SessionId: 1  Cid: 08dc    Peb: 7fffffdf000  ParentCid: 076c
    DirBase: 3cc09000  ObjectTable: 00000000  HandleCount:   0.
    Image: notepad.exe

kd&gt; !process fffffa8002236b30
PROCESS fffffa8002236b30
    SessionId: 1  Cid: 08dc    Peb: 7fffffdf000  ParentCid: 076c
    DirBase: 3cc09000  ObjectTable: 00000000  HandleCount:   0.
    Image: notepad.exe
    VadRoot 0000000000000000 Vads 0 Clone 0 Private 1. Modified 4. Locked 0.
    DeviceMap fffff8a0016b0200
    Token                             fffff8a001c6a060
    ElapsedTime                       00:00:27.341
    UserTime                          00:00:00.046
    KernelTime                        00:00:00.109
    QuotaPoolUsage[PagedPool]         0
    QuotaPoolUsage[NonPagedPool]      0
    Working Set Sizes (now,min,max)  (5, 50, 345) (20KB, 200KB, 1380KB)
    PeakWorkingSetSize                1799
    VirtualSize                       55 Mb
    PeakVirtualSize                   77 Mb
    PageFaultCount                    1850
    MemoryPriority                    BACKGROUND
    BasePriority                      8
    CommitCharge                      0

No active threads
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;아직도 좀비 프로세스가 뭔지 정확하게 이해하지 못하신 분들을 위해서 첨언하면 이렇습니다. 좀비 프로세스란 프로세스 종료 처리가 모두 완전하게 끝났음에도 프로세스 구조체가 사라지지 않고 남아있는 경우를 말합니다. 즉, 프로세스가 죽고 싶어도 죽지를 못하니 그 증상이 마치 좀비 같다고 해서 좀비 프로세스라고 부르는 거지요. 물론 앞선 windbg 출력에 보이는 것처럼 프로세스 종료에 관한 모든 처리가 끝났기 때문에 좀비 프로세스는 어떠한 주소 공간도, 어떠한 커널 오브젝트도, 어떠한 스레드도 포함하고 있지 않습니다. 단지 커널 구조체와 PID란 자원을 낭비하고 있을 뿐이지요.&lt;/p&gt;
&lt;p&gt;그렇다면 이 좀비 프로세스는 도대체 왜 죽지 않고 이렇게 남아 있는 걸까요? 이유는 간단합니다. 프로세스가 죽었음에도 해당 프로세스를 참조하는 다른 프로세스가 남아 있다면 그 죽은 프로세스는 좀비가 됩니다. 뭐 유닉스에서 fork로 좀비가 생기는 원리랑 동일하다고 생각하시면 됩니다. 아래 프로그램을 사용하면 아주 손쉽게 좀비를 만들 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;windows.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tchar.h&quot;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_tmain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; argc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _TCHAR&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; argv&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;argc &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    HANDLE process &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;OpenProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SYNCHRONIZE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_tcstoul&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;argv&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;open error %d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;getchar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;notepad.exe를 실행합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;앞선 코드의 프로그램을 실행합니다. ex) zombie_maker.exe [notepad PID]&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;실행한 notepad를 종료합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이 상태가 되면 죽은 notepad는 좀비가 됩니다. zombie_maker가 죽은 녀석의 핸들을 잡고 있기 때문이지요. 그 핸들이 닫히기 전까지 notepad는 영원히 좀비 상태로 남아있게 됩니다. 그 핸들이 닫히는 순간 비로소 좀비는 죽을 수 있게 되지요.&lt;/p&gt;
&lt;p&gt;결국 좀비 프로세스란 &lt;a href=&quot;http://jiniya.net/tt/769&quot;&gt;탐색기가 파일 핸들을 잡아서 파일 삭제가 안 되는 것처럼&lt;/a&gt; 누군가 프로세스 핸들을 잡고 있어서 그런 경우가 다반사 입니다. 그럼 주로 어떤 놈들이 잡고 있는 경우가 많을까요? 보안 프로그램, 특히 백신같이 프로세스를 스캔하는 녀석들이 잡고 있는 경우가 많이 있습니다. 다행이 유저 레벨에서 벌어지는 일의 경우에는 핸들을 잡고 있는 프로세스만 종료하면 좀비가 사라지지만 커널 모드 드라이버에서 핸들릭이 발생해서 좀비가 된 프로세스는 재부팅 전까지는 영.원.히 좀비 상태가 된다는 것에 주의해야 합니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[에디터 열전]]></title><description><![CDATA[프로그래머에게 도구가 중요합니다. 그 중에서도 에디터는 정말 백미라고 할 수 있죠. 어떤 에디터를 사용하는지로 그 프로그래머의 정체성을 엿볼 수 있다고도 생각됩니다. vi와 emacs…]]></description><link>https://jiniya.net/wp/archives/10567</link><guid isPermaLink="false">https://jiniya.net/wp/archives/10567</guid><pubDate>Tue, 02 Apr 2013 23:58:49 GMT</pubDate><content:encoded>&lt;p&gt;프로그래머에게 도구가 중요합니다. 그 중에서도 에디터는 정말 백미라고 할 수 있죠. 어떤 에디터를 사용하는지로 그 프로그래머의 정체성을 엿볼 수 있다고도 생각됩니다. vi와 emacs의 논쟁은 프로그래밍 언어에 관한 논쟁만큼 오래 되었지요. 오늘 아시는 분이 notepad++에 관한 기능을 물어보셔서 생각난 김에 정리해 봅니다. 예전에 제가 썼었던 &lt;a href=&quot;http://jiniya.net/tt/376&quot;&gt;소스 인사이트에 관한 글&lt;/a&gt;도 참고하시면 좋을 것 같네요.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; margin-bottom: 16px;&apos; data-url=&apos;./에디터_열전.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/24fac61cd544bd1f41861dd88db2c943/b0db9/%EC%97%90%EB%94%94%ED%84%B0_%EC%97%B4%EC%A0%84.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 63.68421052631579%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACNElEQVR42oXQ3UtTcRzH8fNPdLPc3Hl++p1tZzvueWdPPoQhRUZW4EX1FwQRgcMdG6YuosugbsRqoCnVhdBNQSycZ61y5+whp1u2hzR1m4soumvhnUWD1+2b74cv9OBldTa+2/ZwpX73qXJzLi7NxiNziTtLH24vpKLzb6MLqZn51FRMnny0cismzyypbdOLyv17zyAlk9utfdrfrvz4Vo9OSaJgOBEQgn2mXr/V4+QdVs4mMAJPcgwMaD1g9CylY+luBtcYrDYonS9ubm7UatvNZmssHKK6tD4LK9hxFNch2KFuFNdjxCH4DxJBMS3Lm6HCVi2bUbK5/N7eXmRSAijsMQOrnWZYjKAQ8t9QgtABswUqVnYyqrK2lm4dtCYiYQ6BfQLncrNmnqQZtFNc3smqiprJNptNKTJuRJA+m8njBUYjTna+XN7JZdVkMtmeLUXCAO728Gx7NstiFN0pXn2nyqsJWZbXC4XrN64RGOyymoQeCgCUojvN/lisqEq6WCzV6/VwOEQD0ut38TzgDBTNYB3i9VK1/bCtrc8HB62wFDLxTP+A3x9wi6IDcCRBwf+L32fWNzYK5Uq13mhIE+MsoESvQ/Q6RZ/TLdp5C0fR2F9wktRzlh4oXyh9/VJu7O/++vk9MjFG4F2i2+K0G80mEseOk4QWQzVHoKgG0R+jOBaKLSeeLL9+/PzV4os3V0PT/qGRkyOXB89dGhgeDQydD566cETv6Yv9Z0Z9g2eDw1d+A+0bFGnm5WmsAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 0&apos; title=&apos;&apos; src=&apos;/static/24fac61cd544bd1f41861dd88db2c943/b0db9/%EC%97%90%EB%94%94%ED%84%B0_%EC%97%B4%EC%A0%84.md_0.png&apos; srcset=&apos;/static/24fac61cd544bd1f41861dd88db2c943/08678/%EC%97%90%EB%94%94%ED%84%B0_%EC%97%B4%EC%A0%84.md_0.png 190w,
/static/24fac61cd544bd1f41861dd88db2c943/2edd7/%EC%97%90%EB%94%94%ED%84%B0_%EC%97%B4%EC%A0%84.md_0.png 380w,
/static/24fac61cd544bd1f41861dd88db2c943/b0db9/%EC%97%90%EB%94%94%ED%84%B0_%EC%97%B4%EC%A0%84.md_0.png 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;내가 요즘 대세 Sublime Text&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;요즘 프로그래머들 사이에 가장 핫한 텍스트 에디터인 &lt;a href=&quot;http://www.sublimetext.com/2&quot;&gt;Sublime Text 2&lt;/a&gt;입니다. 파이썬으로 만든 녀석인데 파이썬으로 이렇게 빠르게 동작한다는 게 가능한 줄은 정말 몰랐습니다. C++로 만들고 플러그인만 파이썬 입니다. ㅋㅋ~ 거기다 정말 기가막힌 다양한 기능에 손쉬운 플러그인 설치. 뭐하나 흠잡을데 없는 최고급 텍스트 에디터입니다. 맞아요. 가격이 비싼게 흠이라면 흠이겠군요. 근데 내그웨어인데다 광고가 많이 뜨지도 않기 때문에 무료로도 크게 불편함 없이 사용하실 수 있습니다. 처음 사용하시면 다소 당황할 수 있는데 아래 도움글을 보시고 연습 후에 쓰시면 감칠맛이 백배더 증가하는 버프를 받으실 수 있습니다. 환골탈태한 Sublime Text 3가 곧 출시한다니 엄청 기대되는 시점입니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://windtale.net/blog/sublime-text-tip/&quot;&gt;http://windtale.net/blog/sublime-text-tip/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; margin-bottom: 16px;&apos; data-url=&apos;./에디터_열전.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/b6dbdaef82f07dcaa527d29509d6b8da/b0db9/%EC%97%90%EB%94%94%ED%84%B0_%EC%97%B4%EC%A0%84.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 62.10526315789474%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACG0lEQVR42k2R627TQBCF/f6vAQhoSsMPEKgVqFJpSgtp0jr23q/e9SVOk7o0TuI0DpPQSoxWR2PvfjpnZ4NOzx30VKfnu1fj7mV+dJEdXhTdy/LwzL4+ta++qzen8t1ZchzVJ/FityLQ5fFt9elLGPRHUvIR57TI89Slo5vPBB9Q/IGgw8HNQRx3EH4/Ct/Cp2BdRo5AOfsoWedn1A9CxmZ35XyxepzX1cMfpTHnt8YgIUOEr71nWS4IHUbxb6FGmAyUjoSMBBuc98NAeu0NXj+1m01b1wulDOcqsV4ITQh3Ps/yMfzBmElpuNDWOq0TLVVvyAM/nS/r6apZt+2mns8llBCJNUKIGCGf+jzPCCUIxVIJSonRSiq4KekNaBCp8bppmvVTs14/Ps6BIYQkieWCxzFyzmVZhjGJo0hKBVtaKyGk4PT8mgTfLm58YrdQ7baua845HLXWMMbAeQ+nwMRxDMwe1gKMKfkV6eBHH03KYruvfzCUtRYUQWy/c36BBQVYaYjAKR5SF4D73X/w/srCJQk0mNA0S+EJIQXGSGkNjTUWGinokPrAThbbdtO27bOzEHDCGJg5DAw773fOlD7HpnRHKg2xB8QFws+emuVytWyaVXU/s0ZZo1PvnDUwlqLIyrKwOysOTwDNbguCaRkyH3y9RCdX7Dy0zOTaT9z43pdVWj54WOMK1BX3STFLXtTmMzeu8kk1kNO/GXxzNG7++90AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 1&apos; title=&apos;&apos; src=&apos;/static/b6dbdaef82f07dcaa527d29509d6b8da/b0db9/%EC%97%90%EB%94%94%ED%84%B0_%EC%97%B4%EC%A0%84.md_1.png&apos; srcset=&apos;/static/b6dbdaef82f07dcaa527d29509d6b8da/08678/%EC%97%90%EB%94%94%ED%84%B0_%EC%97%B4%EC%A0%84.md_1.png 190w,
/static/b6dbdaef82f07dcaa527d29509d6b8da/2edd7/%EC%97%90%EB%94%94%ED%84%B0_%EC%97%B4%EC%A0%84.md_1.png 380w,
/static/b6dbdaef82f07dcaa527d29509d6b8da/b0db9/%EC%97%90%EB%94%94%ED%84%B0_%EC%97%B4%EC%A0%84.md_1.png 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;에디터 계의 영원한 스테디 셀러 EditPlus&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;국산 에디터의 자존심이죠. 제가 notepad++을 사용하지 않는 이유도 &lt;a href=&quot;http://editplus.co.kr/&quot;&gt;editplus&lt;/a&gt;가 있기 때문입니다. 주로 전 엄청 큰(몇십메가에서 몇백메가) 텍스트 파일을 작업할 때 이 녀석을 사용하는데요. 정말이지 그렇게 큰 텍스트 파일도 아주 부드럽게 뷰잉해 줍니다. notepad++은 약간 한계를 보이더군요. 거기다 ftp 연동 기능이 아주 편리하게 구성돼 있는것도 장점인 것 같구요. 여튼 정말 강추하고 싶은 텍스트 에디터예요.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 420px; margin-bottom: 16px;&apos; data-url=&apos;./에디터_열전.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ef996bd44919a15eebbbbb055eed1825/b0db9/%EC%97%90%EB%94%94%ED%84%B0_%EC%97%B4%EC%A0%84.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 52.63157894736842%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAB6klEQVR42m2RT2/TMBjG85E4cOLAHwHajU+104QQm0pHJyGVgbggIUFBO7QFOjJEBe3asrbbaNLEiR07dv7NTdy01CEdYlTaXv1e6zn4J0uPlc0ay9mqe1v1ZXhcJQ8r44232uYeKNbwkxoqVHPgdiMsqXFJnZRUvn2QlPf0108rCnMNB0FMSOB7LnH4WeQxSqnLOU/T6VSIv4gk/k8ci2nSxTOF4IDSIGReHHERCzERCU/EJBE8vyfms9nvfGdpOptfME3n2WI+MHzFNlITRx964fufvNIJ3x0GlW6UhzftsDXmkEYGjgAJspWRcnkOrVAhlih8W9x4Ju/vynu72d3n2doLufYyu76TrTcWbc2vD7y2weUl+RRNFALEekNe28lulpfcKmd3yvLBK3m7nG2oi5Yefhz4XSu+WrbHojqIH30+K6qTwpeoeMCL+/7+wP16TPsgHAK/M8K6haWUV8iGNs179glkGGLbINDAtuk6kGLkM4ps2zIM7KAVd0U2deGyACFsIwyRAywbANswAUTID8L8CzVNsyx76fxjcS6f5DK2UubS/B0XOxhazjnIBow4gcdMfYRMPQ+X2x45XGkdez2dqR3t+xB2RqSr0R9D2DwCPZ3mHP7CzT5o9q1TxC84gVzHk09H7A/ZVEYCu8723gAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 2&apos; title=&apos;&apos; src=&apos;/static/ef996bd44919a15eebbbbb055eed1825/b0db9/%EC%97%90%EB%94%94%ED%84%B0_%EC%97%B4%EC%A0%84.md_2.png&apos; srcset=&apos;/static/ef996bd44919a15eebbbbb055eed1825/08678/%EC%97%90%EB%94%94%ED%84%B0_%EC%97%B4%EC%A0%84.md_2.png 190w,
/static/ef996bd44919a15eebbbbb055eed1825/2edd7/%EC%97%90%EB%94%94%ED%84%B0_%EC%97%B4%EC%A0%84.md_2.png 380w,
/static/ef996bd44919a15eebbbbb055eed1825/b0db9/%EC%97%90%EB%94%94%ED%84%B0_%EC%97%B4%EC%A0%84.md_2.png 420w&apos; sizes=&apos;(max-width: 420px) 100vw, 420px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;헥사가 필요할 땐, HxD&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이러니 저러니해도 시스템 프로그래머라면 raw data를 처리할 일이 많이 있습니다. 그럴 때 간편하게 사용할 수 있는 헥사 에디터입니다. 크게 특출난 기능은 없지만, 그렇다고 크게 빠지는 부분도 없는 문안함이 장점이랄까요? 물론 무료라는 점은 &lt;a href=&quot;http://mh-nexus.de/en/hxd/&quot;&gt;HxD&lt;/a&gt;를 더욱 돋보이게 만들어 줍니다 ㅋㅋ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 안드로이드 입문]]></title><description><![CDATA[얼마전에 윈도우8로 시스템을 업그레이드 하면서 마이크로소프트가 정신을 차리기 시작하고 있다는 생각이 들었습니다. 가히 저에게는 혁신적인 운영체제라고 할 만큼 만족스러웠거든요. 그런데! 그런데! 윈도우…]]></description><link>https://jiniya.net/wp/archives/9960</link><guid isPermaLink="false">https://jiniya.net/wp/archives/9960</guid><pubDate>Wed, 27 Mar 2013 23:58:48 GMT</pubDate><content:encoded>&lt;p&gt;얼마전에 윈도우8로 시스템을 업그레이드 하면서 마이크로소프트가 정신을 차리기 시작하고 있다는 생각이 들었습니다. 가히 저에게는 혁신적인 운영체제라고 할 만큼 만족스러웠거든요. 그런데! 그런데! 윈도우8 태블릿이나 폰을 사고 싶어도 이건 시장에 물건이 없어도 너무 없더군요. 핡~ MS가 어쩌다가 이런 지경까지…&lt;/p&gt;
&lt;p&gt;그런 찰나에 항상 그렇듯이 남들보다 한 세박자 늦게 모바일 개발에 뛰어들게 되었습니다. 말도 많고 탈도 많다는 바로 그 안드로이드 플랫폼으로 말이죠. 십만년전에 쓰던 구형 갤s 폰이 하나 있었는데 루팅하고 머 하고 해서 개발하려고 세팅 좀 하는데 느려도 너무 느린데다 화면까지 작으니 갑갑해서 태블릿을 하나 사야겠다고 생각을 했습니다. 그나마 넥서스7이 괜찮더군요. 부담없는 가격에 레퍼런스 버프까지. 급한 마음에 지르겠다고 하이마트를 갔는데 16기가는 품절이라 허탕만 쳤습니다. 그러다 우연찮게 점심 먹다 그 이야기가 나오게 됐는데 다음날 제 책상으로 넥서스7이 배달돼 있는 기적이 ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;이클레어, 프로요, 진저브레드를 갤s로 경험한 저에게 안드로이드란 그저 음악 끊기는 플랫폼이었습니다. 그런데 이번에 접하게 된 넥서스7, 거기다 안드로이드 젤리빈 4.2.1 쇼킹했습니다. 왜냐구요? 여전히 음악 끊기는 플랫폼이었거든요. ㅋㅋㅋ~ 물론 이건 좀 농담이구요. 음악이 끊긴다는 사실은 진실입니다. 여튼 진짜 놀란건 안드로이드의 진화였습니다. UI부터 시스템까지 때깔벗기고 날아갈 준비가 된 것처럼 보였거든요.&lt;/p&gt;
&lt;p&gt;몇 일 태블릿을 쪼물딱거리면서 드는 생각이 아~ 윈도우 힘들겠는데, … 라는 생각이었습니다. 그 쪼그만한 넥서스7에서 안 되는게 없었거든요. RDP, 삼바, FTP, SSH, 터미널, 토렌트, … 제가 생각하는 그 모든 툴들이 벌써 앱으로 모두 공짜로 제공되고 있었습니다. 거기다 만화책 뷰어는 어찌나 아름다운지… 윈도우가 아쉬운 시점은 글 쓸 때하고 프로그래밍 할 때 말곤 없었습니다. 컨텐츠 소비 플랫폼으로는 슈퍼갑이었지요. 모바일 시장 점유율 75%가 괜한 소리가 아니었습니다.&lt;/p&gt;
&lt;p&gt;Chart: Worldwide Smartphone OS Market Share, 2012Q3Description: IDC’s Worldwide Quarterly Mobile Phone Tracker provides smart phone and feature phone market data in 60 countries and 8 regions by vendor, device type, air interface, operating systems and platforms, and generation. Over 20 additional technical segmentations are provided. The data is provided four times a year and includes historical and forecast trend analysis. For more information, or to subscribe to the research, please contact Kathy Nagamine at 1-650-350-6423 or &lt;a href=&quot;mailto:knagamine@idc.com.Further&quot;&gt;knagamine@idc.com.Further&lt;/a&gt; detail about this tracker can be found at:&lt;a href=&quot;http://www.idc.com/tracker/showproductinfo.jsp?prod%5C_id=37Tags&quot;&gt;http://www.idc.com/tracker/showproductinfo.jsp?prod\_id=37Tags&lt;/a&gt;: Samsung, Apple, Mobile Phone, Smartphone, IDC, tracker, Q3 2012, mobile phones, 3Q 2012, market share, galaxy, iPhone, Android, iOS, BlackBerry, Symbian, Windows Phone, Linux, 2012Q3, AnniversaryAuthor: &lt;a href=&quot;http://www.idc.com/iCharts_Tracker/chartsapp.jsp&quot;&gt;IDC&lt;/a&gt;&lt;a href=&quot;http://www.icharts.net&quot;&gt;charts powered by iCharts&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;안드로이드: 모바일은 내가 제일 잘나가~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이렇게 저의 험난한 안드로이드 입문이 시작됐습니다. libcurl 포팅이 골때린다는 인터넷 글들에 쫄았는데 막상 해보니 libcurl 안드로이드 지원이 삼십만년전에 끝났다는 사실에 놀랐고, boost를 어쩌지 이러고 있는데 Boost for Android가 벌써 만들어져 있다는 사실에 감탄했습니다. 그러면서… 아 이래서 세박자 늦게 시작하는게 좋구나라며 꿀빨고 있는데 프로요까지는 wchar_t 타입이 지원되지 않았다는 사실에 급 좌절했고 시스템에서 지원해주는 표준 유니코드 변환 함수가 없다는 사실에 무릎 꿀었습니다. iconv는 GPL 이슈 때문에 쓰기가 지랄맞다는 사실에 가슴 아팠고, ICU를 힘겼게 컴파일 했는데 빌드하니 so 파일 크기가 20메가가 넘어서 포기해야 했습니다. 결국 안드로이드 폴랫폼에 있는 ICU 라이브러리를 써야겠다고 생각했는데 이놈 조차도 안드로이드 버전 별로 다른 ICU가 포함돼 있어서 익스포트된 함수명이 다 다르다는 사실에 피를 토했지요.&lt;/p&gt;
&lt;p&gt;이 모든 기간동안 저를 가장 괴롭혔던 것은 Visual Sutdio가 없다는 점이었습니다. 처음엔 Visual Studio로 작업을 했는데 하도 빨간줄을 그어대는 바람에 짜증나서 Sublime Text 2로 작업을 했습니다. 그럭저럭 쓰긴 편한데 인공위성 쓰다가 나침반들고 작업하려니 기가 막힐 노릇이었습니다. 거기가 학부시절 자바 실험 때부터 저하고는 안 맞았던 이클립스는 여전히 그 철학적 기반이 저와는 180도 다르다는 사실을 새롭게 확인하는 과정을 반복했습니다. 그나마 P가 자바 버프를 제공해서 네이티브 코딩을 제외한 부분에서 걱정할 필요가 없어서 다행이었지요. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;XIGNCODE 클라이언트 코드도 장난 아니었습니다. 몇년된 프로젝트 답게 레거시 코드가 너무 많았고 그 모든 레거시 코드들이 다 윈도우를 가정하고 작성된 것들이라 여기저기 수정할 곳이 장난 아니게 많았습니다. 처음에는 크로스 컴파일 할 수 있도록 소스를 구성하다가 이러다간 죽도 밥도 안될 것 같아서 아예 복사해서 새로 다 고치는 대규모 토목 공사를 해야 했습니다. 이렇게 험난한 크런치 모드 끝에 마침내, 기어이, 우리는 안드로이드 플랫폼에서 알흠답게 동작하는 XIGNCODE 바이너리 파일을 획득할 수 있었습니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 320px; margin-bottom: 16px;&apos; data-url=&apos;./안드로이드_입문.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/72add1f39fac8821c58c115b5ef4dbc0/dd4a7/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C_%EC%9E%85%EB%AC%B8.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 177.89473684210526%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAkCAIAAAAGkY33AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAEm0lEQVR42o2W604bRxTHV1DgAxBSiTZQWiUUA6GJUKRyUaGiqpCoxK15or5DH4UvoEgIAYYkwsFgG9/A2AbfvV6vr9hgzPa3MzKQNG34a3R05sycOWfOZXaV7u7ukZHnY2M/K19Ca8ejRwMvukanHw+/au7qbvthUHn69NnzEcvAwMBjga6urq8b+OYTfPukp3+w76dX3/VbnvR93/NsQBmbHPnr7/nffv9lcWFp7o+5+fn5paWlhYWF2dnZ4eHhoU9gsQz+2D9oGRgaHIRXXrwcnluaGB19OTMzM/3r9NTU1OTk5MTExPj4uIWtApYGzMnQkDkEFK/Xd+T0+ny+o6Mjt4CngePjY7/AcQPwvntQarWaqqaz2ezFxYWmaYVCIZPJqKqKJJfLXV5eVqvVdDqNsChg3IOSz+cdDgfHRCIRjAcCAajT6YQGg0F0wuEwXuARljn65uamLgCjcBj7Tk5O4vE49OzsjE0woVAItWQyiX2W4M/PzzkLnTvL5XLZ6/WylX3RaLRSqeB/qVQqC1wISAbK6tXVFReBmspYxknc5mCXy4XbGAkKcFYsFkOOI1CcgnI7NsCbbmOEyYmAVMPP6+tr4wEw3ZZ3xm3o6ekp+eCS9+/2n8pYlsqpVApKtNDHN+L5IGXujI6MtowzeWbtRuB2q+Q/ivatciKR4MKEBE3yiZyoPsCyw4G7CZKJ0WCQeoIGiEIioamqJiounUrFY7EsNUiquZGwr5BQB2UcDCbSaX8goBcKWi4XS6XK1SojXyrpxaKq62ldT2YyTHPFYr3huVKORo/W1/1WaxL7Ozuh9+/De3uVSKRweho/PFQ9nnomY+Ryhq6bQ9OMbNZAkkoZtZpCfblttoDdHvP7occfPiS5gt9/sr/PCBwcMCJud8TjCTudLIVdrrDbXQ0GDVVVSh6Pz+Xy2e1R8uRwZGMxg+orFC7z+ctcrqLrJs1mq7pO08GUVLWoafV43EgmlYtAwP3mjW99Pbm/H9rZybpcCZvt7O3bwNZWxuFAGN7Zibx7F7Rarzk3kTCEmnF2ZpTLSrFcdnq9FHQ8nSZRRO44FEppWlLTYMJExO8vVirVev3qXzWn0Cw8EFS9mk5DY9FoMh7P6TqZi56fkxgyxIhGImTuulYzkyTHbXlSJKRXFialkhX4YnvcVRi1HRKQdS5r++ZjfEaZNpZdhWVZoZzFlNb//966s4zDtDiPgfSc3sYLngoeOUr9s3Vu9jOWUcYglmE4QnY1vHz35DtDFOTDyoN7p8wOtspm0nVdWmMffF4gJ4CEoNJ8t61uvtuI0OQUpEQYiXxZ5RTmugH56F4JmG8YIm5IwDDuFYDZ29vb3t7e3d212WxWqxWKkNfb2wD7saEQUgJmt9sPBQ4ODphubW2trKysra1tbm6urq5ubGwgZOl2D2FCUcH1egP3vwb3c3srvw/zznxQ/xRYXl5eXFyUU3jJvH79elkAHolkJJjeffg7Ozvb29tbWlrktLm5me87n3sYKWlra+vr6+vp6TH/ElpbTflXDbDG17+jowMpU5a7BWCYNjU1cXpvby8Uns0tLS3/APmncGcEzbQaAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;         md 0&apos; title=&apos;&apos; src=&apos;/static/72add1f39fac8821c58c115b5ef4dbc0/dd4a7/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C_%EC%9E%85%EB%AC%B8.md_0.png&apos; srcset=&apos;/static/72add1f39fac8821c58c115b5ef4dbc0/08678/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C_%EC%9E%85%EB%AC%B8.md_0.png 190w,
/static/72add1f39fac8821c58c115b5ef4dbc0/dd4a7/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C_%EC%9E%85%EB%AC%B8.md_0.png 320w&apos; sizes=&apos;(max-width: 320px) 100vw, 320px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;모바일 게임 보안도 이제 XIGNCODE가 책임지겠습니다 ㅋㅋ~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;**그나저나 삼전구글 직원 분들이 참치, 마구로, 약주를 좋아하나 봅니다.**&lt;strong&gt;빌드명이 아스트랄하네요 ㅋ~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;웃을 일이 아닙니다. 겁난다면 루팅하고 리눅스를 공부한 다음에 SSHDroid를 설치하시길 권장해 드립니다~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;작업하는 내내 드는 생각은 안드로이드 플랫폼 참 문제있다라는 생각이었습니다. 안드로이드 플랫폼의 기본적인 보안 정책은 앱들에 별도의 uid, gid를 할당하는 방식을 사용합니다. 이게 좀 욱긴게 사실 백신 앱이 있어도 그놈도 이런 일반 권한으로 동작하는 개별 앱이기 때문에 접근 제한이 엄.청.나.게 심하다는 점입니다. 멀쩡히 백신에 탐지되는 프로그램도 아주 손쉽게 백신은 영원히 탐지하지 못하도록 만들 수 있는 방법이 지천으로 널린 노다지지요. 스파이앱이 활개치는 것을 막을 수가 없습니다. 스파이앱을 막기 위한 유일한 방법은 루팅을 하고 시스템 권한으로 동작하는 보안 소프트웨어를 직접 만드는 방법 밖에는 없습니다. 권한 구성이 신묘하게 돼 있는데 단지 참신하기만 합니다.&lt;/p&gt;
&lt;p&gt;여튼 이제 시작입니다. 아직도 포팅해야 할 코드의 압박이…&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 게임 보안: 마이너리티 리포트 딜레마 #0]]></title><description><![CDATA[IRIS 
Because these Minority Reports are destroyed the instant they occur. 단독 의견의 리포트는 파괴되거든요.  ANDERTON 
Why? 왜요?  IRIS 
Obviously, for…]]></description><link>https://jiniya.net/wp/archives/9494</link><guid isPermaLink="false">https://jiniya.net/wp/archives/9494</guid><pubDate>Thu, 21 Feb 2013 23:58:47 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 750px; margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_마이너리티_리포트_딜레마_0.md_0.jpg&apos; data-width=&apos;320&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/1c52ed50002cae0901f1dc68e5ba9164/d0f75/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%A7%88%EC%9D%B4%EB%84%88%EB%A6%AC%ED%8B%B0_%EB%A6%AC%ED%8F%AC%ED%8A%B8_%EB%94%9C%EB%A0%88%EB%A7%88_0.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 147.89473684210526%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAeABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQDBQYB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgAB/9oADAMBAAIQAxAAAAGlkXesnJxGqeQ4VpDLlf/EABwQAAICAgMAAAAAAAAAAAAAAAECABEDEhATMf/aAAgBAQABBQJqMRbnWDwQVVBajC2qHIrLlBA8uptP/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwEf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAHBAAAQQDAQAAAAAAAAAAAAAAEQABAhAhMUFh/9oACAEBAAY/Aly8aooxjH1kXixo1//EABsQAQADAAMBAAAAAAAAAAAAAAEAESExQVFh/9oACAEBAAE/IURWV8ibUCeQGOENd5gtGuyV6Iei1UWMxCqJ8Ib9ZTHZjwiW6Wf/2gAMAwEAAgADAAAAEG/azv/EABgRAAMBAQAAAAAAAAAAAAAAAAABERAx/9oACAEDAQE/EOFeRn//xAAWEQADAAAAAAAAAAAAAAAAAAAAECH/2gAIAQIBAT8QcP/EAB4QAQACAgMAAwAAAAAAAAAAAAEAESFBMWFxUYGh/9oACAEBAAE/EDM3NBhfruPuZ29Q/FlxKCqquIwNjhYU1IvKXs68hP6YsihTqIILnmuINcylPA1f3B4VoBFAqtbgUGPyTrHtT//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                    0 md 0&apos; title=&apos;&apos; src=&apos;/static/1c52ed50002cae0901f1dc68e5ba9164/d0f75/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%A7%88%EC%9D%B4%EB%84%88%EB%A6%AC%ED%8B%B0_%EB%A6%AC%ED%8F%AC%ED%8A%B8_%EB%94%9C%EB%A0%88%EB%A7%88_0.md_0.jpg&apos; srcset=&apos;/static/1c52ed50002cae0901f1dc68e5ba9164/8ccab/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%A7%88%EC%9D%B4%EB%84%88%EB%A6%AC%ED%8B%B0_%EB%A6%AC%ED%8F%AC%ED%8A%B8_%EB%94%9C%EB%A0%88%EB%A7%88_0.md_0.jpg 190w,
/static/1c52ed50002cae0901f1dc68e5ba9164/ea4c8/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%A7%88%EC%9D%B4%EB%84%88%EB%A6%AC%ED%8B%B0_%EB%A6%AC%ED%8F%AC%ED%8A%B8_%EB%94%9C%EB%A0%88%EB%A7%88_0.md_0.jpg 380w,
/static/1c52ed50002cae0901f1dc68e5ba9164/d0f75/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%A7%88%EC%9D%B4%EB%84%88%EB%A6%AC%ED%8B%B0_%EB%A6%AC%ED%8F%AC%ED%8A%B8_%EB%94%9C%EB%A0%88%EB%A7%88_0.md_0.jpg 750w&apos; sizes=&apos;(max-width: 750px) 100vw, 750px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;IRIS&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;
Because these Minority Reports are destroyed the instant they occur.&lt;br&gt;
단독 의견의 리포트는 파괴되거든요.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ANDERTON&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;
Why?&lt;br&gt;
왜요?&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IRIS&lt;/strong&gt;&lt;br&gt;
&lt;br&gt;
Obviously, for Precrime to function, there can’t be any suggestion of fallibility.&lt;br&gt;
After all, what good is a Justice system that instills doubt?&lt;br&gt;
It may be reasonable, but it’s still doubt.&lt;br&gt;
시스템의 완벽성엔 흠집이 없어야 돼요&lt;br&gt;
오류의 여지를 인정하면 효율성에 문제가 생기죠&lt;br&gt;
&lt;br&gt;
– 마이너리티 리포트, 2002&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;역자가 시스템 엔지니어가 아닌지 의심이 들 정도로 원문보다 번역이 아름다운 마이너리티 리포트의 한 장면. 실제로 시스템 상의 오류의 여지를 인정하면 효율성에 문제가 생기는 경우는 수도 없이 찾을 수 있다. 게임 보안 프로그래머들은 속도와 공간의 문제처럼 오류의 여지와 효율성 사이에서 항상 트레이드오프를 강요 받는다.&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/wp/archives/tag/xigncode&quot;&gt;XIGNCODE&lt;/a&gt; 개발팀에서는 지속적으로 새로운 탐지 루틴을 개발한다. 이때 우리가 개발한 탐지 루틴을 P라고 생각해 보자. 우리는 이 코드 P의 성능을 0에서 1사이의 값으로 표기할 수 있다. 성능이 0이란 말은 과거에 알려진 해킹툴은 차단할 수 있지만 미래에 출현할 해킹툴에 대해서는 하나도 차단할 수 없다는 것을, 반대로 1은 미래에 출현할 모든 해킹툴까지 예측해서 차단할 수 있다는 것을 의미한다. P가 1인 루틴이 하는 일이 마이너리티 리포트에서 나오는 프리크라임 시스템과 동일하다고 생각하면 되겠다.&lt;/p&gt;
&lt;p&gt;여기까지만 살펴보면 당연히 P의 성능이 1인 루틴이 최고인 것처럼 판단된다. 하지만 여기엔 “마이너리티 리포트”에서 지적한 것과 동일한 함정이 숨어있다. 바로 오진이다. 물론 루틴의 구현 방식에 따라서 성능과 오진 사이에 큰 상관 관계가 없는 경우도 있지만 대부분의 경우에 성능 지표가 올라가면 덩달아 오진 지표도 같이 올라간다. 성능이 1이면서 오진 가능성은 0인 ‘현자의 돌’같은 루틴이 있다면 좋겠지만 현실 세계에 그러한 것은 존재하지 않는다. 물론 아직 그런 방법을 우리가 찾지 못한 것일 수도 있다. 어쨌든 이러한 성능과 오진의 관계성 때문에 게임 보안 프로그래머들은 항상 아이리스가 말한 것처럼 reasonable과 doubt 사이에서 갈등한다. 이 정도면 reasonable한 것일까? 이건 너무 doubt 스럽진 않은걸까? 하고 말이다. 그리고 그러한 의문에 따라서 루틴의 성능 지표를 강제로 조금씩 조정한다. 실제 세상에서 봐줄만한 수준으로 돌아가도록 말이다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;그렇다면 왜 굳이 P의 성능을 높이는 방식으로 문제를 해결하려 했던 것일까? P가 0인 루틴을 사용하고 빠르게 과거를 추적한다면 효과를 볼 수 있지도 않을까? 맞다. 영리한 생각이다. 하지만 이런 전략이 실패하는 이유는 크게 세 가지 정도가 있다.&lt;/p&gt;
&lt;p&gt;첫째는 업데이트 속도다. 지난 글에서도 꾸준히 말하고 있지만 엄청나게 많은 사람들이 사용하는 게임과 관련된 코드를 자주 업데이트 하는 일에는 굉장히 많은 검증 작업이 필요할 수 밖에 없고, 또 위험할 수 밖에 없다. 따라서 자연히 업데이트 속도가 빠를 수가 없다. 그러니 덜 업데이트하고 더 효과적인 코드를 만드는 수 밖에는 없다.&lt;/p&gt;
&lt;p&gt;둘째는 해킹툴의 배포 속도다. 일반적으로 해킹툴의 배포 수준을 우리는 실행 대비 해킹툴 검출 비율로 판단한다. 이 오염도가 1%를 넘어서는 게임들에 대해서는 과거를 추적하는 방식으로는 제 아무리 업데이트 속도가 빠르다고 한들 큰 효과를 보기가 힘들다. 해커는 우리가 설날 떡국을 삼키는 그 순간에서 컴파일을 하고 코드를 고치고 릴리즈를 한다. 물론 쪽수는 우리가 상상도 하지 못할 정도로 많다. 그러니 속도전으로 가는 것은 크게 좋은 전략은 아니다. 하지만 아이러니 하게도 속도전이 반드시 필요한 순간도 있긴 하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_마이너리티_리포트_딜레마_0.md_1.png&apos; data-alt=&apos;정말 10명중 한명은 핵을 사용하는 상황. 방마다 핵이 넘쳐 난다는 말이 거짓말은 아니다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 401px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/db69e553b0a444990780ff1361e3b45b/25946/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%A7%88%EC%9D%B4%EB%84%88%EB%A6%AC%ED%8B%B0_%EB%A6%AC%ED%8F%AC%ED%8A%B8_%EB%94%9C%EB%A0%88%EB%A7%88_0.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 32.10526315789474%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABKElEQVR42o2MTUsCURSG51eFfSza9gPaFiMhrVq3rYU/J0M0MGRMjaYoDULSQCO8945T92s+7tz5Eqeji9bBw+G8D+85BqPsYzKZTadoTqQQnPH/AFdSeoaUAmGECcYLzCXlggv4sYEKSvnPXxSSs43hgkH0fM/49MaV7v6xVbp8MavDU9Mqla1d4Ki9dfF8Uh1WTGvbtHaAcmfv3D6Ezln/APpjNjCoch7d1h2+7pFGB11ZuNZ3GvbiFmKX1Lu43iNNe9HqOY1756aDan3ShMV2W65CRpB4RbEi4dc7H0zlaO7PolwVRcFjd8Se4P23clfFKlnqIBVv9GHMX0mIwISJZ8SpjrJAZyrOo2SZwAxSqTJ/bbIoybXOlUr9MJWbjl6bTEEhTvUvDc0vNrrgsLcAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;정말 10명중 한명은 핵을 사용하는 상황. 방마다 핵이 넘쳐 난다는 말이 거짓말은 아니다.&apos; title=&apos;&apos; src=&apos;/static/db69e553b0a444990780ff1361e3b45b/25946/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%A7%88%EC%9D%B4%EB%84%88%EB%A6%AC%ED%8B%B0_%EB%A6%AC%ED%8F%AC%ED%8A%B8_%EB%94%9C%EB%A0%88%EB%A7%88_0.md_1.png&apos; srcset=&apos;/static/db69e553b0a444990780ff1361e3b45b/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%A7%88%EC%9D%B4%EB%84%88%EB%A6%AC%ED%8B%B0_%EB%A6%AC%ED%8F%AC%ED%8A%B8_%EB%94%9C%EB%A0%88%EB%A7%88_0.md_1.png 190w,
/static/db69e553b0a444990780ff1361e3b45b/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%A7%88%EC%9D%B4%EB%84%88%EB%A6%AC%ED%8B%B0_%EB%A6%AC%ED%8F%AC%ED%8A%B8_%EB%94%9C%EB%A0%88%EB%A7%88_0.md_1.png 380w,
/static/db69e553b0a444990780ff1361e3b45b/25946/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%A7%88%EC%9D%B4%EB%84%88%EB%A6%AC%ED%8B%B0_%EB%A6%AC%ED%8F%AC%ED%8A%B8_%EB%94%9C%EB%A0%88%EB%A7%88_0.md_1.png 401w&apos; sizes=&apos;(max-width: 401px) 100vw, 401px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;정말 10명중 한명은 핵을 사용하는 상황. 방마다 핵이 넘쳐 난다는 말이 거짓말은 아니다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;셋째는 추적의 비 효율성이다. 우리가 수집할 수 있는 해킹툴이란 정말 빙산에 일각에 불과하다. 통상적으로 우리는 하루에 1500-2000개 정도의 해킹툴 샘플을 수집한다. 물론 이 수치는 적용되는 게임이 늘어나면 늘어날수록 기하급수적으로 높아진다. 하지만 이것 또한 정말 아주 큰 빙산에 점하나 정도 밖에는 되지 않는다. 세상에는 정말 다양한 게임핵들이 있고, 또 지금 이 순간에도 만들어진다. 그걸 우리가 모두 찾아낸다는 것은 정말이지 불가능에 가깝다.&lt;/p&gt;
&lt;p&gt;이런 다양한 이유 때문에 일정 수준 오진율을 감수하고서라도 P의 성능이 높은 루틴을 사용할 수 밖에 없다. 물론 오진도 낮추면서 성능을 높이는 것이 최고라는 건 두말하면 입아푸다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;그렇다면 어떤 것들이 주로 오진의 범주에 포함될까? 탐지 루틴의 성격에 따라서 천차만별이긴 하지만 대다수 탐지 루틴에서 공통적으로 높은 오진율을 자랑하는 것들이 있다. 바로 악성코드이거나 바이러스다. 일부는 게임 계정을 탈취하는 목적으로 사용되는 것도 있으니 각별한 주의가 필요하다. 종종 이런 심각한 악성 코드나 바이러스에 감염된 사용자들이 문의를 해오곤 한다.&lt;/p&gt;
&lt;p&gt;대부분 원격으로 게임을 할 수 있도록 대응을 해주고 있는데, 가끔씩은 백신으로 아예 치료가 불가능한 것들이 있기도 하고, 더러는 치료를 하고 나면 인터넷이 먹통이 되는 경우도 있다. 이런 경우는 실컷 도와주고도 난감한 상황에 봉착하는 경우가 한두번이 아니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_마이너리티_리포트_딜레마_0.md_2.png&apos; data-alt=&apos;안타깝지만 이런 일이 더 많아 질수록 우리는 더 많은 해킹툴을 놓칠 수 밖에 없다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/48ff904d72efebff70bd912ccb3936a8/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%A7%88%EC%9D%B4%EB%84%88%EB%A6%AC%ED%8B%B0_%EB%A6%AC%ED%8F%AC%ED%8A%B8_%EB%94%9C%EB%A0%88%EB%A7%88_0.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 44.21052631578947%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABG0lEQVR42nWPCW7CMBBFfYOSAFlskziLt8SEhFIIi3r/Y/XHIRUVqvRkvT/SzHiIyhPQ1Lu2pIavC7Yp+QLz/MpbJFqkpmRHp05WdDxkcZDFwW5ilSVhlswSwPN04tWJzBNBNzxaseiDRoES1BRpU6a6YAXbljzCpwQNBV37nrWteO4dkKaitkjRoPNYZZEtKSpOsrbmxtedhCRa4LpYixh1vHBAxoO6Hc211/ejxXs5SMjYqzneB3PQmaupq9lecgDfy6eTSyevg7kNZpqyyLU3j087x3NXYwqKED9XTy29/nIVQf4+O/RDsPZxam6D7U3u/OxlG+/Ua1w2T2vxQ78E7Gvm/tKCioJn9NJ6J+Ny7Xx2p3burf8/fgCSGExVQ6BScAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;안타깝지만 이런 일이 더 많아 질수록 우리는 더 많은 해킹툴을 놓칠 수 밖에 없다.&apos; title=&apos;&apos; src=&apos;/static/48ff904d72efebff70bd912ccb3936a8/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%A7%88%EC%9D%B4%EB%84%88%EB%A6%AC%ED%8B%B0_%EB%A6%AC%ED%8F%AC%ED%8A%B8_%EB%94%9C%EB%A0%88%EB%A7%88_0.md_2.png&apos; srcset=&apos;/static/48ff904d72efebff70bd912ccb3936a8/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%A7%88%EC%9D%B4%EB%84%88%EB%A6%AC%ED%8B%B0_%EB%A6%AC%ED%8F%AC%ED%8A%B8_%EB%94%9C%EB%A0%88%EB%A7%88_0.md_2.png 190w,
/static/48ff904d72efebff70bd912ccb3936a8/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%A7%88%EC%9D%B4%EB%84%88%EB%A6%AC%ED%8B%B0_%EB%A6%AC%ED%8F%AC%ED%8A%B8_%EB%94%9C%EB%A0%88%EB%A7%88_0.md_2.png 380w,
/static/48ff904d72efebff70bd912ccb3936a8/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%A7%88%EC%9D%B4%EB%84%88%EB%A6%AC%ED%8B%B0_%EB%A6%AC%ED%8F%AC%ED%8A%B8_%EB%94%9C%EB%A0%88%EB%A7%88_0.md_2.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;안타깝지만 이런 일이 더 많아 질수록 우리는 더 많은 해킹툴을 놓칠 수 밖에 없다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;많은 게이머들이 공정한 게임을 하고 싶어한다. 정말 공정한 게임을 하고 싶다면 바이러스나 악성코드에 감염되지 말자. 그러면 게이머는 계정탈취나 랙을 겪지 않아서 좋고, 우리는 루틴의 성능 지표를 강제로 조정하지 않아서 좋고, 탐지율은 올라가서 좋고, 게임 운영자는 클레임이 줄어서 좋다. 이렇게 몇 바퀴만 구르면 깨끗한 게임 환경을 만드는 것도 어렵지 않다.&lt;/p&gt;
&lt;p&gt;명심하자. 무리 중에 더러운 녀석을 찾는 가장 쉬운 방법은 모두가 깨끗해지는 것이다. 모두 똥을 묻히고 있으면 누가 더러운지 판단이 잘 서지 않는다. 자 이제 가서 무료 백신을 설치하고 실시간 감시기를 켜도록 하자. 그리고 절.대.로 인터넷에서 받은 이상한 파일은 실행하지 말도록 하자. 설령 백신이 그 파일이 문제없다고 보고할지라도 말이다. 참고로 무료 백신 중에는 광고가 뜨긴 하지만 Avira가 제일 잘 잡는 것 같다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[죽기 전에 이런 코드 한 번 쓸 수 있을까?]]></title><description><![CDATA[요즘 별 일 없이 바쁘다는 핑계로 책도 안 읽고, 코드도 너무 안 읽었다. 넥서스…]]></description><link>https://jiniya.net/wp/archives/10329</link><guid isPermaLink="false">https://jiniya.net/wp/archives/10329</guid><pubDate>Tue, 19 Feb 2013 23:58:46 GMT</pubDate><content:encoded>&lt;p&gt;요즘 별 일 없이 바쁘다는 핑계로 책도 안 읽고, 코드도 너무 안 읽었다. 넥서스7로 침대에서 뒹굴거리다 트위터와 뉴스질에 지쳐갈 무렵, 소설책도 읽기 싫은 그 시점, 코드나 읽을까, 라는 생각이 들었다. 잽싸게 요즘 가장 뜨겁다는 깃허브에 들렀다. 어떤 코드가 좋을까를 생각하던 중 막연하게 탐색해 보기로 했다. 그리곤 언어별로 저장소에 있는 소스를 정렬해 봤는데. 헉. C/C++ 없어도 너무 없다. 아래는 깃허브 통계 자료~&lt;/p&gt;
&lt;center&gt;  
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 620px; margin-bottom: 16px;&apos; data-url=&apos;./죽기_전에_이런_코드_한_번_쓸_수_있을까.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/c50dc7d1286dc1ffae95626c4efade6e/abf7b/%EC%A3%BD%EA%B8%B0_%EC%A0%84%EC%97%90_%EC%9D%B4%EB%9F%B0_%EC%BD%94%EB%93%9C_%ED%95%9C_%EB%B2%88_%EC%93%B8_%EC%88%98_%EC%9E%88%EC%9D%84%EA%B9%8C.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 39.473684210526315%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAA7DAAAOwwHHb6hkAAABTElEQVR42mN4+/bdx/fvv/78M3f/g8a1N1rX32wBIyCjYc31yuXXqlZcA5JN6250bbrVCUPtG25O2nGX4eWLl79+/Xz/5WfW3AvOLUc9Oo65t4OQa+vRiEmnixZfLlh4KXPuhU1nnr368P3h6y+P33wFokdvvj59+43h1YtXf37//vTtV/7CSz5dxwP7TgT0ngjuP+nadnT67nv/////8/fv////wAgdMDx/8vz3r19AzXkLLnp1HvfvAWo+CSSdWo4sOvQQpPnPn3///mIFDO/ffgCa+uHLz9wFF707jwf1nQS63LPz2JLDj4B6/vz5iwcwfP3+HWj8h68/gc726z7h2XG8ed31A9deAXXhshCh+dXL10Bnv//yI2XWebvGI0DLj996CzTu9++/BAHDu7dvP334+Pnbr0WHHjWvu3Ho+mugL37++vOXCAAArsSWQQgf8ToAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                        md 0&apos; title=&apos;&apos; src=&apos;/static/c50dc7d1286dc1ffae95626c4efade6e/abf7b/%EC%A3%BD%EA%B8%B0_%EC%A0%84%EC%97%90_%EC%9D%B4%EB%9F%B0_%EC%BD%94%EB%93%9C_%ED%95%9C_%EB%B2%88_%EC%93%B8_%EC%88%98_%EC%9E%88%EC%9D%84%EA%B9%8C.md_0.png&apos; srcset=&apos;/static/c50dc7d1286dc1ffae95626c4efade6e/08678/%EC%A3%BD%EA%B8%B0_%EC%A0%84%EC%97%90_%EC%9D%B4%EB%9F%B0_%EC%BD%94%EB%93%9C_%ED%95%9C_%EB%B2%88_%EC%93%B8_%EC%88%98_%EC%9E%88%EC%9D%84%EA%B9%8C.md_0.png 190w,
/static/c50dc7d1286dc1ffae95626c4efade6e/2edd7/%EC%A3%BD%EA%B8%B0_%EC%A0%84%EC%97%90_%EC%9D%B4%EB%9F%B0_%EC%BD%94%EB%93%9C_%ED%95%9C_%EB%B2%88_%EC%93%B8_%EC%88%98_%EC%9E%88%EC%9D%84%EA%B9%8C.md_0.png 380w,
/static/c50dc7d1286dc1ffae95626c4efade6e/abf7b/%EC%A3%BD%EA%B8%B0_%EC%A0%84%EC%97%90_%EC%9D%B4%EB%9F%B0_%EC%BD%94%EB%93%9C_%ED%95%9C_%EB%B2%88_%EC%93%B8_%EC%88%98_%EC%9E%88%EC%9D%84%EA%B9%8C.md_0.png 620w&apos; sizes=&apos;(max-width: 620px) 100vw, 620px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;C/C++ 형님께서 아사 직전입니다. 대조적인 자바스크립트의 위용~&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;  
&lt;p&gt;초라한 C++의 저장소 개수를 보면서 그래도 남자라면 C++을 외치면서 클릭을 해봤다. 남자라면 most watched를 외치며 줏대없이 클릭을 했는데 그 중에 단연 돋보이는 소스 코드가 있었으니 카맥옹의 DOOM3 소스였다. 예전에 퀘이크 소스를 보고 충격을 먹었던 기억을 되살리며 그래 한 줄을 읽어도 카맥옹의 소스를 읽어야지, 라며 들어가서는 DOOM3 저장소 탐방을 시작했다. 군더더기 없는 소스 트리하며, 정갈한 소스 코드는 퀘이크 때의 그것과 크게 다르지 않았다. 단지 C에서 C++로 간 느낌? idlib과 sys쪽 코드를 좀 읽었는데 눈물을 감출 길이 없었다. 보는내내 촌스럽고, 안스럽고, 황당하기 그지없는 나 자신을 발견했다. 부끄러웠다. 난 과연 지난 시간 무엇을 한 것인가? 언제 이런 코드 한 번 써보나 하는 생각. 죽기 전에 한 번 써 볼 수 있을까?, 라며 감탄사를 남발하는 그 순간 카맥 옹의 훅 코드에서 나의 멘탈은 초라한 안정을 되찾을 수 있었다. 그래도 훅은 내가 좀 더 아는 것 같다며… 굼벵이도 구르는 재주가 있다고 했던가 ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;카맥옹의 단정한 코드는 그 코드를 읽는 것만으로도 한 수 배울 수 있어서 큰 도움이 되지만 그것 외에도 멘탈적으로 큰 힐링이 되는 느낌이다. 그의 단아한 코드는 나에게 전 우주적 자괴감과 초라함, 미칠듯한 열등감을 선사하지만 그 와중에도 코딩을 하고 싶게 만드는 묘한 매력이 있기 때문이다.&lt;/p&gt;
&lt;p&gt;코드를 좀 읽고는 이것 저것 찾다가 &lt;a href=&quot;http://fabiensanglard.net/doom3/index.php&quot;&gt;DOOM3 코드를 분석한 블로그&lt;/a&gt;를 찾았다. 꿈보다 해몽이라고 했던가? 코드보다 이 블로거의 분석이 더 놀라웠다. 퀘이크 소스 분석도 있는데, 드는 생각은 와~ 블로그 저렇게 해야 하는데 라는 생각 … ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;20살 이후로 단 한 번도 훌륭한 프로그래머가 되고 싶다는 생각을 버린 적이 없었다. 토나오게 많은 시간이 지났지만 그 꿈이 이뤄질 기미는 전.혀. 보이질 않는다. 당췌. 이번 생은 아닌건가~ @.@&lt;/p&gt;
&lt;p&gt;덧) 카맥옹하니 중학교 땐가 고등학교 땐가 컴퓨터 잡지에 실렸던 인터뷰 기사가 생각난다. “하루라도 코딩하지 않으면 입에 가시가 돋힌다”라는 내용이었는데 어린 마음에 참 신선한 충격이었다. 송재경님은 아들이 커서 아들이랑 같이 코딩하는게 꿈이라는 인터뷰를 했던 기사가 있었던 것 같다. 근데 안타깝게도 카맥옹이 선수를 친 건 아닌지? ㅎㅎ~ 리틀카맥 뒷모습에서 우월한 유전자의 포스가 뿜어져 나온다~&lt;/p&gt;
&lt;center&gt;  
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 320px; margin-bottom: 16px;&apos; data-url=&apos;./죽기_전에_이런_코드_한_번_쓸_수_있을까.md_1.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/644602804e712817dd00d249f777de7c/8980b/%EC%A3%BD%EA%B8%B0_%EC%A0%84%EC%97%90_%EC%9D%B4%EB%9F%B0_%EC%BD%94%EB%93%9C_%ED%95%9C_%EB%B2%88_%EC%93%B8_%EC%88%98_%EC%9E%88%EC%9D%84%EA%B9%8C.md_1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 133.1578947368421%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAMEBQH/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQP/2gAMAwEAAhADEAAAAchYDSQC1InNBsKA3//EAB4QAAIBAwUAAAAAAAAAAAAAAAECEQADEhAhIjFB/9oACAEBAAEFAiNFEBFzd1wuBtpip5E2TXp7r//EABYRAAMAAAAAAAAAAAAAAAAAAAAQEf/aAAgBAwEBPwFw/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAGRABAAIDAAAAAAAAAAAAAAAAARAxAAIg/9oACAEBAAY/ApDHWLik4//EABsQAQADAQADAAAAAAAAAAAAAAEAESExEEFR/9oACAEBAAE/Id+wLKojjhMHUXQh3IU89xClQJaeOPJqzbKB5eFst19d8Jps/9oADAMBAAIAAwAAABAQLI//xAAXEQADAQAAAAAAAAAAAAAAAAAAARFR/9oACAEDAQE/EHE4UbpWn//EABcRAQEBAQAAAAAAAAAAAAAAAAEAESH/2gAIAQIBAT8QFy7Blt//xAAeEAEAAwACAgMAAAAAAAAAAAABABEhUXExQWGBkf/aAAgBAQABPxCq1kv23OLjd1sKjXdg00FBWpeBaK8evi4SDe2FzXBVVXcftRtr+xzTDwHdkWNt0cwBQ5mV1P/Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                        md 1&apos; title=&apos;&apos; src=&apos;/static/644602804e712817dd00d249f777de7c/8980b/%EC%A3%BD%EA%B8%B0_%EC%A0%84%EC%97%90_%EC%9D%B4%EB%9F%B0_%EC%BD%94%EB%93%9C_%ED%95%9C_%EB%B2%88_%EC%93%B8_%EC%88%98_%EC%9E%88%EC%9D%84%EA%B9%8C.md_1.jpg&apos; srcset=&apos;/static/644602804e712817dd00d249f777de7c/8ccab/%EC%A3%BD%EA%B8%B0_%EC%A0%84%EC%97%90_%EC%9D%B4%EB%9F%B0_%EC%BD%94%EB%93%9C_%ED%95%9C_%EB%B2%88_%EC%93%B8_%EC%88%98_%EC%9E%88%EC%9D%84%EA%B9%8C.md_1.jpg 190w,
/static/644602804e712817dd00d249f777de7c/8980b/%EC%A3%BD%EA%B8%B0_%EC%A0%84%EC%97%90_%EC%9D%B4%EB%9F%B0_%EC%BD%94%EB%93%9C_%ED%95%9C_%EB%B2%88_%EC%93%B8_%EC%88%98_%EC%9E%88%EC%9D%84%EA%B9%8C.md_1.jpg 320w&apos; sizes=&apos;(max-width: 320px) 100vw, 320px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;리틀카맥! 아빠가 3D를 개척했으니까 전 4D를 개척하겠어요~&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;  </content:encoded></item><item><title><![CDATA[XLGAMES 커버 스토리]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/10295</link><guid isPermaLink="false">https://jiniya.net/wp/archives/10295</guid><pubDate>Wed, 13 Feb 2013 23:58:45 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 510px; margin-bottom: 16px;&apos; data-url=&apos;./XLGAMES_커버_스토리.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/36b41332a9c2eebdec615beafb93b785/1b7d6/XLGAMES_%EC%BB%A4%EB%B2%84_%EC%8A%A4%ED%86%A0%EB%A6%AC.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 49.473684210526315%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABvElEQVR42mWRW0/iUBSFz2+AWOQBGEpoC7QBez1Dy6XogC0XDfqgqBEdoiY1ahTQh7kZZzJj1IlOxsub/8Jnf5oLFWN0pV0n2Xt9+5yeEo7jRFFMp9OZTGbsUbIsp1KpuYXFdqeztLKKRxLFsaEQQxgIQIJFVVVK6cehTMvSVeXbyd/bm59HP3YPzy6ormez2ZcAwoqiACQYYxiGaZq5ofL5vKFpX/6c3t9d3159P/h1nM9ZhULhqQVHGAhAIkmSpmmDDYeybTtnmSf/r4/OT3uHX3//u1QV2aAULcuy4DgFDguQJJNJfAl4DIMX7VJ/v9/f3+t2e96mt7Oz3V5ue57X63ZLdhEBSgcxIAAJz/OYgUtSFIxTdV1/2mFra3tjbb3zubOyvFosFMvlMjUMVR2EFFkGApCwbBTX3JxuVt1qpVJu1OpuxSmNj7fmW4vzC1PTzdmZ2U8TE7Vq3Zl0nUm8bs11xZTIsiwJh8OxWCwej/M8xz9KEARuIKFRbziOk0gkBIGH89xzAGEgAEkwGAyFQpFI5MMrRaNRuCSl8U/ftCBUgAAkPp+PYZhAIDD6TqiPMMz7OsJo+f3+BwHdh7pghr3rAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;XLGAMES        md 0&apos; title=&apos;&apos; src=&apos;/static/36b41332a9c2eebdec615beafb93b785/1b7d6/XLGAMES_%EC%BB%A4%EB%B2%84_%EC%8A%A4%ED%86%A0%EB%A6%AC.md_0.png&apos; srcset=&apos;/static/36b41332a9c2eebdec615beafb93b785/08678/XLGAMES_%EC%BB%A4%EB%B2%84_%EC%8A%A4%ED%86%A0%EB%A6%AC.md_0.png 190w,
/static/36b41332a9c2eebdec615beafb93b785/2edd7/XLGAMES_%EC%BB%A4%EB%B2%84_%EC%8A%A4%ED%86%A0%EB%A6%AC.md_0.png 380w,
/static/36b41332a9c2eebdec615beafb93b785/1b7d6/XLGAMES_%EC%BB%A4%EB%B2%84_%EC%8A%A4%ED%86%A0%EB%A6%AC.md_0.png 510w&apos; sizes=&apos;(max-width: 510px) 100vw, 510px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;가끔 프로그래머끼리 술 마실 때 우스갯소리로 전 송재경 선생님 초상화를 걸어 놓고는 아침, 저녁으로 삼배씩 드린다는 농담을 하곤 합니다. &lt;a href=&quot;http://www.jiniya.net/wp/archives/4806&quot;&gt;지난 글&lt;/a&gt;에서도 밝혔듯이 전 우리나라 프로그래머 중에서는 그 분을 제일 존경합니다. 근데 욱긴건 사실 뭐 그 분을 만나본 적도, 강연을 들은 적도, 그렇다고 그 분이 쓴 글을 읽은 적도 그다지 많지는 않습니다. 근데 왜 존경하냐구요? ArcheAge, Lineage, Kingdom of the Winds, Hanterm. 더 말이 필요한가요? 이쯤이면 뭐 게임 끝이죠. 진짜 프로그래머라면 전 작품으로 말해야 한다고 생각합니다. 작품이 없으니 글이 많아지고, 말이 많아진다고 전 생각하거든요.&lt;/p&gt;
&lt;p&gt;어쨌든 사설이 길었습니다. 오늘 이 이야기를 꺼낸 이유는 다름이 아니라 XLGAMES 홈페이지를 들어갔다가 충격을 받아서 였습니다. “모든 개발자는 QA다.”라는 대문에 걸린 저 말을 보는 순간 망치로 머리를 한 대 맞은 느낌이었거든요. 역시 뭔가 다르다는 느낌 ㅋ~ 커버 스토리에 있는 다른 글들도 다 좋은 내용인 것 같아서 과감하게 같이 퍼왔습니다. 눈물은 좀 닦고 배꼽을 바라보면서 묵념 자세로 충분한 반성의 시간을 가지도록 해야 겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 555px; margin-bottom: 16px;&apos; data-url=&apos;./xl20.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/59a7089016e3013060e1478b7ee7dd9a/f20da/xl20.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 72.10526315789473%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAdxaAD//xAAVEAEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAQABBQKsf//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEABj8CX//EABwQAAMAAQUAAAAAAAAAAAAAAAABERAhQWFxkf/aAAgBAQABPyGLKa3jHYj2a8Iz/9oADAMBAAIAAwAAABATD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABwQAQACAQUAAAAAAAAAAAAAAAEAEUEhMVHB8f/aAAgBAQABPxB2jfFx06QylpmW8R71AZSk/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;xl20&apos; title=&apos;&apos; src=&apos;/static/59a7089016e3013060e1478b7ee7dd9a/f20da/xl20.jpg&apos; srcset=&apos;/static/59a7089016e3013060e1478b7ee7dd9a/8ccab/xl20.jpg 190w,
/static/59a7089016e3013060e1478b7ee7dd9a/ea4c8/xl20.jpg 380w,
/static/59a7089016e3013060e1478b7ee7dd9a/f20da/xl20.jpg 555w&apos; sizes=&apos;(max-width: 555px) 100vw, 555px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 555px; margin-bottom: 16px;&apos; data-url=&apos;./xl6.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a544ef8f0d1149e01ab85c85e8208d4c/f20da/xl6.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 72.10526315789473%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAe5NQoP/xAAXEAADAQAAAAAAAAAAAAAAAAAAEBEB/9oACAEBAAEFAjFCL//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEABj8CX//EABsQAAIBBQAAAAAAAAAAAAAAAAARkQEQQWGB/9oACAEBAAE/IWNm3MGqgVT/2gAMAwEAAgADAAAAENMP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGxABAAIDAQEAAAAAAAAAAAAAAQARIUFhMVH/2gAIAQEAAT8QcPZZlVyWm5Vv64ijTIZSk//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;xl6&apos; title=&apos;&apos; src=&apos;/static/a544ef8f0d1149e01ab85c85e8208d4c/f20da/xl6.jpg&apos; srcset=&apos;/static/a544ef8f0d1149e01ab85c85e8208d4c/8ccab/xl6.jpg 190w,
/static/a544ef8f0d1149e01ab85c85e8208d4c/ea4c8/xl6.jpg 380w,
/static/a544ef8f0d1149e01ab85c85e8208d4c/f20da/xl6.jpg 555w&apos; sizes=&apos;(max-width: 555px) 100vw, 555px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 555px; margin-bottom: 16px;&apos; data-url=&apos;./xl19.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/05b3b8c81564fc18198d68c63f797e15/f20da/xl19.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 72.10526315789473%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAe5NwA//xAAXEAADAQAAAAAAAAAAAAAAAAAAEBEh/9oACAEBAAEFAqVQ1f/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEABj8CX//EABwQAAIBBQEAAAAAAAAAAAAAAAABERBBUWFxof/aAAgBAQABPyGGTRqnRFj8IZ//2gAMAwEAAgADAAAAEFMP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAGxABAAIDAQEAAAAAAAAAAAAAAQARITFBgfH/2gAIAQEAAT8QSaqVuUxtOW9RU7LfEeT7AZSk/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;xl19&apos; title=&apos;&apos; src=&apos;/static/05b3b8c81564fc18198d68c63f797e15/f20da/xl19.jpg&apos; srcset=&apos;/static/05b3b8c81564fc18198d68c63f797e15/8ccab/xl19.jpg 190w,
/static/05b3b8c81564fc18198d68c63f797e15/ea4c8/xl19.jpg 380w,
/static/05b3b8c81564fc18198d68c63f797e15/f20da/xl19.jpg 555w&apos; sizes=&apos;(max-width: 555px) 100vw, 555px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 555px; margin-bottom: 16px;&apos; data-url=&apos;./xl11.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/29cc75d105bd9660f082a868759e79b5/f20da/xl11.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 72.10526315789473%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIDBP/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHfPcsVHK//xAAaEAADAAMBAAAAAAAAAAAAAAABAgMQERMS/9oACAEBAAEFAqW836EFDtWmGbimP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABwQAAIBBQEAAAAAAAAAAAAAAAABAhAREiEyYf/aAAgBAQAGPwLHwinLbEXZyqf/xAAaEAADAAMBAAAAAAAAAAAAAAAAAREhUfBx/9oACAEBAAE/Icc0ZYBUqt6FERkr4cEEoj//2gAMAwEAAgADAAAAEHgP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAHBABAAICAwEAAAAAAAAAAAAAAQARITFBYXGB/9oACAEBAAE/EG3wMPbhcVEaEcrfFqD2EbmyJE1RaVx3Fdo6vOHyAAAHU//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;xl11&apos; title=&apos;&apos; src=&apos;/static/29cc75d105bd9660f082a868759e79b5/f20da/xl11.jpg&apos; srcset=&apos;/static/29cc75d105bd9660f082a868759e79b5/8ccab/xl11.jpg 190w,
/static/29cc75d105bd9660f082a868759e79b5/ea4c8/xl11.jpg 380w,
/static/29cc75d105bd9660f082a868759e79b5/f20da/xl11.jpg 555w&apos; sizes=&apos;(max-width: 555px) 100vw, 555px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 555px; margin-bottom: 16px;&apos; data-url=&apos;./xl10.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/aa2c09ba6c71b887773502ad60545af5/f20da/xl10.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 72.10526315789473%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAe20Io//xAAWEAEBAQAAAAAAAAAAAAAAAAAQEQD/2gAIAQEAAQUCZof/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAg/9oACAEBAAY/Al//xAAaEAADAAMBAAAAAAAAAAAAAAAAARFBYZGB/9oACAEBAAE/IW9leGK5PPCsThHo/9oADAMBAAIAAwAAABAjD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABwQAAICAgMAAAAAAAAAAAAAAAABESExQXGBwf/aAAgBAQABPxBurTcsyQO6vI8NHyNHPgPcUpShvof/2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;xl10&apos; title=&apos;&apos; src=&apos;/static/aa2c09ba6c71b887773502ad60545af5/f20da/xl10.jpg&apos; srcset=&apos;/static/aa2c09ba6c71b887773502ad60545af5/8ccab/xl10.jpg 190w,
/static/aa2c09ba6c71b887773502ad60545af5/ea4c8/xl10.jpg 380w,
/static/aa2c09ba6c71b887773502ad60545af5/f20da/xl10.jpg 555w&apos; sizes=&apos;(max-width: 555px) 100vw, 555px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 555px; margin-bottom: 16px;&apos; data-url=&apos;./xl9.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ad9c321e331d25d143d1634d1dbb0df7/f20da/xl9.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 72.10526315789473%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAECAwX/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHbjYhgH//EABYQAQEBAAAAAAAAAAAAAAAAAAARIf/aAAgBAQABBQKrqIj/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAWEAEBAQAAAAAAAAAAAAAAAAAxACD/2gAIAQEABj8CZz//xAAdEAACAgEFAAAAAAAAAAAAAAAAARExkUFhcYHx/9oACAEBAAE/IWnobUSObJOuDbGBNGh//9oADAMBAAIAAwAAABCQD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABwQAQACAQUAAAAAAAAAAAAAAAEAESExQVFhof/aAAgBAQABPxDQtKekaEJbgWLHEStvhGuzIALhxP/Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;xl9&apos; title=&apos;&apos; src=&apos;/static/ad9c321e331d25d143d1634d1dbb0df7/f20da/xl9.jpg&apos; srcset=&apos;/static/ad9c321e331d25d143d1634d1dbb0df7/8ccab/xl9.jpg 190w,
/static/ad9c321e331d25d143d1634d1dbb0df7/ea4c8/xl9.jpg 380w,
/static/ad9c321e331d25d143d1634d1dbb0df7/f20da/xl9.jpg 555w&apos; sizes=&apos;(max-width: 555px) 100vw, 555px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 555px; margin-bottom: 16px;&apos; data-url=&apos;./xl8.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/2825c6c7bfab683e6582f2f96c4276c0/f20da/xl8.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 72.10526315789473%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAEDBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAdqLAB//xAAXEAEBAQEAAAAAAAAAAAAAAAARABAB/9oACAEBAAEFAme4Rn//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAXEAADAQAAAAAAAAAAAAAAAAAAATEg/9oACAEBAAY/AqirP//EABsQAAIBBQAAAAAAAAAAAAAAAAABERAhQYGR/9oACAEBAAE/IW02BUHXg2wyGf/aAAwDAQACAAMAAAAQQw//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAbEAEAAgIDAAAAAAAAAAAAAAABABEhMXGxwf/aAAgBAQABPxDWgDNubiPC86uWkQwUUIcV0wMpSf/Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;xl8&apos; title=&apos;&apos; src=&apos;/static/2825c6c7bfab683e6582f2f96c4276c0/f20da/xl8.jpg&apos; srcset=&apos;/static/2825c6c7bfab683e6582f2f96c4276c0/8ccab/xl8.jpg 190w,
/static/2825c6c7bfab683e6582f2f96c4276c0/ea4c8/xl8.jpg 380w,
/static/2825c6c7bfab683e6582f2f96c4276c0/f20da/xl8.jpg 555w&apos; sizes=&apos;(max-width: 555px) 100vw, 555px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 555px; margin-bottom: 16px;&apos; data-url=&apos;./xl7.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/efeab9a5cb8a791313b61eda0ed139c0/f20da/xl7.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 72.10526315789473%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAECBf/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhADEAAAAe3NwoP/xAAXEAADAQAAAAAAAAAAAAAAAAAAAREQ/9oACAEBAAEFAmy5CZ//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAUEAEAAAAAAAAAAAAAAAAAAAAg/9oACAEBAAY/Al//xAAcEAABAwUAAAAAAAAAAAAAAAAAARFhECFRkaH/2gAIAQEAAT8hwrcSXR5pi2hlP//aAAwDAQACAAMAAAAQMA//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAbEAEAAgMBAQAAAAAAAAAAAAABABEhMUFhgf/aAAgBAQABPxCgQOMupXhD8bhbViUV1nyL6kGUpP/Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;xl7&apos; title=&apos;&apos; src=&apos;/static/efeab9a5cb8a791313b61eda0ed139c0/f20da/xl7.jpg&apos; srcset=&apos;/static/efeab9a5cb8a791313b61eda0ed139c0/8ccab/xl7.jpg 190w,
/static/efeab9a5cb8a791313b61eda0ed139c0/ea4c8/xl7.jpg 380w,
/static/efeab9a5cb8a791313b61eda0ed139c0/f20da/xl7.jpg 555w&apos; sizes=&apos;(max-width: 555px) 100vw, 555px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 555px; margin-bottom: 16px;&apos; data-url=&apos;./xl5.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/70cda96d75586d97cac0aafa7d56a411/f20da/xl5.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 72.10526315789473%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAEF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAdtUUV//xAAXEAADAQAAAAAAAAAAAAAAAAAAEBES/9oACAEBAAEFAq8kX//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABYQAQEBAAAAAAAAAAAAAAAAADEAIP/aAAgBAQAGPwJnP//EABkQAQADAQEAAAAAAAAAAAAAAAEAEWEQkf/aAAgBAQABPyFEDjiWZryU5P/aAAwDAQACAAMAAAAQmw//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAbEAEAAgIDAAAAAAAAAAAAAAABABExYSFBUf/aAAgBAQABPxDllBNwbrI+3cVO4kqCuoszMBlLbU//2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;xl5&apos; title=&apos;&apos; src=&apos;/static/70cda96d75586d97cac0aafa7d56a411/f20da/xl5.jpg&apos; srcset=&apos;/static/70cda96d75586d97cac0aafa7d56a411/8ccab/xl5.jpg 190w,
/static/70cda96d75586d97cac0aafa7d56a411/ea4c8/xl5.jpg 380w,
/static/70cda96d75586d97cac0aafa7d56a411/f20da/xl5.jpg 555w&apos; sizes=&apos;(max-width: 555px) 100vw, 555px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 555px; margin-bottom: 16px;&apos; data-url=&apos;./xl4.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/e77b7fb724a90f62103a57c6532bb6fb/f20da/xl4.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 72.10526315789473%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB21AD/8QAFxAAAwEAAAAAAAAAAAAAAAAAABARAf/aAAgBAQABBQKmqEX/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAXEAADAQAAAAAAAAAAAAAAAAAAICEx/9oACAEBAAY/AtIv/8QAHBAAAgICAwAAAAAAAAAAAAAAABEBQRCRUWGB/9oACAEBAAE/IV4DLtePOhqmNCk//9oADAMBAAIAAwAAABCDD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABkQAQEBAQEBAAAAAAAAAAAAAAERAEEhYf/aAAgBAQABPxBFRocuS9n4c+707oW4lZMDIpv/2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;xl4&apos; title=&apos;&apos; src=&apos;/static/e77b7fb724a90f62103a57c6532bb6fb/f20da/xl4.jpg&apos; srcset=&apos;/static/e77b7fb724a90f62103a57c6532bb6fb/8ccab/xl4.jpg 190w,
/static/e77b7fb724a90f62103a57c6532bb6fb/ea4c8/xl4.jpg 380w,
/static/e77b7fb724a90f62103a57c6532bb6fb/f20da/xl4.jpg 555w&apos; sizes=&apos;(max-width: 555px) 100vw, 555px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./xl3.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./xl2.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./xl1.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[여가부 헌정 동영상]]></title><description><![CDATA[0
 0]]></description><link>https://jiniya.net/wp/archives/10271</link><guid isPermaLink="false">https://jiniya.net/wp/archives/10271</guid><pubDate>Tue, 05 Feb 2013 23:58:44 GMT</pubDate><content:encoded>&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[리눅스 포팅의 기본]]></title><description><![CDATA[예나 지금이나 리눅스의 백미는 여자 연예인 배위에서 코딩하는 그 맛~ 보고있나 Visual Studio !!! 리눅스를 처음 본 게 아마 95년인가 96년인가 그랬던 것 같다. 당시 커널이 1.2였던 시절이었다. 디스켓 2-3…]]></description><link>https://jiniya.net/wp/archives/5589</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5589</guid><pubDate>Mon, 04 Feb 2013 23:58:43 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;http://www.dettus.net/photos/openbsd_icewm_eterm_vim_screenshot.jpg&quot; alt=&quot;&quot;&gt;
&lt;strong&gt;예나 지금이나 리눅스의 백미는 여자 연예인 배위에서 코딩하는 그 맛~ 보고있나 Visual Studio !!!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;리눅스를 처음 본 게 아마 95년인가 96년인가 그랬던 것 같다. 당시 커널이 1.2였던 시절이었다. 디스켓 2-30장을 넣어가면서 설치하던 시절은 아니었고 CD를 통해서 설치하던 시절이었다. 물론 그렇다고 지금만큼 편한 시절은 아니었다. 온갖 설정들을 다 해줘야 뭐라도 동작하던 시절이었다. 수많은 밤을 지새면서 X-Window를 처음 띄우고는 그 단순하다 못해 허무한 X 아이콘에 눈물을 흘리기도 했었고, 구형 사블 호환 카드에서 소리가 나오는 것을 보고는 탄성을 지르기도 했었다. 그 당시만 해도 리눅스를 쓴다고 하면 아무도 모를 뿐더러 진정한 괴짜 취급을 받던 시절이었다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/07/alinux.png&quot;&gt;&lt;img src=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/07/alinux.png&quot; alt=&quot;&quot; title=&quot;alinux&quot;&gt;&lt;/a&gt;
&lt;strong&gt;내가 바로 국내 리눅스 전도사. 알짜 리눅스!!!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;그렇게 세월이 흘렀고 1997년이 도래했다. 이때가 국내 리눅스의 일대 부흥기라 할 수 있다. 알짜 리눅스를 필두로 여기저기 배포판 만드는 사람들이 늘어났다. 마소나 프세같은 잡지에도 종종 리눅스 특집 기사가 실리곤 했었다. 상황이 그렇게 바뀌자 어디가서 리눅스 쓴다고 하면 고수 대접을 받는 웃지 못할 일도 있었다. 그러다 대학교를 들어가면서 부터는 아예 리눅스를 쓰지 않았다. 그때부터 소프트웨어는 너무 구하기 쉬워졌고 더이상 불편한 리눅스를 사용할 필요가 없었기 때문이었다.&lt;/p&gt;
&lt;p&gt;그리고 또 결정적으로 리눅스계를 떠나 사건이 있었다. 병특 자리를 구하던 중에 학교 내에 있는 리눅스 벤처에서 알바를 했었는데, 거기서 내 평생내 정말 쿨~하게 돈을 떼이는 경험을 했기 때문이었다. 그 사장은 어처구니 없게도 리누스 토발즈도 이런걸 만들어서 공짜로 공개하는데 니까짓게 뭐한다고 돈을 받아야 하느냐는 토나오게 말도 안 되는 마인드의 소유자였다. 여튼 그래서 윈도우로 옮겨탔는데 그때나 지금이 그 선택에 후회는 없다.&lt;/p&gt;
&lt;p&gt;그렇게 나의 기억속에서 영원히 잊혀질 것 같았던 리눅스가 최근에 다시 등장했다. 리눅스를 사용하는 게임 서버 프로그램들을 마주하면서 XIGNCODE 코드를 리눅스로 포팅할 필요가 있었기 때문에다. 사실 뭐 포팅 작업 자체는 크게 힘들지 않았는데 엉뚱한 부분들에서 엄청 헤맸다. 아주 사소한 타입 차이를 간과했다거나 UCS2/4의 변환 문제 같은 것들이었다. 포팅을 하고나서 이런 것들을 미리 알았더라면 하는 몇 가지를 여기에다 끄적여 본다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;우선 여러분이 제법 큰 소프트웨어를 만들고 있었다면 당연히 여러분만의 타입시스템을 가지고 있어야 한다. 소프트웨어의 모든 부분을 관통하는 타입시스템이 없다면 좀 곤혹을 치를 수 있다. 그러니 무엇을 만들던지 규모가 좀 있다면 사전에 반드시 먼저 타입시스템을 설계하도로 하자. 뭐 타입시스템 같은건 모르겠다 싶으면 stdint.h같은 호환성 있는 타입시스템을 사용하는 것이 여러분의 포팅을 수월하게 해 줄 것이다. win32 타입시스템이라도 썼다면 그걸 기준으로 리눅스용 헤더를 작성하면 된다. 그런데 그 조차도 없이 진짜 네이티브 타입시스템(int, char, long 따위)을 썼다면 흠~ 생각 좀 해보자. 눈물 좀 닦고.&lt;/p&gt;
&lt;p&gt;타입시스템을 쓰는 가장 큰 이유는 우리가 사용하는 타입의 크기가 시스템마다 다르기 때문이다. 흔한 예로 int는 16비트 시스템에서는 16비트, 32비트 시스템에서는 32비트가 된다. 따라서 시스템이 변경되면 타입의 크기가 달라지면서 많은 문제가 생길 수 밖에 없다. 전 16비트 시스템을 사용하지 않는데염, 따위의 소리를 해도 소용없다. 지금은 64비트가 있다. 너무나 당연한 이야기겠지만 리눅스와 윈도우는 서로 다른 64비트 타입 시스템을 채용하고 있다. 윈도우는 아래 표에 나오는 LLP64 시스템을, 리눅스는 LP64 시스템을 사용한다. 따라서 생각없이 long을 사용했다면 불지옥을 맛볼 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Type           ILP64   LP64   LLP64
char              8      8       8
short            16     16      16
int              64     32      32
long             64     64      32
long long        64     64      64
pointer          64     64      64&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;주저리 주저리 떠들었는데 타입시스템이 있으면 무엇을 해야 하느냐? 그걸 리눅스에 맞도록 변경해주면 된다. 여러분이 윈도우에서 typedef long mylong;과 같이 사용했다면 64비트 리눅스에서는 typedef int mylong;을 해야 한다는 이야기다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;타입을 넘어가면 다음으로 우리를 괴롭히는 녀석은 유니코드다. 기본적으로 Visual C++은 UCS2를 사용한다. 안타깝지만 너무나 당연하게도 gcc는 UCS4를 사용한다. 이 말이 의미하는 바는 다음과 같다. Visual C++에서 L”Hello”를 하면 6글자를(NULL 포함) 저장하기 위해서 12바이트를 사용하지만, gcc는 UCS4를 사용하기에 24바이트를 사용한다는 의미다. 이건 기본적으로 섬세하게 코딩됐다면 큰 문제를 일으키지는 않는다. 섬세하게 코딩되지 않았다는 말은 sizeof(wchar_t) 따위를 사용하지 않고 2를 하드코딩 하는 것과 같은 것을 의미한다. 그런 기본적인 실수만 없다면 프로그램 동작 상에 발생하는 큰 문제는 없다.&lt;/p&gt;
&lt;p&gt;하지만 진짜 문제는 바이너리 파일을 사용할 때 발생한다. 여러분이 설계한 바이너리 파일이 UCS2의 데이터를 가정하고 있고 그걸 변환없이 Visual C++에서 읽어들이면서 재미를 봤다면 조금 골치가 아파진다. 그런 부분은 전부 별도로 처리를 해야한다. 이게 생각보다 골치아푸다. 괜히 UTF-8같은 걸 사용하는 게 아니다. 어쨌든 이런 부분이 있다면 아주 섬세하게 꼼꼼하게 생각해서 변환 루틴들을 적용시켜 주어야 하겠다.&lt;/p&gt;
&lt;p&gt;윈도우는 MultiByteToWideChar나 WideCharToMultiByte 함수를 사용해서 문자열 변환을 쉽게 할 수 있지만 당연히 리눅스에는 그런 것 따위는 없다. iconv 라이브러리를 사용하면 동일한 버전을 구현할 수 있으니 해당 라이브러리를 사용해서 변환 함수를 구현해주면 되겠다.&lt;/p&gt;
&lt;p&gt;_wfopen 같은 함수를 찾아 헤맬지도 모르겠다. 리눅스에는 애초에 그런 종류의 함수는 없다. 따라서 해당 함수가 필요하다면 직접 구현해야 한다. 윈도우의 A/W 전략과는 반대로 gcc는 대체로 기존 함수에다 UTF-8 문자열 입력 기능을 추가해서 유니코드에 대응하는 방식을 채택하고 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;여러분이 fopen보다는 CreateFile에 더 익숙하고, fstat보다는 GetFileAttribute에 더 익숙해서 프로그램 전반에 이런 API를 사용하는 부분이 많이 있다면 일일이 API를 사용한 부분을 변경하는 것보다는 CreateFile, GetFileAttribute와 같은 함수의 리눅스 버전을 작성하는 것이 좋다. 이런 작업을 한다면 &lt;a href=&quot;http://www.winehq.org/&quot;&gt;wine&lt;/a&gt;(리눅스에서 윈도우를 구동시켜주는 에뮬레이터 프로젝트) 소스 코드가 큰 도움이 될 것이다. 거의 모든 API가 구현돼 있기 때문에 내부를 살펴보면 어떻게 만들어야 하는지 대충 감을 잡을 수 있다.&lt;/p&gt;
&lt;p&gt;다음으로 호환성 있는 함수라고 생각하고 썼는데도 함수명이 다른 경우도 있다. fstat 같은 함수도 그렇다. gcc에서는 fstat이지만 Visual C++에서는 _fstat이다. 이런 함수들은 당연히 호출 부분마다 전처리기를 사용해서 별도로 처리하기 보다는 mystat 같은 래퍼 함수를 만들거나 매크로를 선언해서 해당 함수를 호출하도록 만들어주는 것이 좋다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;문자열에 관한 함정이 또 하나 있다. 바로 포매팅 문자열이다. 윈도우에서는 printf 같은 멀티바이트 함수에서 %s는 멀티바이트 문자열을 %S는 유니코드 문자열을 나타내고, wprintf 같은 유니코드 함수에서는 %s는 유니코드 문자열을, %S는 멀티바이트 문자열을 나타낸다. 근데 gcc에는 이렇지가 않다. printf, wprintf 모두 %s는 멀티바이트, %S는 유니코드를 나타낸다. 따라서 %s, %S 따위를 쓰면 십중팔구 바보가 될 수 있다. 전처리기로 처리하는 것 또한 좋은 생각이 아니다. 가장 좋은 방법은 애초에 %s, %S를 사용하지 않는 것이다. %hs, %hc, %ls, %lc를 사용하는 습관이 도움이 된다. 함수에 관계없이 %hs, %hc는 멀티바이트를, %ls, %lc는 유니코드를 나타낸다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#4&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;끝으로 가장 골치 아픈 부분인데 여러분의 코드가 어떻게든 시스템의 도움을 받는 부분들이 있을 것이다. 이 부분이 가장 크리티컬하다. 예를 들면 윈도우 프로그램이라면 별 생각없이 스레드를 사용했을 것이다. 이런 경우에 그런 부분들에 해당하는 함수를 일일이 만드는 행위나 함수 호출 부분을 별도로 코딩하는 일은 실수를 많이 만들어낸다. 자신들과 비슷한 구조를 가진 검증된 라이브러리가 있다면 그걸 사용하는 것이 훨씬 좋다. 우리 같은 경우에는 윈도우 스레드를 자체적으로 추상화 시켜서 사용하고 있었는데 구조가 boost 스레드랑 유사했다. 그래서 해당 부분을 boost 스레드로 교체함으로써 플랫폼 중립적인 코드로 만들 수 있었다.&lt;/p&gt;
&lt;p&gt;또 다른 흔한 예로 GUI가 있다. GUI 관련 코드도 플랫폼에 마다 별도로 직접 만드는 것보다는 QT같은 플랫폼 중립적인 라이브러리를 사용하는 것이 훨씬 정신 건강에 좋다. 그게 포팅 시간도 줄인다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#5&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;아래 두 글도 더불어 같이 읽어보도록 하자. 분명 큰 도움을 줄 것이다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.ibm.com/developerworks/aix/library/au-porting/&quot;&gt;http://www.ibm.com/developerworks/aix/library/au-porting/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.ibm.com/developerworks/aix/library/au-porting2/&quot;&gt;http://www.ibm.com/developerworks/aix/library/au-porting2/&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[멘.탈.붕.괴.]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/10216</link><guid isPermaLink="false">https://jiniya.net/wp/archives/10216</guid><pubDate>Thu, 31 Jan 2013 23:58:42 GMT</pubDate><content:encoded>&lt;p&gt;바이러스에 난자 당한 컴퓨터,&lt;/p&gt;
&lt;p&gt;전원이 나가버린 새 장난감,&lt;/p&gt;
&lt;p&gt;구현해야 하는 기능 더미,&lt;/p&gt;
&lt;p&gt;써야하는 문서,&lt;/p&gt;
&lt;p&gt;풀리지 않는 문제,&lt;/p&gt;
&lt;p&gt;안드로메다로 가버린 일정,&lt;/p&gt;
&lt;p&gt;심리적 부채가 되버린 계약,&lt;/p&gt;
&lt;p&gt;잡힐 줄 모르는 버그,&lt;/p&gt;
&lt;p&gt;쏟아지는 해킹툴,&lt;/p&gt;
&lt;p&gt;흐트러진 집중력,&lt;/p&gt;
&lt;p&gt;넘쳐나는 사람들,&lt;/p&gt;
&lt;p&gt;하지만 정작 일 할 사람은 없는 아이러니,&lt;/p&gt;
&lt;p&gt;참… 맨정신으로 살기 힘드네.&lt;/p&gt;
&lt;p&gt;지금 한 번 해보자는 거지~&lt;/p&gt;
&lt;p&gt;그래 덤버라!!!&lt;/p&gt;
&lt;p&gt;2013.01.31.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[프로세스 명령줄 정보 삭제하기]]></title><description><![CDATA[cmdline…]]></description><link>https://jiniya.net/wp/archives/10147</link><guid isPermaLink="false">https://jiniya.net/wp/archives/10147</guid><pubDate>Mon, 14 Jan 2013 23:58:41 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/wp/wp-content/uploads/2013/01/cmdline.png&quot;&gt;&lt;img src=&quot;http://www.jiniya.net/wp/wp-content/uploads/2013/01/cmdline.png&quot; alt=&quot;cmdline&quot;&gt;&lt;/a&gt;
&lt;strong&gt;커맨드 라인 정보는 어디로??&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;후배 녀석이 자신이 실행시킨 프로그램 명령줄 정보를 못 보게 하는 방법이 없냐고 해서 만들어 본 프로그램입니다. 위에 보이는 것처럼 프로세스 정보를 조회하는 툴에서 명령줄 정보를 볼 수 없도록 삭제해 줍니다. 다.만. 별로 의미없는 이유는 대부분 프로세스 모니터링 프로그램이 프로세스 생성 시점에 바로 정보를 저장해 두었다가 보여주기 때문에 우리가 정보를 지워도 계속 노출된다는 단점이 있습니다. 우리가 정보를 삭제한 다음에 프로세스 모니터링 도구를 띄워서 체크해보면 위에 보이는 것처럼 삭제된 것을 확인할 수 있습니다. 결국 별로 쓰잘때기 없는 코드라는 이야깁니다. ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;윈도우에서 명령줄 정보는 PEB의 RTL_USER_PROCESS_PARAMETERS 구조체의 CommandLine 필드에 저장됩니다. 그곳에 저장된 정보를 제거해 주면 다른 프로그램에서 해당 정보를 참조하지 못하겠지요. 이런 원리로 아래 프로그램은 명령줄 정보를 삭제하는 방법을 보여주고 있습니다. 코드 흐름만 보여주기 위해서 에러 처리 따위는 모두 삭제돼 있습니다. 32비트에서만 동작하는데요. 관심 있으신 분들은 64비트 버전을 만들어보는 것도 실력 향상에 도움이 될 것 같습니다. 난 고수다. 실력 쫌 되는데 하시는 분들은 WoW64 프로세스에서 32비트나 64비트 프로세스 정보를 제거하는데 도전해 보세요. 64비트는 아래 구조체도 일부 포함시켜두었기 때문에 크게 어렵진 않은데, WoW64는 초큼 어렵습니다 ㅋ~&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;windows.h&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;pragma&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token function&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_PEB32&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ULONG reserved&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG param&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; PEB32&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PPEB32&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_PEB64&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ULONG64 reserved&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG64 param&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; PEB64&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PPEB64&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_UNICODE_STRING32&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	USHORT  Length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	USHORT  MaximumLength&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG  Buffer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; UNICODE_STRING32&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PUNICODE_STRING32&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_UNICODE_STRING64&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	USHORT  Length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	USHORT  MaximumLength&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG Pad1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG64  Buffer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; UNICODE_STRING64&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PUNICODE_STRING64&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_RUPP32&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ULONG reserved1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG reserved2&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	ULONG reserved3&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG reserved4&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	ULONG reserved5&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	ULONG reserved6&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	UNICODE_STRING32 path&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	UNICODE_STRING32 image&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	UNICODE_STRING32 cmd&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; RUPP32&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PRUPP32&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_RUPP64&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ULONG reserved1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG reserved2&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	ULONG reserved3&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG reserved4&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	ULONG64 reserved5&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	UNICODE_STRING64 reserved6&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG64 reserved7&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	UNICODE_STRING64 path&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	UNICODE_STRING64 image&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	UNICODE_STRING64 cmd&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; RUPP64&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PRUPP64&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__success&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; LONG NTSTATUS&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PNTSTATUS&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_PROCESS_BASIC_INFORMATION32&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    NTSTATUS ExitStatus&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ULONG PebBaseAddress&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ULONG AffinityMask&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ULONG BasePriority&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    HANDLE UniqueProcessId&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    HANDLE InheritedFromUniqueProcessId&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; PROCESS_BASIC_INFORMATION32&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PPROCESS_BASIC_INFORMATION32&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_PROCESS_BASIC_INFORMATION64&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    NTSTATUS ExitStatus&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ULONG Pad1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    PVOID64 PebBaseAddress&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ULONGLONG AffinityMask&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ULONGLONG BasePriority&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    PVOID64 UniqueProcessId&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    PVOID64 InheritedFromUniqueProcessId&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; PROCESS_BASIC_INFORMATION64&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PPROCESS_BASIC_INFORMATION64&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;_WIN64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;PROCESS_BASIC_INFORMATION&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;PROCESS_BASIC_INFORMATION64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;PPROCESS_BASIC_INFORMATION&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;PPROCESS_BASIC_INFORMATION64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;PROCESS_BASIC_INFORMATION&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;PROCESS_BASIC_INFORMATION32&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;PPROCESS_BASIC_INFORMATION&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;PPROCESS_BASIC_INFORMATION32&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;


&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;pragma&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token function&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NTSTATUS&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WINAPI &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;NtQueryInformationProcessT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LONG&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PVOID&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ULONG&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PULONG&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateProcessAndClean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPWSTR cmdline&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	PROCESS_INFORMATION pi&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	STARTUPINFO si &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;si&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;CreateProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cmdline&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;si&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;pi&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;press any key to clean command line information.\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;getchar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	ULONG req&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	PROCESS_BASIC_INFORMATION pbi&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	HANDLE process &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; pi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hProcess&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	NtQueryInformationProcessT pNtQueryInformationProcess&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	
	HMODULE ntdll &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetModuleHandleW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;ntdll.dll&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	pNtQueryInformationProcess 
		&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NtQueryInformationProcessT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
			&lt;span class=&quot;token function&quot;&gt;GetProcAddress&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ntdll&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NtQueryInformationProcess&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;pNtQueryInformationProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process
									&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
									&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;pbi
									&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pbi&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
									&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	SIZE_T readed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	PEB32 peb32&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	RUPP32 rupp32&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;ReadProcessMemory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; pbi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PebBaseAddress
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;peb32
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;peb32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;readed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;ReadProcessMemory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; peb32&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;param
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;rupp32
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rupp32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;readed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	SIZE_T written&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	WCHAR cmd&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;MAX_PATH&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;ReadProcessMemory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; rupp32&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cmd&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Buffer
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cmd
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;cmd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; rupp32&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cmd&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Length
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;readed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%p %ws %d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rupp32&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cmd&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cmd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dwProcessId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	rupp32&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cmd&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Length &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;WriteProcessMemory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; peb32&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;param
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;rupp32
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rupp32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;written&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hProcess&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hThread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_tmain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; argc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _TCHAR&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; argv&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	WCHAR cmd&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;c:\\windows\\system32\\notepad.exe c:\\abc.txt&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;CreateProcessAndClean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cmd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;getchar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[홀리데이 – 유전무죄 무전유죄]]></title><description><![CDATA[“유전무죄, 무전유죄” 탈주범의 절규 몇 해 전 본 TV 프로그램 중에 “1달러의 삶”이란 다큐가 있어. 세계 각지에서…]]></description><link>https://jiniya.net/wp/archives/4581</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4581</guid><pubDate>Sat, 05 Jan 2013 23:58:38 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;http://www.sisapress.com/news/articleView.html?idxno=59324&quot;&gt;“유전무죄, 무전유죄” 탈주범의 절규&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;몇 해 전 본 TV 프로그램 중에 “1달러의 삶”이란 다큐가 있어. 세계 각지에서 1달러로 하루를 해결하는 사람들의 이야기를 담고 있어. 주로 멕시코, 브라질, 인도에 관한 이야긴데, 그 곳 사람들은 단 하나의 기회도 없어. 단지 그곳에서 태어났다는 이유로 8살부터 벽돌을 깨거나, 사람들 앞에서 저글링을 하거나, 맥도날드 앞에서 구걸을 하지. 정말 불쌍하다는 생각을 많이 했어. 진짜 단 1%의 선택권도 없거든. 죽거나 구걸하는 ㅠㅜ 그때 가장 가슴 아팠던 인도 여자 아이에 관한 대사, 일년 삼백육십오일을 맥도날드 앞에서 구걸 하는데 맥도날드 햄버거는 태어나서 한번도 먹어본 적이 없다는 이야기…&lt;/p&gt;
&lt;p&gt;세상이 좀 더 편평했으면 좋겠어. 모든 사람들이 행복하면 우리도 쉽게 행복할 수 있지 않을까?&lt;/p&gt;
&lt;p&gt;영화보는 내내 그런 생각이 들더라.&lt;/p&gt;
&lt;p&gt;– 그 남자&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;내일은 아무 생각 안하고… 아무 걱정없이… 정말 행복하게 보냈음 좋겠어.&lt;/p&gt;
&lt;p&gt;영화 보고… 맛난거 먹고… 얘기도 하고… 웃다가… 그렇게 하루가 갔음.&lt;/p&gt;
&lt;p&gt;손에서 계속 땀이나서… 글씨가 잘 안 써져…&lt;/p&gt;
&lt;p&gt;자꾸 삐뚤삐뚤하고… 이상하네…&lt;/p&gt;
&lt;p&gt;그만 쓰고 전화할께…&lt;/p&gt;
&lt;p&gt;“압뿌라쑝”&lt;/p&gt;
&lt;p&gt;“라삘루뚜루뚜”&lt;/p&gt;
&lt;p&gt;– 그 여자&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;내가 초등학교 다닐 때는 참 웃긴 설문 조사를 많이 했다. 그 중에 지금 생각해도 제일 웃기다고 생각하는 설문이 대한민국에 태어난 게 자랑스럽냐는 내용이었다. 초등학교 2-3학년이 대한민국에 태어난 게 자랑스러운지 아닌지를 무슨 근거로 판단을 하겠는가? 그나마 부모덕에 외국이라고 한 번 나가본 아이들이라면 비교라고 하겠지만 말이다. 난 그때 초딩이었지만 참 우스꽝스러운 설문이라고 생각했다.&lt;/p&gt;
&lt;p&gt;정말 많은 시간이 흘렀다. 아이러니하게도 지금 난 대한민국에 태어난 게 자랑스럽다고 생각한다. 좀 더 솔직하게 말하자면 단지 다행이라는 생각이 들 때가 많다. 그나마 이곳에 태어나서 그래도 고생은 좀 덜하면서 사는구나, 라는 생각이 들기 때문이다. 언젠가 신문 기사에 난 것 처럼 우리가 벌어들이는 소득은 거의 대부분 우리가 어느 지역에 태어났는지로 결정된다고 생각하기 때문이다. 그나마 중간은 되는 나라에 중간은 되는 지역에 태어나서 나름 기회도 있었고, 굶지 않고 살 수 있었던 것 같다. 나의 의지와는 0.00000001%의 관계도 없는 단순한 그 사실 때문에 말이다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;사회주의 역시 돈에 대한 욕구를 완전히 없앨 수는 없었다. 전쟁이 끝난 직후인 1946년에 나는 헝가리 부다페스트에 간 적이 있다. 당시 미국에서는 자본주의 열풍이 뜨거웠고, 사람들이 모이기만 하면 오가는 대화의 주제는 오직 돈이었다. 누가 무슨 직업을 갖고 있느냐가 중요한 것이 아니라 얼마나 돈을 많이 벌 수 있는가가 문제였다. 그런데 나는 부다페스트에서 이와 전혀 다른 현상을 목격했다. 거기서는 누가 무슨 일을 하는지, 어떤 성공을 거두었는지 등에 대해 이야기했다. 어떤 사람이 작곡 분야에서 성공을 했고, 어떤 사람이 베스트셀러 작가가 되었으며, 또 어떤 사람이 인정받는 화학자가 되었는지 등등… 사실 이러한 분위기는 미국의 분위기보다 훨씬 내 마음에 들었다. 그때 한 친구가 이렇게 말했다.&lt;/p&gt;
&lt;p&gt;“어느 누구도 돈에 대해 말하지 않아. 그렇지만 모든 사람들이 그걸 생각하지.”&lt;/p&gt;
&lt;p&gt;그들은 돈을 소유할 수 있다는 희망이 없기 때문에 차라리 말하지 않는 편을 택했던 것이다.&lt;/p&gt;
&lt;p&gt;– 돈, 뜨겁게 사랑하고 차갑게 다루어라, 앙드레 코스톨라니&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;조카들이 내 나이가 됐을 때를 상상해본다. 그때는 나처럼 다행이라는 안도가 아닌 자랑스럽다는 생각을 할 수 있었으면 좋겠다. 편평하고 공정한 그런 세상. 그리고 조금은 누가 얼마를 번다는 이야기 보다는 무슨 일을 한다는 이야기를 더 많이 할 수 있는 세상이 됐으면 좋겠다. 소유의 포기 때문이 아닌 진심으로 하는 이야기로 말이다.&lt;/p&gt;
&lt;p&gt;기회는 평등할 것입니다.&lt;/p&gt;
&lt;p&gt;과정은 공정할 것입니다.&lt;/p&gt;
&lt;p&gt;결과는 정의로울 것입니다.&lt;/p&gt;
&lt;p&gt;문재인 캠프의 슬로건 같은 세상이 올 수 있기를 기도하며 주문을 외워본다.&lt;/p&gt;
&lt;p&gt;압뿌라쑝, 라삘루뚜루뚜~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;기회는 평등할 것입니다. 과정은 공정할 것입니다. 결과는 정의로울 것입니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[포맷스트링이 부릅니다. 헬게이트2…]]></title><description><![CDATA[최근에 포맷 스트링과 관련된 문제를 한 번 더 겪어서 여기다 기록을 남겨본다. 문제는 다음과 같은 부분에서 출발했다. 크래시가 났는데 log_writer의 Write…]]></description><link>https://jiniya.net/wp/archives/9392</link><guid isPermaLink="false">https://jiniya.net/wp/archives/9392</guid><pubDate>Thu, 03 Jan 2013 23:58:37 GMT</pubDate><content:encoded>&lt;p&gt;최근에 포맷 스트링과 관련된 문제를 한 번 더 겪어서 여기다 기록을 남겨본다. 문제는 다음과 같은 부분에서 출발했다. 크래시가 났는데 log_writer의 Write 함수를 호출하는 부분에서 났다. 그간 문제없이 잘 사용했던 함수라 증말 증상이 이해가 되질 않았다. 뭔가 buffer 값이 잘못됐는지만 계속 추적했는데 buffer 같은 이상이 없었다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// 버퍼 계산하는 부분&lt;/span&gt;
log_writer&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;buffer = &apos;%hs&apos;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그렇게 한참을 시도를 하다 놀라운 사실을 발견했다.&lt;/p&gt;
&lt;p&gt;클래스가 다음과 같이 선언돼 있었던 것이다. 문제를 눈치 챘는가?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LogWriter&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token base-clause&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ILogWriter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; XCALL &lt;span class=&quot;token function&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;xcwstr fmt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; XCALL &lt;span class=&quot;token function&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;xcstr fmt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; XCALL &lt;span class=&quot;token function&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;xcwstr fmt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; va_arg ap&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; XCALL &lt;span class=&quot;token function&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;xcstr fmt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; va_arg ap&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;맞다. 인자가 두개인 함수가 같이 선언된 것이 문제였다. 내가 원했던 링크 경로는 Write(xcwstr fmt, …)이었는데, Write(xcwstr fmt, va_arg ap)로 연결이 됐던 것이다. 흙~ 그래서 클래스를 다음과 같이 바꿨다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LogWriter&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token base-clause&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ILogWriter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; XCALL &lt;span class=&quot;token function&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;xcwstr fmt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; XCALL &lt;span class=&quot;token function&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;xcstr fmt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; XCALL &lt;span class=&quot;token function&quot;&gt;WriteV&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;xcwstr fmt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; va_arg ap&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; XCALL &lt;span class=&quot;token function&quot;&gt;WriteV&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;xcstr fmt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; va_arg ap&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;가변 인자 함수를 정의할 때에는 각별히 주의해야겠다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Fighters fight]]></title><description><![CDATA[Fighters fight – Rocky Balboa, 2006 우리는 생각보다 다른 사람의 시선을 더 많이 신경 쓰고 있는 건 아닐까? #0 서울에 괜찮은…]]></description><link>https://jiniya.net/wp/archives/8782</link><guid isPermaLink="false">https://jiniya.net/wp/archives/8782</guid><pubDate>Thu, 03 Jan 2013 23:58:36 GMT</pubDate><content:encoded>&lt;p&gt;Fighters fight – Rocky Balboa, 2006&lt;/p&gt;
&lt;p&gt;우리는 생각보다 다른 사람의 시선을 더 많이 신경 쓰고 있는 건 아닐까?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;서울에 괜찮은 4년제 대학교를 나와서&lt;/p&gt;
&lt;p&gt;나름의 토익 점수라든지 시험점수도 충분히 되고&lt;/p&gt;
&lt;p&gt;자격증도 충분히 따놨는데&lt;/p&gt;
&lt;p&gt;아무도 모르는 중소기업이라든지&lt;/p&gt;
&lt;p&gt;아니면 지방에 있는 그런 작은 회사를&lt;/p&gt;
&lt;p&gt;가고 싶어하는 사람은 없잖아요&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;남들이 ‘요즘 얼마나 먹고 살기 힘든데’&lt;/p&gt;
&lt;p&gt;‘야 죽을 맛이야 너 빨리 아무 데나 잡아라’&lt;/p&gt;
&lt;p&gt;그 말 듣고 가기에는 내 인생이 너무 밑지는 것 같은&lt;/p&gt;
&lt;p&gt;손해 보는 것 같은&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;저는 기업에 가서 하면&lt;/p&gt;
&lt;p&gt;엄청 힘든 일이 있어도&lt;/p&gt;
&lt;p&gt;그냥 제가 원하는 기업이라면&lt;/p&gt;
&lt;p&gt;그 배지나 로고를 보면서&lt;/p&gt;
&lt;p&gt;행복해 할 것 같아요&lt;/p&gt;
&lt;p&gt;그게 맞는 거죠&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;제가 큰 기업에 가고 싶은 이유는&lt;/p&gt;
&lt;p&gt;정말 효도하고 싶어서&lt;/p&gt;
&lt;p&gt;그러는 거예요&lt;/p&gt;
&lt;p&gt;부모님께,&lt;/p&gt;
&lt;p&gt;부모님이 정말 자랑할 수 있게끔&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;서울로 올라가서 일을 한다든지&lt;/p&gt;
&lt;p&gt;본사에서 좋은 조건에서&lt;/p&gt;
&lt;p&gt;돈 많이 받고 일을 하게 되면&lt;/p&gt;
&lt;p&gt;전 제 스스로&lt;/p&gt;
&lt;p&gt;프라이드를 가질 것 같아요&lt;/p&gt;
&lt;p&gt;나 정말 인생 잘 살고 있구나&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;얼마 전, 어려운 취업 현실에 관한 다큐를 한 편 보았다. 단군이례 최고의 스펙임에도 취업이 어려운 요즘 세상에 관한 이야기였다. 공감을 하면서 보다가도 다큐 마지막에 나오는 미취업자들의 인터뷰 내용에는 경악할 수 밖에 없었다. 그 누구도 자신이 뭘 잘 하는지 무엇을 하고 싶은지에 대한 고민은 하지 않았기 때문이다. 모두가 약속이라도 한 것처럼 하나같이 다른 사람이 자신을 어떻게 바라볼지에 대해서만 생각하는 것처럼 보였다.&lt;/p&gt;
&lt;p&gt;평생 직장 내지는 업이라는 것이 사라진 요즘이지만 그래도 한 직장, 내지는 한 업계에 몸을 담으면 상당히 오랜 기간 그 일을 하면서 보낸다. 또한 그렇게 선택한 직업을 가진 동안에는 일과 시간의 대부분을 그 일을 하는데 오롯이 할당할 수 밖에 없다. 그렇게 생활의 대부분을 차지하게 될 업을 선택하는데 자신의 적성, 특기를 고려하기 보다는 일년에 한두 번 만날지도 모르는 주변 사람들 내지는 부모님의 위신만을 고려해서 선택한다면 과연 옳은 것일까? 평생 그 일을 참고 꾸역꾸역 해 나가야 할 자신에게 너무 미안한 선택 아닐까?&lt;/p&gt;
&lt;p&gt;싸움꾼은 싸움을 하고, 가수는 노래를 하고, 화가는 그림을 그리고, 작가는 글을 쓰고, 포토그래퍼는 사진을 찍고, 프로그래머는 프로그래밍을 한다. 주변의 시선 따위는 잠시 쓰레기통에 넣어 두고 먼저 난 어떤 일을 좋아하는지, 내가 잘 할 수 있는 일은 무엇인지를 생각해 보는 시간을 가져보는건 어떨까?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;행복이란 자신이 가치있다고 생각하는 일에 오랫동안 몰두할 수 있는 권리라고도 할 수 있다. 어떤 사람은 아내와 아이들을 돌보는 데서 행복을 찾는다. 어떤 사람은 은행을 터는 데에서 행복을 느낀다. 뚜렷한 성과도 없는 순수한 연구에 매달리며 행복을 느끼는 사람도 있다.&lt;/p&gt;
&lt;p&gt;자신과, 자신을 둘러싸고 있는 환경을 둘러보자. 똑같은 사람은 둘도 없으며 똑같은 사람이 있으리라고 생각하는 것도 얼토당토않은 일이다. 남자든 여자든, 사람은 누구나 오랜 동안 열심히 일하면서 행복을 느낄 수 있는 직업을 찾아야 한다. 거꾸로 말하면, 지금 일을 좀 덜했으면 싶거나 긴 휴가와 퇴직을 바란다면 직업을 잘못 선택했다. 차라리 은행털이를 하거나 한탕할 건수를 찾는 것이 낫다. 아니면 정치를 하거나.&lt;/p&gt;
&lt;p&gt;– 로버트 하인라인의 “해 지는 곳 너머로 돛을 올려서”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[윈도우 8에 관한 10원 짜리 팁들…]]></title><description><![CDATA[지난 주에 Hyper-V 때문에 윈도우8 업그레이드를 단행했습니다. 제가 Hyper-V를 좀 잘못 이해해서 벌어진 해프닝인데 지금은 굉장히 만족하면서 사용하고 있습니다. 사실 사람들이 시작 버튼 없어진 걸 마치 대단한 일인것처럼 말하는데 윈도…]]></description><link>https://jiniya.net/wp/archives/9771</link><guid isPermaLink="false">https://jiniya.net/wp/archives/9771</guid><pubDate>Thu, 27 Dec 2012 23:58:35 GMT</pubDate><content:encoded>&lt;p&gt;지난 주에 Hyper-V 때문에 윈도우8 업그레이드를 단행했습니다. 제가 Hyper-V를 좀 잘못 이해해서 벌어진 해프닝인데 지금은 굉장히 만족하면서 사용하고 있습니다. 사실 사람들이 시작 버튼 없어진 걸 마치 대단한 일인것처럼 말하는데 윈도7에서 작업 표시줄에 PIN 기능 생기고 나서 전 시작 메뉴를 눌러본 적이 거의 없는 것 같습니다. 오히려 없는 게 깔끔하니 좋더군요.&lt;/p&gt;
&lt;p&gt;제가 가장 점수를 많이 주고 싶은 건 live.com 계정을 통해서 모든 것이 자동으로 동기화 된다는 점 입니다. 메일, 일정, SkyDrive로 파일 등을 손쉽게 여러 환경에서 편리하게 쓸 수 있습니다. 데탑에서 앱이 필요없는 기능이라는 의견도 많은데 정작 써보면 단지 뷰가 바꼈을 뿐인데 전혀 새로운 경험을 하게 해주는 경우가 많습니다. 물론 유용하다는 말은 아닙니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;미디어 플레이어 설치&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;N 버전을 사용하시면 미플이 기본적으로 설치되지 않습니다.&lt;/p&gt;
&lt;p&gt;아래 페이지를 방문 하셔서 다운로드 받아서 설치하시면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://windows.microsoft.com/ko-KR/windows/download-windows-media-player&quot;&gt;미플 다운로드 페이지&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;시작 프로그램 등록하기&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;shell:startup&lt;/strong&gt; 커맨드를 입력하면 시작 프로그램 등록하는 폴더가 나옵니다.&lt;/p&gt;
&lt;p&gt;거기다 바로가기를 추가해 주시면 되겠습니다.&lt;/p&gt;
&lt;p&gt;자세한 설명은 아래 페이지에…&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://bbokkun.tistory.com/4&quot;&gt;http://bbokkun.tistory.com/4&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;단축키 정리&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;몇 가지 단축키를 알면 정말 쓰기가 편해집니다. 모르면 마우스 동선이 좀 많아서 단축키가 효율적인 것 같아요.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.addictivetips.com/windows-tips/30-new-hotkeys-for-windows-8/&quot;&gt;http://www.addictivetips.com/windows-tips/30-new-hotkeys-for-windows-8/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;W + Q (필수 서치 단축키)&lt;/p&gt;
&lt;p&gt;W + C (참바 나오는 단축키)&lt;/p&gt;
&lt;p&gt;W (시작 화면 표시)&lt;/p&gt;
&lt;p&gt;W + D (데스크톱으로 전환)&lt;/p&gt;
&lt;p&gt;W + T (앱 전환)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;라이브닷컴 계정 만들기&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;한국이면 live.co.kr같은 알흠답지 않은 계정이 생성되는데요. 아래 페이지로 접속해서 계정 생성하면 live.com 계정을 만들 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://signup.live.com/signup.aspx?mkt=en-US&amp;#x26;id=251248&quot;&gt;https://signup.live.com/signup.aspx?mkt=en-US&amp;#x26;id=251248&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;타일 관리 하는 방법&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;뭐 굳이 강좌를 안 봐도 잘 쓸 수 있도록 직관적이지만 그래도 한 번 읽어보면 훨씬 빠르게 적응할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://archwin.net/32&quot;&gt;http://archwin.net/32&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;윈도우 스토어&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;아직 한국 앱은 많지 않습니다. 언어에 영어를 추가하면 앱이 갑자기 폭발적으로 늘어납니다. 큰 모니터에 앱을 띄워 놓는게 비효율적이라고 생각들 많이 하는데 27인치 화면에 트위터 앱 띄워놓고 보면 새로운 경험을 하게 됩니다. 그렇게 속이 시원할 수가 없습니다 ㅋㅋ~ 다른 앱들도 데탑 화면에서 써보면 전혀 새로운 경험을 하게 해주는 경우가 더러 있습니다. 단지 뷰가 바꼈을 뿐인데 말이죠. 그렇게 쓸모없지는 않다는 생각입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;정품 인증&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;설치하고 가끔 정품 인증이 안 되는 경우가 있었습니다. 당황하지 말고 윈도키 R 눌러서 실행창 나오면 아래 명령어를 입력하면 제품키를 다시 입력할 수 있는 화면이 출력됩니다. 그 때 제품키 입력하고 인증 받으면 됩니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;slui 3&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;원격 데스크톱 오류&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;윈도우 8에서 윈도우 8로 원격 데스크톱 접속을 하려고 할 때 MicrosoftAccount 오류라고 하면서 접속 안 되는 문제가 발생하는 경우가 있습니다. 아래 방법대로 커스텀 파일을 만들어서 사용하면 문제없이 접속할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://support.microsoft.com/kb/941641&quot;&gt;http://support.microsoft.com/kb/941641&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;키보드 101키 변경&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://answers.microsoft.com/ko-kr/windows/forum/windows%5C_8-hardware/windows-8-%EC%97%90%EC%84%9C-%ED%95%9C%EC%98%81/56039823-78f9-4666-be98-830444eef89c?msgId=432b960d-f2bd-4b4f-9906-b8b4b1e051c3&quot;&gt;http://answers.microsoft.com/ko-kr/windows/forum/windows\_8-hardware/windows-8-%EC%97%90%EC%84%9C-%ED%95%9C%EC%98%81/56039823-78f9-4666-be98-830444eef89c?msgId=432b960d-f2bd-4b4f-9906-b8b4b1e051c3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; 0
 14&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[마이크로소트웨어 29주년 기념식]]></title><description><![CDATA[명함 뽑기에서 상품권을 받는 행운까지 ㅋㅋ~ 수욜날 마소 29주년 기념식이 있었습니다. 마소에서 감사하게도 별로 한 것도 없는 저에게 감사패를 주셨습니다. 10…]]></description><link>https://jiniya.net/wp/archives/9828</link><guid isPermaLink="false">https://jiniya.net/wp/archives/9828</guid><pubDate>Fri, 07 Dec 2012 23:58:34 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./마이크로소트웨어_29주년_기념식.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/2092692f3eeeaa539e78be715179dffa/e224a/%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%86%8C%ED%8A%B8%EC%9B%A8%EC%96%B4_29%EC%A3%BC%EB%85%84_%EA%B8%B0%EB%85%90%EC%8B%9D.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 74.73684210526315%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAQCBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAG+JXG3NL//xAAcEAACAgIDAAAAAAAAAAAAAAABAgADBBESExX/2gAIAQEAAQUCCLxSveX0VyrIDkDTeg0//8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQMBAT8BV//EABURAQEAAAAAAAAAAAAAAAAAAAAR/9oACAECAQE/AUf/xAAbEAACAgMBAAAAAAAAAAAAAAAAASEyERITQf/aAAgBAQAGPwJQPKhIojmjb0of/8QAGxAAAwEAAwEAAAAAAAAAAAAAAAERMVFxgdH/2gAIAQEAAT8hqowUoh2yDd8RQpjeFJW7XJ1PT//aAAwDAQACAAMAAAAQVx//xAAWEQEBAQAAAAAAAAAAAAAAAAAAEQH/2gAIAQMBAT8Quqf/xAAWEQEBAQAAAAAAAAAAAAAAAAAAESH/2gAIAQIBAT8QxD//xAAdEAEAAwABBQAAAAAAAAAAAAABABEhUTFBcYGx/9oACAEBAAE/EE3p6su3mIFmEE1oz3FrW8V+R3Q6MPMES0V7jio4FUY1fZ//2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;         29       md 0&apos; title=&apos;&apos; src=&apos;/static/2092692f3eeeaa539e78be715179dffa/e224a/%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%86%8C%ED%8A%B8%EC%9B%A8%EC%96%B4_29%EC%A3%BC%EB%85%84_%EA%B8%B0%EB%85%90%EC%8B%9D.md_0.jpg&apos; srcset=&apos;/static/2092692f3eeeaa539e78be715179dffa/8ccab/%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%86%8C%ED%8A%B8%EC%9B%A8%EC%96%B4_29%EC%A3%BC%EB%85%84_%EA%B8%B0%EB%85%90%EC%8B%9D.md_0.jpg 190w,
/static/2092692f3eeeaa539e78be715179dffa/ea4c8/%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%86%8C%ED%8A%B8%EC%9B%A8%EC%96%B4_29%EC%A3%BC%EB%85%84_%EA%B8%B0%EB%85%90%EC%8B%9D.md_0.jpg 380w,
/static/2092692f3eeeaa539e78be715179dffa/e224a/%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%86%8C%ED%8A%B8%EC%9B%A8%EC%96%B4_29%EC%A3%BC%EB%85%84_%EA%B8%B0%EB%85%90%EC%8B%9D.md_0.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;명함 뽑기에서 상품권을 받는 행운까지 ㅋㅋ~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;수욜날 마소 29주년 기념식이 있었습니다. 마소에서 감사하게도 별로 한 것도 없는 저에게 감사패를 주셨습니다. 100만 정기구독자로 보답하도록 하겠습니닷 ㅋ~ 물론 이게 끝이 아닙니다. 무려 명함 뽑기에서 상품권을 득템하는 행운까지~ 헐 ㅋ~ 네 맞습니다. 이상 자랑질이었습니다…&lt;/p&gt;
&lt;p&gt;마술쇼가 있었는데요. 마술사가 테이블마다 돌아다니면서 자기 마술을 보여주고 있었습니다. 우리 테이블에도 와서는 볼트/너트 푸는 마술을 보여주겠다고 하더군요. 내가 손을 돌리면 너트가 풀리는 걸 보여주겠다고 했습니다. 그래서 시작에 맞춰서 손을 돌리니 마치 모터가 돌리는 것처럼 너트가 풀리더군요. 심심해서는 돌리던 손을 멈추었습니다. 그래도 여전히 돌아가는 너트… 마술사가 초본지 당황해서는 똥씹은 표정이 되더군요. 저도 울고 마술사도 울었습니다. ㅠㅜ~ 프로그래머와 마술사는 그닥 어울리는 조합은 아닌것 같아요 ㅋㅋㅋ&lt;/p&gt;
&lt;p&gt;강의실 옆 운죽정에서 원고를 쓰던 학생이 졸업해서 회사를 다닌지도 몇 해는 지났고, 그 때 학생의 원고를 처음 교정해 주셨던 기자님이 편집장이 된지도 몇 해는 지났습니다. 세월 참 빨라요. 시간이 많이 흘렀지만 처음 원고를 쓰던 그 때의 열정은 잊지 않고 계속 가지고 있었으면 좋겠습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[이다르크의 위엄…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/9798</link><guid isPermaLink="false">https://jiniya.net/wp/archives/9798</guid><pubDate>Thu, 06 Dec 2012 23:58:33 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;네. 대단히 궁금하신 것 같아서,&lt;/p&gt;
&lt;p&gt;이것만 기억하시면 됩니다.&lt;/p&gt;
&lt;p&gt;박근혜 후보 떨어뜨리기 위한 겁니다.&lt;/p&gt;
&lt;p&gt;저는 박근혜 후보를 반.드.시 떨어뜨릴 겁니다.&lt;/p&gt;
&lt;p&gt;그리고 진보적 정권 교체를 해낼 겁니다.&lt;/p&gt;
&lt;p&gt;– 이정희&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;어제 있었던 대선 티비 토론회를 이제서야 봤는데 이정희 후보 장난 아니네욤. 칼을 갈아도 너&lt;del&gt;무&lt;/del&gt; 잘 갈아서 나온 것 같은 느낌이 들었습니다 ㅋㅋㅋ~ 문재인 후보나 박근혜 후보가 면도칼 들고와서 깨작되고 있는데 혼자 전기톱 들고 와서 제압하는 느낌이랄까? ㅋㅋ~ 보는 내내 어찌나 속이 시원하든지 ㅋ~ 박근혜 떨으뜨리려고 나왔다고 답변할 때에는 레알 소름 돋았습니다. 화이팅이예요. ㅋ~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;어제 토론회도 그랬지만 정치적 성향을 떠나서 좀 부끄럽습니다. ㅠㅜ&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[C++ 개발자를 위한 게임 개발 전략 세미나]]></title><description><![CDATA[마이크로소프트웨어 창간 29주년 기념 세미나를 개최합니다. 우왕 짝짝짝. ㅋㅋ~ 이름도 거창하게 “C…]]></description><link>https://jiniya.net/wp/archives/9651</link><guid isPermaLink="false">https://jiniya.net/wp/archives/9651</guid><pubDate>Fri, 16 Nov 2012 23:58:32 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://new.imaso.co.kr/seminars/cgpc2012/agenda/&quot;&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 610px; margin-bottom: 16px;&apos; data-url=&apos;./C++_개발자를_위한_게임_개발_전략_세미나.md_0.png&apos;&gt;
      &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 53.1578947368421%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACp0lEQVR42hWP309SARTH79/RU6uX5ltbrqz5o0xl2ixb5fyxCtl8YBU5apLEpibmDyqdik6NzZwzEVPCDYeIAqJw+SGWCMjPey9wL/cXF0Epe6Dr2Xfn4ez7Od9zgCgMo8mkci8wYvEorAer+k0bCBotuybztmXHumXaVmtWlzVK8HDR5lDtHiwaXMueQ99vj4cFAYLAYyjK+bZVvwReH1fzhGKb1WW2usL+oN/jPzr0G9Y3Bj8L10zCiQV+90jND7vEtf9rz+0OhkIAjmFQHK2ct3P1oVszxt5PUodeZdKptSvz/T3tQ4OdJs38zLT46zpH0N78srt0zt1id7rsTmcEigIYhsXjcfmMXDIo6R3ueS983sbl8OoKqytvFhYVlRdfqX9UzX32kC8tbuHfftVV/mGyxev1e/0+iqYA9JyG/w1X5MeqTmWlo2/K5VKOZporFT0Q8O9O9dW2Nl6rKCloul/bWFPBqyrjNTUj8TiMIDiOAykmnSKTZ1+q8lNPjvvvDAsKFicLNzV83fILg7pxaaykV3CR33D5aW1Z9Y2rjy9daKi7R9LnlclkAIIkSQLPrA3lFt7Sqs5xWadiXPZTqVArFUtzE99npwf6PkrEHe9Eog6RSPxaMDk6wjAMRVHnMAzDSCwGEwxMZWEiTdIpnKQSWDKWQFklEihJUSmGyWSOs9mT3Nnf7Ek2nkDxJMaGA+zpbHaKxBmKYGiCZq0pGkFgCIJi7FIYCYfDkUiEbewkEIzorD4dGADdR39ypwBJEKw7hiCskhjGvhDw++w2awyBdnfMkXDA5QQDAe++2wlFgw77XuuAtq7fMKvayefzAJ3NMqc5nEknaCZKMiE87YEJ0IschGmjLaw3RbX60IYR2jBDVgdqd2AyuaWtS6tdCUe8mf82utmEcvSccgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;C                        md 0&apos; title=&apos;&apos; src=&apos;/static/c014cde5891a166668d81f7d7151373b/5d5ad/C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC_%EC%9C%84%ED%95%9C_%EA%B2%8C%EC%9E%84_%EA%B0%9C%EB%B0%9C_%EC%A0%84%EB%9E%B5_%EC%84%B8%EB%AF%B8%EB%82%98.md_0.png&apos; srcset=&apos;/static/c014cde5891a166668d81f7d7151373b/08678/C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC_%EC%9C%84%ED%95%9C_%EA%B2%8C%EC%9E%84_%EA%B0%9C%EB%B0%9C_%EC%A0%84%EB%9E%B5_%EC%84%B8%EB%AF%B8%EB%82%98.md_0.png 190w,
/static/c014cde5891a166668d81f7d7151373b/2edd7/C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC_%EC%9C%84%ED%95%9C_%EA%B2%8C%EC%9E%84_%EA%B0%9C%EB%B0%9C_%EC%A0%84%EB%9E%B5_%EC%84%B8%EB%AF%B8%EB%82%98.md_0.png 380w,
/static/c014cde5891a166668d81f7d7151373b/5d5ad/C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC_%EC%9C%84%ED%95%9C_%EA%B2%8C%EC%9E%84_%EA%B0%9C%EB%B0%9C_%EC%A0%84%EB%9E%B5_%EC%84%B8%EB%AF%B8%EB%82%98.md_0.png 610w&apos; sizes=&apos;(max-width: 610px) 100vw, 610px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
    &lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://new.imaso.co.kr/seminars/cgpc2012/agenda/&quot;&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 585px; margin-bottom: 16px;&apos; data-url=&apos;./C++_개발자를_위한_게임_개발_전략_세미나.md_1.png&apos;&gt;
      &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 24.210526315789476%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAIAAADKYVtkAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAu0lEQVR42mWOyQ7CIBRF+f8/M6Ym0gEsUylDEbuptdWlN5h040m4OfdBAKLj3LvcDYnZdHN3FR4mzirMwufP5/3Pvu+Hk5qrM+Un2l86eeW67Y32SdhJjulZWNf1yINlWTAhwXuj1aCVs4N3ox0MlrM2xagLSinkWIAYY6SUGKISIQSllDHeAcZQ27Ytyuq6bpoGXlXVb8I5xwE4EheRaZpCwPMemVJCjTEi4c65n2A354yKLfz5Vdi27QtuTwtzhJsqtAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;C                        md 1&apos; title=&apos;&apos; src=&apos;/static/f03b23112fbc9b2d8dfbfa2747d2c380/51d84/C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC_%EC%9C%84%ED%95%9C_%EA%B2%8C%EC%9E%84_%EA%B0%9C%EB%B0%9C_%EC%A0%84%EB%9E%B5_%EC%84%B8%EB%AF%B8%EB%82%98.md_1.png&apos; srcset=&apos;/static/f03b23112fbc9b2d8dfbfa2747d2c380/08678/C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC_%EC%9C%84%ED%95%9C_%EA%B2%8C%EC%9E%84_%EA%B0%9C%EB%B0%9C_%EC%A0%84%EB%9E%B5_%EC%84%B8%EB%AF%B8%EB%82%98.md_1.png 190w,
/static/f03b23112fbc9b2d8dfbfa2747d2c380/2edd7/C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC_%EC%9C%84%ED%95%9C_%EA%B2%8C%EC%9E%84_%EA%B0%9C%EB%B0%9C_%EC%A0%84%EB%9E%B5_%EC%84%B8%EB%AF%B8%EB%82%98.md_1.png 380w,
/static/f03b23112fbc9b2d8dfbfa2747d2c380/51d84/C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC_%EC%9C%84%ED%95%9C_%EA%B2%8C%EC%9E%84_%EA%B0%9C%EB%B0%9C_%EC%A0%84%EB%9E%B5_%EC%84%B8%EB%AF%B8%EB%82%98.md_1.png 585w&apos; sizes=&apos;(max-width: 585px) 100vw, 585px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
    &lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;마이크로소프트웨어 창간 29주년 기념 세미나를 개최합니다. 우왕 짝짝짝. ㅋㅋ~ 이름도 거창하게 “C++ 개발자를 위한 게임 개발 전략 세미나”라는 군요. 게임 개발자를 대상으로 한다니 뉴요커 게임 개발자라면 꼭 참석하도록 합시닷.&lt;/p&gt;
&lt;p&gt;저도 게임 보안으로 한 꼭지를 맡았습니다. 싸인코드 깔때기는 없으니 너무 많이 걱정하실 필요는 없습니다. ㅋㅋㅋ~ 게임 개발자들을 대상으로 하기 때문에 해킹툴 차단 기법같은 내용은 없을 거구요. 게임 개발자들이 신경 써야 하는 보안 요소들에 대해서 좀 다뤄볼까 생각 중입니다. 리소스 핵, 사설 서버, 디지털 서명 같은 주제를 생각만 해보고 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 300px; margin-bottom: 16px;&apos; data-url=&apos;./C++_개발자를_위한_게임_개발_전략_세미나.md_2.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f4aeaac359474d44335e86e3c00dcdd3/0cdb7/C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC_%EC%9C%84%ED%95%9C_%EA%B2%8C%EC%9E%84_%EA%B0%9C%EB%B0%9C_%EC%A0%84%EB%9E%B5_%EC%84%B8%EB%AF%B8%EB%82%98.md_2.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 133.68421052631578%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAwABBAL/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQP/2gAMAwEAAhADEAAAAdbWLGSzXF5BLO2WK//EABsQAAMAAwEBAAAAAAAAAAAAAAECEQADIRIy/9oACAEBAAEFAukng1GquXgyxPZGrR8OLiKIgi//xAAYEQACAwAAAAAAAAAAAAAAAAAAEQEQEv/aAAgBAwEBPwFxWRH/xAAYEQEBAAMAAAAAAAAAAAAAAAAAEQESIf/aAAgBAgEBPwGMtuK//8QAHBAAAgICAwAAAAAAAAAAAAAAASEAEAJxEUFC/9oACAEBAAY/Ai7R3HkjWR57g9Tcd//EAB0QAQADAQACAwAAAAAAAAAAAAEAESFBMVFhgbH/2gAIAQEAAT8hC58HMgbdzssLb2XtaA4NlqWGBdQ+TLGmpbGe0Coe72oHeauA+vuAoWHwsLD9n//aAAwDAQACAAMAAAAQk+uC/8QAGREBAQEAAwAAAAAAAAAAAAAAAQAhEUHB/9oACAEDAQE/EAsfY0npHDL/xAAXEQEBAQEAAAAAAAAAAAAAAAABEQAh/9oACAECAQE/ECy7hmA403f/xAAgEAEBAAICAgIDAAAAAAAAAAABEQAhQVExYXGRobHw/9oACAEBAAE/EGZAWDhdY3Exv+GI4oYL1xjDEelttkxZF+sleCT5wpupTxUxXIoBJ9TrJ4iKQHlqcd5v7sme/XGRVi2VL3MJVz4Efhw0XtrU/vP/2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;C                        md 2&apos; title=&apos;&apos; src=&apos;/static/f4aeaac359474d44335e86e3c00dcdd3/0cdb7/C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC_%EC%9C%84%ED%95%9C_%EA%B2%8C%EC%9E%84_%EA%B0%9C%EB%B0%9C_%EC%A0%84%EB%9E%B5_%EC%84%B8%EB%AF%B8%EB%82%98.md_2.jpg&apos; srcset=&apos;/static/f4aeaac359474d44335e86e3c00dcdd3/8ccab/C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC_%EC%9C%84%ED%95%9C_%EA%B2%8C%EC%9E%84_%EA%B0%9C%EB%B0%9C_%EC%A0%84%EB%9E%B5_%EC%84%B8%EB%AF%B8%EB%82%98.md_2.jpg 190w,
/static/f4aeaac359474d44335e86e3c00dcdd3/0cdb7/C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC_%EC%9C%84%ED%95%9C_%EA%B2%8C%EC%9E%84_%EA%B0%9C%EB%B0%9C_%EC%A0%84%EB%9E%B5_%EC%84%B8%EB%AF%B8%EB%82%98.md_2.jpg 300w&apos; sizes=&apos;(max-width: 300px) 100vw, 300px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;내 생애 첫 마소. 뭔 글인지도 모르고 읽고 또 읽던 까까머리 중학생이 …&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;지난 달 마소 인터뷰가 생각나서 본가에 갈 일이 있었을 때 한 컷 찍어 봤습니다. 중학교 때 친구 녀석이 생일 선물로 사 준 마소가 제 인생에 첫 번째 마소였던거 같은데요. 무슨 말인도 모르는 글을 밤새도록 읽고 또 읽었던 기억이 납니다. 그냥 막연하게 내가 하고 싶어하는 일을 하는 사람들은 이런 사람들이구나, 라는 생각을 많이 했었던 것 같습니다.&lt;/p&gt;
&lt;p&gt;고등학교 때는 전 사실 마소보다는 프세를 더 즐겨 봤었는데요. 마소는 좀 덜 실용적인 글들이 많았고 프세는 따라해볼 수 있는 글들이 많았었거든요. 그러다 대학교 때에는 마소를 정기 구독 했었습니다. 신승근씨가 비베 책을 몇 천 권 읽었다는 글을 보면서 연구 도서관에 있는 모든 컴퓨터 책을 다 읽겠다는 어처구니 없는 생각을 했었던 적도 있었고, &lt;a href=&quot;http://www.jiniya.net/wp/archives/1208&quot;&gt;지난 글&lt;/a&gt;에도 언급했었지만 나성언님의 “디지털 메신저”란 칼럼은 기다려가면서 읽을 정도로 재미있게 봤습니다. 연구 도서관에 보관된 오래된 먼지투성이 마이크로소프트웨어 잡지 철 속에서 안철수 선생님이 기고하셨던 글을 찾아보던 때도 생각나네요.&lt;/p&gt;
&lt;p&gt;글 내용을 하나도 몰랐던 까까머리 중학생이 이제는 한 솔루션 개발을 책임지는 프로그래머가 되었고, 선배 개발자들이 그랬던 것처럼 가끔은 신입 개발자를 위한답시고 유치한 글들을 쓰기도 합니다. 그럴 때마다 참 ‘격세지감’이란 단어를 온몸으로 느끼곤 합니다. 이렇게 또 세월의 수레바퀴가 굴러가는 거겠지요? 훗~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[오류의 역사…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/8314</link><guid isPermaLink="false">https://jiniya.net/wp/archives/8314</guid><pubDate>Thu, 01 Nov 2012 23:58:31 GMT</pubDate><content:encoded>&lt;center&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./오류의_역사.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/3da5f93c5cffb09c1fc2c779ce97074b/e224a/%EC%98%A4%EB%A5%98%EC%9D%98_%EC%97%AD%EC%82%AC.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 56.315789473684205%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAIDBAX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAByNZpZHcD/8QAHBAAAgICAwAAAAAAAAAAAAAAAQIRIQADBCIz/9oACAEBAAEFAoaEXqNLgHz4l4DX/8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQMBAT8Bqv/EABURAQEAAAAAAAAAAAAAAAAAAAAR/9oACAECAQE/AYj/xAAbEAACAQUAAAAAAAAAAAAAAAAAATECEYGC0f/aAAgBAQAGPwKSLohs14VYEf/EABwQAQACAwADAAAAAAAAAAAAAAEAESExcVGR0f/aAAgBAQABPyF2OLNyy9qKRzBR2BErXZU9fUwB8whmn//aAAwDAQACAAMAAAAQTw//xAAXEQEAAwAAAAAAAAAAAAAAAAABEBEx/9oACAEDAQE/EAXkP//EABYRAAMAAAAAAAAAAAAAAAAAAAEQIf/aAAgBAgEBPxAyn//EAB0QAAICAwADAAAAAAAAAAAAAAERACExQVGBkaH/2gAIAQEAAT8QXkhQBorkkx7iREZNVqEpXpjxUKE2Dg1cy9wyQsKUXSMP7P/Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 0&apos; title=&apos;&apos; src=&apos;/static/3da5f93c5cffb09c1fc2c779ce97074b/e224a/%EC%98%A4%EB%A5%98%EC%9D%98_%EC%97%AD%EC%82%AC.md_0.jpg&apos; srcset=&apos;/static/3da5f93c5cffb09c1fc2c779ce97074b/8ccab/%EC%98%A4%EB%A5%98%EC%9D%98_%EC%97%AD%EC%82%AC.md_0.jpg 190w,
/static/3da5f93c5cffb09c1fc2c779ce97074b/ea4c8/%EC%98%A4%EB%A5%98%EC%9D%98_%EC%97%AD%EC%82%AC.md_0.jpg 380w,
/static/3da5f93c5cffb09c1fc2c779ce97074b/e224a/%EC%98%A4%EB%A5%98%EC%9D%98_%EC%97%AD%EC%82%AC.md_0.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;상식적으로 수술 직후에 나빠진 거니까 수술 부위 확인하자고 말씀 드린…&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;뭐 상식? 내가 지금 상식이 없다는 거야? 그럼 내 수술이 잘못됐다는 거야? 뭐야?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;아니… 사고는 누구한테나 생기는 거잖아요.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./오류의_역사.md_1.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f3ffa1a400f3605ae570b2c0f1f7a472/e224a/%EC%98%A4%EB%A5%98%EC%9D%98_%EC%97%AD%EC%82%AC.md_1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 56.315789473684205%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAEEAv/EABYBAQEBAAAAAAAAAAAAAAAAAAABA//aAAwDAQACEAMQAAABo3S80oyv/8QAGhAAAwADAQAAAAAAAAAAAAAAAAECAxESIf/aAAgBAQABBQKey+tRjpxPo0hs/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAHhAAAAQHAAAAAAAAAAAAAAAAAAEREgIgISIxQWH/2gAIAQEABj8CNYS5UW50CejpP//EABoQAQADAAMAAAAAAAAAAAAAAAEAEUEhMVH/2gAIAQEAAT8hJqRHhohXh1HADVMIm8lbqIVSz//aAAwDAQACAAMAAAAQB+//xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAwEBPxAn/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAR/9oACAECAQE/EFywv//EAB0QAQACAgIDAAAAAAAAAAAAAAEAESFBMVFhgcH/2gAIAQEAAT8QVoBh7F6Y1SdzXmr+RZQMbDmKJFSEO0IguMSjCK0z/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 1&apos; title=&apos;&apos; src=&apos;/static/f3ffa1a400f3605ae570b2c0f1f7a472/e224a/%EC%98%A4%EB%A5%98%EC%9D%98_%EC%97%AD%EC%82%AC.md_1.jpg&apos; srcset=&apos;/static/f3ffa1a400f3605ae570b2c0f1f7a472/8ccab/%EC%98%A4%EB%A5%98%EC%9D%98_%EC%97%AD%EC%82%AC.md_1.jpg 190w,
/static/f3ffa1a400f3605ae570b2c0f1f7a472/ea4c8/%EC%98%A4%EB%A5%98%EC%9D%98_%EC%97%AD%EC%82%AC.md_1.jpg 380w,
/static/f3ffa1a400f3605ae570b2c0f1f7a472/e224a/%EC%98%A4%EB%A5%98%EC%9D%98_%EC%97%AD%EC%82%AC.md_1.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;권위의 함점에 빠질 때, 자만에 빠질 때 우리는 상식을 놓친다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;그리고 그렇게 놓쳐버린 상식은 항상 돌이킬 수 없는 사고로 우리를 반겨준다.&lt;/strong&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;요즘 참 재미난 드라마 많이 한다. 특히나 난 의학 드라마를 좋아하는 편인데 골든타임이라는 의학 드라마가 새로 시작했다. 대박~ 원고 때문에 못 보고 있다가 원고 마감을 아슬하게 겨우 넘기고 어제는 홀가분한 마음으로 밀린 드라마 정주행을 시작했다. 굳굳~ 그런데 드라마 보는데 너무 가슴을 후벼파는 장면이 나와서 이 글을 쓰게 되었다. 일단 골든타임의 한 장면을 먼저 바라보고…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;작년에 내가 한 큰 작업 중에 하나는 XIGNCODE 서버 코드를 새로 작성하는 일이었다. 새로 작성하게 된 계기는 여러 가지가 있는데 설계 당시 우리가 생각했던 것보다 서버 쪽 기능이 많아지기도 했고, 서버 적용 난이도를 좀 더 낮출 필요가 있었기 때문이다. 코드를 좀 더 세분화 시키고 싶은 마음도 있었다. 어쨌든 이런 목적으로 작업을 시작했는데 생각보다 이 일은 내가 작년에 한 일 중에 가장 잘한 일이 되었다.&lt;/p&gt;
&lt;p&gt;새로 서버를 작성하면서 난 파이썬에 심취해서 파이썬을 연동해서 사용했다. 많은 잡다한 기능을 파이썬 코드로 작성할 수 있어서 참 매력적인 일이었다. 그런데 문제는 시간이 조금 지난 후에 나타났다. 고객사에서 잘 동작했고, 우리 테스트 PC에서도 잘 동작했는데, 유독 테스트 PC 중에 한 대에서만 바탕 화면에 게임 서버를 설치하는 경우에 시작 시에 크래시가 발생하는 것이었다. 그.것.도. 파이썬 DLL에서.&lt;/p&gt;
&lt;p&gt;난 치기에 불타 올랐다. 후훗. 파이썬 DLL에 숨겨진 버그를 찾아서 파이썬 커뮤니티를 놀라게 해주겠어, 라며 말이다. 크래시는 파이썬 DLL 내의 메모리를 해제하는 지점에서 발생했다. 그래서 난 힙 할당/해제 함수를 후킹해서 모두 추적/기록 하는 엄청난 모듈을 만들었고 파이썬 DLL에서 발생하는 모든 메모리 사용 내역을 뽑아 볼 수 있게 되었다. 그렇게 엄청난 분량의 로그가 출력됐고, 그 엄청난 분량의 로그를 파이썬으로 다시 분석했는데 오류가 없었다. 안타깝게 한 톨의 오류도 없었다. 한 바이트의 힙 오버런도 없었고, 이중 해제도 없었다. 완벽했다.&lt;/p&gt;
&lt;p&gt;멘붕에 빠진 나는 python.org에 들어갔고 2.7.2가 올라왔다는 사실을 알게 되었다. 내가 사용했던 소스는 이전 버전이었다. 그래서 2.7.2 소스를 컴파일해서 넣었다. 그랬더니 마법같이 잘 됐다. 그래서 난 속으로 아 형님들이 그 새 뭘 고쳤구나, 라고 생각하며 변경 로그를 뒤졌지만 그런 수정 사항은 애초에 찾을 수 없었다. 잠수함 패치라도 했나, 라는 생각까지……&lt;/p&gt;
&lt;p&gt;이렇게 하루가 지났다. 난 왜 2.7.1은 안 되고 2.7.2는 되는지에 집요하게 매달렸다. 뭐가 잘못일까? 뭐가 잘못일까? 그러다가 2.7.1 소스를 다시 받아서 컴파일해서 실행하는 짓까지 하게 되었는데… 결과는 정말 참혹스러웠다. 멀쩡하게 잘 실행되는 것이 아닌가? 그 때 깨달았다. 맞아, 내가 뭘 고쳤었지 ㅠㅜ~ 파이썬 소스의 초기화 부분에서 쓸모 없는 부분이라고 내가 일부를 고친 것이 생각났다. 기존에 컴파일했던 소스에서 그걸 다시 원복 시키고 컴파일을 했더니 멀쩡하게 잘 되는 것이 아닌가? ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;사무실에 혼자였지만 너무 얼척이 없어서 한바탕 웃었던 기억이 아직도 생생하다. 이틀간의 개.삽.질…&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;자 이제 진짜 좀 임팩트있는 고백을 할 차롄 것 같다. 몇 해전 초여름 나는 내 인생에서 가장 어려운 버그를 마주하고 있었다. 그 이전에도 그 이후에도 나를 그만큼 괴롭혔던 버그는 없었던 것 같다. 심지어 꿈에도 게임 캐릭터가 나타나서 나를 마구 짓누르곤 했다.&lt;/p&gt;
&lt;p&gt;버그는 단순했다. 어느 순간 갑자기 게임이 데드락에 빠지는 문제였다. 그냥 게임을 플레이 할 때에는 잘 발생하지 않았고, 8명이 들어가서 방을 만든 다음에 한 30분쯤 게임을 하면 간헐적으로 데드락이 발생했다. 이 문제를 해결하기 위해서 정말 많은 인원이 같은 게임을 지루하리만큼 많이 플레이를 해야 했다.&lt;/p&gt;
&lt;p&gt;한 달여가 지나서 모두가 그 게임의 고수가 됐을 즈음에 버그의 원인을 찾을 수 있었다. 그 결과는 나를 재차 멘붕에 빠트리기에 충분했고, 다시는 이런 실수를 되풀이하지 않겠다는 마음으로 이 버그에 다음과 같은 거창한 비문을 달았다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/*--

여기에 xxx 버그가 있었다.

xxx 캠페인 모드에서 게임이 행이 걸리는 버그가 있었다.
4.18일부터 근 한 달간 해당 문제를 해결하지 못해서 골치가 아팠다.
문제는 다름아닌 이 코드. 0x1234가 하드 코딩된 것이 화근이었다.

xxx 오디오 파일 핸들이 0x1234인 경우에 이 코드가 그 핸들을 닫아버려서,
xxx 특정 스레드가 무한 루프에 빠지게 되었다.

한 달간 엉뚱한 곳만 찾아 헤매었는데...
O 대리가 만든 logsteps.dll이 문제 해결의 단초를 제공했다.
CreateFile/CloseHandle을 훅해서 모니터링한 결과 그 핸들을 우리가 닫고 있었던 것이다.

---
해당 행 현상의 원인은 크리티컬 섹션으로 인한 데드락입니다. 
데드락이 발생하게 된 원인은 파일 핸들이 의도하지 않은 곳에서 먼저 닫혔기 때문으로 판단됩니다. 
데드락은 다음과 갈은 시나리오로 발생한 것으로 추정됩니다.

1. 무슨 스레드인지 모르는 어디선가에서 사운드 파일 핸들이 닫힘
2. ALAudio.dll!FALAudioStreamManager::DestroyStream 스레드가 생성됨
	A. FScopeCriticalSection을 사용해서 크리티컬 섹션 획득
	B. ALAudio.dll!FALAudioStreamOgg::ReadChunks 호출
		i. vorbisfile.dll!ov_read 호출
			1. 상기 닫힌 핸들로 ReadFile 호출함. 
			   닫힌 핸들이기 때문에 정상적이 값을 반환하지 못하고 실패함. 
			   이로 인해서 ReadChunks 함수가 리턴하지 못하고 무한 루프를 돌게 됨.

3. 메인 스레드에서 Engine.dll!ALAudioSubsystem::Update 함수가 호출됨
	A. 상기 DestroyStream이 획득하고 있는 크리티컬 섹션을 획득하려고 시도함. 
	   상기 스레드가 무한 루프에 빠져 있기 때문에 같이 무한 루프에 빠짐. 
	   게임 메인 스레드이기 때문에 다른 모든 작업이 진행되지 않고 멈추게 됨.
---

내가 썼던 보고서의 일부다. 1번 항목 무슨 스레드인지 모르는 어디선가가 바로 여기였다.
모두 꼼꼼하게 체크하지 않은 내 탓이었다. 
이 보고서를 쓰고 나서도 진짜 문제를 찾기까지 2주가 더 걸렸다.
어쨌든 O 대리가 고생한 덕에 찾게 되어서 다행이다.

이 한 줄 때문에 우리는 한 달 동안 200시간 넘게 xxx를 해야만 했다.
정말 토나오는 시간이었다.

--*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그렇다면 얼마나 대단한 코드가 이 엄청난 버그를 불러온 것일까? 문제의 코드는 정말 어처구니 없을 정도로 간단하다. 아래 코드가 전부다. 간단한 디버그 체크 루틴이다. 내 실수는 다름아닌 핸들 값으로 나와도 전혀 어색하지 않은 0x1234라는 값을 선택한 데 있었다. 생.각.이 없었던 것이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;__try
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x1234&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;__except&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EXCEPTION_EXECUTE_HANDLER&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token comment&quot;&gt;// 디버거 탐지&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;마지막 이야기는 우리 이야기는 아니고 다른 업체 이야기다. 최근에 알약 드라이버가 업데이트 되면서 우리 게임과 충돌이 발생하는 문제가 있었다. 2009년 만들 당시를 제외하고는 거의 블루스크린 이슈가 없었는데 그 날 따라 이상하게 블루스크린 클레임이 세 건이나 들어왔다. 그 중에 한 건은 고객이 풀덤프를 메일로 보내주는 수고를 아끼지 않았다. 난 개발팀 팀장과 앉아서 12시가 넘을 때까지 그 덤프를 봤는데 원인이 다소 불분명했다. 메모리의 모든 값들이 모두 제 자리에 우리가 예상했던 대로 들어있었는데 블루스크린이 발생했던 것이다. 우리는 윈도우 소스코드 까지 뒤져가면서 윈도우 내부 함수에서 왜 블루스크린이 발생했을 지를 추적했지만 오리무중이었다.&lt;/p&gt;
&lt;p&gt;시간이 너무 늦었고 덤프만 봐서는 답이 없을 것 같아서 일단 다음날 유저에게 다시 연락을 해보기로 했다. 블소가 OBT를 시작하던 날이었다. 집에 가는데 옆에 회사 다니는 녀석한테 전화가 와서는 PC방에 가서 그 쩐다는 블소 캐릭터를 만들고 무려 7렙까지 키우고는 — 블소 결제는 안했다. — 집으로 돌아왔다. 씻고는 컴퓨터를 켜서는 게임 사이트 모니터링을 잠깐 했는데 난리가 났다는 것을 직감했다. 블루스크린 발생한다는 글이 도배가…… 핡~ 그리고 그 중에 아주 똑똑한 유저가 알약을 끄면 된다는 것까지 알아내서 올려놨다.&lt;/p&gt;
&lt;p&gt;다시 회사로 왔다. 알약을 설치해서 테스트를 했다. 100% 블루스크린이 재현됐다. 알약 드라이버는 전날 빌드된 타임스탬프였다. 알약이 게임 프로세스에 접근하는 것을 차단하면 블루스크린이 발생하는 것처럼 보였다. 그 새벽에 일단 사이트 담당자 분들께 현상을 설명 드리고 수정 작업이 진행된다고 했다. 그리고 드라이버 코드에서 알약을 허용 처리해 준 다음 빌드를 했다.&lt;/p&gt;
&lt;p&gt;다음날 QA팀에서 테스트를하고 수정한 드라이버를 배포했다. 더불어 이스트소프트 측에도 연락을 했는데 내가 놀란 점은 이스트소프트의 대응이었다. 보통 큰 업체들은 이런 종류의 이야기를 하면 니들 잘못이니까 니들이 고치세요~ 이런 반응이 대부분이다. 그런데 이스트소프트는 달랐다. 덤프가 필요하다고 해서 QA팀에서 덤프를 보내 줬는데 바로 자신들의 자체 보호 기능과 충돌이 난 것 같다고 4-5시간 내에 수정해 주겠다는 회신이 온 것이다. 그리고 4-5시간만에 수정된 드라이버를 업데이트해 주었다.&lt;/p&gt;
&lt;p&gt;난 이스트소프트의 이 대응에 정말 진짜 감동을 받았는데 왜냐하면 그 전에는 그 어떤 국내 업체에게서도 그런 반응을 받은 적이 없었기 때문이다. 이스트소프트의 대응은 너무나 상식적이다. 블루스크린이 났으니 덤프가 필요하다는 말. 덤프를 분석했더니 자신의 모듈의 수정 내용에 문제가 있을 수도 있겠다는 말. 그리고 광속으로 수정 업데이트를 진행해 주었다. 난 이 경험이 있고 난 다음 알툴바를 교묘하게 설치하는 것쯤은 눈감아 주기로 했다. ㅋ~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;주저리 주저리 긴 이야기를 했는데 내가 하고 싶은 이야기는 간단하다. 알약 개발자들은 그렇게 쉽게 찾아낸 오류를 난 왜 이렇게 어렵게 찾아낸 것일까? 왜 그 사소한 버그를 발견하는 데에 터무니없이 오랜 시간이 걸렸을까? 내가 고친 부분은 기억도 못하고 그.렇.게.나 많은 사람들에게 검증 받은 모듈에 문제가 있다고 생각했을까? 소스 코드 한 줄 없는 게임은 디버깅을 해서 데드락의 원인을 완벽하게 찾아내는 동안에 모든 소스 코드를 가지고 있는 우리 제품에서 왜 버그를 발견하지 못했을까?&lt;/p&gt;
&lt;p&gt;답은 간단하다. 바로 문제가 나에게 있지 않고 다른 곳에 있다고 생각했던 나의 오만한 마음이다. 프로세스의 문제도, 스킬의 문제도 아니었다. 지식의 문제가 아닌 마음가짐의 문제였던 것이다. 이런 일련의 사건을 경험하면서 나는 인간의 한계를 뛰어넘는 개발 스킬, 최고의 프로세스, 쩌는 팀을 가지고 있다 해도 오만한 마음가짐으로는 자기 발등에 떨어진 왕방울만한 문제도 제대로 볼 수 없다는 생각이 들었다.&lt;/p&gt;
&lt;p&gt;많은 개발자들이 버그로 고생한다. 그리고 버그를 빠르게 찾는 방법을 고민한다. 디버깅 스킬, 개발 지식, 뛰어난 직관, 방법론 등을 찾아 헤맨다. 하지만 진짜 답은 그런 복잡한 도구와 어려운 지식에 있지 않고 문제가 나에게 있다고 생각하는 겸손한 마음가짐 속에 있는 건 아닐까? 그 옛날 맹자 선생님께서 하신 말씀과 다르지 않다. 지난 10년간 내가 프로그래머로 일하면서 배운 가장 중요한 지식은 거의 모든 경우에 자신의 잘못을 먼저 바라보는 사고가 문제 해결에 가장 큰 도움이 된다는 것이었다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;인이라는 것은 활 쏘는 것과 같다. 활을 쏠 때는 자세를 바르게 한 후에 쏘는 법이다. 화살이 과녁에 맞지 않으면 자기를 이긴 자를 원망할 것이 아니라 (과녁에 맞지 않은 까닭을) 도리어 자기 자신에게서 찾는다. – 맹자&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[[소고] 게임 보안: 특허와 보고서에 숨겨진 진실]]></title><description><![CDATA[요즘 신규 업체 미팅을 하면 항상 단골 손님으로 특허와 보고서 친구들이 등장합니다. 관련 업체 분들께서 여기에 엄청난 환상을 가지고 계신 것 같아서 오늘은 그 이야기를 좀 해볼까 합니다. #…]]></description><link>https://jiniya.net/wp/archives/9368</link><guid isPermaLink="false">https://jiniya.net/wp/archives/9368</guid><pubDate>Tue, 30 Oct 2012 23:58:30 GMT</pubDate><content:encoded>&lt;p&gt;요즘 신규 업체 미팅을 하면 항상 단골 손님으로 특허와 보고서 친구들이 등장합니다. 관련 업체 분들께서 여기에 엄청난 환상을 가지고 계신 것 같아서 오늘은 그 이야기를 좀 해볼까 합니다.&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;특허부터 시작해 볼까요? 일단 전 기본적으로 소프트웨어 특허 자체가 좀 코메디라고 생각합니다. 욱기잖아요 이건 ㅋ~ 그래도 어쨌든 고매하신 분들께서 관련 법안을 만드셨으니 특허 시스템은 존재하고 사람들은 자신의 권리 보호를 위해서 특허를 출원합니다. 게임 보안 업체도 너도나도 할 것 없이 특허를 많이 출원하고 있습니다. 물론 큰 업체같은 경우는 특허 지원 시스템이 있어서 — 특허를 출원하는 경우에 포상금이 주어지는 — 더 많은 특허를 내기 위해서 직원들이 매일같이 고민하고 있습니다.&lt;/p&gt;
&lt;p&gt;이렇게 많은 업체들이 경쟁적으로 특허를 출원하는 만큼 특허에 관한 오해도 심각한 수준입니다. 가장 큰 오해는 이런 겁니다. 와 A라는 업체에서 이런 해킹툴을 막는 희깔난 특허를 등록했다는 신문 기사를 보니 해당 업체 솔루션을 사용하면 그런 종류의 해킹툴은 다 차단되겠구나, 라는 정말 순.진.한 생각입니다. 차단 될까요? 전 차단 안 된다에 올인 하겠습니다. 왜냐구요? 현실 세계에 존재하는 초딩이 만드는 해킹툴도 그런 몇 페이지짜리 말장난으로는 절대 차단을 할 수 없기 때문입니다. 하물며 그들이 말하는 그 엄청난 범위의 해킹툴을 그 몇 페이지짜리로 다 차단한다구요. 네. 맞습니다. 어림도 없습니다.&lt;/p&gt;
&lt;p&gt;두 번째 오해는 이런 겁니다. 특허가 등록 됐으니 해당 기능이 솔루션에 탑재됐을 거라는 생각입니다. 뭐 첫 번째 생각도 이 두 번째 생각의 근간에서 출발한다고 볼 수 있습니다. 그런데 말이죠. 소프트웨어 특허란 건 그 사람의 생각에 대한 권리를 인정해 주는 것이지 그 사람이 그걸 만들었는지 안 만들었는지를 검증하는 것이 아닙니다. 즉, 임플멘테이션이 존재하지 않더라도 특허 등록이 가능합니다. 그러니 특허가 등록 됐다고 그 기술이 탑재 됐다고 생각하는 오해는 이제 여기까지만 해주시면 되겠습니다. 특허는 말 그대로 특.허. 일 뿐 아무거도 아닙니다.&lt;/p&gt;
&lt;p&gt;끝으로 게임 보안 솔루션의 특허에 관해서 좀 더 재미난 부분을 살펴보면 이렇습니다. 일반적으로 게임 보안 특허는 연립 방정식과 유사한 구성을 가집니다. 해킹툴을 잡기위한 가설들을 세우고, 그 가설들을 이렇게 저렇게 연결해서 이런 조건을 만족하다면 그 놈은 해킹툴로 간주할 수 있다, 라는 방식을 따르게 됩니다. 결국 따지고보면 여러 개의 방정식을 사용해서 미지수들을 소거해 가면서 해를 구하는 연립 방정식인 셈이죠. 그런데 이 연립 방정식이란게 중학교 정도의 수학 지식을 가지고도 알 수 있겠지만 미지수 개수만큼 방정식이 있어야 해를 구할 수 있습니다. 즉, 미지수가 x, y, z 세 개라면 방정식이 세 개가 있어야 한다는 말이죠. 정수론 따위에서 말하는 브루트포스의 접근을 한다면 방정식이 모자라도 풀 수 있는 경우가 있긴 하지만 어쨌든 일반적이지는 않습니다. 그런데 여러분이 게임 보안 특허에 관심이 많다면 이제부터 그걸 잘 살펴보십시오. 놀라운 발견을 하게 될 겁니다. 상당히 많은 특허에 방정식이 모자라는 경우가 많다는 사실입니다. 어 이렇게 해서는 연립 방정식을 풀수가 없는데, 라는 생각이 드는 경우가 대부분입니다.&lt;/p&gt;
&lt;p&gt;왜 방정식이 모자랄까요? 중요해서 숨겼을 수도 있고, 나머지 방정식을 모르지만 과시용 특허를 등록하기 위해서 출원했을 수도 있습니다. 제가 살펴본 특허 중에 일부는 그 숨겨진 나머지 방정식에 구현이 까다로운 부분이 많이 있었습니다. 어 이걸 구현하려면 뭔가 굉장히 복잡할 텐데 진짜 구현했을까, 라고 생각해서 들춰보면 없는 경우가 많았습니다. 제가 게임 보안 일을 하면서 지난 시간 동안 느낀 것은 거의 모든 경우에 생각이 어려운 부분은 없다는 점입니다. 사실 말로 하면 이 세상에 못 잡을 해킹툴이 없습니다. 어렵지도 않아요. 그거 뭐 게임에 접근 좀 못하게 하고 변조하면 차단하고 그러면 되는 거죠 ㅋ~ 문제는 구현입니다. 제대로 동작하는 코드를 만드는 일은 그 어떤 일보다도 어렵습니다. 특히나 해커를 상대로 싸울 수 있을 만큼 쓸모 있는 코드를 만드는 일은 더욱 어렵습니다. 특허는 특허일 뿐입니다. 그러니 특허가 해킹툴을 차단해 준다는 순진한 생각은 이제 과감하게 버리도록 합시다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;다음으로 보고서를 좀 살펴봅시다. 정말 웃기게도 요즘 보고서를 잘 쓴다는 광고를 하면서 다니는 업체가 있는 것 같습니다. 이 이야기를 들었을 때 전 참 아이돌스러운 광고가 아닐 수 없다는 생각을 했습니다. 가수는 노래를 부르는 게 주업입니다. 당연히 노래를 잘 부른다는 이야기가 먼저 나와야 합니다. 하지만 아이돌들은 그렇지는 않죠 ㅋ~ 전 춤을 잘춰요, 내지는 전 얼굴이 이뻐요, 라는 이야기로 들이 댑니다. 보고서를 잘 쓴다는 게 아이돌의 그것과 별반 다를바가 없는 이야기라는 생각입니다.&lt;/p&gt;
&lt;p&gt;이 바닥에서 6년 정도 일하다 보니 해킹툴을 막을 수 있다는 방법이란 방법은 다 찾아서 해 본 것 같습니다. 절에 가서 기도도 했으니 말이죠 ㅋ~ 당연히 보고서를 만들었던 시절도 있었습니다. 이뿌게 포맷도 정해서 워드 문서로 차곡차곡 정리해서 저장소의 문서 폴더에 하나하나 올렸드랬죠. 나중에 살펴보면서 뿌듯해 하면서 말이죠. 그런데 그런 보고서가 하나 둘 모여감에도 해킹툴 차단은 나날이 구려지는 안습한 시츄에이션이 발생했습니다. 고민했습니다. 우리가 이.렇.게.나 열심히 분석하고 정리하는데 왜 해킹툴은 더 못 막는 걸까, 라는 생각이 저의 뇌를 후벼팠습니다. 결론은 단순했습니다. 보고서 포맷 맞추고, 캡처하고, 코드 붙여넣느라 시간 다 보내고 있으니 정작 차단 코드를 만들 시간이 없었던 겁니다. 해킹툴은 누가 막나요? 패턴이랑 차단 코드가 막습니다. 그걸 업데이트는 안 하고 허구헌날 보고서만 쓰고 있으니 우리는 점점 더 구려졌던 것이죠. 그래서 과감하게 보고서 따위 개나주자. 쓰지 말자는 선택을 했습니다. 그러자 마법처럼 해킹툴이 차곡차곡 막히는 기적을 경험하게 되었습니다. 보고서가 해킹툴을 막아주진 않습니다. 또한 디테일하게 분석할수록 더 원천적으로 차단 억제력이 높은 코드를 만들 수 있다는 것도 진짜 도시전설과 같은 생각입니다. 전혀 그렇지가 않아요. 그 이야기는 다음에 기회가 된다면 자세히 하도록 하겠습니다 ㅋ~&lt;/p&gt;
&lt;p&gt;돌려서 생각해 봅시다. 왜 게임 보안 업체가 보고서를 써야 할까요? 언제 분석 보고서를 쓸까요? 당연합니다. 지독하게 그 해킹툴이 안 막힐 때 쓰는 겁니다. 이게 도저히 안 막히니까 우리가 이렇게 고생해서 분석한 거라도 보여드립니다, 라고는 제품을 구매한 업체에게 전달하는 것이죠. 막히면요? 보고서를 쓸 일도 없습니다. 그러니 다시 생각해보면 보고서를 잘 씁니다. 많이 씁니다, 라고 광고하는 건 우린 해킹툴을 겁나 못 막습니다, 라고 광고하는 것과 다를바가 없는 이야깁니다.&lt;/p&gt;
&lt;p&gt;주간 회의가 있었습니다. 정말 한참만에 보고서를 쓰라는 이야기를 했습니다. 왜 했을까요? 지독하게 안 막히고 계속 꾸역꾸역 업데이트되는 해킹툴이기에 쓰자는 이야기를 한 것이지요. 2개를 이야기 했는데 하나는 벌써 GG를 쳤다는군요. 그래서 하나만 쓰기로 했습니다. 통상 일주일에 4,000개에서 10,000개 정도의 신규 해킹툴이 수집됩니다. 실행해 본다는 게 가능할 것 같나요? 테스트 하는 건요? 보고서는 당.연.히 못 씁니다. 왜냐하면 우리는 패턴 추가하고, 차단 코드 만들고, 취약점 수정하기에도 충분히 바쁘거든요.&lt;/p&gt;
&lt;p&gt;꼭 기억하세요.&lt;/p&gt;
&lt;p&gt;분석 보고서는 지.독.하.게 해킹툴이 안 막힐 때 쓴다는 거.&lt;/p&gt;
&lt;p&gt;그리고 보고서가 해킹툴을 막아주진 않는다는 거.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_특허와_보고서에_숨겨진_진실.md_0.png&apos; data-alt=&apos;특허도 보고서도 해킹툴을 막아주진 않습니다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5dc23be4fe0d2e5a5d3b4926d8ca3e72/0eb09/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%8A%B9%ED%97%88%EC%99%80_%EB%B3%B4%EA%B3%A0%EC%84%9C%EC%97%90_%EC%88%A8%EA%B2%A8%EC%A7%84_%EC%A7%84%EC%8B%A4.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 31.578947368421055%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABGElEQVR42jVPW26DMBDk/ofoHXqJJvkpDaVAUBNi8zBgY2NsMJhXN4k6Wo1mR1rtjIPOl+QzbPJKVIwXtagbmhGWlX2nlJC67YZeR0HycayTOynyFCGEU0wpnefZqTEhMWqySpSPY4ZL4LZksApCQU/DONnpdDq4rhsEYRRFvu97nocxdjqpRVbJqtn3fVtXzaViYlT9/o91Xa+3wj0XshtGM5gnrLXgO8nXqfy9c1w2mNBbzhAZpB7VYLQShnHdbMucofRwvPrflyD4gdhhGMZxLIRwOEG9VLOZHvF6A7wuy/aE3axdLDy3s204XZ4AHxgKAzujMpp3igoI/BJQgWcVjBFDV6eEvNXlu8xZS1hHeVtQiPZq9AeU8UycLcGSOwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;특허도 보고서도 해킹툴을 막아주진 않습니다.&apos; title=&apos;&apos; src=&apos;/static/5dc23be4fe0d2e5a5d3b4926d8ca3e72/0eb09/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%8A%B9%ED%97%88%EC%99%80_%EB%B3%B4%EA%B3%A0%EC%84%9C%EC%97%90_%EC%88%A8%EA%B2%A8%EC%A7%84_%EC%A7%84%EC%8B%A4.md_0.png&apos; srcset=&apos;/static/5dc23be4fe0d2e5a5d3b4926d8ca3e72/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%8A%B9%ED%97%88%EC%99%80_%EB%B3%B4%EA%B3%A0%EC%84%9C%EC%97%90_%EC%88%A8%EA%B2%A8%EC%A7%84_%EC%A7%84%EC%8B%A4.md_0.png 190w,
/static/5dc23be4fe0d2e5a5d3b4926d8ca3e72/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%8A%B9%ED%97%88%EC%99%80_%EB%B3%B4%EA%B3%A0%EC%84%9C%EC%97%90_%EC%88%A8%EA%B2%A8%EC%A7%84_%EC%A7%84%EC%8B%A4.md_0.png 380w,
/static/5dc23be4fe0d2e5a5d3b4926d8ca3e72/0eb09/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%8A%B9%ED%97%88%EC%99%80_%EB%B3%B4%EA%B3%A0%EC%84%9C%EC%97%90_%EC%88%A8%EA%B2%A8%EC%A7%84_%EC%A7%84%EC%8B%A4.md_0.png 500w&apos; sizes=&apos;(max-width: 500px) 100vw, 500px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;특허도 보고서도 해킹툴을 막아주진 않습니다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 게임 보안 솔루션 그놈이 그놈 아닌가요?]]></title><description><![CDATA[게임보안 제품 이거 쓰나 저거 쓰나 그놈이 그놈 아닌가요? 
어차피 100% 막지도 못하잖아요. 업체 분들을 만나면 이런 이야기를 많이 하십니다. 네. 맞습니다. 그 어떤 솔루션도 해킹을 100% 막지는 못합니다. 하지만 10…]]></description><link>https://jiniya.net/wp/archives/9191</link><guid isPermaLink="false">https://jiniya.net/wp/archives/9191</guid><pubDate>Fri, 19 Oct 2012 23:58:29 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;게임보안 제품 이거 쓰나 저거 쓰나 그놈이 그놈 아닌가요?&lt;br&gt;
&lt;br&gt;
어차피 100% 막지도 못하잖아요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;업체 분들을 만나면 이런 이야기를 많이 하십니다. 네. 맞습니다. 그 어떤 솔루션도 해킹을 100% 막지는 못합니다. 하지만 100% 막지 못한다고 해서 다 그놈이 그놈인 건 아니랍니다.&lt;/p&gt;
&lt;p&gt;일반적으로 많은 분들이 게임 보안 솔루션하면 게임 해킹을 100% 차단하기 위한 솔루션이라고 생각을 합니다. 하지만 이건 정말 아주 많이 잘못된 생각입니다. 왜냐하면 어떠한 보안도 100%가 있을 수는 없거든요. 이 세상에 그렇게 많은 경찰과 군인이 있지만 범죄와 테러가 끊임없이 발생하는 것과 똑같은 원리입니다.&lt;/p&gt;
&lt;p&gt;게임 보안 솔루션이 하는 일은 100% 차단하는 것이 아닌 게임 내에서 유통되는 해킹툴의 수치를 관리하는 일에 가깝습니다. 게임 보안 솔루션이 없을 때에는 착한 사용자가 게임 내에서 아주 손쉽게 모든 지역에서 해킹툴을 사용하는 게이머를 만났다면, 게임 보안 솔루션을 적용한 후에는 그 빈도를 좀 낮춰서 가끔 만나도록 만들어 주는 역할을 하는 것이죠.&lt;/p&gt;
&lt;p&gt;일종에 당뇨병 환자의 당 수치를 관리하는 것과 비슷한 일입니다. 당뇨병을 완치할 순 없지만 당 수치를 잘 관리한다면 생존에는 문제가 없습니다. 당 수치를 관리하는 것에는 여러가지 방법이 있죠. 식이요법도 있고, 당뇨약을 시간에 맞춰서 복용하는 방법도 있습니다. 자동으로 인슐린을 투입해주는 인슐린 펌프도 있죠. 모든 방법이 당뇨병을 완치하진 못하지만 심각한 당뇨 환자라면 인슐린 펌프가 제일 편한 방법입니다.&lt;/p&gt;
&lt;p&gt;게임 보안 솔루션도 마찬가지입니다. 많은 솔루션이 존재하지만 100% 모든 해킹툴을 차단하는 솔루션은 단 하나도 없습니다. 하지만 그 솔루션들의 해킹툴 수집 능력, 신규 핵킹툴 출현 억제력, 해킹툴 출현 시 대응 속도에는 식이요법과 인슐린 펌프만큼이나 큰 차이가 있습니다. 이제 게임 보안 솔루션의 기능이 동일하다고 성능도 동일하다는 생각은 과감하게 옆집 멍멍이에게 주도록 합시다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://sa.nexon.com/community/free/view.aspx?n4PageNo=1&amp;#x26;emSearchType=Title&amp;#x26;strSearch=%c7%d9&amp;#x26;n4ArticleSN=811427&amp;#x26;n4ArticleCategorySN=1&quot;&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_솔루션_그놈이_그놈_아닌가요.md_0.png&apos; data-alt=&apos;반도의 흔한 게이머의 합.성.짤.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; &apos;&gt;
      &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 112.63157894736841%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAXCAIAAACEf/j0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAELUlEQVR42mVUXW/bZBT27+GCO9DuuENITAghLpAQoF1QaRKIDU2q1m1dp7bQdq12sbGOtc062kKF1qofdKPdaLfBurZpSJo0tlMn8bcT+/VXnDi2Y8fhxNbQpD1yjs57fD6e87xWsAu/osvL3pUVp2/ZObdQu7BY719xBlbdbxfsnl+8L6ZrZ6b1r2bUr+83zs57Z+fdbxb8njnn/KI7t0RgosSUuQwvHktyoUSnBSkvVQmazegG1bA5vVYyzYJu5q06Zdu0bZdlM+ValFejEWKwHLV/SGdLqoostWoi2UTI0hRLFQ2NUdgj8oBhCU4ucVKhyB7nqeQBuUWSL0l8nyQyWJY9ojNrydXJmuVYtbpVb1YqMssKIsOI+L9U9pDEcZLATV2z6/U6ZNTqsiLrmsxLCpYn2fT2xb3F74+JslSROp0OLwhZnKyWjoP0ukencjhOs5zjum6rBT/P9VpB2w/bWj3Atnb2/txObj5LJeaXHj7ZXXm4s/V0f+mP7aW1x1N3Evd/3xi/cXf2t/X5xOzsTCJxd+523+DCg0c7u5m/D0vYtR8mx27M/jieGB6bHpm4NzJ+b2QiMTQ6NTw6NTYxc/HqrSuDP/f2/3Tp2uSlgdsDQ3d6+2/2Xr11rvf66M0HmOs22xHCsGtivxMhDEPHC2yn+zSavu22/XZoOp7ecHgZVfUG1nSajuPYdhOWAqfZ7Drha2i3A8/3vVYr9L124PMcJ3AcQ9MqqmKB73fewOvFcHpBo79Sgnew2TaQrOpyFSBrGsJarRbwDILgFfnwzV7xSp1uVqDpuqwoCCH4MjBd17UIiqLIstxoNKBdTL4ZwYkAR+gCxZCtIgTG0FWMYZhcLkeSZLlcpiiKpulisQjB2AFbKpUIguR5Hpbxg8BsNI26XVV1w7IwQRBEUYwtiqBErGAt1J2gqapaq9WAEWzk+YGADF7WKFasajoGvVmWhZkwASzMh7HxcDiCA5FKpQKNYlEkUeRYFh5JFDCW7aYWCoWYs/IKMFOOEGsB0kTX1lY1DXpBuCsYTZehEnbGcTyfz5+cnMQs8hHiOEEQEI9vJNqoAleFkNwthtRyBHBAmHja//vDEdYGByZDPUitInirdIuBA0gVWwAUw7agQiwhxA3DAM6WZYHaLT8wbVerNURoaJhdwSAXiB3lsql0GlaAGkmSOI4DIvGdgQ/1vu9DMV9VabGaPykzvIgNDw18/tmnpz/84J233n7/1KmJiesCz1FUgWXgj0YBbcHhWEYQeLiwsBOCzvB5Q1NR4LD+y32ffPzRl2d6Tr/73uB351fX13TTQloNaaasaAwrsrzEi1Wxgmyn5fltEFmHz8vQKrKCrTz6Z3nj2dLG843HL3cPyc2d5PP9Y3D20tR+hjrIFFPZ8tNU4cmLbPKolMFpqlQkKSqXJ5Lp7H/UBaCjNXYqAAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;반도의 흔한 게이머의 합.성.짤.&apos; title=&apos;&apos; src=&apos;/static/b58304b65e8591793dad0be44fb2dd33/efd7b/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_0.png&apos; srcset=&apos;/static/b58304b65e8591793dad0be44fb2dd33/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_0.png 190w,
/static/b58304b65e8591793dad0be44fb2dd33/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_0.png 380w,
/static/b58304b65e8591793dad0be44fb2dd33/efd7b/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_0.png 760w,
/static/b58304b65e8591793dad0be44fb2dd33/24c26/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_0.png 921w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;반도의 흔한 게이머의 합.성.짤.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_솔루션_그놈이_그놈_아닌가요.md_1.png&apos; data-alt=&apos;반도의 흔한 게임 보안 솔루션의 네이버 테스트&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/e6a9e9b0327cb941c7833b6628c0dabe/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 50%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAB1UlEQVR42iVRuZLTQBTU/weEEEAE2RZVFCQUGxHgpWyzCz7Kt2TNPaM5pNG5liWLp92uCaZmut973S8wdhtFHyi9M0ZJKQlBVVUOw1Bpfvr3nuzeqtO04nJoLnlO4vijEJ+NSbzPAUFWemuZtTzLUq2d95eyPHg/KZ1WeJGKpVk9uP2mltLWBRN7KU9JkmitR7F1TinJGPe+9n7F+Z3WD4x9V5KXRZO5nP2dhk9Ti1B3G4TUjAGZwYzX6zXgXCMkwjCMY6zU0do/bVt13ZBxkYShB95+4xgd6qrMc5emPhvRti1YC87RD0q+gg2MsTGuvdxut370nKjksHNRVFBqwvCidV3BaL4oiq4fCaM4Qp8QfoNxiDElhICf14/aeLk/p3HcWwOncxbEeZHnaF3iqCvyIc8Cu3uih0eZKGusfkGaZs1zTeMvJPomqXTJI4vftbWAin3fyfXv9c97i869M0EhJIsxIkQIQV7AwW2iwugXJvMYIcoQJtuyhOUUsEW5nR1nk+NyUSkZ2DQ1xnBQCGGthTDcmL8yxidJCndYCcTUNM899O2uejc3h/V5vWqUCMAF+IS0KaUgBjZlDMKDEeCFMyakhFqQ82sW8rDYTCfL+czg+D+NpSAET1QP6AAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;반도의 흔한 게임 보안 솔루션의 네이버 테스트&apos; title=&apos;&apos; src=&apos;/static/e6a9e9b0327cb941c7833b6628c0dabe/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_1.png&apos; srcset=&apos;/static/e6a9e9b0327cb941c7833b6628c0dabe/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_1.png 190w,
/static/e6a9e9b0327cb941c7833b6628c0dabe/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_1.png 380w,
/static/e6a9e9b0327cb941c7833b6628c0dabe/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_1.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;반도의 흔한 게임 보안 솔루션의 네이버 테스트&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_솔루션_그놈이_그놈_아닌가요.md_2.png&apos; data-alt=&apos;반도의 흔한 게임 보안 솔루션 개발자 블로그 검색어 유입 순위&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 238px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5ccefc2eda66240172c4bb2cc8cc3c87/da2e6/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 169.4736842105263%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAiCAIAAADQyG7qAAAACXBIWXMAAA7DAAAOwwHHb6hkAAADDElEQVR42o1V23KbMBDl/3+pD51OL9PEaZI6tgmFYEAWN4EQQuImIF1ht33oGLwjyxprZJ09Z/fIGKdJtn3bq0K2tGpIWbdqeL8tDDh294pMn9gh3Xrkw08/oBVsTBCrhwcIpaf3adQHxmkcRhgTTLCzGIaQMs6KJGdxzkJSJBlDYZbRMspYznjbLIXBK3F38O4P/stb+GChwzHeO9h08f0rCmLad13TtNfC6PseYAPEGbHGCjNAGlSveji7FEY/DHHBY1qlTOCM47wyT5TL9szZCmG9GnbHeHdM3YjaOHfC4tkjTdvfJBXABrAA9QwbGIZJqRXAF9iVkHaQ2Ch1Q2L58THKd36aUA5715n6Q1glxE8bbR1so8T0Yi/KXxGJsrJdVuksFRTIdK4nXSSjTkF/rZTHpUi6XlmIWChzo8IMCE7LrZukhbiJbbjZT2iQMMJElFdctBkTddtPZzSLYQAxmmOl63gG2w8gQN/p0XUrhJWVuDf9jRk8O/j73rdxdncIHu3T1kvuTCTrJcqNuq5DQiNSFGWVFZxxwXgFLXEiBSasrhfZvtA7j5nsESiEJM4KjIthtJ16dsJnJwKqn5zoGBVf9miH8pvYhj/gsqnqFi6ED5SnaDqmG2PlWn0zZDXnVcu6ht4uuKBlBZmnBedCrphBycW3F/fry/HJxp+3RysAkv1HG3988f2UDWrRDEBnAZfWDWgKa5BY6dENc2Ot6Awt2HSqnROuZFvVXcJkVsqIwlK9vy9XWK82FnqwMLC9sbCfluDBZpB/OqCE18ucGxfjBQDDPw+DA6u+q7tKyjpMKU6LkDAvzMBxwTTdEGpMrKWszUBuTO8BHg0v/mGhN0zeTmTzCyd52XftuTyXrPfiYbONjbOH6V/0Qk264dR161VDkDIYmHAH5yGtgrR0Y4ZzjvLKjWlCxXUzUMNrkIKZnEj565SBTpiUp4w7IbUjtg9IkM3v3jXr/Yv5TPI4u4JW4Y89XIUNZrB38c4ND178aCELpf+38HW2pURxBu+bH+cuJnFetjfHb1Pio2peVF2zAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;반도의 흔한 게임 보안 솔루션 개발자 블로그 검색어 유입 순위&apos; title=&apos;&apos; src=&apos;/static/5ccefc2eda66240172c4bb2cc8cc3c87/da2e6/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_2.png&apos; srcset=&apos;/static/5ccefc2eda66240172c4bb2cc8cc3c87/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_2.png 190w,
/static/5ccefc2eda66240172c4bb2cc8cc3c87/da2e6/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_2.png 238w&apos; sizes=&apos;(max-width: 238px) 100vw, 238px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;반도의 흔한 게임 보안 솔루션 개발자 블로그 검색어 유입 순위&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_솔루션_그놈이_그놈_아닌가요.md_3.png&apos; data-alt=&apos;미디엄과 하드, 사소하지만 굉장히 큰 차이&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 244px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f6ac1f7dfe4793bb46b91b6aefd2e690/d3a2b/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 44.21052631578947%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAA7CAAAOwgEVKEqAAAABT0lEQVR42oVQ21LCMBDtN4jQll4SIL2mLSFpem9BERxlEEfF8f+/xKUo45Oc2WxOstns2VUm02mSJBGljuNQSgPfpzR2yUzX9fE1KI7rFmUpUzlnvGs6wXleVDENNU27nuy6XlEUdVVDfS5EmkoBSGWWZROM/6+vIIQ8z/N9n/zIDqIImqBwaVuW8YvT2wu5JOu6pqojgKapt8PBYHADa9hj1OMcVlX1TP5qUQhxpMwFT2eEMMbruk1FGgRhkjC+4FJmQUjBg5gwjDOZYYwv41B8j7zt2fEl2azw09o9Htj7Ptlt3Ndd9HFgYLut//Um9o/e4Tn6PMRibhuGZfb6Feita4v7u4ovwjAky67YbldtU5T5XKbJclk+rJuuzcqcQahr8q6tyqoihEB9xTRN20Y2wrCPx6ZlIctGwOF7A04Wtu2TIYRR7zGewIzPk/sGBKhQ0lB7OXEAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;미디엄과 하드, 사소하지만 굉장히 큰 차이&apos; title=&apos;&apos; src=&apos;/static/f6ac1f7dfe4793bb46b91b6aefd2e690/d3a2b/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_3.png&apos; srcset=&apos;/static/f6ac1f7dfe4793bb46b91b6aefd2e690/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_3.png 190w,
/static/f6ac1f7dfe4793bb46b91b6aefd2e690/d3a2b/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_3.png 244w&apos; sizes=&apos;(max-width: 244px) 100vw, 244px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;미디엄과 하드, 사소하지만 굉장히 큰 차이&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_솔루션_그놈이_그놈_아닌가요.md_4.png&apos; data-alt=&apos;해커들에게 가장 어려운 게임 보안 제품&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 497px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/7204ca97f96a2cb9fba37ac184c69684/c8b0d/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 11.578947368421053%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAIAAADXZGvcAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAYklEQVR42j2NXQ6AIAyDuQawISFRkD81GhC8/72cPPilabdkS5n3IaU8lEKIFFprCShBAUykfwBUiEohrSAGzLo1fqScN3omyPc8t2Kf6ltx5Vp69f125+GoiS6NMZxzIcQLKHMSB2SPhRIAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;해커들에게 가장 어려운 게임 보안 제품&apos; title=&apos;&apos; src=&apos;/static/7204ca97f96a2cb9fba37ac184c69684/c8b0d/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_4.png&apos; srcset=&apos;/static/7204ca97f96a2cb9fba37ac184c69684/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_4.png 190w,
/static/7204ca97f96a2cb9fba37ac184c69684/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_4.png 380w,
/static/7204ca97f96a2cb9fba37ac184c69684/c8b0d/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_4.png 497w&apos; sizes=&apos;(max-width: 497px) 100vw, 497px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;해커들에게 가장 어려운 게임 보안 제품&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_솔루션_그놈이_그놈_아닌가요.md_5.png&apos; data-alt=&apos;해커들에게 가장 골치아픈 게임 보안 제품&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 620px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/cd8e03f8dda5114b9730a61d739a7804/abf7b/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_5.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 6.315789473684211%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAABCAIAAABR8BlyAAAACXBIWXMAAA7CAAAOwgEVKEqAAAAAPElEQVR42iXJQQ4AEAwFUfc/oX7VhUSVIBEXIOzeZFwfXUUMsBCy9+WhMrcYv435ZgHd20RmSkqkwF7rAEcqNL1I69bmAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;해커들에게 가장 골치아픈 게임 보안 제품&apos; title=&apos;&apos; src=&apos;/static/cd8e03f8dda5114b9730a61d739a7804/abf7b/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_5.png&apos; srcset=&apos;/static/cd8e03f8dda5114b9730a61d739a7804/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_5.png 190w,
/static/cd8e03f8dda5114b9730a61d739a7804/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_5.png 380w,
/static/cd8e03f8dda5114b9730a61d739a7804/abf7b/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_5.png 620w&apos; sizes=&apos;(max-width: 620px) 100vw, 620px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;해커들에게 가장 골치아픈 게임 보안 제품&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_솔루션_그놈이_그놈_아닌가요.md_6.png&apos; data-alt=&apos;해커들에게 가장 터프한 게임 보안 제품&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 596px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/70fa78790c65c2a653e185654aa75632/fe133/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_6.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 11.578947368421053%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAIAAADXZGvcAAAACXBIWXMAAA7CAAAOwgEVKEqAAAAAV0lEQVR42h2MUQ6AMAxCPY52QGuNZk69/7VsRgh5fMBC2JFCW3NX7gxHBopdrVIiSIBmRsrdq7cpkct18hscvT03n44JKB4d740jITnnvlxyD9u2+gqPH0PeFjLzkT8ZAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;해커들에게 가장 터프한 게임 보안 제품&apos; title=&apos;&apos; src=&apos;/static/70fa78790c65c2a653e185654aa75632/fe133/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_6.png&apos; srcset=&apos;/static/70fa78790c65c2a653e185654aa75632/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_6.png 190w,
/static/70fa78790c65c2a653e185654aa75632/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_6.png 380w,
/static/70fa78790c65c2a653e185654aa75632/fe133/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_6.png 596w&apos; sizes=&apos;(max-width: 596px) 100vw, 596px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;해커들에게 가장 터프한 게임 보안 제품&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_솔루션_그놈이_그놈_아닌가요.md_7.png&apos; data-alt=&apos;그리고 게이머들이 탑재를 요구하는 게임 보안 제품&lt;br&gt;&lt;br&gt;오늘도 XIGNCODE 개발팀은 그런 제품을 만들기 위해서 최선을 다한다는거, 아시죠? ㅋ~&lt;br&gt;&lt;br&gt;기능이 똑같다고 성능도 똑같다는 편견은 이제 버릴 때가 되었습니다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 414px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/3015e53f0784ecfd278aaffdb30356a7/c6ea4/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_7.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 27.89473684210526%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABJUlEQVR42hXQy27iQBBAUUt0VXVV9cM2dmOCxsEYjQlPESCQaJIsk0X+/3vCSGd9Fzc7BLtnGtRugz16u/N2EFyiuVuhadHM0AxMS8YOTU+wIJgTrJzNBbM+ly7wn8DzyI+Rp4K1hUQmETQIJZkCYao2MZUEycID/dcFWypl26S7SlalvAj+I9igeUZzhLvRBUaDGZ0RLo6PBFczOoGpyMi9nvMkl2xd67HW1cRtaj0oLhgGgYVAL7i20HpaBl4HHiKvGTrBKOi8LQqtomTzXNpC+1r/Nr5rXBMoeZo6HCs0JZ+Svia9zsI5ud3E38Z6qt25lPfK9ZXLziUfct7ft3m7jbKN/OTsPsrtIX60xXdb/Mzi59i9eXsp9Evp6uiN8ca4KOUXFbocBIvA3IUAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그리고 게이머들이 탑재를 요구하는 게임 보안 제품&lt;br&gt;&lt;br&gt;오늘도 XIGNCODE 개발팀은 그런 제품을 만들기 위해서 최선을 다한다는거, 아시죠? ㅋ~&lt;br&gt;&lt;br&gt;기능이 똑같다고 성능도 똑같다는 편견은 이제 버릴 때가 되었습니다.&apos; title=&apos;&apos; src=&apos;/static/3015e53f0784ecfd278aaffdb30356a7/c6ea4/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_7.png&apos; srcset=&apos;/static/3015e53f0784ecfd278aaffdb30356a7/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_7.png 190w,
/static/3015e53f0784ecfd278aaffdb30356a7/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_7.png 380w,
/static/3015e53f0784ecfd278aaffdb30356a7/c6ea4/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%86%94%EB%A3%A8%EC%85%98_%EA%B7%B8%EB%86%88%EC%9D%B4_%EA%B7%B8%EB%86%88_%EC%95%84%EB%8B%8C%EA%B0%80%EC%9A%94.md_7.png 414w&apos; sizes=&apos;(max-width: 414px) 100vw, 414px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그리고 게이머들이 탑재를 요구하는 게임 보안 제품&lt;br&gt;&lt;br&gt;오늘도 XIGNCODE 개발팀은 그런 제품을 만들기 위해서 최선을 다한다는거, 아시죠? ㅋ~&lt;br&gt;&lt;br&gt;기능이 똑같다고 성능도 똑같다는 편견은 이제 버릴 때가 되었습니다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[비주얼 스튜디오 2012 테스트 익스플로러 활용]]></title><description><![CDATA[지난…]]></description><link>https://jiniya.net/wp/archives/9157</link><guid isPermaLink="false">https://jiniya.net/wp/archives/9157</guid><pubDate>Mon, 15 Oct 2012 23:58:28 GMT</pubDate><content:encoded>&lt;p&gt;지난 5년간 게임 보안 제품을 개발하면서 보낸 시간은 정말이지 하루도 빠지지 않고 전쟁터 같은 일상이었다. 항상 새로 추가해야 할 기능들이 있었고, 그런 일정을 비웃기라도 하듯 해킹툴은 하루도 거르지 않고 새롭게 나타났다. 이런 연유로 우리는 빌드를 밥 먹듯이 할 수 밖에 없었다.&lt;/p&gt;
&lt;p&gt;빌드 서버 로그 기록을 살펴보니 릴리즈 빌드 서버에서 지난 1년 동안 엔진 빌드를 214번, 차단 코드 빌드를 400번, 패턴을 포함한 전체 릴리즈 빌드를 무려 1078회나 진행했다. 릴리즈 빌드는 거의 매일 3-4회씩은 있었다는 이야기고, 차단 코드를 변경하는 일도 거의 매일 한 번 이상은 있었다는 의미다. &amp;#x3C;화면 1&gt;에 나와 있는 최근 빌드 내역을 살펴보면 정말 매일같이 빌드가 있다는 말이 거짓말이 아님을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 571px; margin-bottom: 16px;&apos; data-url=&apos;./비주얼_스튜디오_2012_테스트_익스플로러_활용.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/41dba41421da18e5e01deec22af9d10d/503dd/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 64.21052631578948%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAACuUlEQVR42nWOW0hTcRzHD9GThYhhIS7NICjoqaeeegrqIUFQpMKXiFQaM+qlh4ggiiLbnLo2NBVHKpVuZ2te57xMdzmblnO6rLObbnM7x/O/nHN2cb1ox6CQoh8fPg9fvl/4EXv/3O7uviGHUnFmmwFISO/95whRFBCCGKODIAx8CfcMPbbgM6VcNgzB3wUEBUEgkskQAEGOOwjNcuuJbR8LoktcR+9GJfidSwYgvG8umEwGCZYN83wY4z+EMI6mBY7H0R0M/bhLx8l4PoJwSMRbm7yVBNdYflnAGwwTJBhmf4BQ+BchjGIMpJwbCgYuZhH0QZ2OkWEcgYgWUYrmjeqtE0ns5dFmKiWNuTgS4xDS0hiioIBZlrVNO0s41pNDaR+v7RRlUs6jWAaCkGDoRqXSWPqCZSIEG3WJCSqHRKmRRuwaryfFi8b4qQDuBZkk/tq9NSTLo8yGaGfxWlA0t6VLOBxwZB7OgEcEGmlKkGfmc48BXBdRYkZ40h8vyPSeHgwd+pLriSf67a4CSng2AI5T209RyuaeKxYBPcZVW2LXCWFU8d1y5E2+MguRLX2rhy/vy5YNwHIHVbS4fH40caEtX9iVOTfpJ0Jh5U7YIWqO5djYaqDu8/JNQvikCJFHO3+cTInzw7lL7XyRPltKxmXabLEtUDa3UqHNF+rTZweZwy5wH2x2C7piK75iABX2yG2Cdqkcs1XvEtUfo/WDsWp9pNZE16xa6t5Hqu3eugXnDX2sanCz3jtVZfXWmsI1/pG6vshl+8LVb/ZXhGHp7fOJO8rRRs34PcnqEblqXN4yrVCONSmtCqW1+bWlQTv+4OVUo3JSrpq82zLb3DoqfzHR8MGjI5x+y5BDNUypTZTW4FEbPR1Gqt3k1hjcatLdQbo0Umj26kiP2uTpID3tZkoj2eBuXVgx/wToAFQSlughegAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;         2012              md 0&apos; title=&apos;&apos; src=&apos;/static/41dba41421da18e5e01deec22af9d10d/503dd/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_0.png&apos; srcset=&apos;/static/41dba41421da18e5e01deec22af9d10d/08678/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_0.png 190w,
/static/41dba41421da18e5e01deec22af9d10d/2edd7/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_0.png 380w,
/static/41dba41421da18e5e01deec22af9d10d/503dd/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_0.png 571w&apos; sizes=&apos;(max-width: 571px) 100vw, 571px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;화면 1 최근 릴리즈 빌드 내역&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이렇게 매일 빌드하고 릴리즈를 하다 보니 해킹툴 만큼이나 버그와의 전쟁을 치러야 하는 처지가 돼 버렸고, 가장 큰 고민 중에 하나가 ‘어떻게 하면 버그 없는 소프트웨어를 개발할 수 있을까?’ 라는 다소 원초적인 문제가 돼 버렸다. 다행스럽게도 이런 문제를 고민했던 수많은 책들이 있었고, 먼저 고민한 선배들은 다양한 실천적인 해법을 제시해 주었다. 그런 다양한 조언과 실천적인 해법을 여기다 조금 옮겨보면 다음과 같다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;똑똑한 프로그래머를 뽑아서 애초에 버그가 없는 코드를 만들도록 해야 한다.&lt;/li&gt;
&lt;li&gt;모니터 한 대를 두고 두 명의 프로그래머가 같이 개발을 한다.&lt;/li&gt;
&lt;li&gt;전문 프로그래머 한 명에게 적어도 한 명 이상의 테스트 프로그래머를 배정해서 전문 프로그래머가 작성한 코드를 집중적으로 테스트 하도록 만들어야 한다.&lt;/li&gt;
&lt;li&gt;코드 리뷰를 철저하게 수행해서 리뷰를 통과하지 않은 코드는 애초에 커밋조차 할 수 없도록 만들어야 한다.&lt;/li&gt;
&lt;li&gt;코드를 작성하기 전에 먼저 테스트 프로그램부터 만들어야 한다.&lt;/li&gt;
&lt;li&gt;컴파일러 경고 레벨을 올리고 정적 분석기를 확실하게 활용해서 그 어떤 경고도 용납하지 않아야 한다.&lt;/li&gt;
&lt;li&gt;코드 커버리지를 철처하게 측정해서 릴리즈 코드는 적어도 일정 수준 이상의 커버리지를 확보하도록 매 순간 확인해야 한다.&lt;/li&gt;
&lt;li&gt;버그가 없도록 만드는 훌륭한 컨벤션을 만들고 모두가 그 방식을 따르도록 강요한다.&lt;/li&gt;
&lt;li&gt;전문 테스터를 고용해서 매 순간 테스터들이 무작위적으로 제품을 테스트할 수 있도록 한다.&lt;/li&gt;
&lt;li&gt;구조화된 체크 리스트를 만들고 제품 릴리즈 시에는 해당 리스트를 모두 만족 시키는지 빼먹지 않고 테스트 하도록 한다.&lt;/li&gt;
&lt;li&gt;같은 제품을 개발하는 프로그램 팀 회식을 매주 한 번씩 한다.&lt;/li&gt;
&lt;li&gt;약수 물을 떠놓고 산신령께 빈다. 우리 제품에 버그가 없기를.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;버그 없는 개발을 위한 이런 수많은 방법들 중에서도 단위 테스트, 코드 커버리지, 정적 분석기와 같은 것들은 투입 대비 효과가 굉장히 높은 편에 속하는 방법들이다. 왜냐하면 이것들을 수행하는 데에는 추가적인 리소스가 많이 필요하지 않기 때문이다. 프로그래머가 조금만 신경 쓴다면 이런 방법을 이용해서 손쉽게 많은 수의 버그를 줄일 수 있다.&lt;/p&gt;
&lt;p&gt;하지만 이런 방법의 중요성을 충분히 깨닫고도 그것들을 충분히 활용하는 데에는 늘 주저했다. 왜일까? 우리가 사용하는 도구가 단위 테스트나 코드 커버리지 측정을 편하게 실행할 수 있도록 만들어주지 않았기 때문이다. 단위 테스트를 한 번 수행하기 위해서는 별도로 복잡한 과정을 거쳐야 하고, 코드 커버리지나 프로파일링 데이터라도 측정할라치면 무슨 화성에 로보트를 보내는 것과 같은 복잡한 과정을 거쳐야 했다. 효과는 있지만 충분히 쉽지 않았던 것이다. 하지만 이번에 출시된 Visual Studio 2012는 다르다. 이 모든 것들을 새롭게 추가된 Test Explorer를 통해서 손쉽게 수행할 수 있도록 만들었다. 클릭 한번으로 단위테스트를 수행할 수 있고, 클릭 한 번으로 코드 커버리지를 실시간으로 확인할 수 있도록 만든 것이다. 물론 결과 데이터도 번잡하지 않다. 우리가 확인하고 싶은 것만 빠르게 확인할 수 있도록 만들어 준다. ‘진화’라는 단어가 전혀 어색하지 않을 만큼 엄청난 이 기능을 사용해서 어떻게 버그 없는 소프트웨어 개발을 할 수 있는지 살펴보도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;단위 테스트&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;최근에 나는 리포팅 클래스에 캐시를 하나 더 추가할 일이 있었다. 이 과정에서 조건문을 잘못 추가하는 사소한 실수 때문에 치명적인 버그를 만들어낸 경험이 있다. 이 클래스를 가지고 단위 테스트와 코드 커버리지를 측정하는 방법을 알아보도록 하자.&lt;/p&gt;
&lt;p&gt;내가 만들어야 했던 클래스 명세를 해보면 다음과 같다. 나는 이 클래스를 &amp;#x3C;리스트 3&gt;과 &amp;#x3C;리스트 4&gt;에 나온 것과 같이 만들었다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Notifier 클래스는 전달된 메시지를 화면에 출력하는 기능을 한다.&lt;/li&gt;
&lt;li&gt;메시지는 악성(CODE_BLACK), 의심(CODE_SUSPICIOUS), 기타(CODE_EXTRA)로 구분된다.&lt;/li&gt;
&lt;li&gt;Notifier 클래스는 각각의 메시지를 필터링해서 이미 출력한 메시지는 두 번 출력하지 않도록 한다.&lt;/li&gt;
&lt;li&gt;필터링은 악성 메시지와 나머지 메시지를 구분해서 한다. 즉, 의심으로 이미 추가된 메시지가 기타나 의심으로 보고된다면 출력하지 않지만 악성으로 보고되면 출력한다는 의미다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;리스트 3 notifier.hpp 소스 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifndef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;NOTIFIER_HPP&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;NOTIFIER_HPP&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;set&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;string&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Notifier&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NotifyCode&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        CODE_BLACK &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; CODE_SUSPICOUS
        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; CODE_EXTRA
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;set StrSet&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;set&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;iterator StrSit&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

 StrSet b\_cache\_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 StrSet s\_cache\_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

 BOOL &lt;span class=&quot;token function&quot;&gt;Notify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NotifyCode code&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCWSTR msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
 BOOL &lt;span class=&quot;token function&quot;&gt;IsCacheItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;StrSet &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCWSTR msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 4 notifier.cpp 소스 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;stdafx.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;windows.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;notifier.hpp&quot;&lt;/span&gt;&lt;/span&gt;

BOOL
&lt;span class=&quot;token class-name&quot;&gt;Notifier&lt;/span&gt;&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;IsCacheItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;StrSet &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCWSTR msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    StrSit it &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;it &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

BOOL
&lt;span class=&quot;token class-name&quot;&gt;Notifier&lt;/span&gt;&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Notify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NotifyCode code&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCWSTR msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;code &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; CODE_BLACK &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;IsCacheItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b_cache_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;   
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;IsCacheItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s_cache_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%d %ws\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그럼 이제 프로젝트 구성을 해보도록 하자. Visual Studio 2012에서 utest라는 콘솔 프로젝트를 솔루션 구조로 생성한다. 프로젝트를 생성했으면 이 솔루션에 utest-test라는 네이티브 단위 테스트 프로젝트를 추가하자. 이 프로젝트 타입은 &amp;#x3C;화면 2&gt;에 나타난 것과 같이 Test 탭에 포함돼 있다. 프로젝트 생성이 끝나면 utest 프로젝트에 notifier.hpp와 notifier.cpp를 추가한다. 각각의 소스 코드는 &amp;#x3C;리스트 4&gt;와 &amp;#x3C;리스트 6&gt;에 나와 있는 코드대로 입력하도록 하자. 끝으로 notifier.cpp의 설정 항목에 들어가서 미리 컴파일된 헤더를 사용하지 않도록 만들어준다. 여기까지 모든 과정을 정상적으로 수행했다면 &amp;#x3C;화면 3&gt;에 나타난 것과 같은 솔루션 구조를 가지게 되고 탐색기에서 해당 솔루션 폴더를 찾아가보면 &amp;#x3C;화면 4&gt;에 나타난 것과 같이 디렉터리 구조가 생성된 것을 살펴볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; margin-bottom: 16px;&apos; data-url=&apos;./비주얼_스튜디오_2012_테스트_익스플로러_활용.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/878b4f60c29a92b2fe3fe1b3033f729b/78d47/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 56.84210526315789%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsTAAALEwEAmpwYAAABvUlEQVR42mWSC2+bMBSF+f//Z+q2bonSKFOVgHjkCYQY29iGAMbGhqRJJ82Ualo76+j6SubzuT7CmjxOnaXrroLnp+Xs+3z6df7jy3Ty8OQsfHvhL34un2fO2g63brxz49WvbeCEWy/c2+5mNreWy8DzI5AWEJUQV4xxlEIpRNtKpVqtlZDN7fbS9z2l+SlFZd1wLqTuMTlbxxgAgIuirqqmriXC7NvDxHZ2K3tjdIiQF0SeHycJjqNjhqkRIXmRlxmi1imBEOI8L4VQTdPWdQMAwllOSDFUWhJ6JuRcVULK4YNRUmqCcwsCEkagKCpzxrlsW32/382cRsP2ch17rTvO38mGD3CGmJXE6X4fQZiNzqZ2H1Y/VnPpX9vReYDD/XG3CwN/Y14ihDZw/9+6XHql/oHfnHFKjTPIMsbYua6FIaVo+777JAMbZxPnR5hYSZTWJvpWl5XIi1q0ZsbrJ+mu16oz/Pi0cWwMqZUmQEphQqqFQsyEqivRlaIz9cxVyZVp1PU355xSopQaMrxebq+3sqis3XpPMsJoTgnLUIZSBAGEKTSN+VvGhlEGTiA+hMERPW6xfQBrz3Md/w8LmlWuVj5NQgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;         2012              md 1&apos; title=&apos;&apos; src=&apos;/static/878b4f60c29a92b2fe3fe1b3033f729b/efd7b/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_1.png&apos; srcset=&apos;/static/878b4f60c29a92b2fe3fe1b3033f729b/08678/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_1.png 190w,
/static/878b4f60c29a92b2fe3fe1b3033f729b/2edd7/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_1.png 380w,
/static/878b4f60c29a92b2fe3fe1b3033f729b/efd7b/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_1.png 760w,
/static/878b4f60c29a92b2fe3fe1b3033f729b/78d47/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_1.png 800w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;화면 2 네이티브 단위 테스트 프로젝트 선택 화면&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; margin-bottom: 16px;&apos; data-url=&apos;./비주얼_스튜디오_2012_테스트_익스플로러_활용.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/3189bf6dc7a762fdd944d642c187149e/c84e4/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 63.15789473684211%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAABzElEQVR42nVS626bMBjltVPtvnfZCyxTmj3CfnQ/qk5aA8TYgA02NuArJkBN027Skh0dS8effPxd7AgABGGRJBmEJUIFxvWZlDa0Zquo6o7RjjFaU8YapTTnoq4YYzzKYAFh/ng4QkTyHP8+JClAKMcwx4x3hNT3x+rLD7R/qADCKCcQlSWmhPKyrKMgy7LCmHAmIKkeYpoCBiFtOiOU67UrWntXqF9ECWU7PaxBOza9idM8Oh5BTeumaZx1pcBpYXjZGy6WeXllWM+Yg5zPW2sdpTw6Zlmappxza1zJcUZ6ZaZpnpZXnM//ueEM5wZKRQQACGYppXNr5t7qTlrCxeD98n+8mJMY/ry7D+MhRGRVbkajpKvCVI0Zp8mfptO84pqZRznM4zgRQmhlscBCa1J70ba9Nsp56bwL/mm+nvnxEEMIueDOWtISPsiKC0wqPXjjnLRDaOeybO/HpukihFCSpEqpddoc15001usAN9jBS+v8teZfzEVeHuKUt602rmqbkPDvGz0zlPwPQ9D5MfyEaJmHeZDzqJfZnpy6nM1VTOM4GRndfEs322SzjTdf45tt/HYHLvlxn73bgc/fs/e34NM+e7MDQXy4BU8hTtQTAM4yowAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;         2012              md 2&apos; title=&apos;&apos; src=&apos;/static/3189bf6dc7a762fdd944d642c187149e/efd7b/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_2.png&apos; srcset=&apos;/static/3189bf6dc7a762fdd944d642c187149e/08678/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_2.png 190w,
/static/3189bf6dc7a762fdd944d642c187149e/2edd7/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_2.png 380w,
/static/3189bf6dc7a762fdd944d642c187149e/efd7b/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_2.png 760w,
/static/3189bf6dc7a762fdd944d642c187149e/c84e4/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_2.png 1037w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;화면 3 utest와 utest-test 프로젝트가 추가된 화면&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; margin-bottom: 16px;&apos; data-url=&apos;./비주얼_스튜디오_2012_테스트_익스플로러_활용.md_3.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/27d146566e21ae6f703c50a0bbcb3f7f/f843c/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 54.736842105263165%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB50lEQVR42lVRa2/aMBTN//8n01Rt6iY2VvpCUKDtymOgEiBZEuK87PhFQh4OyS4K/bCjo6urYx8fX1v72X2dDeej3uCpO376MXq47t99fbi56t1+uR91J5Obl+fey++7t2Fn3L8eDL4Pf33u3X7rjzv3z5+utMfJZrn6u91a84Wh6/v1u7NcmtPZVt84a93Z7lzLjpDHTAsbhm8YaLfzdoZvOvFshbQAob2HeZJjdnApNaNoF4YWITKrWKqwLFhSiqOSmYIaJ0VAk5ClPsuQh7UwCN51HYchY4xynhVFXp5ZVZWqqiTNhEyUqk6nU5YXparyvACxOtWSCy0KI3AJIUlMBXMPBwn7qg9IKSljQkql1AGQpLAKfd3UlFDNBjgOwQTM2F85tg05LWAfpTQMQ4xJWZacc8Z5XdetmRGm+T4x3SA7plxIRmwPoSzL23CoMEuEcRzHSpWCczjrVJ+TYZXFXENeYO5RnuUA5LqWaRVF8X9yRMg5WQoBt0iSFMwwDouZZlu+5/mCs+PxSEKM3PNBqixbgoHSmDNWFkVyOMTwC1JCn6YJxbGGAzfCyEFYJFnVNFXdqFMDM7U8K61Yn2vLEq7eNPC+2qjfmb4+vrzps/n6wsWlmX7wIrb6Qp//2SyW2/Fo+g/BUFjqAcsyxgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;         2012              md 3&apos; title=&apos;&apos; src=&apos;/static/27d146566e21ae6f703c50a0bbcb3f7f/efd7b/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_3.png&apos; srcset=&apos;/static/27d146566e21ae6f703c50a0bbcb3f7f/08678/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_3.png 190w,
/static/27d146566e21ae6f703c50a0bbcb3f7f/2edd7/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_3.png 380w,
/static/27d146566e21ae6f703c50a0bbcb3f7f/efd7b/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_3.png 760w,
/static/27d146566e21ae6f703c50a0bbcb3f7f/f843c/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_3.png 861w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;화면 4 utest 솔루션 디렉터리 구조&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;프로젝트 구성이 끝났으면 utest-test 단위 테스트 프로젝트에서 utest 프로젝트를 참조할 수 있도록 디렉터리 설정을 변경해 주어야 한다. 아래 순서를 따라서 설정을 변경하도록 하자.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;utest-test 프로젝트 설정 화면에 들어간 다음 C++ 탭의 General 페이지에 있는 Additional Include Directories 항목에 “..\utest”를 추가한다. 이 설정은 단위 테스트 프로젝트에서 utest 프로젝트에 포함된 헤더 파일을 바로 추가할 수 있도록 만들어 주는 기능을 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Link 탭의 General 페이지에 Additional Library Directories 항목에 “..\utest$(Configuration)”을 추가한다. utest에서 빌드한 오브젝트를 참조할 수 있도록 해준다. 이 설정은 단위 테스트 프로젝트에서 utest 오브젝트 파일을 바로 포함할 수 있도록 만들어주는 기능을 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;끝으로 Link 탭의 Input 페이지에 Additional Dependency 부분에 notify.obj 항목을 추가한다. 이 설정은 단위 테스트 프로젝트에서 notifier.cpp의 컴파일된 코드를 사용할 수 있도록 만들어주는 기능을 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;여기까지 마쳤으면 utest-test 단위 테스트 프로젝트에 테스트를 추가할 모든 준비가 끝났다. &amp;#x3C;리스트 5&gt;에 나와 있는 것과 갈이 테스트 케이스를 추가해 보도록 하자. Assert::ArrEqual 함수는 n.Notify(Notifier::CODE_BLACK, L”BITEM”)의 실행 결과가 TRUE와 같은지 체크하는 기능을 한다. TRUE와 같으면 테스트가 성공하고, TRUE가 아닌 다른 값이 반환되면 테스트가 실패했음을 알려준다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 5 unittest1.cpp 소스 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;stdafx.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;CppUnitTest.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Windows.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;notifier.hpp&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;namespace&lt;/span&gt; Microsoft&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;VisualStudio&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;CppUnitTestFramework&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;namespace&lt;/span&gt; utesttest
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;       
    &lt;span class=&quot;token function&quot;&gt;TEST_CLASS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NotifyTester&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
        
        &lt;span class=&quot;token function&quot;&gt;TEST_METHOD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BlackNotifyTest&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            Notifier n&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token class-name&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AreEqual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;TRUE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Notify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Notifier&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;CODE_BLACK&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;BITEM&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;코드 추가가 끝났으면 각 프로젝트를 빌드하고 Visual Studio 2012 메뉴에서 Test, Window, Test Explorer 항목을 선택한다. 그러면 &amp;#x3C;화면 5&gt;에 나타난 것과 같이 테스트 익스플로러가 화면에 표시된다. 우리가 앞으로 진행할 단위 테스트와 코드 커버리지는 모두 이 창을 통해서 손쉽게 제어할 수 있다. BlackNotifyTest를 수행하기 위해서는 해당 테스트 이름에서 오른쪽을 클릭한 다음 메뉴에서 “Run Selected Tests” 항목을 선택하면 된다. 그러면 Visual Studio가 알아서 테스트를 진행한 다음 결과를 우리에게 알려준다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 224px; margin-bottom: 16px;&apos; data-url=&apos;./비주얼_스튜디오_2012_테스트_익스플로러_활용.md_4.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5f178f45f823a7fb636afac6d7d6d4b0/773ea/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 137.89473684210526%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAcCAIAAADuuAg3AAAACXBIWXMAAAsTAAALEwEAmpwYAAAEq0lEQVR42n2US48UVRSAi4ULly58JkRNxJjgwp0aYmJk6UbDQhf8DsXEjYbHQmBAE1AgMWxUiAaJIMM4PcPAdE/39Lu6a/pR09VdXe/Xrep636qeLk91wQCinny5Offcc869de65RTx3tPHs0caLxxovHW+8cKwJ+lNfVIjPynuOlPd8/ghHymB8+svqM1/V3zpL7T3RfP5og3jn/Nb7F7sHfuh+/NPo4KXewUvd/WeofafbbyxQ+0619p0k73OKfO0k+fopcv9C670L3QMX+m+f7xDrFLfZE8kuvZIvD0WdUy1JMwBB1ZHjOUFk+zjDCeZjGEvGpNrqKKZN0EN5o1SnyNatGzeQZvi2ZyEkC6ImKzgIkp1ZMt3ZZRZPkyQxdUPk+BhjompX614jr65vmqWiXiho+ZJR3ETFslna0At5NQ/GDS1fgDFdzRw2yla5oJeI3PrKL9eubMlqV5JoRenJyraidCWZ5MWBqgx1tSPJjKZuq2pfUUaGBpa2IG/xHCsNiVqlurqcoyW7PkQ1BlFjq7xtMJINY21ojmS7ROs1xmixZm2AKgMD7Ju0QfMGHJ6w/VB3sO24iulaE8sykWq5E8fDge86kzAMIhxEYRDjFBze1yMcghC8aq1tydTYKNIaw0ljXtqgtSqc2LAURfF83/V8798AIaI0iQ8pZ7NZFE9t14vjeLqz4wWh6wWO5/8PRJMkqRa1mS8U11crhbVeu35v9XZ5467AbnNMN9kJkshP4ieY+rPYJ3zHyW8L3yy1Ttzgvv6D/+7u5PifwrGb4rd3zNMrxvel6EkubkbnitGPFUwkcXKVXPrw57Of/JYcvjb79Nfk8O+gJB9dSQ5dTT64nOxdSF49k7wy5+WF5M1zybuXkoOXk0NXZgS0UV+Z/NU3lvt4bRDmaJyjw1U6zPVTZWUbL3bx7d5jLKc++B6DCdf1Qt+fBv40dOMgZRp6KZkeuDvhP5mmPukq4Tiu7Tg+xhPHt13f8UO4ZGQ5rh+6qe7/F+BMsCx7/fr1Qj6/dHsxt7y8uHhrZSVXKhbv3FmtVioBiP+YwHwXwrZtURQFQVBVVdd1TdNkWUaGbhraBOkxDqEF4ijts6zDwkeSEWnuMAhwMBwOR6MRwzCSJMqmR45RfYTarNHlEdDjUWOo06IJumm7WQrC87wYx4AkSSw7BlFVRbF8RrF7gsXq7kh1OqLNag6ne4LhQl5o2Gx7Yoqna4O1wrBgaiacXJ6LqshI1yamIXCsoSmKJCBNlQRe5DlFllwo8Dw8Db7ZublELyEVVWvVwWBAkmStVqNpGnKVSqVGEzqYbLfbYOx0OjAahgFPan5sPz12FEa8wGcFy/YHxbIsx3EQQmAH13AuURQ9LJifPjroFLfVasE+lUoF9qEoqtlsQvHgVUIhYQniobLeXB4Gew8EY5wl3hWYpleR7ZZG+hC3SxoMa3gumV8mWeJsCUZIDXcTZX+SB/+TNJjjBEAQRLgnIJtqGmJZDhiNxqIo6chi5AmvTYayNVZBsQXdRpZNMMyIojq9Hj0YjOp1+Nput9tTFJ3jxFaLarc7na2+ppljDa4ddXizPNApDvVFyzAmfwMD8K/Q8OdiYAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;         2012              md 4&apos; title=&apos;&apos; src=&apos;/static/5f178f45f823a7fb636afac6d7d6d4b0/773ea/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_4.png&apos; srcset=&apos;/static/5f178f45f823a7fb636afac6d7d6d4b0/08678/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_4.png 190w,
/static/5f178f45f823a7fb636afac6d7d6d4b0/773ea/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_4.png 224w&apos; sizes=&apos;(max-width: 224px) 100vw, 224px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;화면 5 Test Explorer 창&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;코드 커버리지&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;코드 커버리지는 테스트를 통해서 코드의 얼마나 많은 부분이 실행되었는지를 나타내는 값이다. 코드 커버리지가 100%라는 의미는 코드의 모든 부분이 테스트를 통해서 실행됐다는 이야기를 나타낸다. 그러면 앞서 우리가 만든 BlackNotifyTest 코드는 Notifier 클래스를 얼만큼 테스트 하는지 측정해 보도록 하자. Test Explorer에서 BlackNotifyTest에 오른쪽 버튼을 누른 다음 표시되는 메뉴에서 “Analyze Code Coverage for Selected Tests” 항목을 선택하면 된다. 그러면 단위 테스트를 수행하는 것과 똑같이 테스트가 진행되고 &amp;#x3C;화면 6&gt;에 나타난 것과 같이 코드 커버리지 측정 결과가 나타난다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 707px; margin-bottom: 16px;&apos; data-url=&apos;./비주얼_스튜디오_2012_테스트_익스플로러_활용.md_5.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/b15deed96d511f4758f90087785e37e7/e9ffe/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_5.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 30.526315789473685%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAAsTAAALEwEAmpwYAAABR0lEQVR42i2OW2vCMBiG+1c3GHOgwmC4PzS01c3JThcD2cXmWVcZbGrVpLVamyZt0jTxMB0sO8DHx8PDe/FouTuYu52eVUbZsnVcGqVKo5NLK1WyjvSPg8Lg8OI9W55kKjB9DTKV/0tX4OkNPL+3NX8G8XIuaCgoERRLSpIIU7QMXAd5nu/YCUGcBBvOeBjEGImIxNhngb/iTCMz6I7HNhi79iQOEY+Q+lvJdisuGbEnQ8GI4pj4PAr26wTN7RmwlNkIqhXNdb6Jr2pWvr4otKNijxVa2DCFYUq9y/IN33jlP9yhei82+iu9TXQ16Eujx7XmNOnYwrRwtQcf2qA2imoDrGQTCMWPXVi3WAvI5wF+GUZtKJ/evGrfbQHRmMSaCkhogBbzwHO3ku7WyV+nKlzF4cIBW8H2v3Kd0K+NCNHCc4AafMr4G+FVMJSEJGirAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;         2012              md 5&apos; title=&apos;&apos; src=&apos;/static/b15deed96d511f4758f90087785e37e7/e9ffe/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_5.png&apos; srcset=&apos;/static/b15deed96d511f4758f90087785e37e7/08678/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_5.png 190w,
/static/b15deed96d511f4758f90087785e37e7/2edd7/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_5.png 380w,
/static/b15deed96d511f4758f90087785e37e7/e9ffe/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_5.png 707w&apos; sizes=&apos;(max-width: 707px) 100vw, 707px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;화면 6 코드 커버리지 결과 화면&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;#x3C;화면 6&gt;의 측정 결과를 살펴보면 우리가 작성한 테스트는 Notifier 클래스의 87.5%를 실행하고 있음을 알 수 있다. 세부적으로는 IsCacheItem 함수를 90%, Notify 함수를 83.33% 커버한다. 여기서 중요한 것은 어떤 부분이 테스트 되지 않았는지 살펴보는 것이다. IsCacheItem 함수 이름이 있는 줄을 더블 클릭하면 &amp;#x3C;화면 7&gt;에 나타난 것과 갈이 실제 코드에서 테스트가 진행된 부분과 진행되지 않은 부분을 명확하게 나누어서 표시해준다. 붉은색으로 표시된 부분이 BlackNotifyTest를 통해서 테스트되지 않은 부분이다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 760px; margin-bottom: 16px;&apos; data-url=&apos;./비주얼_스튜디오_2012_테스트_익스플로러_활용.md_6.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/68bb7709295fcf64b86b5010a5c4c698/c84e4/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_6.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 63.15789473684211%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB5klEQVR42o1R227UMBTMb7dAW34GiWeKdvsDPPQRVFh1N4nj2I7jaxLHXjtOsni5iFJRidHo6EjWnBmfkwFQQ4jzvIKQ1Ag3DaMNS5VzyZiglCW2LeeMD0rYXtvRKqlZK4RQWQUxhOhxX0BEYY0fD3lZIVA3EDVC9ZgwhFkyKLF8f1+/+1TsS9RQTpkihGWENIS0TUPTPEDI11yx1mgm9eA6G3obtPFUdBVV96W8L0XbjcZHOdhDgbKyBIwzKaU/+kY3UPfpcZDCWOenmDjP8+kp1nM5Hj3nKgNVVRSFUuroPFG06jQUtsCSaxPnZV5+Yn3K32KdgRIksTHmhzNlvSZE1khMcTm9DO/DWSwYz/eHfuhjCCm2kNi1bRzdef76Cy+IVVbk1cPDjrZcqQFyhE1n/aSN7ZwfrEuLMaML0/xsRAiTEDr7/OXbbrdPBxa8qwXhDPN0JYB0Z/rRDWNaRUhre2YfY1SqzzBCoCydc1MItG8ZhTTP8S7Xqh/9lDz/+edpilL2GUJkv8+l7pz1SDVIS4hU26YDz9bHZV3n9bT8zRQiZeFJfFrDGswax9Oa8ul5mU7/gSXGxZns8mNxcZtf3h4uPhxe3ebX2+pqC94kbv7w5q662oC3d9X19lxfb0BqbrbgO36O0H6L4LtdAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;         2012              md 6&apos; title=&apos;&apos; src=&apos;/static/68bb7709295fcf64b86b5010a5c4c698/efd7b/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_6.png&apos; srcset=&apos;/static/68bb7709295fcf64b86b5010a5c4c698/08678/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_6.png 190w,
/static/68bb7709295fcf64b86b5010a5c4c698/2edd7/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_6.png 380w,
/static/68bb7709295fcf64b86b5010a5c4c698/efd7b/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_6.png 760w,
/static/68bb7709295fcf64b86b5010a5c4c698/c84e4/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_6.png 1037w&apos; sizes=&apos;(max-width: 760px) 100vw, 760px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;화면 7 코드 커버리지 테스트 결과 화면&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이제 코드의 어떤 부분들이 테스트를 통해서 실행되지 않았는지 알 수 있으니 그 부분들을 실행할 수 있는 테스트 케이스를 추가하도록 해보자. &amp;#x3C;리스트 6&gt;에는 테스트되지 않은 부분을 모두 실행할 수 있도록 만들어진 테스트 케이스가 나와 있다. 이 테스트 케이스를 추가한 후에 빌드하고 다시 코드 커버리지를 측정해보면 &amp;#x3C;화면 8&gt;에 나타난 것과 같이 코드 커버리지가 100%로 출력되는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 6 BlackNotifyTest, SuspNotifyTest 테스트 케이스 소스 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;TEST_METHOD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BlackNotifyTest&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    Notifier n&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token class-name&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AreEqual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;TRUE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Notify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Notifier&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;CODE_BLACK&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;BITEM&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AreEqual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;FALSE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Notify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Notifier&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;CODE_BLACK&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;BITEM&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;TEST_METHOD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SuspNotifyTest&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    Notifier n&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token class-name&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AreEqual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;TRUE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Notify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Notifier&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;CODE_SUSPICOUS&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;SITEM&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AreEqual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;FALSE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Notify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Notifier&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;CODE_SUSPICOUS&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;SITEM&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 707px; margin-bottom: 16px;&apos; data-url=&apos;./비주얼_스튜디오_2012_테스트_익스플로러_활용.md_7.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/23e1e5bd2c77aade3e4ea562fe630b1d/e9ffe/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_7.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 30.526315789473685%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAAsTAAALEwEAmpwYAAABQ0lEQVR42j2QW0/CQBCF+2ONECMmJgb/EaUQkHh7MJqYKFqKtSZesBfaAq3tdtvudi8FCjGuPphMTs58Mw8zR2qee82z6dHAPOhbta5Z75p7PbvetXbkj11lUpPfG32nMfD2T9zG4L+8w1P/+MKX4rkHo4ChjKGU5ZALRSkCEVjMsjjMAp+mgKRgRRBJkwICMcVJjJOoJFhK597Ctn3XXvhOkQGSA6FrjrclYQh6zueSoqosMIwF3y4pCHzHfFsxtGZY6hjLlgp7Q6v1EMpa3tGxrEHFYIrB209YVoFi0F8/Rm2dKC+lPIJ/kCs6ldQpHfvMsOCN7l1q7tDM7yeJgKrLhL9+nj06ZOSyu0kqWs3jt6/Rle6LBcGlTUkoSkAYJF+LNUebJRXXCiguLIssnE0rXghPRRw4/V5zEYR4sCpJxYsf8LowiKw6FTYAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;         2012              md 7&apos; title=&apos;&apos; src=&apos;/static/23e1e5bd2c77aade3e4ea562fe630b1d/e9ffe/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_7.png&apos; srcset=&apos;/static/23e1e5bd2c77aade3e4ea562fe630b1d/08678/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_7.png 190w,
/static/23e1e5bd2c77aade3e4ea562fe630b1d/2edd7/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_7.png 380w,
/static/23e1e5bd2c77aade3e4ea562fe630b1d/e9ffe/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_7.png 707w&apos; sizes=&apos;(max-width: 707px) 100vw, 707px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;화면 8 수정된 테스트 케이스 커버리지 측정 결과&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이제 코드 커버리지 100%를 충족시켰으니 과연 완벽한 테스트 케이스이고 우리가 만든 Notifier 클래스가 우리의 의도를 100% 만족한다고 자신할 수 있을까? 안타깝게도 아니다. 코드 커버리지의 함정은 이 수치가 우리가 만든 테스트가 실제 코드의 어떤 부분을 실행했는지를 나타내는 기계적인 값이란 점에 있다. 즉 이것은 신택스만(syntax) 확인할 수 있을 뿐이지 시맨틱(semantic)은 검증할 수 없다는 것을 의미한다.&lt;/p&gt;
&lt;p&gt;앞서 Notifier 클래스 코드 명세에서 이 클래스가 가지고 있는 두 개의 캐시는 독립적으로 동작해야 한다고 했었다. 그렇다면 명세대로 과연 각각의 캐시가 독립적으로 동작하는지 살펴보도록 하자. &amp;#x3C;리스트 7&gt;에는 캐시의 독립성을 검증할 수 있는 테스트 케이스가 나와 있다. 이 테스트를 추가한 다음 Test Explorer를 통해서 테스트를 진행해보면 &amp;#x3C;화면 9&gt;에 나타난 것과 같이 테스트가 실패하는 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 7 SBTest 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;TEST_METHOD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SBTest&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    Notifier n&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token class-name&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AreEqual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;TRUE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Notify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Notifier&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;CODE_SUSPICOUS&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;ITEM&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AreEqual&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;TRUE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Notify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Notifier&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;CODE_BLACK&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;ITEM&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 242px; margin-bottom: 16px;&apos; data-url=&apos;./비주얼_스튜디오_2012_테스트_익스플로러_활용.md_8.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/b776230100cabede16b4b0204ce9d7c4/9ccb4/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_8.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 169.4736842105263%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAiCAIAAADQyG7qAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFK0lEQVR42n1VSY8bVRDuA0ck4EI4ceDfZIYggRCcwiI2AQckhBAXRCSChDhwQZG4IBKSiSCJFE0SkSFjjzPjzOKxPXa8u/e2e19e76+7vVLtnkSzIEpfl17Xe/WqXn3Vr4nnvjs4c/Hxme/rL16sv/TD4+cv1Iiv9omvM5RP4Jlvys9+W33lp8bLPz5+4cIB8fpV8vxfzLs32E9u8+/dZN6+Ti1dpl79g16+Qp79vQ9YupzicLx4ff8me/4G8+Z1mqhSco1RDur10kHdsH0fR8i2LBsFYTg/JbNZqr0Qd0gySkaE2Or3S9XGw81avoAozmV5o0/qvb7NcliUTiOWZZthYU0syYR29675931voxBvbnq53AJ5N5/3c3lnfR3wxJjz1nN+Lmc/AEs+2NhQVu8Q99bXr9y4VdOivaFfU/G+FLb0qCKHO0OfsuM9MThQcV3DVSVs6LiihEXB75gxg0JGFAlZknRVtUxrqBiqagwkXVZN07RkxTANS9VMeNV0U1KMoWzIqqGkFsOyEKwmRNPbpzRyaNQ4UxEFWjRKlKZaLjLV0PdGMR7F4ShaIA6fjmMchiEmYozlcCSEE8PGppvCcELHx16A/TA6Ci+IkHcImA2CkEhmU3pj59LP/3x6f/753ckHq9NzK9Olq9Pla7OlIzh7dXZuZfbxndmHq7O3bs5/3fYHLE9M53Pq4f6lXwpfFOZfPph9dm/yxq35a3/OllemyytHnK/NXl1JPT9anb1ze/5bCRuKSnTb7YMeVax1io92H+3tV+uN4tYWQ1M0RdkIJXEcRzhDFMFBsA8J49i07D7JEa7rGabK8RRN9ocCr6syTZOyJCqS6HvuU89D4DAKgyQOkYV6fZYYJSPDMxRXAbaAHBVosyxd142F4OPieR5CCOyaZqSR4yg2XENBio0gTSul2DrUjuOccPZ9H4ye5xqGRVICAWfRbF22ZNMwJUmCyIoCSgNAhPC4uK67iAyZmRwnEsD1eDwZJWPQcZxgqEsUgREGACDzBLKphcYE7LS5udloNLrdrqLIUN1sPtP/L1BtFzwpiiJJEjaCBICSURyNkmicREmc6vT1CY45Q5LTyQRskpwKz/PIcVnVbQ9RR0Sc6jCqw2lgSQekbB/1JtL8xpMgjgeCwHHcYCBYjkepHqU4pOLJKGwO7b5k07JDK87AcI9FxpOpv5V3KyXNdoAiqKMsSw4yHWQNeFaRxcBzxkkMpxglp9IGZy+/FlR2B5pOQZMNh81Wi+cFwzAZlu2kVVTg5gIiwlM1TNOOJhMf493dXWohLMsKgtBut3u9HpSgXq9XKhWwQC1PuBMZoZ7rFovFnZ2dQqGwtrbWbDb39va2t7eBCDBubW21Wi1ou5NU4UVbQNNWq1VwgEWgISYwNxgMyuUy2Gu1GmxXKpWgC046Z00LiQFVcMJMQ+UyDQJbxws5GRmOkSQJBIdQrXYbQDMMgKQonuOBPKgCfGNRFJ/uOQL2g8MwDAPrYC3cARzLSqIIO8LUKIkn4zFcCNF/tmfmnKVK0iw/lLokQ3MD1w88P7TdQLd9GNtw5Z12hmQgZ6BxPEoUG5dZtM+gKm/vkvoOqVdYs9DRyoy53dddf/HBHD5PImcZPhXYKwhxNk7SufTzgLRBZePsPgMQUAxJgpQ1WVYB6R2gm6qSXgaSJGvws0Au/Bg05MtWqhXLtxy4T6AzfEIQxGaz3e2S/T5drzeBYJrmRVGjaQ5eO52+qlus5vZEuz2067zVHKCB7iL4pSDvXxsGAJnwNMJCAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;         2012              md 8&apos; title=&apos;&apos; src=&apos;/static/b776230100cabede16b4b0204ce9d7c4/9ccb4/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_8.png&apos; srcset=&apos;/static/b776230100cabede16b4b0204ce9d7c4/08678/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_8.png 190w,
/static/b776230100cabede16b4b0204ce9d7c4/9ccb4/%EB%B9%84%EC%A3%BC%EC%96%BC_%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4_2012_%ED%85%8C%EC%8A%A4%ED%8A%B8_%EC%9D%B5%EC%8A%A4%ED%94%8C%EB%A1%9C%EB%9F%AC_%ED%99%9C%EC%9A%A9.md_8.png 242w&apos; sizes=&apos;(max-width: 242px) 100vw, 242px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;화면 9 SBTest 실패 화면&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;문제는 if문장에 숨어 있었다. CODE_BLACK 아이템에 대해서는 else if 줄이 검사되지 않아야 한다. 하지만 &amp;#x3C;리스트 4&gt;에 나타난 코드의 else if 구문에는 ‘code != CODE_BLACK’과 같은 조건이 없었기 때문에 해당 else if 문이 검사되면서 이런 결과가 나타난 것이다. 이런 문제를 미연에 방지하기 위해서는 &amp;#x3C;리스트 8&gt;에 나타난 것과 같이 코드를 명확하게 분리해서 작성하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 8 수정된 Notify 함수&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;BOOL
&lt;span class=&quot;token class-name&quot;&gt;Notifier&lt;/span&gt;&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Notify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NotifyCode code&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCWSTR msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;code&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; CODE_BLACK&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;IsCacheItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b_cache_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;IsCacheItem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s_cache_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%d %ws\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;앞서도 살펴보았던 것과 같이 코드 커버리지는 보조적인 지표 역할을 해줄 뿐 커버리지가 높다고 테스트 품질이 높다는 것을 의미하지는 않는다. 따라서 테스트 케이스는 명세를 바탕으로 꼼꼼하게 먼저 작성하는 습관을 들이는 것이 중요하다. 코드 커버리지는 작성한 테스트를 통해서 어떤 부분이 실행되지 않는지를 확인하고 추가적으로 어떤 테스트 케이스를 만들어야 하는지를 참고하는 지표 정도로 활용하는 것이 좋겠다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[포맷 스트링이 부릅니다. 헬게이트~]]></title><description><![CDATA[게임 보안을 하면 참 다양한 이슈를 겪는다. 그 이슈들도 크게 몇 가지 종류로 나뉘는데 종류별로 심각성을 살펴보면 다음과 같다. 서버 크래시 >>>>> 78.2차원문 >>>> 넘사벽 >>> 블랙홀 >> BSOD…]]></description><link>https://jiniya.net/wp/archives/9059</link><guid isPermaLink="false">https://jiniya.net/wp/archives/9059</guid><pubDate>Thu, 11 Oct 2012 23:58:27 GMT</pubDate><content:encoded>&lt;p&gt;게임 보안을 하면 참 다양한 이슈를 겪는다.&lt;/p&gt;
&lt;p&gt;그 이슈들도 크게 몇 가지 종류로 나뉘는데 종류별로 심각성을 살펴보면 다음과 같다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;서버 크래시&lt;/strong&gt; &gt;&gt;&gt;&gt;&gt; 78.2차원문 &gt;&gt;&gt;&gt; 넘사벽 &gt;&gt;&gt; 블랙홀 &gt;&gt; &lt;strong&gt;BSOD&lt;/strong&gt; &gt; 미로 &gt; &lt;strong&gt;클라이언트 크래시&lt;/strong&gt; &gt;= &lt;strong&gt;충돌&lt;/strong&gt; &gt; (퇴근 가능 영역) &lt;strong&gt;오진&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;그렇다. 다른 모든 것을 떠나서 서버 크래시는 재앙이다. 대재앙이다. 클라이언트에서 발생한 몇 년 동안의 이슈를 모두 합쳐도 서버 이슈 한 건 보다 못하다고 할만큼 서버 이슈는 심각하다. 서버 이슈는 크리티컬 하고 엄청나며 어렵고, 애매하고, 난감한 그야말로 안드로메다급 문제라고 할 수 있다. 이런 어려움에도 불구하고 고품격 보안 기능을 제공하기 위해서는 복잡하고 난해한 서버 코드를 추가할 수 밖에 읍다. 흙~&lt;/p&gt;
&lt;p&gt;썰이 너무 장황했다. 맞다. 서버가 다운됐다. 큭~ 그 오랜기간 문제없이 동작하던 서버가 다운됐다. 다운됐다. 다운됐다. (에코 메아리)~~&lt;/p&gt;
&lt;p&gt;서버 이슈가 어려운건 한 가지 밖에 없다. 재현이 쉽지 않고 동작하는 서버를 우리가 라이브 단계에서 어떻게 할 수 없다는 점이다. 즉, 서버 문제는 모두가 추측의 영역에서 이루어질 수 밖에 없다. 그나마 이런 어려운 문제를 돕기 위해서 대부분의 게임 서버 프로그램은 고품격 덤프 기능을 가지고 있다. 그런데 그런 고품격 덤프 기능들이 실상은 도움이 별반 되질 않는다. 왜냐하면 진짜 문제가 생겼을 때 제대로된 정보를 우리에게 주는 경우가 드물기 때문이다. 그래도 오늘은 운이 좋았다. 덤프는 없었으나 크래시 로그가 남았고 콜스택이 있었다. 부왘~ 천만다행. 거기다 심볼까지 아름답게 존재해 주시고, 콜스택 로그 또한 아름답게 착착 맞아떨어졌다.&lt;/p&gt;
&lt;p&gt;이쯤되면 뭔가 사소한 버그겠구나 라고 생각할 법 한데, 여기에 반전은 그 콜스택이 가르키는 지점은 다름아닌 StringCchVPrintfW 라는 점, 그리고 그 안의 _woutput_l이라는 함수에서 발생 했다는 점. 그 넓디 넓은 서버 소스 코드 중에 StringCchVPrintfW라는 함수를 얼마나 많이 쓰겠냐는 말. 이쯤되면 해운대 바닷가에서 낚시바늘 찾기만큼 어려워져 버렸다고 생각하는 것이 당연한 진리~ 그런데 왠걸 ㅋㅋㅋ~ 희한하게도 소스 코드에 전부 StringCbVPrintfW를 썼는데 단 한 곳. 단 한 곳만 StringCchVPrintfW를 쓴 것이었다. 럭키가이라고 생각을 하는데. 그 함수가 엄청 많이 호출되는 로그 출력 함수라는 건 또 반전 ㅠㅜ~&lt;/p&gt;
&lt;p&gt;중간 썰도 길었다. IDA로 파일을 열어서 번지를 보니 이렇다. _woutput_l이라는 이 망망대해 함수 속에 우리의 크래시 지점은 저 빨갛게 표시된 좁쌀만한 영역 ㅠㅜ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/10/woutput_l.png&quot;&gt;&lt;img src=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/10/woutput_l.png&quot; alt=&quot;&quot; title=&quot;_woutput_l&quot;&gt;&lt;/a&gt;
&lt;strong&gt;인간이 이렇게 긴 함수를 작성하는 것이 가능하단 말인가?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;외계인이 작성한 것이라고 밖에는 생각되지 않는 _woutput_l&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/10/woutput_l2.png&quot;&gt;&lt;img src=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/10/woutput_l2.png&quot; alt=&quot;&quot; title=&quot;_woutput_l2&quot;&gt;&lt;/a&gt;
&lt;strong&gt;여기서 난 과연 무엇을 깨달아야 하는가?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;_woutput_l이라는 거대한 함수 속에서 난 어떤 힌트도 찾을 수 없었다. 그저 함수가 굉장히 거대하다는 것 밖에는 느끼지 못했다. 이제는 그저 촉에 맞기는 수 밖에. 딱 떠오르는 첫번째 생각은 그랬다. 그래 %s 따위를 썼는데 뒤에 문자열 포이턴가 먼가 이상했던거야. 아마 종료 NULL이 없었겠지. 그래서 메모리를 계속 읽었겠지. 재수없게 그 종료 널 다음이 딱 커밋되지 않은 메모리 영역이었겠지. 하필 또 난 접근 위반 예외처리를 해놓지 않았지. 그러니까 당연히 크래시가 발생했겠지~ 라고 소설을 써봤다.&lt;/p&gt;
&lt;p&gt;가설을 검증하기 위해서 소설대로 샘플을 만들어서 해봤는데. 너.무.도. 당연하게 깔끔하게 종료됐다. 그 어떤 크래시도 없이 말이지. 그런데 그 샘플이 나를 구원했다. ㅋ~ 크래시가 안나서 _woutput_l 함수 내부로 들어가 볼 수 있었는데, 거기서 디스어셈블 창으로 전환하자 앞으로 내가 10년 더 Visual Studio를 써야 할 것 같은 화면이 출력됐다. 그렇다. 소스코드와 함께 디스어셈블 코드가 출력된 것이다. 장장 2370줄에 이르는 _woutput_l 코드를 에디터에 복사했다. 그리곤 IDA에서 보았던 8b 48 04를 검색했다. 이런 마법이!!! 딱 한 군데 밖에 나오질 않는 기적이 발생하는 것이 아닌가? 거기다 코드가 똑같다. 크래시난 지점과. 빙고~&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;                if (pstr == NULL || pstr-&gt;Buffer == NULL) {
00B61D1E 85 C0            test        eax,eax 
00B61D20 74 3A            je          $LN97+224h (0B61D5Ch) 
00B61D22 8B 48 04         mov         ecx,dword ptr [eax+4] 
00B61D25 85 C9            test        ecx,ecx 
00B61D27 74 33            je          $LN97+224h (0B61D5Ch) 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;역시 먼가 NULL과 관계된 문제였어. 코드는 나에게 말해주고 있었다. 그런데 진정한 힌트는 바로 그 위에 있었다. 아래와 같은 케이스 문이 있었던 것이다. Z. 그렇다 이 코드는 %Z 따위를 탔을 때 UNICODE_STRING의 Buffer가 NULL인지를 체크하는 코드였던 것이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;            &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;Z&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이제 제대로 소설을 갈겨 보자면 이렇다. 포맷 스트링으로 %Z가 넘어왔는데 그놈이 가리키는 UNICODE_STRING 포인터는 있는데 그 안의 Buffer를 접근하려고 하니까 예외가 발생한 것이다. 이쯤되면 이제 내가 %Z를 쓴 곳만 찾으면 되지 않겠는가? 근데 사실 %Z는 드라이버 코드에서나 쓰지 유저 코드에서는 거짐 쓰지도 않는데 라고 하면서 로그 출력 함수를 호출하는 부분을 grep했다. 그리곤 %Z로 검색했는데 역시나 없다. 그래서 로그 출력 함수로 넘어가는 포맷 스트링을 모두 점검하는 와중에 난 놀라운 한 줄을 발견하고야 말았다. 내가 작성한 것이라 믿고 싶지 않은 한 줄이었다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;lb_-&gt;Append(LLV_INFO, buffer);&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;lb_-&gt;Append(LLV_INFO, buffer);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이거슨 무엇인가? 대재앙을 부른다는 바로 그 코드. 악마를 워프시킨다는 바로 그 코드. 핡~ 포맷 스트링으로는 절대로 변수를 넘겨서는 안 된다는 불변의 진리~ 그 망망대해 속에 존재하던 딱 한 줄의 코드가 나에게 말.하.고. 있었다. 이 멍청아~ 꺼져~ ㅠㅜ~&lt;/p&gt;
&lt;p&gt;확인 사살을 위해서 샘플을 만들었다. 당.연.하.게 이 샘플은 한치의 오차도 없이 나의 소설대로 동일한 번지에서 크래시를 발생시켰다. 휴~&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;wchar_t&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;%Z&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    PUNICODE_STRING us &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PUNICODE_STRING&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;wprintf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; us&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;사실 위 샘플보다는 아래 샘플이 원 코드의 심각성을 더 잘 보여준다. 마구 %Z%z%Z%Z%Z%Z 따위를 입력해보자. printf의 포맷스트링으로 변수를 전달하는 것이 얼마나 위험 천만한 짓인지 깨닫게 된다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;fgets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ARRAYSIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;stdin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;아직도 헤매는 독자 여러분을 위해서 어떻게 고치는지 살펴보면 아래와 같이 고쳐야 한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;fgets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ARRAYSIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;stdin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%s&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/10/vs2012p.png&quot;&gt;&lt;img src=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/10/vs2012p.png&quot; alt=&quot;&quot; title=&quot;vs2012p&quot;&gt;&lt;/a&gt;
&lt;strong&gt;이래놓곤 난 다음 주엔 VS2012로 어떻게 우아하게 버그를 잡는지 발표하겠지~ 기가찬다 진짜~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;신이시여, 발표 자료가 뚝 떨어지는 기적을 보여 주옵소서~ 아멘!!!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;가을가을한 요즘. 깜냥도 안 되면서 너무 많은 걸 약속한 건 아닐까 반성하는 중 ㅠㅜ~&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[아 멘붕. 돌대가리 ㅠㅜ~]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/8832</link><guid isPermaLink="false">https://jiniya.net/wp/archives/8832</guid><pubDate>Fri, 21 Sep 2012 23:58:26 GMT</pubDate><content:encoded>&lt;p&gt;평균 구할 일이 있었다. 가평균으로 구했으면 했다. 그런데 가평균 공식이 잘 생각이 나질 않는 불편한 상황. 여기까진 이해해 줄만 했다. 다 외울 수는 없다고 자위하면서 말이지. ㅠㅜ~ ‘가평균 공식’으로 구글링. 두둥. 잔뜩 나왔다. 몇 페이지 클릭해서 들어갔는데 어랏 공식보고 단박에 이해가 되질 않는 이상한 시츄에이션. 내 머릿속은 이런 상황 ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;avg = avg + (i – avg) ? / ?&lt;/p&gt;
&lt;p&gt;그래서 속으로 그래. 이런 건 네이버에서 검색해야지 ㅋㅋ~ 이러면서 네이버에서 똑같은 걸 검색. 한 두 페이지 들어가 봤는데 그래도 이놈에 물음표가 채워지질 않는다. 헉. 약간 멘붕. 어쩌다가 이 지경이. 결국 구글에 ‘average without sum’같은 구차한 검색을 통해서 가평균 코드를 보고서야 물음표를 채울 수 있었다.&lt;/p&gt;
&lt;p&gt;와 어쩌다가 이렇게 됐지. 원래 그닥 좋은 머리는 아니었지만 이렇게 심각하지는 않았는데. 맨날 술만 먹었더니 진짜 돌대가리 다 됐다. 이러다 내년에는 다른 파일에 방금 작성한 클래스 이름이 생각나질 않고, 그 다음 해에는 열줄 위에 있는 지역 변수 이름이 기억나질 않고, 그 다음 해에는 sprintf 함수 원형이 가물가물한 지경이 되는건 아닌지 ㅠㅜ~&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[진정한 여행]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/8750</link><guid isPermaLink="false">https://jiniya.net/wp/archives/8750</guid><pubDate>Fri, 17 Aug 2012 23:58:25 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;가장 훌륭한 시는 아직 씌어지지 않았다.&lt;/p&gt;
&lt;p&gt;가장 아름다운 노래는 아직 불려지지 않았다.&lt;/p&gt;
&lt;p&gt;최고의 날들은 아직 살지 않은 날들.&lt;/p&gt;
&lt;p&gt;가장 넓은 바다는 아직 항해되지 않았고,&lt;/p&gt;
&lt;p&gt;가장 먼 여행은 아직 끝나지 않았다.&lt;/p&gt;
&lt;p&gt;불멸의 춤은 아직 추어지지 않았으며,&lt;/p&gt;
&lt;p&gt;가장 빛나는 별은 아직 발견되지 않은 별.&lt;/p&gt;
&lt;p&gt;무엇을 해야 할지 더 이상 알 수 없을 때&lt;/p&gt;
&lt;p&gt;그때 비로소 진정한 무엇인가를 할 수 있다.&lt;/p&gt;
&lt;p&gt;어느 길로 가야 할지 더 이상 알 수 없을 때&lt;/p&gt;
&lt;p&gt;그때가 비로소 진정한 여행의 시작이다.&lt;/p&gt;
&lt;p&gt;– 진정한 여행, 나짐 히크메트&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;너저분하게 널려있는 쓰레기를 싹 버리고,&lt;/p&gt;
&lt;p&gt;탑처럼 쌓여있는 그릇들을 깨끗하게 씻고,&lt;/p&gt;
&lt;p&gt;마른 오징어가 된 빨랫줄의 옷을 개킨다.&lt;/p&gt;
&lt;p&gt;눅눅해진 빨랫감을 세탁기에 넣어 돌리고,&lt;/p&gt;
&lt;p&gt;청소기로 방에 켜켜이 쌓인 머리카락과 먼지를 모두 쓸어내고,&lt;/p&gt;
&lt;p&gt;침대에 깔깔한 순면 시트를 새로 깐다.&lt;/p&gt;
&lt;p&gt;에어컨을 터보 모드로 켠 다음,&lt;/p&gt;
&lt;p&gt;적당한 온도의 물에 샤워를 한다.&lt;/p&gt;
&lt;p&gt;그리곤, 침대에 쏙!&lt;/p&gt;
&lt;p&gt;반쯤 읽은 신경숙의 소설책을 집어든다.&lt;/p&gt;
&lt;p&gt;하염없이 행복한 이 순간,&lt;/p&gt;
&lt;p&gt;진정한 여행이 시작된다.&lt;/p&gt;
&lt;p&gt;훗~&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[생각만 하는 사람]]></title><link>https://jiniya.net/wp/archives/8656</link><guid isPermaLink="false">https://jiniya.net/wp/archives/8656</guid><pubDate>Thu, 16 Aug 2012 23:58:24 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 489px; margin-bottom: 16px;&apos; data-url=&apos;./생각만_하는_사람.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/931fddad1e95b1a9366386d541d78efb/7f605/%EC%83%9D%EA%B0%81%EB%A7%8C_%ED%95%98%EB%8A%94_%EC%82%AC%EB%9E%8C.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.78947368421053%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAA7DAAAOwwHHb6hkAAADHklEQVR42mOoaWyPTiuJSc2Lyyh1cfO2tLCxsLDW1TVUV9fV0zNyc3MNCwvbtm3bz58/P378+BkMPn36BCTfvn3LEBIebe1oZWBiYW1voKQsoqTIJyXJIynJLibGIC8LZEtraGhcuHDh////f//+/Q8G//79A5Jfvnxh8PL2d3QRDI8Uz8zhT0kTCo0SCIvgCgzijI5jMDIREBeXlJAQv3z5MlD1jx8/gPYDjUBoDvb29tYTjHERctbl99Tn9dbjDbXgtFNns5BllOdiFRYSYWFhnjFjxv379zdt2jRnzpx9+/b9+fMHpjnA1UyZy1JTxFxTwEqLy1SRw1iRTVeR1UiB1VidUUiIk4GBycvL8/fv30DVz58/B5oC9DxUc1S0k5sXs48/t4c3V1Iqe0AIh18wS2Q0s7c/i38Qq4gwCzMzG9Dlt27dgmhYvHgxJAiAYcYQEOgWEsTq6cETGMAeGsYRGcHp7cURFcXm78dkasIABOzsbCwsLEA9r169WrRo0YYNG75+/Qq12dbWQUGBOShQICaWz8+X09yC0caGwcuLyddb2tPDOjEpMSQkBGhEQkICJMxQQtvZ2YWXl1dCnJuHl0lOTjQ6JnzpktknT+5/+uThp09f7927d/369enTpwcEBACjF6gHGFoIzfb29kCDZWTk8vLyDx06DAySly9fPXz4CMj4+fM70KkzZ87ctWvXgQMHzp49C4ltpKgKDq6qqnr48AHYPSAnff365dLlS93dXXl5eefPn3/z5k1lZeXkyZP37NkDTFXw1ALSDAx6SLoBWnL48OG9e/feuXMHGDHHjh1TVVUFOmrr1q1btmyRl5dPTU3t7+8HphOEzZBIA3pswoQJ9fX1LS0ttbW1y5YtA/qwp6fH2toa6K4rV66Ym5sDDWJlZZ09ezYkzECanzx5cuLECaCeurq6iRMnAo3o6uoqKChYu3Yt0M6Ghob4+HgjIyNgbDGAATc3986dO4H6gaYz7N69G6insLCwsbFx1qxZwATY3NwMjBhg8FZUVPj5+VlZWZmZmZmamlqAga6ublNTE1Dz27dvAXgK5nut1AfSAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;          md 0&apos; title=&apos;&apos; src=&apos;/static/931fddad1e95b1a9366386d541d78efb/7f605/%EC%83%9D%EA%B0%81%EB%A7%8C_%ED%95%98%EB%8A%94_%EC%82%AC%EB%9E%8C.md_0.png&apos; srcset=&apos;/static/931fddad1e95b1a9366386d541d78efb/08678/%EC%83%9D%EA%B0%81%EB%A7%8C_%ED%95%98%EB%8A%94_%EC%82%AC%EB%9E%8C.md_0.png 190w,
/static/931fddad1e95b1a9366386d541d78efb/2edd7/%EC%83%9D%EA%B0%81%EB%A7%8C_%ED%95%98%EB%8A%94_%EC%82%AC%EB%9E%8C.md_0.png 380w,
/static/931fddad1e95b1a9366386d541d78efb/7f605/%EC%83%9D%EA%B0%81%EB%A7%8C_%ED%95%98%EB%8A%94_%EC%82%AC%EB%9E%8C.md_0.png 489w&apos; sizes=&apos;(max-width: 489px) 100vw, 489px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 489px; margin-bottom: 16px;&apos; data-url=&apos;./생각만_하는_사람.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/d75961ebb031925b23db63a31aa76d55/7f605/%EC%83%9D%EA%B0%81%EB%A7%8C_%ED%95%98%EB%8A%94_%EC%82%AC%EB%9E%8C.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.78947368421053%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAA7DAAAOwwHHb6hkAAADFklEQVR42mNo6+7PLK7NKqwsqGgIi4j08fHx9vZ2dHSys7N3cnIKDQlJSU3duXPnjx8/Pn78+BkMPn36BCTfvXvHEBoZa2jpoGdipaFvJiQiysvDw8PNxc7GysDAwMvLKyUpoaamdvbs2f/////9+/c/GPz79w9IfvnyhcHf389JVSjSSCJIVzhARzRKTyBGmztEnTNSldFdTcBGVVxKSurKlStA1X/+/IFoQ2j28fGVkpJ0UBMzlBSwk+czleS3k+a2l2Q1FGQUYGcTFhZhZWGZP3/+w4cPN2/eDGQcOnQI4gSQZnd3Nx4eflV1MV9fAUsrHidnDicXdlNTdjsHNgcHBnExLgYGJqDrfv78CfTkHTAA+hmq2cXFmZWVQ0qa1zeA1cmFOSyC2dWD0d6JwdmFSVaWlY2NhZWVTVpa+v79+0ANwGBbu3bthQsXgGxgmDF4uHtwcXGKCok7ajr7GvvaqFvYaTi56LhqS2szMjICg42dnZ2FhWXFihWvX79etGjRsmXLIDaDNDs6OrKwskiIS1qqW5kom6uIqioJAz2hoa+sr6en6+/v7+zsDDQiPT0d4lSUAAPK8YIBIxMjFw+Xi5tLS1vzytUrz104//LlywcPHty8ebOtrQ0Y+d++fUMOc5BmB2CwMDCIioomxCds27rt8aPHwIB59fLV50+fgeoeP348Y8YMYAjv3r0b4lVgUCM0e3l5AZ10+fJleBx++PDhzJkz3d3dNTU1d+/effbsWWVl5bx58/bu3QuUQnH29evXIenm/fv3p06dOnbs2NOnT3///r1//34FBQVgaB08eBAYwsrKyoWFhXPmzEFxNjDFAlnA2JsyZUpDQ0Nra2tdXd26deuA4s3Nzdra2hUVFUBvm5iYAH0HTLvLly+HWA7S/OLFi4sXL/b09DQ2Nk6aNGnixIm9vb2lpaW7du0C5gdgUGVmZgJjhIsLmFpAQEREBOg6oH5ghDEAFQFV5+Tk1NbWTp06ddq0aUD7o6OjgcELtNPT09PAwEBdXV1VVVVTU1NLS0tWVhYYFkDNb968AQDV9d7T7Bho2wAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;          md 1&apos; title=&apos;&apos; src=&apos;/static/d75961ebb031925b23db63a31aa76d55/7f605/%EC%83%9D%EA%B0%81%EB%A7%8C_%ED%95%98%EB%8A%94_%EC%82%AC%EB%9E%8C.md_1.png&apos; srcset=&apos;/static/d75961ebb031925b23db63a31aa76d55/08678/%EC%83%9D%EA%B0%81%EB%A7%8C_%ED%95%98%EB%8A%94_%EC%82%AC%EB%9E%8C.md_1.png 190w,
/static/d75961ebb031925b23db63a31aa76d55/2edd7/%EC%83%9D%EA%B0%81%EB%A7%8C_%ED%95%98%EB%8A%94_%EC%82%AC%EB%9E%8C.md_1.png 380w,
/static/d75961ebb031925b23db63a31aa76d55/7f605/%EC%83%9D%EA%B0%81%EB%A7%8C_%ED%95%98%EB%8A%94_%EC%82%AC%EB%9E%8C.md_1.png 489w&apos; sizes=&apos;(max-width: 489px) 100vw, 489px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 489px; margin-bottom: 16px;&apos; data-url=&apos;./생각만_하는_사람.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/b069162a2c1bd94375fd50600360c444/7f605/%EC%83%9D%EA%B0%81%EB%A7%8C_%ED%95%98%EB%8A%94_%EC%82%AC%EB%9E%8C.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.78947368421053%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAA7DAAAOwwHHb6hkAAADIElEQVR42mPomTAlq7gms6Aiv7wpNCzK09MHiOztnWxt7e3tHUNCQpKTk7du3frjx4+PHz9+BoNPnz59+fLl7du3DDEJKVomDnom1sbWZtIyIlKSPCIiXPx8rCzMDAJ8POJiksrKyseOHfv////fv3//g8G/f/+AJFA/Q1RkuKqKsJmZbECAcFCwaEy8gH8At6cXl6sbk4Mjv7KKlIS42NmzZ4Gq//z5A9GG0BwZFWptI+jpKmZjxu/tzBvoyevtymVmwGZvyejmwOJuJ8DOxjxt2vTHjx9v2bJlwYIF+/fv//37N1Szn3+AvBBvioFgki53hhZ7kzFLmBJbuhZrrBpLmhpjpRE7HzuTs5v79+/f3r9/f+fOndu3bwM9D9Xs4+sbr87YZ8dRZMxRa8bWZM5Wbcw83Zap15K52IClxoTFWZ6dR1D01s0bQA2/fv1av379mTNngGxgyDEEBQamaDJ3WnMUG7LmG7Bl6HFUm7J3WLF1WjDHKDNmKjP4ybMzMDIvmD8faPNiMAAyoJp9vL2FOJm1ZYTUJPmlhXjiVRiLNRl0+Rl0pQVczfUyw31CvF0ZGBji4uIgTkUJMF9fX04ubh4+fiZmVj4+Pl9Pt96u9rXr1p05f+np8xd37j+8fvNWT0+Pu7v7hw8fkMMcpNnLywtosKiIcHRU1KaNm+4/eACM/ZcvX3z+9PHvnz/Pnz2bPWvW/gP79+zZA/EqMLYRmoOCgpKSki5evAhJA0CJTx8/nj9/vre3t6qq6saNG69evaqurp49ezZQP9BceGoBab5+/TrEJKCrgGYfPXr0yZMnwJg8cuSImpoaExPTzp07gckTmM7y8vJmzJjx8+dPhM2QSLt///706dMbGhpaW1vr6upWrVoFFO/s7NTR0SksLLx165aNjQ3Qd5ycnPPmzYM4EKT55cuXly9f7uvrA+qcCAZAdmlp6fbt24Hu7OjoyMrKcnZ25ubmZgADfn5+YCID6gdmD4Z9+/b19/fn5ubW1tZOB4OmpiZgxAADsrKy0sfHx9DQUENDA+gFLS0tbW1tOTk5oNFAzW/evAEAHjvpTDU8HwgAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;          md 2&apos; title=&apos;&apos; src=&apos;/static/b069162a2c1bd94375fd50600360c444/7f605/%EC%83%9D%EA%B0%81%EB%A7%8C_%ED%95%98%EB%8A%94_%EC%82%AC%EB%9E%8C.md_2.png&apos; srcset=&apos;/static/b069162a2c1bd94375fd50600360c444/08678/%EC%83%9D%EA%B0%81%EB%A7%8C_%ED%95%98%EB%8A%94_%EC%82%AC%EB%9E%8C.md_2.png 190w,
/static/b069162a2c1bd94375fd50600360c444/2edd7/%EC%83%9D%EA%B0%81%EB%A7%8C_%ED%95%98%EB%8A%94_%EC%82%AC%EB%9E%8C.md_2.png 380w,
/static/b069162a2c1bd94375fd50600360c444/7f605/%EC%83%9D%EA%B0%81%EB%A7%8C_%ED%95%98%EB%8A%94_%EC%82%AC%EB%9E%8C.md_2.png 489w&apos; sizes=&apos;(max-width: 489px) 100vw, 489px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[하운즈 게릴라 테스트]]></title><description><![CDATA[인트로 동영상 기자 간담회 플레이 영상 넷마블 기대작 하운즈가 8월 17일 게릴라 테스트를 진행합니다. 테스트는 8월 17일 17시부터 24시까지 진행되구욤. 하운즈 게시판에 글을 올리고 등급…]]></description><link>https://jiniya.net/wp/archives/8646</link><guid isPermaLink="false">https://jiniya.net/wp/archives/8646</guid><pubDate>Thu, 16 Aug 2012 23:58:23 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;인트로 동영상&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;기자 간담회 플레이 영상&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;넷마블 기대작 하운즈가 8월 17일 게릴라 테스트를 진행합니다. 테스트는 8월 17일 17시부터 24시까지 진행되구욤. 하운즈 게시판에 글을 올리고 등급 2티어 이상 달성한 사용자를 대상으로 진행됩니다. 하운즈는 RPS라는 흔치않은 장르의 게임입니다. RPS가 뭐냐구욤? 롤플레잉과 총싸움을 결합한 게임이라고 생각하시면 됩니다. 여튼 어서어서 게시판에 가서 글쓰고 테스트에 참여하도록 합시닷. 마격타임이예욥 핡~ ㅋㅋㅋ&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[스레드 동기화 전략]]></title><description><![CDATA[<리스트 1>에 나와 있는 dec_counter라는 간단한 프로그램에서 이야기를 시작해보자. dec_counter 프로그램은 전역 변수 counter를 감소시키는 스레드를 생성하는 프로그램이다. 코드를 살펴보면 각 스레드는 DEC_LOOP_MAX…]]></description><link>https://jiniya.net/wp/archives/8669</link><guid isPermaLink="false">https://jiniya.net/wp/archives/8669</guid><pubDate>Thu, 16 Aug 2012 23:58:22 GMT</pubDate><content:encoded>&lt;p&gt;&amp;#x3C;리스트 1&gt;에 나와 있는 dec_counter라는 간단한 프로그램에서 이야기를 시작해보자. dec_counter 프로그램은 전역 변수 counter를 감소시키는 스레드를 생성하는 프로그램이다. 코드를 살펴보면 각 스레드는 DEC_LOOP_MAX 만큼 루프를 반복하면서 counter 값을 1씩 감소시키고, 주 스레드는 counter 값을 DEC_LOOP_MAX * DEC_THREAD_MAX로 초기화 한 후에, DEC_THREAD_MAX 개수만큼 감소시키는 스레드를 생성시켜서 동시에 실행되도록 만든다. 이렇게 했을 때 이론적으로는 모든 스레드의 실행이 완료되고 나면 counter 값은 0이 되어야 한다. 과연 그런지 dec_counter 프로그램을 컴파일해서 실행시켜 보도록 하자. 실행할 때에 주의해야 할 점은 반드시 컴파일 최적화 옵션을 꺼야 한다는 점이다. 최적화 옵션을 켜두면 컴파일러가 스레드 코드를 우리가 의도했던 것과는 다른 형태로 변형시키기 때문에 결과가 달라진다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 1 dec_counter 프로그램&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;windows.h&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; DEC_THREAD_MAX &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; DEC_LOOP_MAX &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

ULONG
CALLBACK
&lt;span class=&quot;token function&quot;&gt;DecCounter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;DEC_LOOP_MAX&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;counter&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_tmain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    HANDLE thread&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;DEC_THREAD_MAX&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        counter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; DEC_THREAD_MAX &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; DEC_LOOP_MAX&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ARRAYSIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            thread&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;
                                     &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
                                     &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DecCounter
                                     &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;
                                     &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; CREATE_SUSPENDED
                                     &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ARRAYSIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;ResumeThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ARRAYSIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;WaitForSingleObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; INFINITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;DTM=%d, DLM=%d, counter=%d\n&quot;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DEC_THREAD_MAX
                &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DEC_LOOP_MAX
                &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; counter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;getchar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&amp;#x3C;화면 1&gt;, &amp;#x3C;화면 2&gt;, &amp;#x3C;화면 3&gt;에는 DEC_THREAD_MAX와 DEC_LOOP_MAX를 변경해 가면서 프로그램을 실행한 결과가 나와 있다. 결과 화면에서 제일 먼저 눈에 띄는 사실은 우리의 예상과는 달리 counter 결과가 0이 아닌 경우도 있다는 점이다. 게다가 더 재미있는 점은 DEC_THREAD_MAX와 DEC_LOOP_MAX가 각각 1000과 1000일 때에는 프로그램 실행 중에도 그 때 그 때 결과가 달라지기도 한다는 것이다. 물론 이 모든 결과는 필자가 테스트한 컴퓨터에서의 결과일 뿐이고 여러분의 컴퓨터에서는 또 다른 결과가 나올지도 모른다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 677px; margin-bottom: 16px;&apos; data-url=&apos;./스레드_동기화_전략.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/73dc7a116b104834d566873a2c00bb3f/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 17.36842105263158%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAIAAAAcOLh5AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAi0lEQVR42mOITsrQNzQ2NrM0s7TV0TfWMzLT1jeVU9aQV9GSVdGQV9VSUNWWV9FUVNdRUNMGkkrqukpqWkrq2qUNvQxObp4c7GwCAgLCwkI83Nz8/HycnJwMuAEjIyOQBGpp7uhl8PYL5ObiEhYWERMX5+PjExYW5uXlhSjCCpiYmICy7OxsU2bMBgB+zBLrupgP9wAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;           md 0&apos; title=&apos;&apos; src=&apos;/static/73dc7a116b104834d566873a2c00bb3f/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_0.png&apos; srcset=&apos;/static/73dc7a116b104834d566873a2c00bb3f/08678/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_0.png 190w,
/static/73dc7a116b104834d566873a2c00bb3f/2edd7/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_0.png 380w,
/static/73dc7a116b104834d566873a2c00bb3f/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_0.png 677w&apos; sizes=&apos;(max-width: 677px) 100vw, 677px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;화면 1 100×100 실행 결과&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 677px; margin-bottom: 16px;&apos; data-url=&apos;./스레드_동기화_전략.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/8daf4fce120f305104de951573aaf772/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 28.947368421052634%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA8ElEQVR42o2OwUrDQBRFJ6Jpk8mkcTIzb96kKrjQn3WTYtVaSi0iKtWCEqXuailBrF3Y/EFdaP/C0ayLXs7iweNwL8lGs2FePEyKwai4fS76+eL65bP/+mW5mS6v8o+jbN64e7ekg7eT+9n54/QyGz91uu2DlCgpk/oWYlLf3omFBG2E0j5lnh+UuFXPrfgVj264VYs91tbd3b394+4FqYVMKSVErAEYY5vRTxzHIStSvhB12myRKKoBgJQSEa0shAiCgKxOKRvE006PxJxLaZsF/DZzzimlf8pJYg7bPQIyBtB2uTEmDEM74Z9yo3X2DZyWP7EJMWWDAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;           md 1&apos; title=&apos;&apos; src=&apos;/static/8daf4fce120f305104de951573aaf772/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_1.png&apos; srcset=&apos;/static/8daf4fce120f305104de951573aaf772/08678/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_1.png 190w,
/static/8daf4fce120f305104de951573aaf772/2edd7/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_1.png 380w,
/static/8daf4fce120f305104de951573aaf772/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_1.png 677w&apos; sizes=&apos;(max-width: 677px) 100vw, 677px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;화면 2 1000×1000 실행 결과&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 677px; margin-bottom: 16px;&apos; data-url=&apos;./스레드_동기화_전략.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/2cff4edd9adc70aa9ef4f88b5b044568/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 16.842105263157894%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAIAAAAcOLh5AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAlElEQVR42mOYPG9V77T5k+eumLxgTc+sFW3Tl7fO3tgxf2vL7I3109Y0TF8LR43T1zbPXNc1e01x44ScjJKmhj4Gn8AwXh5uCQlJFVVVaWlpYWFhcXFxWVlZLi4uBmyAkZERSLKzc9S19TK4e/lxcXKIiIoCNYiJifHx8QkKCkpISHBwcECUogEmJiagOAcbW9+EKQAxrywZVYH1XAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;           md 2&apos; title=&apos;&apos; src=&apos;/static/2cff4edd9adc70aa9ef4f88b5b044568/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_2.png&apos; srcset=&apos;/static/2cff4edd9adc70aa9ef4f88b5b044568/08678/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_2.png 190w,
/static/2cff4edd9adc70aa9ef4f88b5b044568/2edd7/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_2.png 380w,
/static/2cff4edd9adc70aa9ef4f88b5b044568/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_2.png 677w&apos; sizes=&apos;(max-width: 677px) 100vw, 677px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;화면 3 10×100000 실행 결과&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/08/image003.png&quot;&gt;&lt;img src=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/08/image003.png&quot; alt=&quot;&quot; title=&quot;image003&quot;&gt;&lt;/a&gt;
dec_counter 프로그램은 동기화 문제의 가장 큰 특징인 비결정론적인 성질을 잘 보여주고 있다. 비결정론적 성질이란 프로그램이 항상 동일하게 동작하는 것이 아니라 실행 환경에 따라서 동작이 달라지는 것을 말한다. 즉, 진짜로 프로그램이 그 때 그 때 다르게 동작한다는 말이다. 그래서 이런 성격의 동기화 문제는 재현하기도 쉽지 않을뿐더러 관찰하기는 더 어렵다. 이런 점 때문에 동기화 문제는 신입 개발자들에게 거짓말을 시키는 가장 대표적인 버그 중에 하나다.&lt;/p&gt;
&lt;p&gt;동기화 문제가 다루기 어려운 첫 번째 이유는 발생 확률이 낮아서 재현하기가 쉽지 않다는 점에 있다. 만약 여러분의 프로그램이 dec_counter 프로그램의 100×100 정도에 맞먹는 확률로 문제가 발생하는 코드를 가지고 있다면 아마 그 코드는 여러분의 QA팀 테스트 및 사내 테스트를 모두 무사히 통과할 것이다. 하지만 릴리즈하는 순간 고객들에게 프로그램이 정상적으로 동작하지 않는다는 이야기를 듣게 될 것이다. 고객의 클레임을 듣고 문재를 발생시키려고 시도해보아도 쉽지 않다. 왜냐하면 발생 확률이 극히 낮기 때문이다. 이런 어려움 때문에 고객 PC를 직접 디버깅하려고 한들 그것 또한 쉽지 않다. 고객 PC에서도 항상 100% 문제가 동일하게 발생하는 것은 아니기 때문이다.&lt;/p&gt;
&lt;p&gt;동기화 문제가 어려운 두 번째 이유는 동기화 버그를 관찰하려는 시도 자체가 문제를 소멸시키는 성질을 가지고 있다는 점 때문이다. 동기화 문제는 가장 직접적인 디버깅 방법인 코드 트레이싱을 통해서는 문제 원인을 추적할 수 없으며, OutputDebugString 같은 아주 사소한 관찰 기법들이 코드에 추가되더라도 문제가 사라질 수도 있다. 실제로 dec_counter 프로그램의 ResumeThread 다음에 OutputDebugString이나 Sleep과 같은 구문을 넣게 되면 &amp;#x3C;화면 4&gt;에 나타난 것처럼 문제가 사라진 것처럼 보여지게 만들기도 한다. 이런 이유 때문에 신입 개발자들은 곧잘 와서는 “OutputDebugString을 추가하니까 잘 됩니다”, 내지는 “Sleep을 좀 줬더니 버그가 사라졌습니다”같은 이야기를 하는 것이다. 사실 그건 버그를 사라지게 만든 것이 아니라 단순히 재현 확률을 낮췄을 뿐인데도 말이다. 천만 분의 일의 확률로 발생되는 문제를 억만 분의 일로 낮추어 본들 문제가 사라진 것은 아니다. 언젠가 어떤 환경에서 그 문제는 다시 발생할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 677px; margin-bottom: 16px;&apos; data-url=&apos;./스레드_동기화_전략.md_3.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/0e51435cc605216a5e2290ec39e94955/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 18.421052631578945%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAoklEQVR42mPYffzy3lM39p6+tfPUnQ2Hrmw6/WTTxY9rz7xGQ+vOvll04P7kdad6VxzuW7xrxrLt6yZPZ5CTk1NWUdXVMzAyNpWWlVdR01DV0BISFcdEgsJivALCfALC/IIiPPxCUrLyDKwszPz8/GJiYhISEpwcHLw8PDzc3Ax4ASMjI5Dk4eZiYGNlFRQUBOqUkpICagSy+fj4iNHMy8MDAI4ANkR9VPhpAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;           md 3&apos; title=&apos;&apos; src=&apos;/static/0e51435cc605216a5e2290ec39e94955/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_3.png&apos; srcset=&apos;/static/0e51435cc605216a5e2290ec39e94955/08678/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_3.png 190w,
/static/0e51435cc605216a5e2290ec39e94955/2edd7/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_3.png 380w,
/static/0e51435cc605216a5e2290ec39e94955/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EB%8F%99%EA%B8%B0%ED%99%94_%EC%A0%84%EB%9E%B5.md_3.png 677w&apos; sizes=&apos;(max-width: 677px) 100vw, 677px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;화면 4 Sleep을 적용한 10×100000 실행 결과&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;그렇다면 이렇게 다루기 어려운 동기화 문제는 왜 발생하는 것일까? 또 이 문제를 해결하기 위한 방법들에는 어떤 것들이 있을까? 직접 만들지 않은 함수나 라이브러리가 잠재적으로 이런 동기화 문제가 발생할 수 있는지 없는지 사전에 알 수 있는 방법은 없을까? 지금부터 이 질문에 대한 해답을 찾아보도록 하자.&lt;/p&gt;
&lt;p&gt;counter 값이 이상해진 이유&lt;/p&gt;
&lt;p&gt;우리가 사용한 C 코드의 –counter라는 구문은 실제로 CPU 명령어로 번역되면 &amp;#x3C;리스트 2&gt;에 나타난 것과 같이 3개의 명령어로 구성된다. 각 명령어는 counter가 저장된 메모리의 값을 레지스터로 복사하고, 레지스터 값을 1 감소 시키고, 그 감소된 값을 다시 counter가 저장된 메모리에 기록하는 일을 한다. &amp;#x3C;표 1&gt;에는 counter 값이 2인 상황에서 세 개의 명령어를 두 개의 스레드에서 한 번씩 수행할 때에 실행 순서에 따라서 어떤 결과가 나타나는지가 나와 있다. 제일 먼저 나온 실행 순서가 우리가 일반적으로 생각하게 되는 순서다. 이 경우에는 당연히 결과는 우리가 예상한대로 0이 나온다. 반면 두 번째, 세 번째 실행 순서를 보면 실행 순서가 조금 바뀌었을 뿐인데 결과는 우리가 예상하지 않았던 1이 나오는 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;counter 값이 이상해진 이유도 바로 여기에 있다. &amp;#x3C;표 1&gt;에 나타난 것과 같이 실행 순서가 일반적인 경우도 있고, 결과가 이상해지는 경우도 있는 것이다. 실행 순서가 모두 우리가 예상한 일반적인 실행 흐름과 100% 똑같다면 정상적인 결과가 나오게 되는 것이고, 조금이라도 달라졌다면 예측하지 못했던 결과가 나오게 되는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 2 –counter에 대한 어셈블리 명령어&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;mov ecx, dword ptr [counter]
sub ecx, 1
mov dword ptr [counter], ecx
mov ecx, dword ptr [counter]
sub ecx, 1
mov dword ptr [counter], ecx	
---
counter = 0

mov ecx, dword ptr [counter]
mov ecx, dword ptr [counter]
sub ecx, 1
sub ecx, 1
mov dword ptr [counter], ecx
mov dword ptr [counter], ecx	
---
counter = 1

mov ecx, dword ptr [counter]
sub ecx, 1
mov ecx, dword ptr [counter]
sub ecx, 1
mov dword ptr [counter], ecx
mov dword ptr [counter], ecx
---
counter = 1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;원자적 연산 (atomic operation)&lt;/p&gt;
&lt;p&gt;앞서 우리는 –counter라는 구문이 실제로 어셈블리어로는 3개의 명령어로 구성돼 있고, 그 명령어의 실행 순서가 엉키면서 값의 상태가 이상해진다는 것을 배웠다. 그렇다면 3개의 명령어가 아닌 하나의 명령어로 만들면 문제가 사라지지 않을까? 이런 관점에서 동기화 문제에 접근하는 방식이 ‘원자적 연산’이다. 번역해 놓으니 단어가 좀 이상한데 ‘원자적 연산’이란 특정 연산이 한번에 수행된다는 의미를 가진다. 즉, 연산 수행 도중에 동일한 연산이 중첩돼서 실행될 수 없다는 것을 의미한다.&lt;/p&gt;
&lt;p&gt;그렇다면 앞서 살펴본 3개의 어셈블리 명령어를 하나로 만들면 원자적 연산이 되는 것일까? 우리가 흔히 사용하는 인텔의 x86 CPU에는 –counter를 한번에 수행할 수 있는 dec라는 어셈블리 명령어가 존재한다. dec dword ptr [counter]와 같이 사용하면 위 3개의 명령어가 하는 일과 동일한 기능을 수행할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 3 –counter를 하나의 인스트럭션으로 변경한 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;ULONG CALLBACK &lt;span class=&quot;token function&quot;&gt;DecCounter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;DEC_LOOP_MAX&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        __asm dec dword ptr &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;counter&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&amp;#x3C;리스트 3&gt;에는 이렇게 스레드 코드를 하나의 어셈블리 명령어로 고친 것이 나와 있다. 실행을 해보면 여러분의 시스템에 따라서 정상적이기도 하고 정상이 아니기도 한 현상이 발생할 것이다. 이 접근은 반쯤만 원자적인 방법이기 때문이다. 우리가 사용한 이 방법은 시스템이 싱글코어라면 원자성이 보장되지만 멀티코어라면 원자성이 보장되지 않는다. 멀티코어에서는 단일 명령인 dec 명령어 조차도 물리적으로 두 개 이상의 CPU에서 동시에 실행될 수 있기 때문이다. 참고로 멀티코어 환경에서 싱글코어와 동일한 상황의 테스트를 해보고 싶다면 dec_counter 프로그램에서 CreateThread 다음에 SetThreadAffinityMask 함수를 사용해서 모든 스레드가 한 CPU에서만 실행되도록 만들면 된다.&lt;/p&gt;
&lt;p&gt;그렇다면 친화도를 조절하지 않고 멀티코어 환경에서 원자성을 보장할 수 있는 방법은 없을까? 물론 있다. 멀티코어 CPU를 설계한 사람들도 이러한 문제점을 충분히 알고 있었기 때문에 멀티코어 환경에서 원자성을 보장할 방법을 마련해 두었다. x86 CPU에서는 dec 명령어 앞에 lock을 붙여줌으로써 그런 일을 할 수 있다. &amp;#x3C;리스트 3&gt;의 코드에 lock을 붙여서 컴파일하고 실행해보면 코어 개수에 상관 없이 어떠한 환경에서든 정상적으로 실행 결과가 나타나는 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;윈도우는 이러한 어셈블리 명령어를 손쉽게 사용할 수 있도록 원자성이 보장되는 API들을 만들어서 제공해 주고 있다. &amp;#x3C;표 2&gt;에는 이러한 Interlocked 함수 중에서 자주 사용되는 함수들의 이름과 그 함수가 어떠한 동작을 한번에 하는지가 나와 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;표 2 자주사용하는 Interlocked 함수들&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;LONG __cdecl &lt;span class=&quot;token function&quot;&gt;InterlockedExchange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  __inout  LONG &lt;span class=&quot;token keyword&quot;&gt;volatile&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;Target&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  __in     LONG Value
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;	

LONG Old &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;Target&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;Target &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Old

&lt;span class=&quot;token comment&quot;&gt;///&lt;/span&gt;

LONG __cdecl &lt;span class=&quot;token function&quot;&gt;InterlockedExchangeAdd&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  __inout  LONG &lt;span class=&quot;token keyword&quot;&gt;volatile&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;Addend&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  __in     LONG Value
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

LONG Old &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;Target&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;Target &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; Value&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Old

&lt;span class=&quot;token comment&quot;&gt;///&lt;/span&gt;

LONG __cdecl &lt;span class=&quot;token function&quot;&gt;InterlockedCompareExchange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  __inout  LONG &lt;span class=&quot;token keyword&quot;&gt;volatile&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;Destination&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  __in     LONG Exchange&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  __in     LONG Comparand
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;	

LONG Old &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;Target&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;Target &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; Comparand&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;Target &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Exchange&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Old&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;///&lt;/span&gt;

LONG __cdecl &lt;span class=&quot;token function&quot;&gt;InterlockedDecrement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  __inout  LONG &lt;span class=&quot;token keyword&quot;&gt;volatile&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;Addend
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;	

&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;Target&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;Target

&lt;span class=&quot;token comment&quot;&gt;///&lt;/span&gt;

LONG __cdecl &lt;span class=&quot;token function&quot;&gt;InterlockedIncrement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
  __inout  LONG &lt;span class=&quot;token keyword&quot;&gt;volatile&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;Addend
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;	

&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;Target&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;Target&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;바쁜 대기 (busy waiting)&lt;/p&gt;
&lt;p&gt;동기화 이슈를 피하기 위한 다른 방법으로는 바쁜 대기가 있다. 바쁜 대기란 자신이 공유 데이터에 접근할 수 있는지를 수시로 체크하는 것을 말한다. &amp;#x3C;리스트 4&gt;에는 DecCounter 스레드를 바쁜 대기를 사용해서 동기화 시킨 코드가 나와 있다. counter 변수 업데이트 전후로 can_update 값을 변경하고, counter 변수에 접근하기 전에 can_update가 접근 가능한 상태로 되어 있는지를 검사하고 있다. 이렇게 할 경우에 이론적으로는 동시에 하나의 스레드만 counter 변수 값을 변경할 수 있기 때문에 counter 값이 이상해지는 문제를 피할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 4 바쁜 대기를 사용한 동기화&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;LONG can_update &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

ULONG CALLBACK &lt;span class=&quot;token function&quot;&gt;DecCounter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;DEC_LOOP_MAX&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;can_update&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        can_update &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;counter&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        can_update &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&amp;#x3C;리스트 4&gt;의 코드는 바쁜 대기의 기본적인 개념을 보여주기 위한 코드다. 실제로 해당 코드를 사용해서 스레드를 돌려보면 여전히 결과가 이상한 것을 볼 수 있는데 이는 바쁜 대기에 사용된 can_update 변수 조작에 원자적 연산이 사용되지 않았기 때문이다. &amp;#x3C;리스트 5&gt;에는 원자적 연산을 이용해서 바쁜 대기를 완전하게 만든 코드가 나와 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 5 원자적 연산을 사용한 바쁜 대기&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;LONG can_update &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

ULONG CALLBACK &lt;span class=&quot;token function&quot;&gt;DecCounter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;DEC_LOOP_MAX&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;InterlockedCompareExchange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;can_update&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;counter&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;InterlockedExchange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;can_update&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;dec_counter 프로그램의 경우에는 공유 자료에 접근하는 코드가 워낙 간단하고(–counter), 해당 연산 자체를 원자적 연산으로 바꾸는 것이 가능해서 바쁜 대기를 사용하는 의도가 불분명하지만 현실세계에서의 복잡한 연산을 단일화 하는 데에는 가장 손쉽고, 금방 떠오르는 방법이기 때문에 바쁜 대기는 의외로 자주 사용되기도 한다. 하지만 바쁜 대기는 멀티코어 환경이든 싱글코어 환경이든 프로그램이 의미 있는 코드를 수행하는데 보내는 시간보다 바쁜 대기를 위한 루프를 반복하는 곳에 CPU 자원을 더 많이 소모하게 된다는 치명적인 단점이 있기 때문에 가급적 사용하지 않는 것이 좋다.&lt;/p&gt;
&lt;p&gt;잠금 (Lock)&lt;/p&gt;
&lt;p&gt;동기화 문제를 해결하는 가장 일반적인 방법은 운영체제에서 지원하는 잠금 장치를 사용하는 것이다. 잠금 장치는 특정 코드 영역이 여러 곳에서 동시에 실행되지 않도록 만드는 일을 한다. 윈도우에서는 이런 목적을 위해서 크리티컬 섹션, 뮤텍스, 세마포와 같은 다양한 방법을 지원해준다. &amp;#x3C;리스트 6&gt;에는 크리티컬 섹션을 사용해서 –counter가 한번에 하나의 스레드만 실행되도록 만든 코드가 나와 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 6 크리티컬 섹션을 사용한 동기화&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;CRITICAL_SECTION cs&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

ULONG CALLBACK &lt;span class=&quot;token function&quot;&gt;DecCounter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;DEC_LOOP_MAX&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;EnterCriticalSection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;counter&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;LeaveCriticalSection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;잠금 장치의 경우에는 운영체제의 스케줄러와 밀접하게 연계되어 있다. 운영체제는 각 잠금 장치의 상태를 추적할 수 있기 때문에 특정 잠금 장치를 사용할 수 없는 상황에서 스레드가 해당 자원을 요청하면 요청한 스레드를 대기 상태로 만든다. 대기 상태로 만든다는 것은 해당 잠금 장치가 사용 가능해질 때까지 해당 스레드가 CPU 자원을 소모하지 않는다는 것을 의미한다. 이런 특징 때문에 바쁜 대기에서 살펴본 것과 같이 자원 획득을 위한 검사 루프에 CPU 자원이 소모하는 일이 없다.&lt;/p&gt;
&lt;p&gt;그렇다면 잠금 장치를 사용하는 것이 모든 동기화 문제를 해결하는 가장 좋은 방법일까? 그렇지는 않다. 우선 잠금 장치는 특정 코드가 동시에 실행되는 것을 제한하는 기법이기 때문에 멀티코어의 성능을 해치는 결과를 초래한다. 즉, 잠금 장치가 많으면 많을수록 CPU 개수가 증가해도 얻을 수 있는 이득이 없다는 말이다.&lt;/p&gt;
&lt;p&gt;윈도우 커널의 경우에도 내부적으로 디스패처 락이라는 전역 락이 존재한다. 커널 내부의 중요한 함수들은 모두 해당 락을 획득한 다음 작업을 진행하도록 되어 있는데 CPU 개수가 몇 개 안될 때는 문제가 되지 않았는데 CPU 개수가 늘어나면 늘어날수록 대부분의 스레드들이 디스패처 락을 획득하기 위해서 대기하는 상태로 노는 문제가 발생했다. Windows 7부터는 이런 문제점을 해결하기 위해서 디스패처 락의 구조를 변경했고, 그런 개선을 통해서 멀티코어에서의 가용성이 상당히 높아졌다고 한다.&lt;/p&gt;
&lt;p&gt;최근에는 CPU 개수가 지속적으로 증가하는 추세이기 때문에 이러한 CPU 규모 가변성에 대응하기 위해서는 잠금 장치보다는 앞서 살펴본 원자적 연산을 사용한 무잠금 알고리즘들이 활발하게 개발되고 있다.&lt;/p&gt;
&lt;p&gt;버퍼 분리&lt;/p&gt;
&lt;p&gt;동기화 문제의 근본적인 원인은 여러 개의 스레드가 동일한 버퍼에 동시에 접근하려는 것에 있다. 지금까지 소개한 해결책은 모두 ‘동시에’라는 부분에 집중한 방법이었다. 반대로 ‘동일한’이란 말에 집중해서 동기화 문제를 해결할 수도 있다. 공유해서 접근하는 버퍼가 정말 공유되어야 하는 성질의 것인지에 대해서 다시 한번 생각해 보자는 것이다. 그리고 정말 공유할 필요가 없는 것이라면 그것을 분리함으로써 동기화 이슈를 완전히 제거할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;리스트 7&gt;에는 srand, rand 함수의 일반적인 구현이 나와 있다. 코드를 살펴보면 두 함수 모두 전역 변수인 gseed 값을 갱신하는 것을 볼 수 있다. 따라서 이 구현은 다중 스레드에서 호출될 경우에 문제점이 있다고 할 수 있다. 왜냐하면 앞선 counter 예제와 똑같이 rand 함수 호출에 따라서 gseed 값이 불안정한 상태가 될 수 있기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 7 일반적인 srand, rand 함수의 구현&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; gseed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;srand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; seed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    gseed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; seed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;gseed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; gseed &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;214013L&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2531011L&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x7fff&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이러한 문제점을 해결하기 위해서는 앞서 언급했던 원자적 접근이나 잠금을 사용할 수 있다. 하지만 rand 함수의 구조를 살펴보면 사실 gseed 값은 전혀 스레드 별로 공유해야만 하는 성질의 것이 아님을 알 수 있다. 왜냐하면 완전히 독립적으로 움직이는 변수이기 때문이다.&lt;/p&gt;
&lt;p&gt;따라서 이 경우에는 원자적 접근이나 잠금을 사용하는 것보다는 gseed라는 버퍼를 스레드 별로 분리하는 것이 좋은 방법이다. 그런 방법 중에 하나는 우리가 지난 연재에서 살펴보았던 스레드 지역 저장소가 있다. 스레드 지역 저장소를 사용하면 &amp;#x3C;리스트 7&gt;의 코드를 거의 고치지 않고도 버퍼를 바로 분리할 수 있기 때문이다. 실제로 다양한 컴파일러에 포함된 멀티 스레드용 CRT 코드는 이러한 기법을 사용해서 srand와 rand 함수를 스레드 안전한 함수로 구현하고 있다.&lt;/p&gt;
&lt;p&gt;스레드에 안전한 함수(Thread Safe Function)&lt;/p&gt;
&lt;p&gt;동기화 문제가 점점 더 큰 이슈로 부각되면서 프로그래머 사이에는 동기화 이슈의 발생 가능성에 대해서 사전에 예고할 수 있는 장치가 필요했다. 그래서 나온 말이 ‘스레드에 안전한(Thread Safe)’라는 말이다. 스레드에 안전한 함수란 여러 개의 스레드에서 해당 함수를 무작위적으로 마구 호출해도 전혀 문제가 되지 않는 함수를 말한다. 반대로 스레드에 안전하지 않은 함수란 두 개 이상의 스레드에서 호출하면 부작용이 발생할 수 있는 함수를 의미한다.&lt;/p&gt;
&lt;p&gt;일반적으로 요즘은 멀티 스레드 환경이 일반적이기 때문에 별다른 주의가 없으면 대부분의 함수는 스레드에 안전한 것으로 간주된다. 자신이 작성한 함수가 스레드에 안전하지 않고, 다른 개발자가 사용할 가능성도 있다면 관련 문서에 해당 함수가 스레드에 안전하지 않다는 내용을 표시해 주는 것이 좋겠다.&lt;/p&gt;
&lt;p&gt;새롭게 제작되는 함수라면 가급적 인터페이스를 스레드에 안전하게 만드는 것이 좋다. 앞서 &amp;#x3C;리스트 7&gt;에서 살펴본 rand 함수의 구현은 스레드에 안전하지 않은 함수였다. 그것을 대부분의 CRT에서는 스레드 지역 저장소를 사용해서 스레드에 안전한 함수로 제작한다는 것도 배웠다. CRT에서 스레드 지역 저장소를 사용한 이유는 rand 함수의 프로토타입을 변경할 수 없기 때문이다. 만약 rand 함수의 프로토타입을 변경할 수 있다면 &amp;#x3C;리스트 8&gt;과 같이 전역 변수에 대한 의존성 자체를 제거해서 스레드에 안전한 함수로 만드는 것이 좋다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 8 스레드에 안전한 rand 함수&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;seed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;seed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;seed &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;214013L&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2531011L&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;seed &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x7fff&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;재진입 가능한 함수(Reentrant Function)&lt;/p&gt;
&lt;p&gt;끝으로 재진입 가능한 함수에 대해서 알아보자. 재진입이라는 말은 말 그대로 함수 내부로 다시 진입하는 것을 의미한다. ‘다시’라는 말이 의미하듯이 함수 코드가 처리되는 와중에도 다시 함수 내부로 진입됨을 의미한다.&lt;/p&gt;
&lt;p&gt;윈도우 프로시저는 흔히 재진입 가능한 함수라고 표현된다. 이 내용을 보통 신입 개발자들은 &amp;#x3C;리스트 9&gt;와 같은 간단한 메시지 처리 루틴에서 WM_PAINT 메시지가 처리되는 동안 Sleep 상태일 때에도 키보드가 눌리면 다시 MyWindowProcedure가 실행되어 WM_KEYDOWN 이벤트가 처리되는 것이라고 생각한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 9 간단한 메시지 처리 루틴&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;LRESULT CALLBACK &lt;span class=&quot;token function&quot;&gt;MyWindowProcedure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HWND Window&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; UINT MsgId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WPARAM W&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPARAM L&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MsgId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WM_PAINT&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WM_KEYDOWN&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;OutputDebugStringA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;WM_KEYDOWN&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DefWindowProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Window&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MsgId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; W&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;하지만 이는 잘못된 생각이다. 실제로 테스트해 보면 알겠지만 Sleep 상태인 동안에 키를 아무리 눌러본들 디버그 메시지는 출력되지 않는다. 이유는 무엇일까? 답은 메시지를 처리하는 방법에 있다. 일반적으로 많은 윈도우 개발 입문서에서 메시지 프로시저를 운영체제가 알아서 호출해 주는 것처럼 설명하지만 실제로 운영체제는 메시지 프로시저를 호출하는 일은 하지 않는다. 해당 일은 &amp;#x3C;리스트 10&gt;에 나타난 것과 같은 메시지 처리 루틴에 의해 이뤄진다. DispatchMessage 함수 내부에서 해당 윈도우에 맞는 메시지 프로시저를 찾아서 호출되는 일이 진행된다. 따라서 해당 메시지 처리가 완료되어서 다음 GetMessage가 호출되기 전까지 메시지 프로시저는 새로운 것을 처리하고 싶어도 할 수 없는 상태인 것이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 10 메시지 처리 루틴&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;Msg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;TranslateMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;Msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;DispatchMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;Msg&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;재진입이란 말이 실제로 하고자 했던 이야기는 윈도우 프로시저는 스레드에 안전하며 병렬적으로 호출이 가능하도록 작성되어야 한다는 것을 나타낸다. &amp;#x3C;리스트 11&gt;과 &amp;#x3C;리스트 12&gt;를 보면 무슨 의미인지가 분명해진다. &amp;#x3C;리스트 11&gt;의 코드는 한 스레드에서 윈도우가 실행될 때와 두 스레드에 윈도우가 실행될 때 동작이 달라진다. 윈도우 의존적으로 처리되어야 하는 데이터가 정적 변수로 되어 있어서 다른 윈도우의 동작에까지 영향을 미치기 때문이다. &amp;#x3C;리스트 12&gt;의 코드는 윈도우 프로시저가 글로벌 크리티컬 섹션에 묶여 있어서 한 스레드의 메시지가 처리되는 동안에 다른 스레드에서 생성한 윈도우는 함수 내부로 진입하지 못하는 문제가 발생한다. 서로 다른 스레드의 윈도우는 상호 동작에 간섭을 받지 않아야 함에도 이 메시지 프로시저는 한 스레드의 메시지 프로시저가 완료되기 전까지는 다른 스레드의 메시지 프로시저가 처리될 수 없게 됨으로써 서로 원활하게 동시 실행이 처리되지 못하는 문제가 있다는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 11 스레드에 안전하지 않은 메시지 프로시저&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;LRESULT CALLBACK &lt;span class=&quot;token function&quot;&gt;MyWindowProcedure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HWND Window&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; UINT MsgId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WPARAM W&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPARAM L&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; Count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MsgId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
　　&lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WM_KEYDOWN&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
　　　　&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;Count&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
　　　　&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Count &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
　　　　　　&lt;span class=&quot;token function&quot;&gt;OutputDebugStringA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;“WM_KEYDOWN”&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
　　　　　　&lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DefWindowProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Window&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MsgId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; W&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 12 병렬적으로 호출이 불가능한 메시지 프로시저&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;LRESULT CALLBACK &lt;span class=&quot;token function&quot;&gt;MyWindowProcedure&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HWND Window&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; UINT MsgId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WPARAM W&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPARAM L&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;EnterCriticalSection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;GlobalCs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MsgId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
　　&lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WM_KEYDOWN&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;OutputDebugStringA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;“WM_KEYDOWN”&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;LeaveSection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;GlobalCs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DefWindowProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Window&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MsgId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; W&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;재진입 가능한 함수란 &amp;#x3C;리스트 11&gt;이나 &amp;#x3C;리스트 12&gt;에 나타난 것과 같은 문제가 없어야 함을 말한다. 결국 이는 스레드에 안전한 함수보다 더 좁은 개념으로 기본적으로 스레드에 안전하면서 멀티 스레드 환경에서 잠금으로 인한 성능상의 이슈도 없어야 한다는 것을 의미한다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[큐리오시티]]></title><description><![CDATA[얼마 전 올림픽 뉴스에 가려서 크게 보도되지는 않았지만 NASA…]]></description><link>https://jiniya.net/wp/archives/8604</link><guid isPermaLink="false">https://jiniya.net/wp/archives/8604</guid><pubDate>Mon, 13 Aug 2012 23:58:21 GMT</pubDate><content:encoded>&lt;p&gt;얼마 전 올림픽 뉴스에 가려서 크게 보도되지는 않았지만 NASA의 큐리오시티가 화성에 착륙하는 이벤트가 있었습니다. 뭐 화성에 로보트를 보낸 게 처음은 아니지만 그래도 이렇게 또 보낸다는 건 말로 표현하기 힘들 정도로 대단한 것 같습니다. 이런 과학자들이 있기에 우리가 지금처럼 편리한 생활을 할 수 있는게 아니겠습니까? ㅋㅋ&lt;/p&gt;
&lt;p&gt;큐리오시티 착륙을 지켜보는 NASA 직원들을 보니 참 대단하다는 생각이 듭니다. 저같으면 저걸 차마 눈뜨고는 못 볼 거 같은데 말이죠. ㅋ~ 혹시나 내가 관여한 부분에서 오류가 나서 이 거대한 프로젝트가 실패할까봐서 말이죠 ㅋㅋ~ 우주선이 분리되지 않는다거나, 낙하산이 펼쳐지지 않는다거나, 커버가 떨어지지 않는다거나, 로보트를 연결한 부분이 끊어졌다거나 ㅋㅋㅋ~ 생각만해도 아찔하지 않나요?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://science.dongascience.com/articleviews/special-view?acIdx=11856&amp;#x26;acCode=1&amp;#x26;year=2012&quot;&gt;큐리오시티 관련 과학동아 기사&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://mars.jpl.nasa.gov/&quot;&gt;NASA 화성 탐사 프로젝트&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;직업이 직업인지라 동영상에서 500,000 LINES OF COD3. ZERO MARGIN OF ERROR. 라는 문구만 눈에 확 들어오는 군요. 이런 극도로 미션 크리티컬한 코드를 작성하는 사람들은 어떤 사람들인지 참 궁금합니다. 동영상을 보면서 느낀건데 탐사 로봇을 보내는 것 자체도 대단한 일이지만 일반인에게 자신들이 하는 일을 어필할 수 있는 동영상을 제작해서 발표하는 일도 NASA가 참 잘한다는 생각이 듭니다. 영상이 왠만한 영화보다 더 멋지네요. ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;예전에 어떤 다큐에서 본 것 같은데 화성을 나중에는 &lt;a href=&quot;http://en.wikipedia.org/wiki/Terraforming_of_Mars&quot;&gt;지구형 행성으로 개조하는&lt;/a&gt; 프로젝트를 진행할 수도 있다고 합니다. 테라포밍이라고 하는데요. 작금의 현실을 보니 정말 불가능한 일은 아닐거 같다는 생각도 드는군요. 후훗 2020 원더키디가 생각나는 지점입니다. 그러고보니 2020도 몇 년 남지도 않았네요 헐~&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./큐리오시티.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/935ba0bb9d410e075f16c030f856a8ad/e224a/%ED%81%90%EB%A6%AC%EC%98%A4%EC%8B%9C%ED%8B%B0.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 56.315789473684205%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIDAf/EABYBAQEBAAAAAAAAAAAAAAAAAAMBAv/aAAwDAQACEAMQAAABWNJ4qmin/8QAHBAAAQQDAQAAAAAAAAAAAAAAAgABETEDEiEi/9oACAEBAAEFAphHl1TemGj6LV//xAAVEQEBAAAAAAAAAAAAAAAAAAAAAf/aAAgBAwEBPwFX/8QAFREBAQAAAAAAAAAAAAAAAAAAAAH/2gAIAQIBAT8BiP/EABgQAAMBAQAAAAAAAAAAAAAAAAABERAh/9oACAEBAAY/AhcEyiuf/8QAGxAAAgIDAQAAAAAAAAAAAAAAAAERUSExQWH/2gAIAQEAAT8hcjVMukjuFalUbehImRo8wf/aAAwDAQACAAMAAAAQHz//xAAXEQEBAQEAAAAAAAAAAAAAAAABACEx/9oACAEDAQE/EHELq//EABcRAQEBAQAAAAAAAAAAAAAAAAEAESH/2gAIAQIBAT8Qwiw4X//EABoQAQACAwEAAAAAAAAAAAAAAAEAESExQVH/2gAIAQEAAT8Qa/2HkSgTvqjHkXmRVZ6+QCks9cwCAHlVMrg2GNAtT//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;      md 0&apos; title=&apos;&apos; src=&apos;/static/935ba0bb9d410e075f16c030f856a8ad/e224a/%ED%81%90%EB%A6%AC%EC%98%A4%EC%8B%9C%ED%8B%B0.md_0.jpg&apos; srcset=&apos;/static/935ba0bb9d410e075f16c030f856a8ad/8ccab/%ED%81%90%EB%A6%AC%EC%98%A4%EC%8B%9C%ED%8B%B0.md_0.jpg 190w,
/static/935ba0bb9d410e075f16c030f856a8ad/ea4c8/%ED%81%90%EB%A6%AC%EC%98%A4%EC%8B%9C%ED%8B%B0.md_0.jpg 380w,
/static/935ba0bb9d410e075f16c030f856a8ad/e224a/%ED%81%90%EB%A6%AC%EC%98%A4%EC%8B%9C%ED%8B%B0.md_0.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;진정한 과학자라면 이 정도는 입어줘야 합니다.&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[한류 열풍의 불편한 진실: 애들이나 하는 게임?]]></title><description><![CDATA[약간은 씁쓸한 보통 사람의 게임에 대한 인식 김성주씨보다 카트라이더를 아는 사람이 더 많을지도 모른답니다 ㅠㅜ~ 얼마 전 흥했던 한 트윗입니다. 세대공감 1억 퀴즈쇼의 400…]]></description><link>https://jiniya.net/wp/archives/8297</link><guid isPermaLink="false">https://jiniya.net/wp/archives/8297</guid><pubDate>Mon, 23 Jul 2012 23:58:20 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 445px; margin-bottom: 16px;&apos; data-url=&apos;./한류_열풍의_불편한_진실_애들이나_하는_게임.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a515d2bbd6b9e172aa2067cee2c425f9/a6969/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 80%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAIAAACZeshMAAAACXBIWXMAAA7DAAAOwwHHb6hkAAADh0lEQVR42mN4++blvXt3X7x4fuvWjWfPnr598/rp00cvXr78TwRgeP36+/PnX1+8+PHwwefnz7+8evn92bMvT558f/Xq/4cP/9+/+//ixf8PH3FofgmUe///7dt/L8CM9+//P38OIoHir17+f/0KhL58Rmj4BwdAzZ8+/v/65f+3byCl377+//79/5tX/z9//v/xE0iQgLMfPnp4+crV23fu3Lp79/qtOzdv3r587frjJ88+v//86eOnN5+/vPv0+dOHj29evgKi58+f37x548a1K7fu3nv48j2Dq4crAwODjIKctraqk4WRs60FKztXY1bBtpnL502eF9cyt2vWuuUTp7XlVE5v6EhKSNGzcZBUUZNW1QnMqWZISYhhYGSwtjD1sTGNdrCM8HQykJbrK6xaXNM/tWWqQ3h9Z8PkRa09nRkly3qnOti5KVk66Tj6S8qrB/h6MZRVlAnLy2soKkZ4eoT5+bm7u9rY2/fXtSyp6VjZP3vNhk0rJs9c0jJhbU1Jb36ajbObgaWll4+3va11fk4Ww7TpE1Jy02OyU5Mz02ID/LSMDXnkFUvjEvZPbNg+ZdbZEwc3L16+o61nW3VOUniwkKy8mKy8i6mRo45GdFgow5wDOyymT1mxakXQrFmKvRM6eycHtXTLdfQsmD8/d+YCuwVL5s5dkjxlZu3kSUmRiSIKKgbmtj62tta6OuGRUQxTdm1hau7qWLDAZNpsht7ptbMXu02az9A3s3nmErsJcxjaJ3VNX6DbM6t00dLqjAItUysnN187K1sVNY2k1DSGpfu2yk2aoDt7msbsmeLTZiktmKs4b77olDn6C2YrzpwrPHmu0YL5sjPnVc6dnxGXaOPg4OXu4WBnr6alHR4dzZCSnS5hom8UGmQaGqzj5qri6ChjY6ft4mrgHaXpGSNp7yrr7KPuFWrk6Obi4KShpm5saBAS5K+rqxsSEsLQ7BoVyiCaxa1TzKlbwaRdw6BVx6DTyqRnLWwmLKTJycopyiPNzy9nwqXQJ+BUzWRaKedS5RaTJGbWbhPFEOHiJsTAIMfMosTAosHAocnAocXAocHAxc7AysDAyMIApJiAqUiQgVWLgUuLgVuNTUBZSFKYgSXQwpGhvKXVNjDYKz7RzD1I29Rd28xL28xdy8zM0NTIxNTU2MzUyMzUxNzcwNxC08JK28Jaz9LRMSjayi8kp6oWAFeY8PQQN42IAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                         md 0&apos; title=&apos;&apos; src=&apos;/static/a515d2bbd6b9e172aa2067cee2c425f9/a6969/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_0.png&apos; srcset=&apos;/static/a515d2bbd6b9e172aa2067cee2c425f9/08678/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_0.png 190w,
/static/a515d2bbd6b9e172aa2067cee2c425f9/2edd7/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_0.png 380w,
/static/a515d2bbd6b9e172aa2067cee2c425f9/a6969/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_0.png 445w&apos; sizes=&apos;(max-width: 445px) 100vw, 445px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;약간은 씁쓸한 보통 사람의 게임에 대한 인식&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;김성주씨보다 카트라이더를 아는 사람이 더 많을지도 모른답니다 ㅠㅜ~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;얼마 전 흥했던 한 트윗입니다. 세대공감 1억 퀴즈쇼의 4000천만원이 걸린 문제였는데요. 작년 한 해 컨텐츠 산업에서 수출액이 높은 순서로 네 개를 나열하는 것이었습니다. 당연히 문제를 푼 분은 음악과 영화를 1, 2위로 지목해서 틀리셨지요. 사실 대부분의 분들이 한류하면 K-POP을 떠올리게 됩니다. 워낙 방송에서 K-POP, K-POP하니 그렇게들 생각하는 것이죠. 그리고 일반인들은 보통 게임은 애들이나 하는 거고 돈은 음악이나 영화가 훠얼씬 많이 벌 거라고 생각들을 하시죠. 하지만 이건 정말 말도 안되는 오해랍니다. 여러분의 그런 잘못된 오해를 바로잡기 위해서 데이터를 좀 모아 봤습니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 584px; margin-bottom: 16px;&apos; data-url=&apos;./한류_열풍의_불편한_진실_애들이나_하는_게임.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/4bd3efc3468f263b10ee70d4bc375533/f5818/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 52.10526315789474%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABjElEQVR42l1STU/CQBTsz/WgHj2bqMGgFxPjxZh49ORHTPyIEJVYjSKCoGigfHQL7e6228W0dKG01VcaAjKbbCbvvZk321T6ncFACF3XLcvS9S7GBO5uV1fVtmFghJDaVl23D2NRFCXzUhAEowl83xdCDMfwxxBiABgOhlDv9/tQ4ZxTSjWEGGOS67owOpgg0Vl2jxCCMbZJDNic2MEtYj9h//QY55LnebNJEoyCACYhSxCvj8ls1w+jx5Mzo1abFwMB5X+rKZIxzYm2Fjd58XUqThqmaTar1TCceiX1hIRhCBw5UWopzd8LU3Ewbpxmyldr20DCmSxzRiDeXE7zUkFyHce2bU948EBoHJxXjlfWQevH7x25rgNfFDZCImzAwb++aPaCjYVUHFvDVu76Xv36rLfUyuvb4VH2cmdfaymfX7X8U17OvVSe8x/V77vbl4eLbPbspizLGbm4u7pHyiWJ936QiphJLYt1kGZRSgiFPZSaBBMNdaiB4bdBqAO83WwpdaVRrytKgzH2B0frKXeDuK50AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                         md 1&apos; title=&apos;&apos; src=&apos;/static/4bd3efc3468f263b10ee70d4bc375533/f5818/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_1.png&apos; srcset=&apos;/static/4bd3efc3468f263b10ee70d4bc375533/08678/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_1.png 190w,
/static/4bd3efc3468f263b10ee70d4bc375533/2edd7/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_1.png 380w,
/static/4bd3efc3468f263b10ee70d4bc375533/f5818/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_1.png 584w&apos; sizes=&apos;(max-width: 584px) 100vw, 584px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;2011 컨텐츠 산업 수출액 비교 자료&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;컨텐츠 진흥원에서 나온 실제 자료 그래프입니다. 문제의 답에서 출처로 사용된 자료랑 동일한 것인데요. 이렇게 보면 게임이 얼마나 넘사벽 압도적으로 수출액이 많은지 감이 옵니다. 딱 봐도 나머지 모든 분야의 컨텐츠 산업 수출 액수를 다 합쳐도 게임 하나보다 못하다는 사실을 알 수 있죠. 정말 불편한 진실이 아닐 수 없군요.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 606px; margin-bottom: 16px;&apos; data-url=&apos;./한류_열풍의_불편한_진실_애들이나_하는_게임.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/9b772adf9385a88d72e039404adeac5c/cec09/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 43.15789473684211%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABc0lEQVR42nVQSU/CQBTufyeeXEjQuMToSY4kLBqMwYQIxgNRZDNAO21ZugK2tbRDl5n62op60G8yM2/5vnnvDRP9wmq1UlVV1zUNtqrCJcuSDFuSBFHUNI0QQikNgmDjeWEYMp7n+VvYtm1ZFpymZX0ktpHCNA1YpgmctW3r+kKazd4Ng8EYw0upOAjCbxASungDxRVFgbCP8VLX57K8dtau66zxxnVdBjqJ/gGNKEmQOBQcmtj12hNbvfUJYaAaJFJqyvkRJ4gTCUhsU1Bndsv9o+Mwir4qb3mpfuv+0QwFzU62Mji/iMWvPZZ/aSfxuEOYBEZPmY7jLjQNIg4M6Tjwkb7vwZOZ/XL/9CwWH5xUm9ncwjBGQ7bV6hbzpW6jiVi01NXC3XMhd1nMV+qF68da4/6m3ntovnHC3mFpcJUPIspMprPZZDqfSwiJaIy4MeI5QRiziiRNphLPIgGJPMezwxE34vrdfqfd6XV7U1HEGH8CUJPxM92UY8YAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                         md 2&apos; title=&apos;&apos; src=&apos;/static/9b772adf9385a88d72e039404adeac5c/cec09/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_2.png&apos; srcset=&apos;/static/9b772adf9385a88d72e039404adeac5c/08678/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_2.png 190w,
/static/9b772adf9385a88d72e039404adeac5c/2edd7/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_2.png 380w,
/static/9b772adf9385a88d72e039404adeac5c/cec09/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_2.png 606w&apos; sizes=&apos;(max-width: 606px) 100vw, 606px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;2011 컨텐츠 산업 매출액 비교 자료&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;그건 수출이니까 그렇고 전체 매출로 따지면 그래도 음악이나 영화겠지, 라고 생각하실 겁니다. 하지만 이것 또한 천만의 말씀. 만만의 콩떡입니다. 전체 매출을 보면 출판, 방송, 광고가 압도적으로 높은 것을 볼 수 있습니다. 하지만 여러분이 생각했던 그 음악과 영화는 여전히 힘을 쓰지 못하는 것 같군요. 영화 음악 다 합쳐본들 게임 하나 넘기가 힘들어 보입니다. 이쯤되면 컨텐츠 산업에서 게임이 차지하는 비중을 무시하진 못하겠죠?&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 632px; margin-bottom: 16px;&apos; data-url=&apos;./한류_열풍의_불편한_진실_애들이나_하는_게임.md_3.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/38edfb4e47645bca046c3a5f9a4e3d51/afa26/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 33.15789473684211%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAIAAACHqfpvAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABiklEQVR42h2O2U/iYBTF+zePT/NodB6cxBcTjDOTNC6JGokiEpjO1DKRUZZSKd2glJamlEKR2vXrAq3ihzf34dzl5HeQG6JOdET8eVBp8YUH6pERsSZbafKkPMXaQkfW7XQtWfHITl6iTPNWUBtBaoTZNEiRHIofoNWve/kvOxdbO+coWt4/vNvO/dn7ge/msOMzPH/17/svIndaw39TJ5dP347uC8XWTxQ7RTEkoqk3ntUqpcH1lVK6HZXvxlg545l3gV0PBIP427vOZyz9xjMZx0CRMvRa4KRiwSwVkfl87ns+1aZqtf+NRlNVVW08tm0nCADsoSTRna7rer4fhGHoeR48JUnCsZyijBDr9RWEgGGZRrNFtklJVmYzc6zrU9OMk0SWZYblAhCGURTFMfT7vp9m6VAeKqq6IcNVt0vXn+rVKtF+7liW5XwW3Pd7AkmSjusCAKDd/qzVaiWK/Q1ZkiTDMOCgaZoxmSwWi+VyGccxBIUAmOZsousw7QYcxdAJyTA2fHMd5wPaxWLK+kdXcAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                         md 3&apos; title=&apos;&apos; src=&apos;/static/38edfb4e47645bca046c3a5f9a4e3d51/afa26/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_3.png&apos; srcset=&apos;/static/38edfb4e47645bca046c3a5f9a4e3d51/08678/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_3.png 190w,
/static/38edfb4e47645bca046c3a5f9a4e3d51/2edd7/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_3.png 380w,
/static/38edfb4e47645bca046c3a5f9a4e3d51/afa26/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_3.png 632w&apos; sizes=&apos;(max-width: 632px) 100vw, 632px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;중국 온라인 게임 순위 자료&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;중국 전체 온라인 게임 순위 자료입니다. 1, 2위에 나란히 국내에서 제작된 게임이 올라 있군요. 1위에 있는 크로스파이어는 중국에서 단일 국가 최다 동시 접속자 수로(350만 명이 넘는 것으로 추정) 기네스북에 오르기도 했습니다. 크로스파이어가 작년 한 해 중국에서 벌어들인 돈은 거의 1조원 가까운 것으로 추정되고 있습니다. 게임 하나가 말이죠. 그것도 한 국가에서. 더 욱긴 사실은 위 순위에서 1, 2위의 점유율을 합하면 50%가 넘는다는 겁니다. 게임을 하는 중국인 두 명 중에 한 명은 저 게임을 하고 있다는 말이죠. 지나가는 중국인 중에 크파나 던파를 아는 사람이 많을까요? 아님 소녀시대나 티아라를 아는 사람이 많을까요? 당연히 전 크파나 던파라고 생각합니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_4.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;
&lt;strong&gt;대륙을 뒤흔은 FPS 게임, 크로스파이어&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;아직도 감이 잘 안오는 분들은 위해서 잠깐 비교를 좀 해보겠습니다. 동방신기, 소녀시대, 보아 등으로 유명한 SM엔터테인먼트의 2011년 매출액은 1430억입니다. 원더걸스로 유명한 JYP는 99억, 2NE1으로 유명한 와이지엔터테인먼트는 781억의 매출을 올렸죠. 눈부신가요? 많아 보이시나요? 그런데 이 세 개 업체가 작년 한 해 동안 벌어들인 돈을 모조리 다 합쳐도 크로스파이어가 중국에서 벌어들인 돈보다 작습니다. 크로스파이어는 2011년 중국에서 1조원 가까운 매출을 올렸다고 했습니다. 국내 개발사와 퍼블리셔인 스마일게이트와 네오위즈는 수출 로열티로 3500억 정도를 벌어들인 것으로 추정됩니다. 중국에 게임 하나 수출해서 벌어들인 돈이 국내에서 가장 유명한 엔터테인먼트 회사 3개가 작년 한 해 동안 모든 지역에서 벌어들인 수입보다 많다는 이야깁니다. 이쯤되면 애들이나 하는 게임이라고 무시하긴 좀 그렇죠?&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 511px; margin-bottom: 16px;&apos; data-url=&apos;./한류_열풍의_불편한_진실_애들이나_하는_게임.md_5.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/524abfd15f9837ad9874face14759fc4/40f84/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_5.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 154.73684210526315%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAfCAIAAABoLHqZAAAACXBIWXMAAAsSAAALEgHS3X78AAAEtUlEQVR42mVV2Y7cRBT157M8IsEDj4h3nlAkAhKKAhIkUkgmM9MzPe1evFd5qc3lWs0p9yRCwqrRlNx165577jnXWTcOx6psKN1fzofigj0Zh0tT+xDW/z3SrUe5XtTaam2Czoqe7KrLiXaPVbGvi7ytsA5tJeyinGFGK2tmZ7FXVh+FftXy1514Q3cXmWeTVg2fKjb4GLAinnXFwg4LP/Fltt4jbS9FJ6YYsQ/a6pYNGd4OUhz7jgpeT6MPwLv9hYhFBMtpN80Sx6Z5fqLkidZm9Y4SvbtJwS2fctouzs7WuBQVrwtXIPN5oExrH9deyXyojkMxr0Y1tfzwPnPed5ydeoLkxUi1NQAerk8MuPfU0/uuFdazRTzS8317Yk7Vh/b88s9scQ6AZ7Mgj7uGbGXjvwuxYFM+DDtCmUGwPPb1Q1PI4Pp9Wf/8a2ady4fu7fnwsS7umqJLFxmUp51XPpwm9kD727YRRkszA9q+raY1rB/e+W+/yRbvR9K0l7wp8q66lMf9pW0ujHHjtV+xOY9dxXoXHEipp+FIW+FsmCZzOAC2pWw8d3U1kCPpctIe+n7fjzRV4mre77tKWwte1aIvI33qamaN7/vl/j4Fl9NQMbaEKF1gJnAblLXWW2RDq059x/Sc5LXo80By2gjvQk/N7W1iu+GcSqmsYzZI5xdvfSIrgLZOMAQgHjrheq6mwTrr1tUQutzcbJnZuKek5Wz2q4NA4nOr4xrJ1kWowHg32wUX7btauyWv+PnF7xnqgRKGeQYE4xyWD5/aHGOvxGWgR9qhKYCNW6hgSVdPdfXbH5kyC8Cce1zZ1Ntm2XTit2DUvAW3CGazeiINsCDYEpIIQ2ZIWiwarxLQuIb/ZIb4EAyGjbN8Vo9thVb7NaqJN3mRgp9I3bARxUObfnPFdSEa4isGirps8DgAIIAmcbIbxM1dhnaChgNp4R6wisrX+PzAmb3kqHNUAleBDdRotp5396f6pxcZaEA/HrsakSB2UAJvUAXOpVQSsAmQAwiMed+UHRuToT+8C99/lwgDGKgatFHJSzaUU9/yETeSbT20JcpBNqrUri0I5sEaRU34Px8zeBjA4Ec0aY3rFe7n5yoSuZjNzxyWJGLEReX+Uv7yOtPOjvgZGhrpMvYLbdFsn0SS/FxO465rpDEuLoOGli4Np6nmU9u8epNgo+/o5Im2W3kEWJAc8wz2LhnbESLRhWgmzU5DCwq3YFK/fpttM8DjqPXuOm7RIeuDdtB5EDCf8bODCY3zDgpHO5J4PV4saYY1bIIAkRNdBWDtw+wRGRF5GOj78iiX5KpByYe2xgzFno+iyssUDHqv0l98VA6WjMJhg2FggRMtxKhKbEsO8q5jmA+82J9T8KhkMY0V5xgd0uKzEDEGYGagI4KDlOvnQhmNdo5KJW8L3VR9GkPCWGm9chF+1t4ZlJ/UmWYoJA3NoFqwj2ohx+t49RjG45DZuBZjj0EHerYwt0U9T18MmV1TqGXZACZXTVJgSLg3f/uvv8xsWGs23dRFJ8WnMRA+L5gURCL/RpjADAPxW/Bf7qsvMuwwosqxh9fAWTLmszXj9WMiN7emOo2G+LlONfu72/DjD/8C0VXfQD+gPDQAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                         md 5&apos; title=&apos;&apos; src=&apos;/static/524abfd15f9837ad9874face14759fc4/40f84/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_5.png&apos; srcset=&apos;/static/524abfd15f9837ad9874face14759fc4/08678/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_5.png 190w,
/static/524abfd15f9837ad9874face14759fc4/2edd7/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_5.png 380w,
/static/524abfd15f9837ad9874face14759fc4/40f84/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_5.png 511w&apos; sizes=&apos;(max-width: 511px) 100vw, 511px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;&lt;a href=&quot;http://www.gameshot.net/common/con_view.php?code=GA4fc77a1d28041&quot;&gt;전세계 게임 업체 매출 순위&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;매출액 기준 전세계 게임 업체 순위입니다. 1위는 스타, 와우, 디아로 유명한 블리자드군요. 2위는 피파로 유명한 EA입니다. 3위에는 크파와 던파를 중국에서 서비스하는 텐센트가 올라있군요. 밑으로 쭉쭉 내려가다보면 반가운 이름이 있습니다. 국내 게임 업체로 유명한 넥슨이 무려 11위에 랭크돼 있군요. 쫌 더 내려가면 낯익은 국내 게임 포털 사이트들도 하나 둘씩 이름이 보이기 시작합니다.&lt;/p&gt;
&lt;p&gt;잘 아시겠지만 국내 재벌 대기업들은 모두 고도성장기에 국가의 엄청난 드라이빙 포스를 받고 지금의 위치에 올라서게 되었습니다. 사실 국가의 전폭적인 지원이 없었다면 당연히 지금의 삼성전자, 현대차, POSCO도 없었을 겁니다. 하지만 게임 업계는 그런 것 하나 없이 맨땅에 헤딩해서 이런 놀라운 성장을 일궈 냈습니다. 그런데 칭찬은 못해줄 망정 국가에서 안티인 정책들을 많이 내놓는 것 같아서 정말 안타깝습니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_6.png&quot; alt=&quot;&quot;&gt;&lt;br&gt;
&lt;strong&gt;&lt;a href=&quot;http://www.dailygame.co.kr/news/read.php?id=58171&quot;&gt;스마일게이트 4년새 매출액 34배&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;2011년 삼성전자 매출은 165조였습니다. 영역이익은 16조 2500억이었죠. 영업이익률이 10% 가량됩니다. 반면 넥슨은 1조 2000억의 매출에 5200억의 영업이익을 냈습니다. 영업이익률이 무려 43%에 육박합니다. 매출로 따지자면 160배가 넘는 차이가 나지만 영업이익으로 따지면 31배 가량 차이납니다. 스마일게이트의 매출 신장 그래프를 보니 앞으로 어떻게 될지는 모르겠다는 생각이 드는군요. 게임 산업은 확실한 고부가가치 산업입니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 614px; margin-bottom: 16px;&apos; data-url=&apos;./한류_열풍의_불편한_진실_애들이나_하는_게임.md_7.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a501f6bff990a688ea6690bddc5e6135/c42f5/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_7.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 69.47368421052632%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAIAAACgpqunAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACT0lEQVR42jVSCXuiMBDl//+htl+3hxwi2qXtKl4oKkIghASQiihF94XtPq7Jm3sGpWmakT0ZfTjO3LUni61P3sdz8+1zutyYo0/PD13Pd+brXRCBH89Wk9lqPHOH7059vijVqTZ/jy3bmbmb0Z85nD+cpWa9L729atrOYgM/19v7IXUW3mK1m7lb+PffxsdTrVDGGWM0YTFNEsZCEoUh4VxQSuOYkkjSYRgFJJIyZR3DYEqTVMHTNzSjb+q6YVnWYGAahjEcDnu9156qjUYjQ9een56NvqHrOtQP9w8Da6BqGompgmjq68vj46Nu6HDQNc227ZeX5/u7O01VreHw6emXqvYgmwPLHAxcd7nqkLBUSXkWR2Tn+4REQRASQvz9vvuSXYeYxkEQgAukOiq/jsUBKFnKFZ6XlOdMHEReJryIWYYjzw6JKEAyXqTZATeY/IAZnctjJe+vSk57tg4/55vJ0l/7seP6H9ONPVl5fjxdBfN14Cx9dxuud9HCCxH3drtdr9fbfyh1XR86FEXxVZaZEHmeAYVEDjbLcvGDjHO5GjAwg6B8f39jC3s0hV0Sst1utjsf7WEKjKXNpTnVdVVVJ/wP9flUVcfj8XSCXINRkP18ufA0xYQQDPGThO79PWTsOeXyiuWyEwioKM+LPM8xMBQlnZE8TZmQ1WQi6wy6N76yVpGlUKNaIZXoub22bfeWzk1zgY4LmeFfc1gP/jDOUU6EIDItF4J3kTKBMhEFh5/MXbWIwDClpJPSlEtIuxyZ0TAs27bL2crcbdv+Ba1O8XcbdOncAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                         md 7&apos; title=&apos;&apos; src=&apos;/static/a501f6bff990a688ea6690bddc5e6135/c42f5/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_7.png&apos; srcset=&apos;/static/a501f6bff990a688ea6690bddc5e6135/08678/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_7.png 190w,
/static/a501f6bff990a688ea6690bddc5e6135/2edd7/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_7.png 380w,
/static/a501f6bff990a688ea6690bddc5e6135/c42f5/%ED%95%9C%EB%A5%98_%EC%97%B4%ED%92%8D%EC%9D%98_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4_%EC%95%A0%EB%93%A4%EC%9D%B4%EB%82%98_%ED%95%98%EB%8A%94_%EA%B2%8C%EC%9E%84.md_7.png 614w&apos; sizes=&apos;(max-width: 614px) 100vw, 614px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;이 모든 사실에 너무 놀라실 필요는 없습니다. 아직 전반전 시작도 안했으니까요.&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[최고령 C++ 개발자는?]]></title><description><![CDATA[채널9을 보는데 재미난 슬라이드가 몇 개 있어서 캡쳐해 봤습니다. 사실 주제는 이게 아닌데 본론보다는 이 부분이 더 재미나더군요 ㅋㅋㅋ~ http://channel9.msdn.com/Events/TechEd/Europe/2012/DEV36…]]></description><link>https://jiniya.net/wp/archives/8185</link><guid isPermaLink="false">https://jiniya.net/wp/archives/8185</guid><pubDate>Wed, 18 Jul 2012 23:58:19 GMT</pubDate><content:encoded>&lt;p&gt;채널9을 보는데 재미난 슬라이드가 몇 개 있어서 캡쳐해 봤습니다.&lt;/p&gt;
&lt;p&gt;사실 주제는 이게 아닌데 본론보다는 이 부분이 더 재미나더군요 ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://channel9.msdn.com/Events/TechEd/Europe/2012/DEV368?format=html5&quot;&gt;http://channel9.msdn.com/Events/TechEd/Europe/2012/DEV368?format=html5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./최고령_C++_개발자는.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/81ef9d33d4baf7fa9806fe5ee255d6d5/dface/%EC%B5%9C%EA%B3%A0%EB%A0%B9_C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8A%94.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 55.78947368421052%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACTklEQVR42mNQ9K/TiWzVjGg2Seg0jO3Uj+nUjmzTjWq1S+s1iuswTeg0TeiySOoGIsvkHiCS9q6W8oIiBlnfauWgBmXvWv/8KcV9y+qnruiavdI9d6JaSKNBTJtORIt6SJNGaJNWeDOQDWTAdYI0S3lVSnlVSbtWFbYuzMlI6ajKWzW7O6JihoBzGdASSc8qoCIJDyAJQjI+1fJ+tTLe1RD7GUA6varFvaqj6+dGhYd21JftXN2X1TJH0LlcMaBO1qdG1rcWqFTOt1bGp0bAqUzIpYLfqVzIuRyqGUhJ+tQE1C5sa6ieOalzx/q52U3ThFwr5P3qZKCaa4BILbihafaakglLExrmehZMlvGugdhcpRzcaJA/L7J1uWfpLMvUPqUAoD3VsiDbgHZWS/tUi3lU2KT0HL+258C2BQf3r1x/YItacBNIM9BjKsGNyhmzxJOmS8ZPlo7skQpolPWplvGqkvUG+hNI1ki4VvoWT5vUU76qq3r1jNbOGZNUgluhmhUC6tUyZ6lmzVXNnqeaM185Y45iwkT58Ha5wCbVwGYV/0Zpz5qw8lllmannD+yd19mUll2oFNIG0xxYr5Y9VzlrnnLaTKW0mQoJk5USJwNJ1diJWrETFcI65ENaVIKa7BL7PQumhZbPdErrBEYBRHO1vH+danSXckS7QkAdMJCB/lTwr1EJrFP0r1X1r1PzrdPwb9Dwr5f3qRb3qOBzKBV0KQfqgoY2CHkCI7xSGhSHoLCV9qpRCqwHxpAUMEphCCgu61OrGtwITC2qwQ0ApebsKkQWCdAAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;    C        md 0&apos; title=&apos;&apos; src=&apos;/static/81ef9d33d4baf7fa9806fe5ee255d6d5/dface/%EC%B5%9C%EA%B3%A0%EB%A0%B9_C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8A%94.md_0.png&apos; srcset=&apos;/static/81ef9d33d4baf7fa9806fe5ee255d6d5/08678/%EC%B5%9C%EA%B3%A0%EB%A0%B9_C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8A%94.md_0.png 190w,
/static/81ef9d33d4baf7fa9806fe5ee255d6d5/2edd7/%EC%B5%9C%EA%B3%A0%EB%A0%B9_C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8A%94.md_0.png 380w,
/static/81ef9d33d4baf7fa9806fe5ee255d6d5/dface/%EC%B5%9C%EA%B3%A0%EB%A0%B9_C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8A%94.md_0.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;네. 92살의 최고령 간달프 느님께서 존재하십니다. 92살이시면 진짜 마법을 쓸 수 있을거 같지 않나요? ㅋ~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;거의 대부분의 개발자가 2-30대에 포진한 것도 인상적입니다 ㅋ~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./최고령_C++_개발자는.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/724593dd7489b01c9505e71586d56e10/dface/%EC%B5%9C%EA%B3%A0%EB%A0%B9_C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8A%94.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 55.78947368421052%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABsElEQVR42mOQ862xS++3SukxSeg0S+qyTO7Wj25TD200TewyS+m1TOpS9K+T9KyW8sKCGKS9q7QjWjTDmpUDG1SCGlSDG5UC6kS9alRDmtwT2/Tju2V8aiXdy7FrlvKqEnOvBCJxjyoJjyoZ72pB9yrHiJrD7a1PJneZN22WL18vF9Yh5V4h5V2DRTOEJelVLedbqxrSaBjeurlryb85Pa+ntjl0bDOZeES/d59EeLuURyWafoRmIJLxrhF0KQ2vWL506dX1E3femzjdvGOXZv129/y1tkG94h4V0l64NUt714i4lKVN3LDw8MlF6xasWFCTm9ie7zOz32dCqmurmFeVNC5nA5GsdxWfc2NxZdDDzapbVqvEr4taGmW/yjagxWNykGuLCH7NwJAXca/VDcyZssSgeYeN4YbZ3RWxHwIl1/l4q7vXiXtX49MMRBqhDSohXWbpheGz0sy2bSppzdvno+fjlyjsVSONNaqQ+cBYlfOrEXerE/Wol4ttUomokXYv5/dsRNYp4QlEVUCErhmYmCQ9q6S8q6SADNdKcfdqca9aGVQ1SoENasGNKkGNAEvY4fIKrYGWAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;    C        md 1&apos; title=&apos;&apos; src=&apos;/static/724593dd7489b01c9505e71586d56e10/dface/%EC%B5%9C%EA%B3%A0%EB%A0%B9_C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8A%94.md_1.png&apos; srcset=&apos;/static/724593dd7489b01c9505e71586d56e10/08678/%EC%B5%9C%EA%B3%A0%EB%A0%B9_C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8A%94.md_1.png 190w,
/static/724593dd7489b01c9505e71586d56e10/2edd7/%EC%B5%9C%EA%B3%A0%EB%A0%B9_C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8A%94.md_1.png 380w,
/static/724593dd7489b01c9505e71586d56e10/dface/%EC%B5%9C%EA%B3%A0%EB%A0%B9_C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8A%94.md_1.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;C++이 가장 많이 사용되는 프로젝트는 다름 아닌 게임이라고 합니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./최고령_C++_개발자는.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ebf5393ab70b4a683d27769380b4cc92/dface/%EC%B5%9C%EA%B3%A0%EB%A0%B9_C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8A%94.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 55.78947368421052%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABy0lEQVR42n2SW0/iYBCG+Q9euIqrKGZdFVyo6EYTNRs1ERAorE0LthVXjdF44VloscXS2haJrjHhEFx3PcXf4L/zLR5QLjZ5M990+s3M0+nYOsKHXk7vZ9SBhOZhdQ973EfneumcK666E9oXSuki5daA2OL/IEQgmz0oOqPZHkrpJOXuWM2JSA5Sgu+MZVG6bTbTHjr8/E6IvCS3BoQWv+DjzTXjIbhZpFJVWrik0pdwEpkrPvsvtl8hOJ1g9UHOko/XXYz6ktwWFJumDpbVe/P6cWzlNLRVwu3oXoXcKZO75chu+cfa7/GV05HFk1q+gTZuRqt3xuGOawRn4GthvSzKm4O8SbCGJc4YWsgj6GI0XMNovlLKe+z0yFJhLlUdWjABDOzk0Q2AZ7eKnnkd+gbL6t6aUKufVmstBSSLn/zCxOoZI/z5nsyD8+d+JbRdQmRy/Xw4mUdz0L6pEdsezPTMKV0RGTzP5X28AUJM3kJtUBzYuddfFRCbZ9LTGxeYtoWdqnLS32XtLrxTQgkMqUFo7qLrna0DML+U29GlQmi7SO6VgQ1+zByjJrj/YuPoCEuwWAZsSGdExsI44JCyMypbj3XhrYTNeU5+Amn/66vdNI8gAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;    C        md 2&apos; title=&apos;&apos; src=&apos;/static/ebf5393ab70b4a683d27769380b4cc92/dface/%EC%B5%9C%EA%B3%A0%EB%A0%B9_C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8A%94.md_2.png&apos; srcset=&apos;/static/ebf5393ab70b4a683d27769380b4cc92/08678/%EC%B5%9C%EA%B3%A0%EB%A0%B9_C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8A%94.md_2.png 190w,
/static/ebf5393ab70b4a683d27769380b4cc92/2edd7/%EC%B5%9C%EA%B3%A0%EB%A0%B9_C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8A%94.md_2.png 380w,
/static/ebf5393ab70b4a683d27769380b4cc92/dface/%EC%B5%9C%EA%B3%A0%EB%A0%B9_C%2B%2B_%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%8A%94.md_2.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;정말 이런 이유로 C++을 선택하셨나요?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;‘학교에서 배워서…’라는 가장 중요한 이유 하나가 빠진 것 같군요 ㅋㅋ~&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 게임 보안: 타이밍 전쟁]]></title><description><![CDATA[A Book On C란 책을 보면 C언어에서의…]]></description><link>https://jiniya.net/wp/archives/6006</link><guid isPermaLink="false">https://jiniya.net/wp/archives/6006</guid><pubDate>Sun, 08 Jul 2012 23:58:18 GMT</pubDate><content:encoded>&lt;p&gt;A Book On C란 책을 보면 C언어에서의 0의 의미에 대해서 설명하면서 시작을 합니다. 배열의 시작 인덱스 번호이기도 하고, 문자열의 끝을 나타내기도 하고, 거짓을 나타내기도 한다… 등등으로 말이죠. 이런 것처럼 게임보안에 있어서도 타이밍이란 참 다양한 의미로 사용되고 또 중요한 개념입니다. 오늘은 이 타이밍에 관한 내용에 대해서 좀 써볼까 합니다.&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;일단 게임보안 제품이 영원히 한 수 접고 시작할 수 밖에 없는 타이밍이 있습니다. 바로 실행 타이밍입니다. 게임보안 제품의 제1공리가 다름아닌 ‘게임보안 제품은 절대로 해킹툴보다 먼저 실행될 수 없다’이기 때문입니다. 이런 전제를 뒤엎기 위해서 바다 건너 P모 제품은 게임 실행과 상관없이 메모리에 상주하기도 합니다. 하지만 이래봐야 운영체제가 실행된 다음에 실행될 뿐입니다. 운영체제 실행 전에 해킹툴이 실행된다면 어쩔 수 없습니다. 물론 그런 극단적인 — 뭐 사실 크게 극단적이지도 않습니다. — 예를 가정하지 않더라도 P모 제품의 전략이 안통하는 가장 큰 이유가 있습니다. 게임보안의 특수성이 그 이유죠. 일반적인 보안 제품은 사용자가 해커로부터 PC를 보호하기 위해서 보안 제품을 사용합니다. 하지만 게임보안에서는 사용자가 곧 해커가 돼 버립니다. 따라서 상주해 있다고 하더라도 사용자가 해킹툴을 사용할 목적으로 프로세스를 종료해 버리면 끝납니다. 아주 은밀하게 구동하겠다구요. 물론 가능합니다. 하지만 그 은밀함이 지나치다보면 옆동네 백신 친구들하고 싸움이 납니다. 화가난 백신 친구들이 우리를 white rootkit으로 분류하고는 마구 삭제해 버리죠. 어쨌든 백신 친구들하고 싸우면 안됩니다. 친하게 지내야죠 ㅋㅋ~&lt;/p&gt;
&lt;p&gt;이런 이유로 게임 실행 전이란 그 영역은 게임보안 제품에게는 영원한 미지의 영역입니다. 마치 우리에게 빅뱅 시점이 영원히 풀지 못할 것처럼 보이는 미지의 영역인 것처럼 말입니다. XIGNCODE는 이런 제약에 보다 효과적으로 대응하기 위해서 대부분의 기술을 차단(blocking)의 관점보다는 탐지(detection)의 관점에서 개발합니다. 왜냐하면 일단 먼저 시작할 수 없기 때문에 차단은 언제나 결국은 실패할 수 밖에 없는 방법이거든요. 역사적인 관점에서 게임보안을 살펴보면 이것도 약간 트렌드가 있는데요. 아주 초장기는 백신에서 차용한 탐지의 관점에서, 그러다가 후킹이 발전하면서 차단의 관점으로, 그러다 해킹툴 진영의 후킹 기술도 덩달아 발전하면서 다시 탐지의 영역으로 돌아오는 형태가 되고 있습니다. 현재 모든 게임보안 제품에서 말하는 차단의 형태는 바보들을 막기위한 껍데기라고 생각하시면 됩니다. 그렇다고 차단 기술이 완전히 의미없진 않습니다. 해킹툴을 만드려고 하는 사람들의 대다수는 그런 바보들이거든요.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;다음으로 게임보안에서 주로 이야기되는 타이밍은 무한(INFINITE)입니다. 게임 보안에서 INFINITE는 금기시 되어야 하는 것 중에 하나입니다. INFINITE가 뭐냐구요? 특정 이벤트나 메시지가 올 때까지 한없이 대기를 한다는 것을 의미합니다. 프로그래밍을 배울 때 개발자들은 동기화 이슈를 만들지 않기 위해서 INFINITE를 써야 한다고 배웁니다. 하지만 게임보안에서 INFINITE는 구린 제품을 만드는 직행 티켓이죠.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;게임_보안_타이밍_전쟁.md_0.png&apos; data-alt=&apos;모든 것이 언젠간 응답할 거란 너의 가정이 얼마나 쉽게 부서지는지 보여줄께!!!&lt;br&gt;&lt;br&gt;영원히 응답하지 않는 세계를 한 번 맛보렴.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 450px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/289ba5a5759f85a84128058aa3d8b3d3/31401/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 74.73684210526315%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAA7DAAAOwwHHb6hkAAADW0lEQVR42nWRa2hbZRzG30lGk7Sr6xwUtB+EOm8oA9mXwQaCfhC/iSLtYt06e1m1lwXXbWYynLdKt7HMTkRowXUUx0CXtE3T7sTGY5o0Mell3U6adrZN1yTnfk5u55z3XJLj2QqCH/zz4+HPw/vw/OEFlW2ItRWpavHWtI4/1e7Ze8K7t82zp2XsMZ6a46O7m11PHnPVfnir/ujNWtsvpsbRnY1uU4PL9P5voOoT/xNt/v3n0DMji0edyPEBtHkAbbrqf6/f907fHdv3oXcvhd66GHGc/wn54qTD3gdskybbxM4jo6YGN6juQi0t3tfPe/3RBPLXA1/0wVRkZWI2MR5cHgtgntCKJ7TqmV0dDyWmY4m+4ek9jSNmm8v0gZEfB7s7EduXP/cPu30z82gs4Y9iKIb/vpydus9PYlkE49EEH1zlwmu5SBz3XnEOnup9rclp9Fc0eUFVh3dwLLiWYpJELs0Ut+jCJiMlWXmdhhu0ofI6BdNZhSpoTFHbIvil+N+HuwbBkYmKYwjY1Tl5J7IsivpDokgwIsNDipf4vMxmIc1LJCPiVJHLQ13Xy+Wyobomv312BNimLB9Ng8puZDRwVyzkKJLCcYIiSEMZmmFZDs9kCIKgadpwUltpQZSMrKrAN3tvgCafuRUF5m7EFVgyXAlCRZGhMZKkKIqqKpIoQQnKj8cwNU17VKzAQyevg2a/+cQMqOjx3Q5gOZ0hWS6T4Sg6S1F8Ok0TJKeoj17/O9tnazI82DMMWgKWj2eB+VP/zT/uGm5ehHkBCpJcEGC2IApQUUslraxvo5bKilZSy7ooCge6roP2oLUrAsy96C0Uy+tsmqRTKYaheaOTprOpFE2SHMvmcJxJpahcXtzuh7J0oPsG6Ahbe2JglyNw7XYgTTNrGWaT4AySOLuBs+tp4/O4TZIzdsPZJPmHJG/s8dW1/R1DOzqjVvs8ePpSvNb+62HHyJ8zYTQY+T/8M+FoNPbVoLu64cfqdrf51JLZvgjqBjZqnMk3hlZ4QWGEEiOo29DF/0DkZaiWh9CNHfa5qnMJy+l7Rh7U/ZB85lry2auJV52Lr1xZfPnywkuXF168uPBC//zz383v+3buuW/m9n0dq78Qrb8Qqfs8XPnZfasjbj2LWU5j/wBak4Frb+8lAgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;모든 것이 언젠간 응답할 거란 너의 가정이 얼마나 쉽게 부서지는지 보여줄께!!!&lt;br&gt;&lt;br&gt;영원히 응답하지 않는 세계를 한 번 맛보렴.&apos; title=&apos;&apos; src=&apos;/static/289ba5a5759f85a84128058aa3d8b3d3/31401/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_0.png&apos; srcset=&apos;/static/289ba5a5759f85a84128058aa3d8b3d3/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_0.png 190w,
/static/289ba5a5759f85a84128058aa3d8b3d3/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_0.png 380w,
/static/289ba5a5759f85a84128058aa3d8b3d3/31401/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_0.png 450w&apos; sizes=&apos;(max-width: 450px) 100vw, 450px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;모든 것이 언젠간 응답할 거란 너의 가정이 얼마나 쉽게 부서지는지 보여줄께!!!&lt;br&gt;&lt;br&gt;영원히 응답하지 않는 세계를 한 번 맛보렴.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;예를 들면 이런 겁니다. 게임보안 제품이 아주 은밀하게 중요한 부분에서 특정 윈도우에 SendMessage를 했다고 생각해 봅시다. 어떤 윈도우인지는 모르겠지만 말입니다. 일반적인 경우라면 메시지가 리턴되겠죠. 해커가 그 사실을 알았다면 어떻게 할까요? 윈도우를 만들어서 SendMessage에 응답을 하지 않도록 만들어버립니다. 당연히 보안 제품은 바보가 돼 버립니다. SendMessage 뿐만 아니라 그 모든 이벤트에 대해서 절대로 무한 대기를 해서는 안됩니다. 이런 것들은 굉장히 쉽게 공격당할 수 있는 포인트거든요. 그래서 게임보안 제품은 대부분의 경우에 타임아웃을 설정합니다. 해당 타임아웃 넘어 응답이 없다면 그 다음 프로시저를 진행할 수 있도록 말이죠.&lt;/p&gt;
&lt;p&gt;똑똑한 신입 게임보안 개발자들은 이런 이야기를 하곤 합니다. “그건 게임보안 제품이 게임과 별개로 동작하니깐 그런거죠. 게임이랑 한몸이 돼서 돌아가면 그렇게 하지는 못할것 같은데요. 그러면 게임도 같이 멈출테니까요?!?!”라고 말입니다. 정말 똑똑한 개발자군요. 우리 회사에 지원했다면 바로 채용했을 겁니다. 게임보안에서 가장 중요하게 생각하는 점을 제대로 짚긴 했습니다만 여기에도 맹점이 있습니다. 렌더링 스레드에 은밀하게 보안 코드가 추가되면 가장 좋긴 합니다. 하지만 다른 100만 가지의 문제를 야기 시키기도 합니다. 바로 랙이죠. 해커가 응답을 지연시키는 행위를 막을 순 있겠지만 정상적인 천만가지 상황에서도 렌더링 스레드가 지연돼서 화면이 프리징되는 문제가 만들어집니다. 그래서 렌더링 스레드에는 아주 섬세하고 조심스럽게 작성된 코드 외에는 추가하지 않는 것이 좋습니다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;음. 다음으로는 또 활성화 타이밍이 있습니다. 해킹툴이 실행된 시점이 아닌 게임 내에서 실제로 활성화되는 시점을 의미하는 말입니다. 요즘 출시되는 대부분의 해킹툴은 실행 시점과 활성화 시점이 같은 경우는 거의 없습니다. 왜냐구요? 보안 제품을 우회하기 위해서입니다. 고전적인 게임보안 제품들은 게임 런칭 시점 외에는 따로 해킹툴 검사를 수행하지 않았습니다. 그래서 해커들은 해당 보안 제품이 스캔한 다음 자신의 해킹툴 코드를 활성화 되도록 만들었습니다. 그러면 스캔이 이미 지나갔기 때문에 예전 방식으로도 손쉽게 보안 제품을 우회할 수 있기 때문이죠.&lt;/p&gt;
&lt;p&gt;게임보안 개발자들도 가만 있진 않았겠죠? 주기적으로 검사를 하도록 만들었습니다. 그랬더니 이번에 해커들은 어떻게 했을까요? 주기적으로 코드를 복원시킵니다. 즉, 초기 회피 타임과 주기를 알고 있다면 자신이 변조한 코드를 그 주기에 맞춰서 원본으로 돌려놓고 보안 제품 스캔이 끝나면 다시 코드를 변조하는 형태로 만들었다는 말입니다. 그 다음은요? 당연히 보안 제품 개발자들은 주기를 랜덤하게 해서 측정할 수 없도록 만들었답니다. 그래도 여전히 이 활성화 타이밍은 굉장히 중요한 부분입니다. 왜냐하면 검사 방식에 따라서는 비용이 너무 높아서 주기적으로 검사 하기는 힘든 것들도 있거든요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;게임_보안_타이밍_전쟁.md_1.png&apos; data-alt=&apos;게이머들은 매뉴얼 방식을 사용해서 인젝션 타이밍을 조절하기도 합니다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 599px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/2d85dd9677b6354bda06c24443d188c5/1906d/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 77.36842105263158%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACoElEQVR42nVSS08TURSe38WShLjGmGjC0pURjHFlULEFDLjQQKXBsGCD/AMjhlBAkj5pWuy0ZdpOZzov5tV5tNPHlM691zOliTHqyZmTM3fy3fN93xwq8ub1ajQa291d3dhYWFiYmZmZnZ29Pz//7PmLl0tPN548LuayhBCEEPkrqHtzc9F368XDw6/RyINHDzc3N78cHMS2t2NbW5/i8VcrkUQi8V/w0uLi8dnp5crK1fLy+48f1tfWYjs7e/v7n/f24vF4NPI2lUr9BmMyrTjsKHoSnCCopqlrWpPjeIZp5nLcZV7O5NjTM71QJIaJND1MVUOqimxnOrlYKPJ8i2EYQ9c7nY7tOO6Nal6V+nR5JIhWrc7lcsQf4cEAd7u408WeFzZuB9+OqWQy6TiOoii2bQNYliS6UmFF0eZb7jWjXf2snCTIcBgIYtDkEN8KGiw0uG3h0YhKp9OAbDQauq67rqveqJIoGppuwl2DgWpb5Wo11Nzv414PQ+16wGJK++Ligms27ya3223LsoCINQnHdeG8UqmAXdj3yTgg4zEZ3UINXzGmUsmUIiss2+R5HvCGYSiyXK5UuXJZS6bE0zPm+IRIcsDxiOODloAgRSlgm7jXp7LZrKZpdeBdb0iSDHjf94cQg8HI98FFulQiXg+5LrIs7LrYcZDjItDcH1DpTBrYlukywCVJArPDHzkJaOBTCcCTk38sSSaTCU2WZdM0QafneXcrMQZhCJmGAVswBU+TTBsAwwJ1ux2AgTeCIArhI0qybDiu3e0qQBsM+9/kQqEAAmE4KJdlBaqqabqq9gTJawlWvcGcn2O+hdptJCt4OJys5/QiKp/P1+v1arUKlWVZmFyr1ao0fX3+o/DtqHD0XaTLBGGQQIKA/Dn/F5+0FDE+rsznAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;게이머들은 매뉴얼 방식을 사용해서 인젝션 타이밍을 조절하기도 합니다.&apos; title=&apos;&apos; src=&apos;/static/2d85dd9677b6354bda06c24443d188c5/1906d/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_1.png&apos; srcset=&apos;/static/2d85dd9677b6354bda06c24443d188c5/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_1.png 190w,
/static/2d85dd9677b6354bda06c24443d188c5/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_1.png 380w,
/static/2d85dd9677b6354bda06c24443d188c5/1906d/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_1.png 599w&apos; sizes=&apos;(max-width: 599px) 100vw, 599px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;게이머들은 매뉴얼 방식을 사용해서 인젝션 타이밍을 조절하기도 합니다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;물론 해커들만 이런 방법을 사용하는 것은 아닙니다. 사용자들도 이런 활성화 타이밍을 사용하는데요. 흔히 인젝션 딜레이라고 말하는 방법들이죠. DLL 인젝션 형태로 구동되는 해킹툴들은 언제 인젝션 하느냐에 따라서 해당 해킹툴이 탐지되기도 하고 안 되기도 합니다. 이런 취약성이 있을 때 쓸 수 있는 방법입니다. 예전에는 매뉴얼 인젝션 기능을 사용해서 게이머가 직접 판단해서 넣는 형태로 조작을 했습니다. 한 해킹툴 사용자가 탐지되지 않는 시점을 찾으면 커뮤니티에 방법을 공유합니다. 언제 게임이 뜨고 머가 나오고 3초 정도 있다가 넣으니까 되더라. 이 추상적인 문구를 토대로 그 글을 본 멍청이들이 모두 따라 해봅니다. 하지만 쉽진 않죠. 이런 백성들을 불쌍히 여긴 해킹툴 제작자가 버전업된 인젝터를 만들기에 이르렀는데요. 바로 인젝션 딜레이를 밀리초 단위로 지정할 수 있게 만든 것이죠. 그 이후로 커뮤니티에는 온갖 추상적인 이야기들은 사라지고 그 밀리초만 공유하게 되었다는 슬픈 이야기가 전해지고 있답니다. 하앍~&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;게임_보안_타이밍_전쟁.md_2.png&apos; data-alt=&apos;내가 바로 그 유명한 알타. 하지만 XIGNCODE는 1000개를 띄워도 한번만 검사할 뿐이고~&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/3ce1cbed7adc9512e5e579fc18a63543/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 55.263157894736835%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACjklEQVR42l3OSU8TYQCA4Q8vRhPj1Z+hFzU1kpAoSgQ1inhQDgi4JBhQqKHIoshiqylbLUhoQ1gLpcTGpZKGTUwNYe3Q6Uy/2ffpAKVQKBBZBL355vkBLxjz3WrpLKiyXi6vTzK8v1BrSevtyx8cfN7elV1jTTa2XanrTGvpuzPwLb/TnVfSdKqwHmSVJqRkg9RcAKb9FQIfC+HoIWxWFMKaHNGkRVVbXwhg1rrqSoP+taG4zdbk6LLrjadvPgVJ945czACX7gPgD9hhgCUCECIYnPdzhEJj7CFCmZyYelWQ2VCU1VCQ867ihc1iNn94rMsAunSguw0S7yaAUV8zS8v+uQA6T5AoSaI0g6sUJpFBkaOjw97pxtZ+W4+nt/fr3Pis2+PNzD+bmH7s/I2jZ1IB6P9epEoRiEEKsjAQJIMhCmfZkEjjAgklBKF7up2m2remyupua7PT6XK77MNfro94UhyOa8A3Y4ssxjiWxRaCJMZyENI4xZLawT8DJZ5b9Y2OWYx6a5neWlvT0WYb8XxGELN36qQPPQEU6dNadFORZYGXGJrFEYzGMBJFeTrMEQIT4lhhbcr701VSpH+Wl5P7qFz/st1S3+o6Z3IcByHizaIa29hYV1SFwAkqxNKQYQmGI3iWlA/QpLIwg44PODvs7R+t9o62rsF+99DQULVNByi+NBr5HY1GVlfXlpeWJVlhKEhABAYnJFmVJFESeV5bgqRgzGusemiqzC0uf6CvK2wssyQDBH9ChgQtrG1tba1EVkRBJEkKQkJVNUaQ+PByOLoejsYkbQWZZPw+EvmFz/lQOiCXNl0F86FEXvwhcGFVUeIb8e3t7Z2/7e7uxOObO3t7u/v7//yXwZz8B7eu2k9+676GAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;내가 바로 그 유명한 알타. 하지만 XIGNCODE는 1000개를 띄워도 한번만 검사할 뿐이고~&apos; title=&apos;&apos; src=&apos;/static/3ce1cbed7adc9512e5e579fc18a63543/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_2.png&apos; srcset=&apos;/static/3ce1cbed7adc9512e5e579fc18a63543/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_2.png 190w,
/static/3ce1cbed7adc9512e5e579fc18a63543/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_2.png 380w,
/static/3ce1cbed7adc9512e5e579fc18a63543/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_2.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;내가 바로 그 유명한 알타. 하지만 XIGNCODE는 1000개를 띄워도 한번만 검사할 뿐이고~&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;또 다른 걸로는 게이머들이 많이 사용하는 용어이긴 한데 ‘알타’라는 말이 있습니다. 알집 타이밍의 준말인데요. 알집을 동시에 여러 개를 실행하는 것을 의미합니다. 알타50, 알타100등이 있는데요. 게임 실행 시점에 알집을 50개, 100개를 동시에 실행 시켜서 게임보안 제품이 알집을 검사하느라 해킹툴을 늦게 발견되도록 만드는 방법입니다. 대단하죠? 이토록 게임 해킹에 대한 사용자들의 욕망은 강렬합니다. 알타랑은 원리가 좀 다르긴 한데 자매품으로 Fraps 타이밍도 있답니다. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;XIGNCODE는 이런 방법에 대응하기 위한 다양한 기법들을 사용합니다. 기본적으로 거의 모든 검사 항목에 캐시를 사용합니다. 동일한 오브젝트를 두 번 검사할 필요는 없잖아요. 또 알집과 같이 알려진 프로그램에 대해서는 아주 빠르게 검사할 수 있도록 화이트 목록을 저장해 두는 방법도 사용하죠. 그리고 지능적으로 해킹툴 같아 보이는 것들부터 먼저 검사하도록 만드는 방법을 사용하기도 한답니다. 결국 뭐 알타는 XIGNCODE에게는 무용지물이라는 말이죠.&lt;/p&gt;
&lt;h3&gt;#4&lt;/h3&gt;
&lt;p&gt;해커와 게임보안 개발자 사이의 신경전적인 타이밍도 존재합니다. 바로 릴리즈 타이밍이죠. 새로 제작된 핵툴을 배포하는 시점과 그 핵툴을 차단하는 업데이트를 적용하는 시점을 의미합니다. 이런데 신경전이 있냐구요? 네 엄청나게 있습니다. 그런데 이것도 사실 게임보안 개발자가 천만배는 불리합니다. 왜냐하면 &lt;a href=&quot;http://www.jiniya.net/wp/archives/5657&quot;&gt;지난 글&lt;/a&gt;에서도 보았듯이 게임보안 제품 업데이트는 수많은 인력의 엄청난 시간과 노력을 필요로 하기 때문입니다.&lt;/p&gt;
&lt;p&gt;그런 신경전을 거는 녀석들은 어떤 녀석들인지 알아볼까요? 여러분이 게임보안 개발자라면 언제 해킹툴이 새로 나오면 제일 짜증날까요? 네. 맞습니다. 짝짝짝 ㅋㅋ~ 불금이죠. 불타는 금요일 밤인데 이 녀석들이 업데이트를 하면 참 뷁스럽지 않겠습니까? 더 얄미운 녀석들은 해킹툴 사이트에 보라고 이렇게 공지를 한답니다. 참고로 해외 해킹툴입니다. 우리는 해킹툴을 이미 다 만들었는데, 한국시간으로 금요일 밤에 업데이트 하겠다. 핡~ 혈압이~ ㅠㅜ~ 이 바닥이 이렇습니다.&lt;/p&gt;
&lt;p&gt;멍청하게 당하고만 있을수는 없지요. XIGNCODE 개발팀에서는 진단 루틴을 하나만 만들지 않고 한번에 여러 개를 만든답니다. 그리고 지난 번에 알려준 것처럼 시스템과 시간에 따라서 다르게 액티베이션되도록 만듭니다. 불금이 왔습니다. 해커는 신나게 릴리즈를 하죠. 어떻게 될까요? 네. 사용자들 원성이 자자하군요. 해커는 멘붕 시츄에이션에 봉착합니다. 자기 PC에서는 되는 것도 같거든요. 이런 불일치가 많아지면 많아질수록 해커는 쉽게 포기합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;게임_보안_타이밍_전쟁.md_3.png&apos; data-alt=&apos;XIGNCODE 개발팀 화이트보드에 붙은 그 녀석의 아바타~&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 178px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f30ee845b66455ca9b37d75d655f8a06/006cf/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 73.59550561797754%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACb0lEQVR42mN49uzZo0ePHj9+/PDhw+fPn799++bp48cvX70Esh8+ePAYL2AAagbpfPQIqOHgvv0T+yamxCaXF5afOH7i1atXQBMJaAaqePX69cZVa8xMbDkEpXj4xKUEpWwNLDZv2PTmzRs8+hmePHny4uXL4wcPOZjaystr8YjIcPGLiAqIKwhIGCqqHz106CVu+0Gagc6ryivSU9a11zFVllIS4hdTF5O1UtDQFJDMiIh+DdQMDhQsmoHW3rh0ycfOxVbHJMTEMtXa2kpJw0FZU19KUUlI1kRO9eyxoy9evXqEzXKGt+/f792yxVLDAIjCLKzm5cQnOTl66uh56+mK84vLcQtvXr78zbt3WF3O8OHjx/VLl6lKKvuamq8qTuxJiz/UXbysNLnC09VORUWaW+jg5s2vcAQbUPOHzavXakqr57g4nO0tvDa/7fr0siNNGUcb0vy01bSlFa6dPfP85ctHj7BpBkbS+RPHnQ0t022tznRkvdrQf3du7dUJBadbUoykpE0lZC8cOvDi9Wvsfn7+4sWdG9e9rF1cNfUOt2Vcn1l1qjX/YlvWtHhvQXY+F0WVXatWPscVYK9ev7l48oSNobmCmGJbqAfQzTemVq7LC9eRkpRg47eRVtiwYOHL16+x+/n582czOzplxWT5eUUzbMyuTSl4tLCm2MOKgYFFXVBciJG9uarmzdu32DXfvHzZ0dSCgYGBlYE93VT30dziV8tr6l3NxRjYRFk42RkYfIyMH925/fjp00cYSYXh5vmzWWGhzo5uLvZunWmJ99dNfL5r3uLCjIrgkHA371RPr31TO589eYw1iQEA6kRD+Uz8ktAAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;XIGNCODE 개발팀 화이트보드에 붙은 그 녀석의 아바타~&apos; title=&apos;&apos; src=&apos;/static/f30ee845b66455ca9b37d75d655f8a06/006cf/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_3.png&apos; srcset=&apos;/static/f30ee845b66455ca9b37d75d655f8a06/006cf/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_3.png 178w&apos; sizes=&apos;(max-width: 178px) 100vw, 178px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;XIGNCODE 개발팀 화이트보드에 붙은 그 녀석의 아바타~&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;신경전 이야기를 하니 예전 생각이 나는군요. XIGNCODE 역사상 이름이 가장 많이 거론된 해커가 한 명 있습니다. 얼마나 유명했냐면 개발팀 화이트보드에 그녀석 아바타 사진과 함께 WANTED가 붙기도 했죠. 걔 말고 그런 것이 붙었던 사람은 없었습니다. XIGNCODE 1.0시절 초창기 바이패스를 제작했던 녀석인데, 지금까지 그 녀석이 제작한 바이패스가 이론적으론 가장 완벽한 모델입니다. 그래서 우리는 아주 골치가 아팠죠. 그 녀석을 막기 위해서는 게임 서버에 있는 XIGNCODE 코드를 업데이트해야 했었거든요. XIGNCODE는 게임 서버가 구동 중인 상태에서도 업데이트가 가능하도록 설계는 돼 있지만 게임사에서 그렇게 하는 것을 별로 좋아라하지는 않습니다. 우리가 할 수 있는 업데이트는 일주일에 딱 한 번 정기 점검인 경우가 많았죠. 우리는 그 한 번의 샷을 최대한 활용하기 위해서 월화수목금토일 코드가 다르게 적용되도록 만들었답니다. 9-10개월 정도 지루한 공방이 이어졌지요. 그러다 세번째 버전인 XIGNCODE3가 나오면서 지금은 커뮤니티에서 자취를 감추었답니다. 다소 비극적인 결말이군요. SEH 하이재킹과 후킹을 참 잘하던 친구였는데. 적이었지만 실력은 인정해주고 싶은 친구였답니다. 부디 영원히 착하게 살아가길 ㅋㅋ~&lt;/p&gt;
&lt;h3&gt;#5&lt;/h3&gt;
&lt;p&gt;전쟁에서 이기기 위해서 가장 중요한 것은 정보고, 그 다음으로 중요한 것은 타이밍입니다. 게임보안에서도 마찬가지입니다. 정보와 타이밍이 참 중요합니다. 같은 값이면 이런 것들을 잘 이해하고 있는 사람들이 만드는 솔루션을 쓰는 게 좋겠다고 저는 생각하는데 말입니다. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;게임_보안_타이밍_전쟁.md_4.png&apos; data-alt=&apos;보안 제품 하나 바꿨을 뿐인데 핵툴 커뮤니티 소문 참 빠르네요. 왜일까요?&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 474px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/30daf1136d70bad5d3a94dd4ffec3b5c/823f8/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 37.89473684210527%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAA7DAAAOwwHHb6hkAAABaklEQVR42nXQO0/CUBQH8G4kFIyAJqa0UPp+A5GBGARbXp9AwIQ4uUhIe/uwmDoq4mdkLISBkR3wFmKCif6Gc/733nOWi4yeR7Ztu64HADAt4DhRPh4d2/Z937LMie9vNpv9fr/b7fYnkHQ6g+NEgaIwLJvLkWSePEsmE2giHo+jKHqeSsViMYIg1us1nN5ut7+WLcvyPM+J2DC4rgvgFYiKaZqwj8fjtyCYz+er1SoMw8VRuFgul0itVqvXG43Gna7rsOuG0Ww2W612t9M9BkM32u1OpVKhaZo6gKFAFjiOQ4qRUqlcLhY1RVXhkKZp8EEURZ7nORbiFEUVhQjPCwzNSJIMA8swiCzJHMtLoiTwIkOziqzAjF1heBYniBzxI3cin8/jOM7AZemaVaqCdiOrVUGtisqharcCTmGZ9MXlP+A3YxiGvLyD108n+PL8KfA/wGRqBzPPn5mPT8P+fX/wMPhTr9cbDoff1dGfwmmrBWEAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;보안 제품 하나 바꿨을 뿐인데 핵툴 커뮤니티 소문 참 빠르네요. 왜일까요?&apos; title=&apos;&apos; src=&apos;/static/30daf1136d70bad5d3a94dd4ffec3b5c/823f8/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_4.png&apos; srcset=&apos;/static/30daf1136d70bad5d3a94dd4ffec3b5c/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_4.png 190w,
/static/30daf1136d70bad5d3a94dd4ffec3b5c/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_4.png 380w,
/static/30daf1136d70bad5d3a94dd4ffec3b5c/823f8/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_4.png 474w&apos; sizes=&apos;(max-width: 474px) 100vw, 474px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;보안 제품 하나 바꿨을 뿐인데 핵툴 커뮤니티 소문 참 빠르네요. 왜일까요?&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;게임_보안_타이밍_전쟁.md_5.png&apos; data-alt=&apos;XIGNCODE는 해킹툴 제작자를 집으로 돌려보내는 유일한 솔루션이기 때문이지요.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/6d99b48ed0a2788e5988a9343ae9a7fd/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_5.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAA7CAAAOwgEVKEqAAAAC/klEQVR42lVTS08TURSeBRsSbWwbaKXtdPoA+pp22k4LKC0t1RX+CuPCBLAFTY1Ka0kf04f0xSN9mZQNBkMaiCgQFl0YiYkkoAnEuhJ8BBpYsbQPzy2Jid+c+e53TnLPuefcGSwcjkw+vu8Njk88HBsff+B0OkdHR8/OzprNZqPRqNfrIMrlstvt9vv9U1Men8/n8bbg8WCJeDKZmknPxeOJGUAiAUu8WCwuvVoqLi7mcrlSqeR0uthsDo7jIiEuEAgIgujqErDZbEwul6vVGoVCqVQoVUqlSqUGt6e7RyaTcbnc9vZ2Pp8/MnKnr3/AMmixWof6+/qUSiVJkr29CkyvN5hok57Sm2gzTdMgaNpEG40KhaIboQeSORwOPv+6mCDwFlgs1lWEK5haoyE1JBQkNRpUFFyShBWSUhQllcrgnNO+6UKhsNBCNpMFA8pmMhgcEypTOkqro4xGo05HGfQGrVYLBwFXLpPjInxrcxPGVqvVmv8DW1lZgalkWsjn8ygjSpoBhnih8BIiu7u7Jycnx8fHPxB+gri4uICLwA4PD6Elu93uGB6224dtNpvVYm25EHAMDNw0m806nQ5a06C+UFMw4/X1dVR5f39fKpXCMCTAsBAS9EoQQ7yrBaFQCJ0LWxCJRBwOG+4Pbd7b28NxMYTgbqRSiVgshuskCDFoSCLvhkfG4/M7Ojt4PF5nC21tbcvLy2hztVqFSc7NzqeSc8nEbCKeTiSQpVPzlyIeT8dicbBodAYsmUqn0umvlQrafDm3hXzU/fRuIOQKMK5AyBkMT0wHxoADzIQ/5AqFJyHIRB89eXZve/vNv8ljjWbjT632+9f3T5XP2c213LvV3MZqYetNFgnk5jfWwCCY31zLvC29/vC+XPm2cXBQOT9HleuNBvCXoyP5rdtSq01isQn6bxCDVonVRgzZebSZo6U6KAOX0nN1epZKfU1DYvDl5HLY5d8DXD09hc6i4fCLaBQYLBaJxEAyTDgUAmOCQQYEw0Qjkede78ednb/5PIzz2F+bLQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;XIGNCODE는 해킹툴 제작자를 집으로 돌려보내는 유일한 솔루션이기 때문이지요.&apos; title=&apos;&apos; src=&apos;/static/6d99b48ed0a2788e5988a9343ae9a7fd/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_5.png&apos; srcset=&apos;/static/6d99b48ed0a2788e5988a9343ae9a7fd/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_5.png 190w,
/static/6d99b48ed0a2788e5988a9343ae9a7fd/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_5.png 380w,
/static/6d99b48ed0a2788e5988a9343ae9a7fd/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%83%80%EC%9D%B4%EB%B0%8D_%EC%A0%84%EC%9F%81.md_5.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;XIGNCODE는 해킹툴 제작자를 집으로 돌려보내는 유일한 솔루션이기 때문이지요.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 게임 보안: 랙에 관한 모든 것]]></title><description><![CDATA[#0 잘나가는 게임에서 가장 민감한 이슈를 하나 꼽으라면 랙이다. 모든 게이머들이 가장 싫어하는 단어 중에 하나고, PC를 업그레이드하는 가장 큰 이유 중에 하나가 랙이다. 그렇다면 도대체 그 랙(lag…]]></description><link>https://jiniya.net/wp/archives/7303</link><guid isPermaLink="false">https://jiniya.net/wp/archives/7303</guid><pubDate>Fri, 06 Jul 2012 23:58:17 GMT</pubDate><content:encoded>&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;잘나가는 게임에서 가장 민감한 이슈를 하나 꼽으라면 랙이다. 모든 게이머들이 가장 싫어하는 단어 중에 하나고, PC를 업그레이드하는 가장 큰 이유 중에 하나가 랙이다. 그렇다면 도대체 그 랙(lag)이란 무엇일까? 랙이란 단어 의미 그대로 지연을 나타낸다. 게임상에서 발생하는 그 모든 지연에 대해서 우리는 랙이라고 이야기한다.&lt;/p&gt;
&lt;p&gt;요즘 가장 핫한 게임을 꼽으라면 단연 디아3를 빼놓을 수 없다. 처음 아시아섭이 혼잡해서 접속이 원활하지 않아서 북미섭에서 노멀을 클리어하면서 난 블리자드 장인 정신의 정수 그 자체를 맛보았다. 엔딩을 보고는 이제껏 단 한 차례도 보지 않았던 크레딧을 무려 5분이 넘게 봤다. 그 정도로 감동적인 게임이었고, 그 정도로 누가 만들었는지 궁금했다. 웃긴건 엔딩 크레딧을 5분 넘게 봤는데 안 끝나서 닫았다. 우리 회사의 한 직원은 15분을 봤는데도 끝나지 않아서 닫았다고 한다. 참고로 모든 엔딩 크레딧을 보는데는 대략 18분 정도가 소요된다. 역시 크레딧도 블리자드 스케일 ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 620px; margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_랙에_관한_모든_것.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5647c4e021823acbee1d83d9963251bb/abf7b/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%9E%99%EC%97%90_%EA%B4%80%ED%95%9C_%EB%AA%A8%EB%93%A0_%EA%B2%83.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 57.89473684210527%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACvElEQVR42gXBSXPSUAAA4Nz1YK0bpBRoWUNIXgIhJCHbewkNSyAhlKVFoKtgbavWUbQuVUenrjMuMx0dHQ8649mDy0HHiz/M78MYyeZhDQclX8oMsvY83+LgsuWMUG1s2JtF72K5uQUrgwV70F3e2N8aDFsbnLWqVPv94Rg7OXUm4J89NR2YngpEfPMwRZWRZ9VXJfcSXd8NzbB4IBOJ6NEgZVKxj3b8ssokCfasP07xJnb8RGDqVOScj5gPMjVRbI0mzWd/UPtGZ+dwcP1llIRAWqo277BAW0bKA0+bNDUX6oDkFOhiZ07PBXzxEJ7mifyoUmzcfrt29Pfuw6f37x08enhYbm1euva85F2J0mVDdQblqquajgbZZEbRG1jYT4RxMhQA0RCPcsVesT668Xxncre/Nu7c+lAa7kNnOyKuzGaHiUwnl3U0sSRnYCwMJNnGwjMgEuLmQnlZrOlwqd5YLzXWGyvXq71tc/N1b/fF4sptt7vnLu0ZrSdq5YAGC2qhQSYlUXYwP87Golo0BgXeyRc8TvESlGF1dy9M3o33Pt88+N4fHa1vHS229xBcUXOLIF6k4iiE5yTFw6zsZiLMg4TJJIuK8yaSHz5Z+7G7+mV549Pl/d/D0Ve7997qvOLFIZ/xMqkSkzRBAiYDWUNzsdcXfphMu0AgnXZluc9Ihq1fW3fe3t/6tb/902u/zKKrGX3MUBYCVYWu0QmDiOvBGU5Wm9jEO/x28x9MWUqqIlIawy5M+8ljJ3DcT5MxwY+nY8FcMlEC8LEi7OhpRyAsLmnEZ2VZ72FE0EDk+XRQmPfFmCiQKBSdKwC6U0G30kKN4ip50DXVSbX3HUlrVBBwESM2B8+eBoJoYyBXz+YqTLaUSJP5vIR4PUNTPOAVoSBIBTmXBSTJEqGi0kCixoK0mncLhS4Jiqjc/g8oksYECmoU1gAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                 md 0&apos; title=&apos;&apos; src=&apos;/static/5647c4e021823acbee1d83d9963251bb/abf7b/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%9E%99%EC%97%90_%EA%B4%80%ED%95%9C_%EB%AA%A8%EB%93%A0_%EA%B2%83.md_0.png&apos; srcset=&apos;/static/5647c4e021823acbee1d83d9963251bb/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%9E%99%EC%97%90_%EA%B4%80%ED%95%9C_%EB%AA%A8%EB%93%A0_%EA%B2%83.md_0.png 190w,
/static/5647c4e021823acbee1d83d9963251bb/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%9E%99%EC%97%90_%EA%B4%80%ED%95%9C_%EB%AA%A8%EB%93%A0_%EA%B2%83.md_0.png 380w,
/static/5647c4e021823acbee1d83d9963251bb/abf7b/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%9E%99%EC%97%90_%EA%B4%80%ED%95%9C_%EB%AA%A8%EB%93%A0_%EA%B2%83.md_0.png 620w&apos; sizes=&apos;(max-width: 620px) 100vw, 620px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
&lt;strong&gt;랙으로 이런 화면을 접하게 된다면 모든 게이머는 뚜껑이 열리는 기분을 느낀다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;그런 초대작 게임도 랙 이슈는 피해가지 못했다. 디아3는 사실 랙도 블리자드 스케일이다. 주로 서버 랙이라고 불리는 것들인데 이런 상황을 말한다. 내가 기술을 사용하고 2초 정도 있다가 실제로 기술이 발동된다거나, 내가 피통을 보고 적절한 시점에 힐링포션을 먹었음에도 랙 때문에 죽는다던가, 골드 위를 지나가고 2초 있다가 골드가 먹어진다거나 하는 상황을 말한다. 물론 그렇다고 클라이언트 랙이 전혀 없는 것도 아니다. 사양이 충분히 좋지 않은 환경에서는 몹이 대량으로 갑자기 출몰하는 지역이라던가 물리적인 시츄에이션이 겹치는 상황에서는 게임 화면이 프리징되는 경우도 종종있다. 경매장 랙은 말할 필요도 없겠다. 이런 랙은 정말 게임의 재미를 천만분의 일로 반감시키는 효과가 있다. 실제로 집에서 디아를 하다가 이런 연유로 챔피언 몹에게 한 세 번 눕고 나니 할맛이 나질 않아서 이 글을 쓰고 있기도 하다. ㅋㅋㅋ~&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;이쯤이면 랙이 뭔지는 충분이 이해했을 것 같다. 그렇다면 다음으로 이런 랙의 원인에 대해서 알아보도록 하자. 도대체 이런 빌어먹을 랙은 어디에서 오는 것일까? 도대체!!!&lt;/p&gt;
&lt;p&gt;가장 흔한 원인은 말 그대로 네트워크 지연 때문이다. 온라인 게임은 대부분 네트웍을 전제로 게임이 진행된다. 응당 서버/클라이언트가 있게 되고 이 사이에 통신 속도가 존재한다. 게이머들은 흔히 이를두고 핑(ping)이라 표현한다. 이 핑이 일정 수준 이상으로 높으면 지연이 발생하고 있다는 것을 직접적으로 말해준다. 지연 속도가 특정 수치 이상이 되면 불일치가 발생한다. 게임 클라이언트에서는 공격 모션이 나왔음에도 실제로 공격 대상에는 피해 수치가 적용되지 않는것과 같은 상황이 발생하는 것이다. 이게 점점 심해지면 어느 순간 자신도 모르게 멀미가 나오는 것을 느낄 수 있다.&lt;/p&gt;
&lt;p&gt;이런 온라인 게임의 네트워크 품질은 비단 자신의 인터넷 회선에만 영향을 받는 것은 아니다. P2P 방식으로 게이머들끼리 네트웍을 형성해서 진행되는 게임의 경우에는 다른 게이머의 네트워크 회선 속도에 자신도 같이 영향을 받는다. 빛의 속도에 근접하면 전혀 다른 세상이 펼쳐지는 것처럼, 핑이 일정 수준 이상으로 높아지면 개발자들이 전혀 예측하지 못했던 새로운 문제들이 발생하기도 한다. 이런 버그들을 악용해서 일부 게이머들은 랜선을 뽑았다 다시 연결하는 태핑이나 특정 패킷을 특정 주소로 무한대로 전송하는 누킹, 자신의 PC에 랙을 의도적으로 유발시키는 랙핵과 같은 방법을 사용해서 추가적인 이득을 얻기도 한다.&lt;/p&gt;
&lt;p&gt;랙의 또 다른 요인은 게임 서버에 존재한다. 최근 온라인 게임의 추세는 클라이언트는 뷰어 역할만 하고 게임 서버에서 모든 게임 상태를 모델링하는 방식으로 진화하고 있다. 왜일까? 당연히 해킹을 막기 위함이다. 디아3에서 간단한 조작으로 화면에 표시되는 골드 값을 변경할 수 있을지 몰라도 실제 그 표시되는 데이터로 경매장을 이용할 순 없는 것과 동일한 이치다. 실제 데이터는 서버에 모두 저장돼 있고 그 값을 토대로 계산이 진행되기 때문이다. 이렇게 서버가 복잡해지다보니 서버의 상태 이상이 고스란히 랙으로 전달된다. 내가 속해 있는 게임 서버의 상태 이상으로 모델링 처리 속도가 지연되면 그 모든 영향을 내가 그대로 받는다는 말이다. 최근에 블리자드는 디아3에서 짧은 간격으로 방을 자주 생성하는 것을 막겠다고 공지를 했다. 방을 자주 생성하면 서버에 상태 이상이 발생하게 되고 그게 해당 서버에 속한 다른 게이머들에게 피해를 주기 때문에 그같은 조치를 취했다고 생각할 수 있다. 이런 점들을 본다면 이런 종류의 랙에 대해서 게이머가 할 수 있는 것은 하나도 없다. 그저 손가락 빨면서 게임 개발사에서 서버를 안정화 시키기를 기다리는 수 밖에는 없다. 디아3 랙이 지금 답이 없는 상태와 같은 이치다.&lt;/p&gt;
&lt;p&gt;랙을 유발하는 마지막 이유는 모든 게이머가 잘 알고 있듯이 컴퓨터 사양에 있다. 컴퓨터 사양이 해당 게임을 구동할 수 있을 정도로 충분히 빠르지 않다면 필연적으로 심각한 랙이 발생한다. 이 경우에는 당연히 업그레이드 말고는 답이 없다. 물론 게임의 그래픽 옵션 사양을 낮추고, 해상도를 낮추는 방법을 통해서 어느 정도의 가용성을 확보할 수 있기도 하지만 실질적으로 쾌적한 게임을 즐기기 위해서는 컴퓨터 업그레이드가 유일한 답이다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;그렇다면 이렇게 게임의 재미를 반감시키고, 유저들의 원성을 사며, 동접을 저하시키고, 게임의 수익 창출을 방해하는 랙을 게임사는 도대체 왜 방치하는 것일까? 왜? 모든 게임마다 모든 게이머들은 랙 때문에 불평 불만을 하는 것일까? 원인이 명확하면 그냥 고치면 되는거 아닐까? 하지만 이 문제를 해결하는 일은 생각처럼 쉽진 않다.&lt;/p&gt;
&lt;p&gt;일단 회선 문제. 여기에 대해서 게임사에서 해줄 수 있는 것은 아무것도 없다. 우리 나라의 경우 회선이 아주 좋은 상태지만 해외의 경우에 그렇지 않은 경우도 많다. 정말 희한한 곳들이 많이 있다. 업로드/다운로드 트래픽이 제한된 곳, 인터넷인데 인터넷이 아니라 인트라넷인 경우, 심지어는 업데이트 패치를 제대로 받지 못해 수동패치를 제공해야 하는 경우도 적지 않다. 뭐 국내라고 마냥 좋은 것만은 아니다. 공유기에 공유기에 공유기에 공유기를 쓰는 환경이라던가. 회선 자체가 불량인 경우라던가. 악성 코드에 감염되서 핑이 불안한 경우라던가. 각종 시츄에이션이 다 있다. 하지만 게이머들은 충분한 기술적인 지식이 없기 때문에 자신의 이러한 인터넷 상태에 대해서 잘 알지 못한다. 그저 게임이 되지 않는다고, 핑이 튄다는 이야기를 한다.&lt;/p&gt;
&lt;p&gt;다음으로 서버 랙. 이 경우는 게임 개발사에서 해결을 해야 하는 문제다. 또한 어느 정도 분명한 원인을 가지고 있는 문제이기도 하다. 하지만 이것 또한 정말 쉽지 않다. 왜냐하면 99.98%의 서버랙 이슈는 사용자가 미치도록 몰리고, 게이머가 개발자가 전혀 예측하지 않은 형태로 플레이를 하면서 발생하기 때문이다. 라이브 환경에서만 문제가 발생하기 때문에 해결이 쉽지 않다는 말이다. 더욱이 요즘 게임 서버는 단순히 게임 서버 하나만이 아니라 우리가 상상할 수 없을 정도로 복잡한 구조로 다양한 서버들이 엮여 있기 때문에 랙이 발생해도 도대체 어떤 부분에서 무엇 때문에 지연이 되는지 찾는 일이 백사장에서 바늘 찾기만큼이나 어렵다. 이 문제를 안드로메다로 데려가는 마지막 이유는 게임이 일단 상용화에 들어가고 나면 게임 개발자가 멋대로 변경할 수 있는 것들이 극도로 제한된다는 점이다. 즉, 거의 대부분의 경우에 크리티컬한 이슈가 아니라면 서버 개발자는 이러지도 저러지도 못하는 상황에 처할 수 밖에 없다. 그래서 CBT를 하고 OBT를 하는데, 안타깝게도 요즘에는 그 마저도 아주 짧게 가져가는 추세다. 그래서 이런 이슈가 더 많이 부각되기도 하는 것 같다.&lt;/p&gt;
&lt;p&gt;끝으로 클라이언트 랙을 살펴보자. 이건 기본적으로 클라이언트 리소스가 크기가 정해지는 순간 개발자의 역량으로 할 수 있는 일은 상당히 제한된다. 요즘 게임은 워낙 규모가 크기도 하고, 그런 규모만큼이나 외부 라이브러리를 많이 사용하기 때문이다. 개발자의 열정으로 최적화를 시키던 시대는 쫌 지났다는 말이다. 사실 클라이언트 랙으로 사용자들이 욕을 하는 이유는 다른 곳에 있다. 바로 최소 사양과 권장 사양이다. 대부분의 게임사에서 권장 사양을 최소 사양으로 공지하는 경우가 많다. 그렇다보니 게이머들은 진짜 그게 권장 사양인줄 알고 자기 PC는 권장 사양보다 좋은데 랙이 발생한다고 징징되는 것이다. 사실 거의 대부분의 경우에 권장 사양은 실질적인 의미의 최소 사양이라고 생각하는 편이 정신 건강에 좋다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_랙에_관한_모든_것.md_1.png&apos; data-alt=&apos;디아블로3 권장사양. 귀가 막히고 코가 막힌다.&lt;br&gt;&lt;br&gt;우리집은 저거보다 훨씬 좋음에도 모든 옵션을 최소로 해야 그나마 랙이 들하다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 530px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/4664e5b0039a62db06025d059243a7dc/a0177/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%9E%99%EC%97%90_%EA%B4%80%ED%95%9C_%EB%AA%A8%EB%93%A0_%EA%B2%83.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 47.368421052631575%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAA0ElEQVR42nWRiw5EMBBF/f/P7SKk2Ch90S2+YY82+wpuJpPbeV4jM8bUdV0URVmWbdtWVaW1DhHbti3L8rxGNs+zVsoagzlrk83TNEiZ53nTNJNzp+a9z57e0081NkWPEaL5frs1QsT0CfbNDJBSdl33iOj7nmcfsa4rysM1MgaM40ipUmqI+DQzC04kcQg1XOHbzGZuRhp/Oj5V+zf+NqOekUIIlCMhreXgcOKQJIdz/O78yiZhLcfeoSNsBE/nXCLUnH8zOOr8kOSPPzmE8AK+X+Tgb0M05AAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;디아블로3 권장사양. 귀가 막히고 코가 막힌다.&lt;br&gt;&lt;br&gt;우리집은 저거보다 훨씬 좋음에도 모든 옵션을 최소로 해야 그나마 랙이 들하다.&apos; title=&apos;&apos; src=&apos;/static/4664e5b0039a62db06025d059243a7dc/a0177/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%9E%99%EC%97%90_%EA%B4%80%ED%95%9C_%EB%AA%A8%EB%93%A0_%EA%B2%83.md_1.png&apos; srcset=&apos;/static/4664e5b0039a62db06025d059243a7dc/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%9E%99%EC%97%90_%EA%B4%80%ED%95%9C_%EB%AA%A8%EB%93%A0_%EA%B2%83.md_1.png 190w,
/static/4664e5b0039a62db06025d059243a7dc/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%9E%99%EC%97%90_%EA%B4%80%ED%95%9C_%EB%AA%A8%EB%93%A0_%EA%B2%83.md_1.png 380w,
/static/4664e5b0039a62db06025d059243a7dc/a0177/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%9E%99%EC%97%90_%EA%B4%80%ED%95%9C_%EB%AA%A8%EB%93%A0_%EA%B2%83.md_1.png 530w&apos; sizes=&apos;(max-width: 530px) 100vw, 530px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;디아블로3 권장사양. 귀가 막히고 코가 막힌다.&lt;br&gt;&lt;br&gt;우리집은 저거보다 훨씬 좋음에도 모든 옵션을 최소로 해야 그나마 랙이 들하다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;클라이언트 랙의 또 다른 이유는 서드파티 제품에 있다. XIGNCODE와 같은 외부 보안 제품도 그런 것들 중에 하나다. 이런 랙 이슈가 게임보안 제품 개발을 어렵게 만드는 이유 중에 하나이기도 하다. 어쨌든 이런 외부 보안 제품도 구동 비용이 0은 아니기 때문에 랙에 영향을 주고 사양에 따라서 미치는 영향이 훨씬 더 커지기도 한다. 안타깝지만 여기에 대해서도 게임 클라이언트 개발자가 해줄 수 있는 일은 사실상 없다. 서드파티 제품 개발자가 할 수 있는 부분이기 때문이다.&lt;/p&gt;
&lt;p&gt;게임 게시판을 모니터링 하다보면 많은 사용자들이 발적화를 운운하며 게임 개발자의 역량을 평가하는 글을 올리는 것을 볼 수 있다. 안타까운 마음에 여기에 몇 글자 덧붙이자면 대부분의 개발자는 거의 비슷한 성능의 코드를 작성한다. 적당히 뛰어난 개발자 A와 그저 그런 개발자 B가 작성한 코드에서 성능 차이는 사실 크지 않다는 말이다. 대부분의 드라마틱한 성능 개선은 개발자의 피땀어린 코딩보다는 문제를 바라보는 시각을 고치는 경우에 만들어진다. 또 그런 문제를 바라보는 시각을 고치는 일은 보통 프로그래머보다는 전산학자들이 하는 일이기도 하다. 그러니 발적화 운운하면서 너무 개발자를 욕하지 말자. 그들은 항상 최선을 다해서 자신이 아는 범위 안에서 가장 빠른 코드를 작성하는 사람들이다.&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;지금까지 주구장창 어렵다는 이야기만 했는데 사실상 이 문제를 힉스 입자를 발견하는 것과 동급으로 만드는 본질적인 이유는 다른 곳에 있다. 바로 게임 개발자, 운영자, QA, 서드파티 제품 개발자, 운영자, QA 모두 랙을 모른다는 것이다. 거의 대부분의 경우에 그 모든 사람들은 게이머가 말하는 랙을 전혀 이해도 하지 못한다. 왜 그럴까? 서로 체감하는 시간의 기준이 다르기 때문이다. 게이머들은 우리가 상상하는 것보다 훨씬 더 민감하다는 말이다.&lt;/p&gt;
&lt;p&gt;예전에 블리자드의 스타크래프트 개발자가 한국에 와서는 임요환 선수가 마린으로 럴커 잡는 것을 보고는 저런 식으로 플레이를 할줄은 상상도 못했다는 이야기를 했다. 그도 그럴것이 럴커는 마린의 상성 유닛이었기 때문이다. 임요환 선수 정도되면 어떤 것을 느끼냐면 럴커의 촉수가 평소보다 빨리 다가오는지 늦게 다가오는지 스팀팩을 쓴 다음 활성화가 어느 정도에 되는지를 느낀다. 물론 직접 물어본 거는 아니니 이걸로 태클걸진 말도록 하자 ㅋㅋ~ 일반 게이머 중에서도 잘하는 게이머들은 이런 아주 마이크로한 부분에 대해서 굉장히 민감하게 반응한다. FPS 게임이라면 총기를 교환하는 속도, 탄환이 발사되는 속도, 줌 속도, MMO 게임에서는 특정 기술이 발동하는 모션의 속도, 자신이 설치한 구조물들이 활성화되는 속도 등등 전혀 게임을 잘하는 사람이 아니라면 알 수 없는 부분에 대해서 불평을 한다. 이게 어려운 점이다. 왜냐하면 게임을 그 정도로 잘하지 않고서는 백날 죽었다 깨어나도 그 속도의 차이를 알 수 없기 때문이다.&lt;/p&gt;
&lt;p&gt;QA 팀에서 백날 랙 테스트를 해도 문제 없다고 하는 이유가 바로 여기 있다. QA 팀에는 실제 유저가 말하는 랙을 체감할 수 있을만큼 그 게임을 잘하는 플레이어가 없기 때문이다. QA 팀에서 봤을 때는 총기 교체 속도가 원래 만큼이나 충분히 빠르기 때문이다. 안타까운 현실이 아닐 수 없다. 이런 점들을 보완하기 위해서 우리같은 게임관련 서드파티 업체들은 항상 채용할 때 물어보곤 한다. 게임 잘 하세요? 좋아하는 온라인 게임 있으세요? 실제로 우리 회사에는 FPS 게임을 제법 잘하는 QA 직원이 한 명 있는데, 그 직원은 다른 직원보다 해당 분야의 게임에 대한 랙이나 핵을 찾는데 훨씬 더 뛰어난 역량을 보여준다. 실제로 게임사나 서드파티나 랙이란 문제에 대해서 진지한 접근을 하고 싶다면 랙을 이해할 수 있을만큼 뛰어난 게이머를 채용해야 한다. 그렇지 않고서는 백날 테스트 해봐야 도로아미타불이다.&lt;/p&gt;
&lt;h3&gt;#4&lt;/h3&gt;
&lt;p&gt;이 글을 쓰던 당시엔 블소가 출시하기 전이었다. 최근에 블소 OBT가 진행됐고, 얼마전에 유료화를 단행했다. 하지만 그런 초핫한 게임인 블소 조차도 랙 이슈는 피해가질 못했다. 게시판을 봐도 블소 하는 사람들 이야기를 들어보아도 랙 이야기는 떠나질 않는다. 어쩌면 랙은 성공한 게임에 따르는 승자의 저주 같은건지도 모르겠다. 일단 사람이 몰려야 발생하니 말이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_랙에_관한_모든_것.md_2.jpg&apos; data-alt=&apos;캐릭터는 슈퍼 갑 블소~ 하앍~&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 480px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/c5dec375a3c9bf6484a6f60b4f2f7045/a3e66/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%9E%99%EC%97%90_%EA%B4%80%ED%95%9C_%EB%AA%A8%EB%93%A0_%EA%B2%83.md_2.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 62.63157894736842%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABQADBP/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAErqN1hOOj/xAAbEAABBQEBAAAAAAAAAAAAAAABAAIDERITFP/aAAgBAQABBQLmLEDMeaJaK6uoykr/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAcEAABAwUAAAAAAAAAAAAAAAAAARAREjEyQXH/2gAIAQEABj8CuVLJlxo03//EABsQAAIDAAMAAAAAAAAAAAAAAAABESExQVFx/9oACAEBAAE/Ic0tgj2NSwWraH2Vos05LwQVKkf/2gAMAwEAAgADAAAAEAzf/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAR/9oACAEDAQE/EBLS/8QAFhEAAwAAAAAAAAAAAAAAAAAAAAER/9oACAECAQE/EHSM/8QAHhABAAICAgMBAAAAAAAAAAAAAQARITFBsVFhgaH/2gAIAQEAAT8QtWEFONeYQ2Kac3fX7GFBmX2O4EHhqCjGG0YH1CL0UF5otn//2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;캐릭터는 슈퍼 갑 블소~ 하앍~&apos; title=&apos;&apos; src=&apos;/static/c5dec375a3c9bf6484a6f60b4f2f7045/a3e66/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%9E%99%EC%97%90_%EA%B4%80%ED%95%9C_%EB%AA%A8%EB%93%A0_%EA%B2%83.md_2.jpg&apos; srcset=&apos;/static/c5dec375a3c9bf6484a6f60b4f2f7045/8ccab/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%9E%99%EC%97%90_%EA%B4%80%ED%95%9C_%EB%AA%A8%EB%93%A0_%EA%B2%83.md_2.jpg 190w,
/static/c5dec375a3c9bf6484a6f60b4f2f7045/ea4c8/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%9E%99%EC%97%90_%EA%B4%80%ED%95%9C_%EB%AA%A8%EB%93%A0_%EA%B2%83.md_2.jpg 380w,
/static/c5dec375a3c9bf6484a6f60b4f2f7045/a3e66/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EB%9E%99%EC%97%90_%EA%B4%80%ED%95%9C_%EB%AA%A8%EB%93%A0_%EA%B2%83.md_2.jpg 480w&apos; sizes=&apos;(max-width: 480px) 100vw, 480px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;캐릭터는 슈퍼 갑 블소~ 하앍~&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[스레드 열거하기]]></title><description><![CDATA[ToolHelp를 사용해서 스레드 열거하기 윈도우 환경에서 시스템에서 수행중인 스레드를 열거하는 가장 손쉬운 방법은 ToolHelp 라이브러리를 사용하는 방법이다. ToolHelp 라이브러리는 kernel32.dll…]]></description><link>https://jiniya.net/wp/archives/7676</link><guid isPermaLink="false">https://jiniya.net/wp/archives/7676</guid><pubDate>Thu, 05 Jul 2012 23:58:16 GMT</pubDate><content:encoded>&lt;p&gt;ToolHelp를 사용해서 스레드 열거하기&lt;/p&gt;
&lt;p&gt;윈도우 환경에서 시스템에서 수행중인 스레드를 열거하는 가장 손쉬운 방법은 ToolHelp 라이브러리를 사용하는 방법이다. ToolHelp 라이브러리는 kernel32.dll에 포함된 프로세스/스레드/모듈 열거 관련 라이브러리를 말한다. kernel32.dll에 포함돼 있기 때문에 별도로 외부 파일을 별도로 설치할 필요 없이 바로 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;ToolHelp 라이브러리에서 스레드 열거에 사용되는 함수 원형이 &amp;#x3C;리스트 1&gt;에 나와 있다. 가장 중요한 함수는 CreateToolhelp32Snapshot 함수다. 이 함수는 호출 시점에 시스템 정보에 대한 스냅샷을 만들어주는 역할을 한다. dwFlags에 TH32CS_SNAPTHREAD를 전달하면 시스템에서 실행되고 있는 스레드 스냅샷을 생성할 수 있다. th32ProcessID는 무시된다. 함수가 성공하면 스냅샷 핸들이 반환된다. 해당 스냅샷 핸들은 사용하고 나서 CloseHandle 함수를 사용해서 닫아주면 된다.&lt;/p&gt;
&lt;p&gt;스냅샷 핸들을 만든 다음에는 해당 스냅샷에 포함된 엔트리 정보를 구할 차례다. 해당 엔트리 정보를 구하는데 Thread32First와 Thread32Next 함수가 사용된다. 각 함수는 첫 번째 엔트리와 다음 엔트리를 반환하는 역할을 한다. 엔트리가 없는 경우에는 함수가 실패한다. 각 함수의 첫 번째 인자에는 스냅샷 핸들을 두 번째 인자에는 정보를 반환 받을 구조체 포인터를 전달하면 된다. 이 때 주의해야 할 점은 구조체의 dwSize 필드를 함수 호출 전에 구조체 크기로 초기화 시켜주어야 한다는 점이다. 스레드 정보를 담고 있는 THREADENTRY32 구조체의 구조와 자주 사용하는 필드의 의미는 &amp;#x3C;리스트 2&gt;에 나와 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 1 스레드 열거 관련 함수 원형&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HANDLE WINAPI &lt;span class=&quot;token function&quot;&gt;CreateToolhelp32Snapshot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DWORD dwFlags&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DWORD th32ProcessID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
BOOL WINAPI &lt;span class=&quot;token function&quot;&gt;Thread32First&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE hSnapshot&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPTHREADENTRY32 lpte&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
BOOL WINAPI &lt;span class=&quot;token function&quot;&gt;Thread32Next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE hSnapshot&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPTHREADENTRY32 lpte&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 2 THREADENTRY32 구조체&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;tagTHREADENTRY32&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  DWORD dwSize&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 구조체 크기&lt;/span&gt;
  DWORD cntUsage&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  DWORD th32ThreadID&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 스레드 아이디&lt;/span&gt;
  DWORD th32OwnerProcessID&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 스레드가 포함된 프로세스 아이디&lt;/span&gt;
  LONG  tpBasePri&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 스레드 우선순위&lt;/span&gt;
  LONG  tpDeltaPri&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  DWORD dwFlags&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; THREADENTRY32&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PTHREADENTRY32&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;ToolHelp 라이브러리를 사용해서 시스템에 수행중인 스레드를 열거하는 프로그램이 &amp;#x3C;리스트 3&gt;에 나와 있다. 각 스레드의 프로세스 아이디와 스레드 아이디를 출력하는 역할을 한다. thread1 프로그램의 실행 결과는 &amp;#x3C;화면 4&gt;에 나와 있다. 화면을 살펴보면 알 수 있겠지만 이 프로그램은 시스템에 수행중인 모든 스레드를 열거하는 역할을 한다. 특정 프로세스에 포함된 스레드 정보를 구하고 싶다면 각 엔트리의 th32OwnerProcessID 필드 값으로 필터링 하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 3 thread1 프로그램&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;windows.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;tlhelp32.h&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Visitor&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; BOOL &lt;span class=&quot;token function&quot;&gt;Visit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;T &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; Visitor&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;THREADENTRY32&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; ThreadVisitor&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

BOOL
&lt;span class=&quot;token function&quot;&gt;EnumThreads&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ThreadVisitor &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;visitor&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    HANDLE snapshot&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    THREADENTRY32 te32&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    snapshot &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateToolhelp32Snapshot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;TH32CS_SNAPTHREAD&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;snapshot &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; INVALID_HANDLE_VALUE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    te32&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dwSize &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;te32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Thread32First&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;snapshot&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;te32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;snapshot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;visitor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Visit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;te32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;snapshot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Thread32Next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;snapshot&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;te32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;snapshot&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ThreadPrinter&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token base-clause&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ThreadVisitor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; BOOL &lt;span class=&quot;token function&quot;&gt;Visit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;THREADENTRY32 &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;PID =&gt; %5d, TID =&gt; %5d\n&quot;&lt;/span&gt;
                 &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;th32OwnerProcessID
                 &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;th32ThreadID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ThreadPrinter printer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;EnumThreads&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;printer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 677px; margin-bottom: 16px;&apos; data-url=&apos;./스레드_열거하기.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/22203cc16cd21ea10d8ff4234a85b905/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EC%97%B4%EA%B1%B0%ED%95%98%EA%B8%B0.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 57.89473684210527%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAAsTAAALEwEAmpwYAAABfklEQVR42pWRa0sCQRSGx1u6qyV5WXfm7OrurLsqKpqZ9d8qCCIwMEtYrW3zlmWZFCoEQX+uEUvoQ7CdeTkf5szD+zIHPU5nk/n7w3RujSad4bhhj07N7lmn335e2G8f5tP88OLmqGkdN62TVvdy8NKfzMavi887yz6vo2hkW6E0n88DQEpR2fH6vAGOW2vDH/iR3x/g+GDI4/NRI3M7GKFQkAeQMrouCAImRJIAIeRyudAftRoRQnrDexTkeQKgL+F4LC5I4AgGQroDBnMBEWNNo9FoREgkCMaOYCAdu4fCmyEGZzIGxlhOpmRZcgaDadkovLWJCRh6WhRFBjuNDdBq3yCe4yRZ1qgajbDYLAT+hzP77aSiZA0jLghLZ8lhbGLedlnsLUWluVyWmapUY4tmM7fb43K7v/Wr2MTDHjCPNoNXe6aqEo/FCAEsig73fNW+RrlCsbK3X6nWCqWd3dpBsVSWFVVWqaKl1bTOOiRTay3vaZrIqXKlelpvfAGRXlf2U+PJvQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;         md 0&apos; title=&apos;&apos; src=&apos;/static/22203cc16cd21ea10d8ff4234a85b905/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EC%97%B4%EA%B1%B0%ED%95%98%EA%B8%B0.md_0.png&apos; srcset=&apos;/static/22203cc16cd21ea10d8ff4234a85b905/08678/%EC%8A%A4%EB%A0%88%EB%93%9C_%EC%97%B4%EA%B1%B0%ED%95%98%EA%B8%B0.md_0.png 190w,
/static/22203cc16cd21ea10d8ff4234a85b905/2edd7/%EC%8A%A4%EB%A0%88%EB%93%9C_%EC%97%B4%EA%B1%B0%ED%95%98%EA%B8%B0.md_0.png 380w,
/static/22203cc16cd21ea10d8ff4234a85b905/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EC%97%B4%EA%B1%B0%ED%95%98%EA%B8%B0.md_0.png 677w&apos; sizes=&apos;(max-width: 677px) 100vw, 677px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;화면 4 ToolHelp 라이브러리를 사용해서 스레드를 열거한 결과&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;NtQuerySystemInformation을 사용해서 스레드 열거하기&lt;/p&gt;
&lt;p&gt;NtQuerySystemInformation 함수는 원래 문서화되지 않은 NT 커널 내부 함수였으나 워낙 강력한 기능을 가지고 있고 다양한 곳에서 광범위하게 사용되면서 현재는 MSDN을 통해서 일부 기능이 공개된 상태다. &amp;#x3C;리스트 4&gt;에 함수 원형이 나와 있다. 함수의 구조는 단순해 보이지만 처음 이 함수를 사용하면 생각보다 사용 방법이 만만하진 않다. 우선 파라미터부터 차근차근 살펴보도록 하자.&lt;/p&gt;
&lt;p&gt;첫 번째 인자는 어떤 정보를 구하고 싶은지를 나타낸다. SYSTEM_INFORMATION_CLASS는 함수 원형 다음에 나와 있는 것과 같이 선언된 열거형 자료 구조다. 중간 중간 값이 비어있는 부분이 있는데 해당 부분은 외부로 공개되지 않은 기능이라고 생각하면 된다. 실제로는 0번부터 차례로 모든 번호에 해당하는 자료가 구해지도록 되어 있다. 이번 시간에 우리가 사용할 스레드 정보를 구하기 위해서는 5번으로 선언된 SystemProcessInformation을 사용하면 된다. 해당 값을 전달하면 현재 수행 중인 프로세스 목록과 각 프로세스 내에 포함된 스레드 목록에 대한 정보가 반환된다.&lt;/p&gt;
&lt;p&gt;두 번째 인자는 해당 정보를 전달받을 버퍼를 전달한다. 이 버퍼는 우리 쪽에서 할당해서 전달해야 하며 첫 번째 인자인 SystemInformationClass에 따라서 미리 약속된 형태로 자료가 반환된다. 세 번째 인자인 SystemInformationLength는 두 번째 인자로 전달한 버퍼의 크기를 나타낸다. 마지막 인자인 ReturnLength는 해당 정보를 기록하기 위해서 필요한 버퍼의 크기를 전달 받는 곳이다. 만약 전달한 버퍼가 전체 정보를 저장하기에 부족하다면 NtQuerySystemInformation 함수는 에러를 리턴하고 필요한 크기를 ReturnLength에 전달해 준다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 4 NtQuerySystemInformation 함수 원형&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;NTSTATUS WINAPI &lt;span class=&quot;token function&quot;&gt;NtQuerySystemInformation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    SYSTEM_INFORMATION_CLASS SystemInformationClass&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    PVOID SystemInformation&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    ULONG SystemInformationLength&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    PULONG ReturnLength
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_SYSTEM_INFORMATION_CLASS&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    SystemBasicInformation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    SystemPerformanceInformation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    SystemTimeOfDayInformation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    SystemProcessInformation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    SystemProcessorPerformanceInformation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    SystemInterruptInformation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    SystemExceptionInformation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;33&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    SystemRegistryQuotaInformation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;37&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    SystemLookasideInformation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;45&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; SYSTEM_INFORMATION_CLASS&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 함수의 사용법을 어렵게 만드는 요인은 바로 리턴되는 버퍼 구조가 명확하지 않다는 점이다. 함수를 범용적으로 사용할 수 있도록 디자인해서 리턴되는 버퍼 구조가 함수 원형을 통해서 명시화되지 않기 때문이다. 따라서 이 경우에는 개별 항목별로 리턴되는 자료의 형태를 개발자가 일일이 숙지하고 있어야 한다.&lt;/p&gt;
&lt;p&gt;SystemProcessInformation를 전달해서 NtQuerySystemInformation 함수를 호출하면 &amp;#x3C;리스트 5&gt;에 나타나 있는 RSYSTEM_PROCESS_INFORMATION 정보와 &amp;#x3C;리스트 6&gt;에 있는 RSYSTEM_THREAD_INFORMATION 구조체 정보가 리턴된다. 각 구조체에서 자주 사용되는 필드는 설명과 함께 진하게 표시되어 있기 때문에 해당 내용을 참고하도록 하자. &amp;#x3C;그림 1&gt;에는 실제로 버퍼에 어떤 구조로 정보가 리턴 되는지가 나와 있다. 그림에서 SPI는 RSYSTEM_PROCESS_INFORMATION 구조체를 STI는 RSYSTEM_THREAD_INFORMATION 구조체를 나타낸다. SPI 구조체는 현재 실행된 프로세스 개수만큼 존재하며, STI 구조체는 각 프로세스에서 실행된 스레드 개수만큼 SPI 구조체 뒤에 따라 붙어 나온다. 이 구조를 열거하기 위해서는 SPI 구조체에 포함된 두 개의 필드가 중요하다. 첫 번째 필드인 NextEntryOffset은 현재 SPI 구조체 포인터에서 다음 SPI 구조체가 있는 곳까지의 오프셋이 저장돼 있다. 두 번째 필드인 NumberOfThreads에는 해당 프로세스에 몇 개의 스레드가 포함돼 있는지가 나와 있다. 따라서 이 필드에 저장된 개수만큼 STI 구조체가 이어진다고 생각하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 512px; margin-bottom: 16px;&apos; data-url=&apos;./스레드_열거하기.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/9b36c9c74fcae7d91124a8667fb01f0f/06341/%EC%8A%A4%EB%A0%88%EB%93%9C_%EC%97%B4%EA%B1%B0%ED%95%98%EA%B8%B0.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 20.52631578947369%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAk0lEQVR42j2P2Q6FIBBD+f9P9AkT9MoiCu65KJ5AYp9Kpy0z4l+QUrrvW0rpnIsxGmN+BVrrfd+VUl3XPc+D7fMDsa4r42maruuy1o7jGEKgAuK9h3xPDCjHcdBOip9E3/fLsjDjTYUroKXGUOZ5tgXnecIJo2/b1rataJoGRpIKKnXBMAz4qshe9YScM6fVhSt5AZNH4b59Bc6LAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;         md 1&apos; title=&apos;&apos; src=&apos;/static/9b36c9c74fcae7d91124a8667fb01f0f/06341/%EC%8A%A4%EB%A0%88%EB%93%9C_%EC%97%B4%EA%B1%B0%ED%95%98%EA%B8%B0.md_1.png&apos; srcset=&apos;/static/9b36c9c74fcae7d91124a8667fb01f0f/08678/%EC%8A%A4%EB%A0%88%EB%93%9C_%EC%97%B4%EA%B1%B0%ED%95%98%EA%B8%B0.md_1.png 190w,
/static/9b36c9c74fcae7d91124a8667fb01f0f/2edd7/%EC%8A%A4%EB%A0%88%EB%93%9C_%EC%97%B4%EA%B1%B0%ED%95%98%EA%B8%B0.md_1.png 380w,
/static/9b36c9c74fcae7d91124a8667fb01f0f/06341/%EC%8A%A4%EB%A0%88%EB%93%9C_%EC%97%B4%EA%B1%B0%ED%95%98%EA%B8%B0.md_1.png 512w&apos; sizes=&apos;(max-width: 512px) 100vw, 512px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;그림 1 SystemProcessInformation 버퍼 리턴 구조&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 5 SYSTEM_PROCESS_INFORMATION 구조체&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_RSYSTEM_PROCESS_INFORMATION&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ULONG NextEntryOffset&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 다음 프로세스 정보 오프셋&lt;/span&gt;
    ULONG NumberOfThreads&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 이 프로세스 포함된 스레드 개수&lt;/span&gt;
    LARGE_INTEGER WorkingSetPrivateSize&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ULONG HardFaultCount&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ULONG NumberOfThreadsHighWatermark&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ULONGLONG CycleTime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 프로세스 수행에 소모된 사이클 시간&lt;/span&gt;
    LARGE_INTEGER CreateTime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 생성 시간&lt;/span&gt;
    LARGE_INTEGER UserTime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 유저 모드에서 수행된 시간&lt;/span&gt;
    LARGE_INTEGER KernelTime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 커널 모드에서 수행된 시간&lt;/span&gt;
    UNICODE_STRING ImageName&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 프로세스 이미지 이름&lt;/span&gt;
    ULONG BasePriority&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    HANDLE UniqueProcessId&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 프로세스 아이디&lt;/span&gt;
    HANDLE InheritedFromUniqueProcessId&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 부모 프로세스 아이디&lt;/span&gt;
    ULONG HandleCount&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ULONG SessionId&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ULONG_PTR UniqueProcessKey&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    SIZE_T PeakVirtualSize&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    SIZE_T VirtualSize&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ULONG PageFaultCount&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    SIZE_T PeakWorkingSetSize&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    SIZE_T WorkingSetSize&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    SIZE_T QuotaPeakPagedPoolUsage&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    SIZE_T QuotaPagedPoolUsage&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    SIZE_T QuotaPeakNonPagedPoolUsage&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    SIZE_T QuotaNonPagedPoolUsage&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    SIZE_T PagefileUsage&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    SIZE_T PeakPagefileUsage&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    SIZE_T PrivatePageCount&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    LARGE_INTEGER ReadOperationCount&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    LARGE_INTEGER WriteOperationCount&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    LARGE_INTEGER OtherOperationCount&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    LARGE_INTEGER ReadTransferCount&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    LARGE_INTEGER WriteTransferCount&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    LARGE_INTEGER OtherTransferCount&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; RSYSTEM_PROCESS_INFORMATION&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PRSYSTEM_PROCESS_INFORMATION&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 6 SYSTEM_THREAD_INFORMATION 구조체&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_CLIENT_ID&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    HANDLE UniqueProcess&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 프로세스 아이디&lt;/span&gt;
    HANDLE UniqueThread&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 스레드 아이디&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; CLIENT_ID&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PCLIENT_ID&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_RSYSTEM_THREAD_INFORMATION&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    LARGE_INTEGER KernelTime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 커널 모드에서 수행된 시간&lt;/span&gt;
    LARGE_INTEGER UserTime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 유저 모드에서 수행된 시간&lt;/span&gt;
    LARGE_INTEGER CreateTime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 생성 시간&lt;/span&gt;
    ULONG WaitTime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    PVOID StartAddress&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 시작 주소&lt;/span&gt;
    CLIENT_ID ClientId&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 프로세스/스레드 아이디&lt;/span&gt;
    ULONG Priority&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
    LONG BasePriority&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ULONG ContextSwitches&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
    ULONG ThreadState&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 현재 스레드 수행 상태&lt;/span&gt;
    ULONG WaitReason&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 대기 사유&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; RSYSTEM_THREAD_INFORMATION&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;PRSYSTEM_THREAD_INFORMATION&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&amp;#x3C;리스트 7&gt;에는 앞서 설명한 내용을 토대로 NtQuerySystemInformation 함수를 사용해서 시스템에서 실행중인 스레드를 열거하는 예제가 나와 있다. 여기서 주의 깊게 살펴볼 점은 NtQuerySystemInformation 함수를 반복적으로 호출하는 부분이다. 통상적으로 NtQuerySystemInformation과 같은 함수는 버퍼 크기를 0으로 해서 필요한 버퍼 크기를 구한 다음 해당 크기만큼 버퍼를 할당하고 다시 호출해서 값을 반환 받는 형태로 사용한다. 그런데 이 때 주의해야 할 점이 이 두 함수를 아주 짧은 시간 간격으로 호출하겠지만 시스템에서는 그 사이에도 스레드가 생성된다는 점이다. 따라서 바로 이어서 호출하는 두 번째 호출이 실패할 수도 있다. &amp;#x3C;리스트 7&gt;의 프로그램은 이런 문제를 해결하기 위해서 반복적으로 성공할 때까지 호출하도록 되어 있다. 또한 NtQuerySystemInformation 함수에서 제공받은 버퍼 보다 NTQSI_BUFFER_MARGIN만큼 더 크게 할당해서 재 호출을 하는데, 이렇게 하는 이유는 NtQuerySystemInformation 함수의 호출 회수를 줄이기 위함이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 7 thread2 프로그램&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;windows.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;winternl.h&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;STATUS_INFO_LENGTH_MISMATCH&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;0xC0000004&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name function&quot;&gt;XGetPtr&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;base&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; offset&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG_PTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;base&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG_PTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;offset&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; 
&lt;span class=&quot;token function&quot;&gt;NTSTATUS&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WINAPI &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;NtQuerySystemInformationT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SYSTEM_INFORMATION_CLASS&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PVOID&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ULONG&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PULONG&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Visitor&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; BOOL &lt;span class=&quot;token function&quot;&gt;Visit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;T &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; Visitor&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;RSYSTEM_THREAD_INFORMATION&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; ThreadVisitor&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

BOOL &lt;span class=&quot;token function&quot;&gt;NtqsiEnumThreads&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ThreadVisitor &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;visitor&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    HMODULE ntdll &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetModuleHandleW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;ntdll.dll&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    NtQuerySystemInformationT pNTQSI&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    pNTQSI &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NtQuerySystemInformationT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
             &lt;span class=&quot;token function&quot;&gt;GetProcAddress&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ntdll&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NtQuerySystemInformation&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; NTQSI_MAX_TRY &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ULONG NTQSI_BUFFER_MARGIN &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4096&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ULONG NTQSI_BUFFER_INIT_SIZE &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    ULONG buffer_size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; NTQSI_BUFFER_INIT_SIZE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    PUCHAR buffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; UCHAR&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;buffer_size&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ULONG req_size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    NTSTATUS s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;NTQSI_MAX_TRY&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        s &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pNTQSI&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SystemProcessInformation&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; buffer_size&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;req_size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;NT_SUCCESS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; STATUS_INFO_LENGTH_MISMATCH&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            buffer_size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; req_size &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; NTQSI_BUFFER_MARGIN&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            buffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; UCHAR&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;buffer_size&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    PRSYSTEM_PROCESS_INFORMATION p &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PRSYSTEM_PROCESS_INFORMATION&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;NextEntryOffset &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        PRSYSTEM_THREAD_INFORMATION t&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        t &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PRSYSTEM_THREAD_INFORMATION&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;XGetPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;NumberOfThreads&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;visitor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Visit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                        &lt;span class=&quot;token keyword&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                    
                    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        p &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PRSYSTEM_PROCESS_INFORMATION&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;XGetPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;p&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; p&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;NextEntryOffset&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; 

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ThreadPrinter&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token base-clause&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ThreadVisitor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; BOOL &lt;span class=&quot;token function&quot;&gt;Visit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;RSYSTEM_THREAD_INFORMATION &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;PID =&gt; %5d TID =&gt; %5d\n&quot;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ClientId&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;UniqueProcess
                &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ClientId&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;UniqueThread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ThreadPrinter printer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;NtqsiEnumThreads&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;printer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;스레드 시작 주소 구하기&lt;/p&gt;
&lt;p&gt;시스템 프로그래밍, 특히나 보안 프로그래밍을 하면 특정 스레드의 시작 주소를 구하는 일이 자주 있다. 스레드의 시작 주소를 통해서 해당 스레드의 보다 많은 특성에 대해서 알 수 있기 때문이다. 이럼에도 불구하고 안타깝게도 윈도우는 아직까지도 스레드 시작 주소를 구하는 편리한 방법을 제공하지 않는다.&lt;/p&gt;
&lt;p&gt;아마 똑똑한 독자라면 앞서 살펴본 RSYSTEM_THREAD_INFORMATION 구조체의 StartAddress 필드를 기억하고는 NtqsiEnumThreads 함수를 사용해서 &amp;#x3C;리스트 8&gt;에 나온 것과 같은 코드를 만들면 된다고 생각할지도 모르겠다. 하지만 실제로 &amp;#x3C;리스트 8&gt;의 예제 코드를 수행해 보면 &amp;#x3C;화면 5&gt;에 나온 것과 같이 우리가 원하는 스레드 시작 주소가 출력되지 않는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 8 NtqsiGetThreadStartAddress 함수&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;StartAddressFinder&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token base-clause&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ThreadVisitor&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    HANDLE target_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    PVOID address_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;StartAddressFinder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG tid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        target_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; tid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        address_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; BOOL &lt;span class=&quot;token function&quot;&gt;Visit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;RSYSTEM_THREAD_INFORMATION &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ClientId&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;UniqueThread &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; target_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            address_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StartAddress&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

BOOL &lt;span class=&quot;token function&quot;&gt;NtqsiGetThreadStartAddress&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG tid&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PVOID &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;address&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    StartAddressFinder &lt;span class=&quot;token function&quot;&gt;finder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;EnumThreads&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;finder&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;finder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;address_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;address &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; finder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;address_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

ULONG
CALLBACK
&lt;span class=&quot;token function&quot;&gt;DummyThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ULONG tid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    HANDLE thread&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    thread &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DummyThread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;tid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        PVOID address &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetThreadStartAddress&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tid&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;address&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;DummyThread = %p, StartAddress = %p\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DummyThread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; address&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;WaitForSingleObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; INFINITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; WAIT_OBJECT_0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;TerminateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 677px; margin-bottom: 16px;&apos; data-url=&apos;./스레드_열거하기.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/98fd03ce28aad43e42aa4a7eb2897123/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EC%97%B4%EA%B1%B0%ED%95%98%EA%B8%B0.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 11.052631578947368%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAIAAADXZGvcAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAeUlEQVR42mOYs2TlgmWrFq5YO2Hmgsr26fkNk6OKesPyOkJz28ILumNLJ4TmdQRmtQSkN4QVdDdOXjhp3pLJcxYv6OtbNXMGg49/oIiIiIyMjJCQkISkpKiYmAAYcHNxsbKy8fHysbGxMTAwMMIBExOQy87N09k/EQDVuCQzvFALFwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;         md 2&apos; title=&apos;&apos; src=&apos;/static/98fd03ce28aad43e42aa4a7eb2897123/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EC%97%B4%EA%B1%B0%ED%95%98%EA%B8%B0.md_2.png&apos; srcset=&apos;/static/98fd03ce28aad43e42aa4a7eb2897123/08678/%EC%8A%A4%EB%A0%88%EB%93%9C_%EC%97%B4%EA%B1%B0%ED%95%98%EA%B8%B0.md_2.png 190w,
/static/98fd03ce28aad43e42aa4a7eb2897123/2edd7/%EC%8A%A4%EB%A0%88%EB%93%9C_%EC%97%B4%EA%B1%B0%ED%95%98%EA%B8%B0.md_2.png 380w,
/static/98fd03ce28aad43e42aa4a7eb2897123/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EC%97%B4%EA%B1%B0%ED%95%98%EA%B8%B0.md_2.png 677w&apos; sizes=&apos;(max-width: 677px) 100vw, 677px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;화면 5 NtqsiGetThreadStartAddress 함수 수행 결과&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;왜 이렇게 엉뚱한 값이 출력된 것일까? 그 이유를 알기 위해서는 윈도우 내부 구조에 대해서 알아야 한다. 윈도우 2000 이후로 모든 윈도우 운영체제는 NT 커널로 되어 있다. 지금은 대부분의 개발자가 NT 커널이 윈도우 커널이라고 생각하지만 사실 NT 커널은 윈도우뿐만 아니라 OS/2, POSIX같은 다른 환경도 수행할 수 있는 별도의 커널이다. 즉, NT 커널에서 윈도우는 하나의 표현 계층에 지나지 않는다. 이번 시간에 살펴본 ToolHelp 라이브러리와 같은 윈도우 API를 Win32 API라고 부르고, 뒤에 살펴본 NtQuerySystemInformation과 같은 함수들은 윈도우 네이티브 API 또는 NT API라고 부른다. 실제로 Win32 API는 이러한 네이티브 API를 조합해서 만든 것이다.&lt;/p&gt;
&lt;p&gt;NT 커널은 내부적으로 스레드를 관리하기 위해서 ETHREAD라는 구조체 리스트를 사용한다. windbg를 통해서 해당 구조체를 덤프해보면 &amp;#x3C;리스트 9&gt;에 나와 있는 것과 같이 구성된 것을 알 수 있다. 구조체를 살펴보면 스레드 시작 주소와 관련해서 두 개의 필드가 존재함을 알 수 있다. 하나는 0x218 오프셋에 위치한 StartAddress이고, 다른 하나는 0x260 오프셋에 위치한 Win32StartAddress다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 9 ETHREAD 구조체&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;3: kd&gt; dt nt!_ETHREAD
   +0x000 Tcb              : _KTHREAD
   +0x200 CreateTime       : _LARGE_INTEGER
   +0x208 ExitTime         : _LARGE_INTEGER
   +0x208 KeyedWaitChain   : _LIST_ENTRY
   +0x210 ExitStatus       : Int4B
   +0x214 PostBlockList    : _LIST_ENTRY
   +0x214 ForwardLinkShadow : Ptr32 Void
   +0x218 StartAddress     : Ptr32 Void
   +0x21c TerminationPort  : Ptr32 _TERMINATION_PORT
   +0x21c ReaperLink       : Ptr32 _ETHREAD
   +0x21c KeyedWaitValue   : Ptr32 Void
   +0x220 ActiveTimerListLock : Uint4B
   +0x224 ActiveTimerListHead : _LIST_ENTRY
   +0x22c Cid              : _CLIENT_ID
   +0x234 KeyedWaitSemaphore : _KSEMAPHORE
   +0x234 AlpcWaitSemaphore : _KSEMAPHORE
   +0x248 ClientSecurity   : _PS_CLIENT_SECURITY_CONTEXT
   +0x24c IrpList          : _LIST_ENTRY
   +0x254 TopLevelIrp      : Uint4B
   +0x258 DeviceToVerify   : Ptr32 _DEVICE_OBJECT
   +0x25c CpuQuotaApc      : Ptr32 _PSP_CPU_QUOTA_APC
   +0x260 Win32StartAddress : Ptr32 Void
   +0x264 LegacyPowerObject : Ptr32 Void
   +0x268 ThreadListEntry  : _LIST_ENTRY
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&amp;#x3C;리스트 8&gt;의 코드는 이 두 가지 필드 중에서 0x218에 위치한 StartAddress를 출력한 것이다. 그런데 실제로 일반적으로 우리가 필요로 하는 주소는 0x260에 위차한 Win32StartAddress다.&lt;/p&gt;
&lt;p&gt;그렇다면 윈도우는 왜 스레드 시작 주소에 대해서 두 가지 주소를 저장하고 있는 것일까? 이는 앞서 설명한 것과 같이 NT와 Win32의 계층 구조 때문에다. 우리는 스레드를 생성하기 위해서 CreateThread라는 Win32 API를 사용한다. CreateThread는 내부적으로 실제로 스레드를 생성하기 위해서 NtCreateThread라는 네이티브 API를 호출한다. 여기서 우리가 CreateThread로 전달한 시작 주소가 Win32StartAddress가 되고, CreateThread가 내부적으로 NtCreateThread를 호출하면서 전달한 시작 주소가 StartAddress가 된다.&lt;/p&gt;
&lt;p&gt;이런 설명이 윈도우 XP까지는 유효하지만 그 이후의 윈도우부터는 구조가 좀 변경됐다. Vista부터는 CreateThread 함수는 단순히 NtCreateThreadEx 함수의 래퍼 역할만 하고 있으며, 실제로 모든 처리를 NtCreateThreadEx 함수에서 모두 수행한다. NtCreateThreadEx 함수는 이전에 CreateThread가 수행하던 역할을 동일하게 수행한다. 별도의 래퍼함수 주소를 만들어서 NT 커널에 전달하는 것이다. 따라서 이 경우에도 계층이 명확하지는 않지만 Win32StartAddress는 우리가 전달한 함수 주소가 되고 StartAddress는 NtCreateThreadEx 함수가 임의로 생성한 주소가 된다.&lt;/p&gt;
&lt;p&gt;여기까지 설명을 듣고 나면 “왜 윈도우는 내가 전달한 시작함수가 아닌 다른 함수에서 스레드가 시작되도록 만드는 것일까?”라는 의문이 또 생기게 마련이다. 그 이유는 &lt;a href=&quot;http://www.jiniya.net/wp/archives/7194&quot;&gt;5월호에&lt;/a&gt; 잠깐 설명했던 것과 같이 우리가 만든 스레드 함수가 리턴되면 자동으로 ExitThread가 호출되도록 만들기 위해서다.&lt;/p&gt;
&lt;p&gt;복잡하게 설명했는데 결론은 간단하다. 윈도우는 내부적으로 두 개의 스레드 시작 주소를 관리하고 있으며, 우리가 앞서 살펴보았던 NtQuerySystemInformation으로는 우리가 원하는 스레드 시작 주소를 출력할 수 없다는 점이다. 앞서 설명한 것과 같이 이런 목적에 부합하는 Win32 API는 없기 때문에 스레드 시작 주소를 구하기 위해서는 NtQueryInformationThread라는 네이티브 API를 사용해야 한다. &amp;#x3C;리스트 10&gt;에 NtQueryInformationThread 함수를 사용해서 스레드 시작 주소를 구하는 GetThreadStartAddress 함수 코드가 나와 있다. NtQueryInformationThread 함수 사용 방법은 크게 복잡하지 않기 때문에 직접 코드를 실행해 보면서 사용 방법을 알아 보도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 10 GetThreadStartAddress&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;windows.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;tlhelp32.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;winternl.h&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;ThreadQuerySetWin32StartAddress&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;9&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; 
&lt;span class=&quot;token function&quot;&gt;NTSTATUS&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;WINAPI &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;NtQueryInformationThreadT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ULONG&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PVOID&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ULONG&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PULONG&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

BOOL
&lt;span class=&quot;token function&quot;&gt;GetThreadStartAddress&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG tid&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PVOID &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;address&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    HMODULE ntdll &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetModuleHandleW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;ntdll.dll&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    NtQueryInformationThreadT pNTQIT&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    pNTQIT &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;NtQueryInformationThreadT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
             &lt;span class=&quot;token function&quot;&gt;GetProcAddress&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ntdll&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;NtQueryInformationThread&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;pNTQIT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    HANDLE h &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;OpenThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;THREAD_QUERY_INFORMATION&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;h&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    PVOID addr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    NTSTATUS s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    s &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;pNTQIT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;h
                &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ThreadQuerySetWin32StartAddress
                &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;addr
                &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;addr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;h&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;NT_SUCCESS&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;address &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; addr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[파이썬에서 엑셀 파일 다루기…]]></title><description><![CDATA[XIGNCODE는 간지나는 엑셀 리포트도 제공해 드립니다 ㅋ~ 최근에 고객사의 요청으로 엑셀 리포트를 만드는 기능을 웹 시스템에 추가했다. 일간, 주간으로 월요일…]]></description><link>https://jiniya.net/wp/archives/7692</link><guid isPermaLink="false">https://jiniya.net/wp/archives/7692</guid><pubDate>Wed, 04 Jul 2012 23:58:15 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 400px; margin-bottom: 16px;&apos; data-url=&apos;./파이썬에서_엑셀_파일_다루기.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5b95c17476ce232142d5643bd0a56000/d9f49/%ED%8C%8C%EC%9D%B4%EC%8D%AC%EC%97%90%EC%84%9C_%EC%97%91%EC%85%80_%ED%8C%8C%EC%9D%BC_%EB%8B%A4%EB%A3%A8%EA%B8%B0.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 62.63157894736842%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAClElEQVR42g1OWW/TQBj0P+YNIVHa/gskQALEqQoqioAWaEkPGuVsEpw0l536WHvX196OHR8p+z2MZuabkUazjJV+09WHvX77qnt9Mug19WHLmA7vlrNRX11z2G1M/p6PO9/Hg8vFeDjXe/NRy5zPvMVSw4QkNMes5LImhCasonJLZM3SbYRLn8qIy4yWQkieVkRsQ1qjOFcxkZead/sgsnaR8YiCXertY2eHgifQeBysHmNnlzr7sb0v0B4Fe4G5I9FuivYk2qfuQ9d4qhHjVQ4PUvfDBh5I5x1dvcHL157+3B09k/b7DHwMpi+r8FMGPvjjF9v4831yWAaH0n4bO6caA5dZ3Oewlce9NOhQr0nANTQaYHEmULsgNxx2KjoSsK3MAg8rOlDJddgOwT+NoHFGTR7NFKZ4ScMphhNv1XOWHRHPC3GXYkMhC6fQusmZuaYGi+YY6j6Ya9Rr5fgfR70sGaXRDfW7CWj75pW3vBRBv+KTnIy36ZSjLlheFEyvxbRgtzLsu6u+xqyjHJ1y90eOfkvvhNo/iPUNzg7B7ScBjqu4sUanW3wuvWO0OKyTP3XSUEnuHEGzoVHraxaccfckQ6ep/4s5x9j67t1+dieq/LNKzvPgzz29Sv3fcPalxhdlclEkV4n51ZqdqdnNHA9E0FWYRn0GO9Rv+cY5WDRE2K24vqH6fTpJox40LyqhZusbPCSg6dsDDSdkvV4zxtbrTHCuZBInAADbthnnRVmqb1VVjFLXdYuiUHyzKfIs82GgqVqe51LKzWaTSqkkoRQh5AFPmSotpajrWggOfViUheLKVGVCmQY86HrQdj3XRwotGzjAN+8cY2UDHwVRgsIkjIkPQ8sBQYQhCu9sa2Fas8XqPwe8q+pkJc4fAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                md 0&apos; title=&apos;&apos; src=&apos;/static/5b95c17476ce232142d5643bd0a56000/d9f49/%ED%8C%8C%EC%9D%B4%EC%8D%AC%EC%97%90%EC%84%9C_%EC%97%91%EC%85%80_%ED%8C%8C%EC%9D%BC_%EB%8B%A4%EB%A3%A8%EA%B8%B0.md_0.png&apos; srcset=&apos;/static/5b95c17476ce232142d5643bd0a56000/08678/%ED%8C%8C%EC%9D%B4%EC%8D%AC%EC%97%90%EC%84%9C_%EC%97%91%EC%85%80_%ED%8C%8C%EC%9D%BC_%EB%8B%A4%EB%A3%A8%EA%B8%B0.md_0.png 190w,
/static/5b95c17476ce232142d5643bd0a56000/2edd7/%ED%8C%8C%EC%9D%B4%EC%8D%AC%EC%97%90%EC%84%9C_%EC%97%91%EC%85%80_%ED%8C%8C%EC%9D%BC_%EB%8B%A4%EB%A3%A8%EA%B8%B0.md_0.png 380w,
/static/5b95c17476ce232142d5643bd0a56000/d9f49/%ED%8C%8C%EC%9D%B4%EC%8D%AC%EC%97%90%EC%84%9C_%EC%97%91%EC%85%80_%ED%8C%8C%EC%9D%BC_%EB%8B%A4%EB%A3%A8%EA%B8%B0.md_0.png 400w&apos; sizes=&apos;(max-width: 400px) 100vw, 400px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;XIGNCODE는 간지나는 엑셀 리포트도 제공해 드립니다 ㅋ~&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;최근에 고객사의 요청으로 엑셀 리포트를 만드는 기능을 웹 시스템에 추가했다. 일간, 주간으로 월요일 0시에 째깍 째깍 리포트를 자동으로 생성할 뿐만 아니라 영정시킬 수 있는 로그는 별도 색깔로 하이라이팅을 해준다. 여기에 덧붙여 게임 운영자가 아주 손쉽게 쓸 수 있도록 사용자 별로 영정 대상 해킹툴 사용 카운트를 소팅해서 보여준다. 진짜 쏘 쿨한 기능이 아닐 수 없다. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;어쨌든 이런 멋진 기능을 만들기 위해서 난 파이썬에서 엑셀 파일을 다루는 라이브러리를 좀 찾아봤다. 배터리가 포함된 파이썬답게 다양한 방법이 있었는데 여기서는 내가 사용해본 3가지 방법에 대해서 이야기 해볼까 한다. 라이브러리를 3가지나 거쳤다는 것은 그만큼 시행 착오를 겪었다는 말이다. 혹시 비슷한 일을 하는 다음 사람은 부디 그런 삽질을 하지 않았으면 한다. 오픈 소스 라이브러리의 경우 문서화가 아주 잘 된 것들도 아니라서 스타일 기능을 쓸 때 마다 라이브러리 소스를 뒤지고, 구글링하는 수고를 거쳐야 했기 때문이다. 몹시 스트레스풀한 작업이었다. ㅋ~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0. xlwt&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;제일 처음 살펴보았던 녀석이 &lt;a href=&quot;http://pypi.python.org/pypi/xlwt&quot;&gt;xlwt&lt;/a&gt;였다. 이놈은 파이썬 독자적으로 엑셀 파일을 다룰 수 있도록 만든 라이브러리다. 하지만 제일 안습했다. 문제는 간단했다. 우리가 만드는 엑셀 파일은 일간 로그는 많게는 한 시트에 2만건 정도의 데이터가 기록되고, 주간 로그는 많게는 15-20만건 정도의 로그가 기록된다. 근데 이 xlwt는 65536개의 데이터만 기록할 수 있는 한계가 있었다. xls 파일의 한계라 그렇다는데 어쨌든 그런 연유로 다 만들었다 제일 먼저 아웃되었다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1. openpyxl&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;다음으로 살펴본 녀석은 &lt;a href=&quot;https://bitbucket.org/ericgazoni/openpyxl/wiki/Home&quot;&gt;openpyxl&lt;/a&gt;이다. 이것도 파이썬 독자적으로 엑셀 파일을 다룰 수 있도록 만든 라이브러리다. 활발하게 만들어지고 있는 녀석답게 xlsx 포맷을 지원하고 20만건의 데이터도 저장할 수 있는 위용을 자랑한다. 크게 문제없이 이 녀석으로 구현해 놓고 사용하고 있었는데 이상하게 월요일만 되면 로그가 생성되지 않는 문제가 발생했다. 그래서 살펴봤더니 서버 메모리가 부족해서 처리를 못하는 문제가 있었다. 리포트 생성 스크립트는 서버에서 동시에 실행되도록 되어 있는데 그래서 그런 줄 알고 하나씩 순차적으로 처리하도록 구조를 변경했다. 그래도 메모리가 부족하긴 마찬가지 였다. 그래서 가장 큰 놈을 실행해서 메모리 점유율을 살펴보았는데, 이건 뭐 2기가 바이트를 넘는 메모리가 필요했다. 잘 아다시피 32비트 윈도에서 특별한 옵션없이 부팅하면 애플리케이션은 2기가 이상을 사용하지 못한다. 첨에는 내가 너무 막짜서 그런 줄 알았다. 파이썬은 막 짜는게 간지지 않은가? 그래서 아래와 같은 글까지 살펴보면서 데이터를 일일이 최적화 시켰다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://stackoverflow.com/questions/2211965/python-memory-usage-loading-large-dictionaries-in-memory&quot;&gt;http://stackoverflow.com/questions/2211965/python-memory-usage-loading-large-dictionaries-in-memory&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://stackoverflow.com/questions/2670005/python-large-variable-ram-useage&quot;&gt;http://stackoverflow.com/questions/2670005/python-large-variable-ram-useage&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;그런데 결론은? 개뻘짓이었다. 왜냐하면 내가 쓰는 메모리가 많은 게 아니라 openpyxl 안에서 너무 많은 메모리를 사용하고 있었기 때문이다. openpyxl이 사용하는 메모리를 줄이기 위해서는 데이터를 끊어서 저장하고 다시 그 파일을 열어서 추가하고 또 저장하고 하는 식으로 처리를 해야 했다. 그래서 5만건씩 데이터를 나눠서 저장하도록 프로그램을 고쳤는데, 그랬더니 이번에는 스타일이 모두 깨지는 문제가 발생했다. 저장하고 다시 열면 해당 파일의 스타일을 제대로 가져오지 못하는 문제가 있었던 것이다. 흙~ 맞다. 오픈 소스는 아직 갈 길이 멀다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2. COM&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;최종 종착지는 &lt;a href=&quot;http://www.pythonexcels.com/Python_Excel_Mini_Cookbook.html&quot;&gt;여기&lt;/a&gt;다. 엑셀을 다루는 가장 좋은 방법은 엑셀을 사용하는 것 아니겠는가? 우리는 다행이도 윈도우 서버를 운영하고 있었다. 서버에 엑셀을 설치했다. 그리고 COM을 사용해서 접근했다. 결과는 어땠을까? 가장 큰 파일을 저장할 때에도 파이썬은 20메가 안팍의 메모리를, 실행된 엑셀도 30메가를 넘지 않는 점유율을 보였다. 당연히 엑셀에서 사용할 수 있는 모든 기능을 자유자재로 사용할 수 있음은 말할 것도 없다. 근데 메모리 점유율은 확 떨어졌지만 그렇게 빠른 편은 아닌 것 같다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3. 결론&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;파이썬에서 엑셀을 다루어야 한다. 파일 크기가 작다면 아무꺼나 쓰든 크게 상관없다. 물론 복잡한 스타일이나 기능을 사용하려면 아무래도 COM이 가장 좋다. 그렇지 않으면 가장 결정적인 순간에 지원되지 않는다거나 아직 구현되지 않았다거나 하는 이유로 결국 다시 COM으로 돌아갈 수 밖에 없기 때문이다. 이런 점을 충분히 고려하고도 독자 라이브러리를 쓰겠다면 openpyxl이 그나마 좀 더 좋은것 같다. 큰 파일을 다루어야 한다. 그러면 걍 COM 쓰자. 그게 편하다. 리눅스 서버다. 그럼 좀 더 고민해보고 ㅋ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 스레드 고급 활용법: 우선순위, 친화도, TLS, APC]]></title><description><![CDATA[스레드 우선 순위(Thread Priority) 윈도우 스케줄러는 상대적인 우선순위에 따라서 스레드를 스케줄링한다. 이러한 우선 순위의 종류가 <표…]]></description><link>https://jiniya.net/wp/archives/7647</link><guid isPermaLink="false">https://jiniya.net/wp/archives/7647</guid><pubDate>Wed, 04 Jul 2012 23:58:14 GMT</pubDate><content:encoded>&lt;h3&gt;스레드 우선 순위(Thread Priority)&lt;/h3&gt;
&lt;p&gt;윈도우 스케줄러는 상대적인 우선순위에 따라서 스레드를 스케줄링한다. 이러한 우선 순위의 종류가 &amp;#x3C;표 1&gt;에 나와 있다. 의미를 살펴보면 마치 말장난같이 적혀 있지만 해당 상수가 의미하는 정확한 내용이다. &amp;#x3C;리스트 1&gt;에는 스레드 우선순위를 조작하는 함수들이 나와 있다. SetThreadPriority 함수는 hThread로 전달된 스레드의 우선 순위를 nPriority로 설정하는 역할을 한다. nPriority로는 &amp;#x3C;표 1&gt;에 나와 있는 상수 값들을 전달할 수 있다. GetThreadPriority 함수를 사용하면 hThread로 전달된 스레드의 우선순위 값을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;표 1 스레드 우선 순위 값&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;상수명                           의미
THREAD_PRIORITY_TIME_CRITICAL   가장 높은 우선 순위보다 더 높은 우선 순위
THREAD_PRIORITY_HIGHEST	        가장 높은 우선 순위
THREAD_PRIORITY_ABOVE_NORMAL    보통 보다 조금 높은 우선 순위
THREAD_PRIORITY_NORMAL          보통
THREAD_PRIORITY_BELOW_NORMAL    보통 보다 조금 낮은 우선 순위
THREAD_PRIORITY_LOWEST          가장 낮은 우선 순위
THREAD_PRIORITY_IDLE            가장 낮은 우선 순위보다 더 낮은 우선 순위&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 1 스레드 우선순위 조절 함수 원형&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;BOOL WINAPI &lt;span class=&quot;token function&quot;&gt;SetThreadPriority&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE hThread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; nPriority&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; WINAPI &lt;span class=&quot;token function&quot;&gt;GetThreadPriority&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE hThread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;윈도우 설계자들은 아마도 정말 많은 고민 끝에 다음 이렇게나 다양한 종류의 우선순위를 만들어 두었을 것이다. 하지만 우리에게는 사실상 거의 쓸모 없는 기능이다. 왜일까? 이건 앞서도 말했던 것처럼 상대적이기 때문이다. 이 상대적이라는 말은 THREAD_PRIORITY_IDLE을 지정할 경우에 THREAD_PRIORITY_LOWEST보다는 덜 스케줄링 되지만 THREAD_PRIORITY_LOWEST로 실행할 스레드 조차 없다면 THREAD_PRIORITY_IDLE로 지정한다고 하더라도 모든 CPU 자원을 쓸 수 있다는 의미다. &amp;#x3C;리스트 2&gt;에 그러한 코드가 나와있다. 아무 일도 하지 않는 스레드를 하나 생성한 다음 해당 스레드의 우선 순위를 THREAD_PRIORITY_IDLE로 지정했다. 여러분의 컴퓨터에서 살펴보면 알겠지만 해당 스레드가 한 코어의 모든 자원을 소모하는 것을 볼 수 있을 것이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 2 100% CPU 점유율을 보여주는 예제&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;ULONG CALLBACK &lt;span class=&quot;token function&quot;&gt;DummyThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// 처리해야 할 작업들&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_tmain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; argc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _TCHAR&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; argv&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    HANDLE thread &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DummyThread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;SetThreadPriority&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; THREAD_PRIORITY_IDLE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;WaitForSingleObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; INFINITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;윈도우가 스케줄러를 잘못 설계한 것일까? 아니다. 당연히 제대로 만들었다. 운영체제 입장에서는 사용할 수 있는 모든 리소스를 사용하는 것이 바람직하기 때문이다. 메모리가 4GB만큼 탑재돼 있다면 필요하다면 4GB를 모두 사용하는 것이, CPU가 3GHz라면 해당 클럭을 모두 빼곡히 실행할 명령어로 채워 넣는 것이 바람직하다는 의미다. 하지만 사용자 입장은 그렇지 않다. 3GHz의 CPU를 사면 좀 더 CPU가 헐렁하기를 바라고, 4GB의 램을 탑재했다면 한 1GB의 여유 공간이 있기를 바라는 게 사람 심리다. 또 그런 심리를 충족시켜야 하는 것이 우리가 만드는 프로그램들이다.&lt;/p&gt;
&lt;p&gt;그래서 현실세계에서 필요한 우선순위는 상대적인 것이 아니다. 절대적인 우선순위가 필요하다. “우리 제품은 2GHz 싱글 코어 CPU에서 초당 2%이상 CPU를 점유하지는 않습니다.”라는 이야기를 할 수 있는 우선순위가 필요하다는 말이다. 안타깝게도 윈도우에서는 그런 것들을 자동으로 해주지 않는다. 우리가 할 수 있는 유일한 방법은 저러한 for 루프마다 CPU 점유율을 계산해서 스레드가 자동으로 쉬도록 만들어주는 것 외에는 없다. 어떻게? Sleep이나 Wait계열의 함수를 호출해서 대기하는 수 밖에는 없다. 내지는 마스터 스레드가 개별 스레드의 동작을 모니터링하면서 Suspend/Resume 시키는 수 밖에는 없다.&lt;/p&gt;
&lt;h3&gt;스레드 친화도 (Thread Affinity Mask)&lt;/h3&gt;
&lt;p&gt;스레드 친화도란 스레드가 어느 CPU에서 스케줄링 될지를 결정하는 값이다. 친화도는 32비트 정수로 표현되며, 개별 비트가 하나의 CPU를 의미한다. 특정 비트가 1이면 해당 CPU에서 스레드가 실행될 수 있음을, 0이면 해당 CPU에서 스레드가 실행될 수 없음을 나타낸다. Process Hacker를 통해서 특정 스레드의 친화도를 설정하는 과정이 &amp;#x3C;화면 1&gt;에 나와 있다. 살펴보면 해당 스레드는 현재 “CPU 1”만 비트가 켜져 있기 때문에 친화도 값은 2가 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./스레드_고급_활용법_우선순위,_친화도,_TLS,_APC.md_0.png&apos; data-alt=&apos;화면 1 작업관리자 프로세스 친화도 설정 화면&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 315px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/8434ab9b620ecffb3e310ba102f8db75/3c1ae/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 86.84210526315789%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAIAAABSJhvpAAAACXBIWXMAAAsTAAALEwEAmpwYAAAC2klEQVR42j1TyW7bSBTkh+cywBzyEwEGc5+LDWcRJollWFashXs396W5tbhvEm3kkilSnjw0iNdkV7161Y/C7bfHu/un1Y7cq8HNRrnbmd9pttLiFe2+mC+fjctX67J2p40/bb3Ljv96uP329Oe79fs/Vh/+Eu53a93VVZ/KLnmm0t5WlMgQA+3IygN7ObCLGE9KMunpZPDJyl9JUCqKqavWVnYFmUqO5RBKIxaZhmGapm1ZBjUMQk1Krsu2TNs0KJnzwPf783k8j5oTCxKRDrvDBvG4FUWZsSiKWBwnUZyEYcgY830/CMIgCDzPx5ss433XDW2rO5FALJImqes4vhc0TTMMQ1XXVVX2XT+OYzNHjcD7oe/r5VNV1X3f2X6EylYcx6IoaTpt2xafUQ9cpzzHNk1T3/OCkJVlVZYlikN2xk9gIqj8Qxap4QJsO27XdVVVsSWKokTRJEmQg6KumzzPl0bC0yk/D71kMuFJlOMo0lTNMKxZYlVHSwCALZ6zByyC1KIokADP+QlgEeDHo5SlqSTKuk6XDhuUQoEsy5q2xRNehTMYUSLFli+VDwYTHvYPSZzKkkKocTUH9LCcc44twKC6VkbPMzgM0PN57PeUCev9GmBJkig1m6ZdwHMkSXoF4zS40DNkh8udpRl/Az/st+gKhumENm0DcYsr0Sx7MQzHcQD3V+T5cuFw+3/w+kCTmCmKqunkKhui3xwGOE3DmezNsDkPA/5b9v1OL3KuqpplO+0SuPa55yyDK3VZ8CTmSdK3LagxeSDFlFzGYW9EwnpHxqHr5wnCzLVQ3mG2hqFoWjUuaJzrjFu8MeI8P+X8xIGHbJA+EyZsJOPn6zT0w3kYpst5wtAPw8t5zMr6lmY3kvv39+PKKb/SMPLd5+3m86ePx+ORJ+GehsI/q08a/irPVR37qBPZNGngLysVnVR0M9k/He1E9TLdTYnPTZbrXkr97N+D8x/XSXsmfqOI8AAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;화면 1 작업관리자 프로세스 친화도 설정 화면&apos; title=&apos;&apos; src=&apos;/static/8434ab9b620ecffb3e310ba102f8db75/3c1ae/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_0.png&apos; srcset=&apos;/static/8434ab9b620ecffb3e310ba102f8db75/08678/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_0.png 190w,
/static/8434ab9b620ecffb3e310ba102f8db75/3c1ae/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_0.png 315w&apos; sizes=&apos;(max-width: 315px) 100vw, 315px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;화면 1 작업관리자 프로세스 친화도 설정 화면&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;윈도우는 스레드와 프로세스에 대해서 개별적으로 친화도 값을 관리한다. 즉, 스레드 친화도 값과는 독립적으로 프로세스 친화도 값이 존재한다는 의미다. 스레드 친화도는 항상 프로세스 친화도의 서브셋이어야 한다. CPU가 4개인 컴퓨터를 생각해보자. 해당 컴퓨터에서 특정 프로세스의 친화도 값이 3이라면 해당 프로세스는 0, 1번 CPU에서만 수행될 수 있음을 의미한다. 이 때 해당 프로세스에 속한 스레드의 친화도 값은 2, 3번 CPU와 관계된 값을 지정할 수 없다. 해당 값을 지정하려고 하면 운영체제에서 오류를 리턴한다. 만약 스레드의 친화도를 2, 3번 CPU와 관계된 값으로 변경하고 싶다면 프로세스 친화도를 먼저 변경한 다음 스레드 친화도를 변경해야 한다.&lt;/p&gt;
&lt;p&gt;스레드와 프로세스의 친화도 값을 설정하는 함수들이 &amp;#x3C;리스트 3&gt;에 나와 있다. SetThreadAffinityMask 함수의 첫 번째 인자로 친화도를 설정할 스레드를, 두 번째 인자로 친화도 값을 지정하면 해당 스레드의 친화도를 지정된 값으로 변경한다. 리턴 값은 이전 친화도 값이다. 실패하면 0이 리턴된다. SetProcessAffinityMask 함수도 사용 방법은 동일하다. 단지 스레드가 아닌 프로세스에 대한 친화도를 설정한다는 차이만 있다. GetProcessAffinityMask 함수는 특정 프로세스의 친화도 값을 구하는 역할을 한다. hProcess로 친화도를 구할 프로세스 핸들을 전달하면 lpProcessAffinityMask로 해당 프로세스의 친화도 값이, lpSystemAffinityMask로는 시스템 친화도 값이 리턴된다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 3 스레드 친화도 설정 함수 원형&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;DWORD_PTR WINAPI &lt;span class=&quot;token function&quot;&gt;SetThreadAffinityMask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    HANDLE hThread
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DWORD_PTR dwThreadAffinityMask
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

BOOL WINAPI &lt;span class=&quot;token function&quot;&gt;SetProcessAffinityMask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    HANDLE hProcess
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DWORD_PTR dwProcessAffinityMask
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

BOOL WINAPI &lt;span class=&quot;token function&quot;&gt;GetProcessAffinityMask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    HANDLE hProcess
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PDWORD_PTR lpProcessAffinityMask
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PDWORD_PTR lpSystemAffinityMask
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&amp;#x3C;리스트 4&gt;에는 친화도를 설정하는 간단한 프로그램이 나와 있다. 듀얼코어 이상인 시스템에서 해당 프로그램을 실행하면 &amp;#x3C;화면 2&gt;에 나타난 것과 같은 출력을 볼 수 있다. 친화도를 설정하기 전에는 해당 스레드가 여러 CPU에서 번갈아 가면서 실행되지만, 친화도를 2로 고정한 다음부터는 1번 CPU에서만 실행되는 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 4 스레드 친화도 변경 예제&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;ULONG
CALLBACK
&lt;span class=&quot;token function&quot;&gt;ThreadProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetCurrentProcessorNumber&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;스레드 친화도 변경\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;SetThreadAffinityMask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetCurrentThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetCurrentProcessorNumber&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;


    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    HANDLE thread &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ThreadProc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;WaitForSingleObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; INFINITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./스레드_고급_활용법_우선순위,_친화도,_TLS,_APC.md_1.png&apos; data-alt=&apos;화면 2 스레드 친화도 프로그램 실행 결과&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 677px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/9e464e8f99ab0ed0880a7e35786a5f43/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 57.89473684210527%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAAsTAAALEwEAmpwYAAABBUlEQVR42mNYs/3w+j0nVu04tmjT4QUbD83YcGLS2pOT12Gg9Senrj85e/OZxVuOLl2/e8fseXP7JjEAAQcnFysrGysbGwsLKzMhxMrGwcjMIq+kPHn2IpBmJiYmBqIBIyMjkJSUlJizYClEMzOpmqWkJBcuWw3iMzMzM4IB8ZqlpSRnL1rFwMbKLCQkxMPDw8vDQ4x+FM1gm1mItRdTMxkBRiXNnFxcbOzswHgGMoAkIyMTIxNOxMQMihppaelZC1eCNXNysrOxsbGycnJwAEmibJaWmrd0DYOcsrqKpp6skpqMgoq0goqMvDKQAeQCxeVVNBRUNNGQoqqWjIKqkbl1W990APEiS6eNJW8CAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;화면 2 스레드 친화도 프로그램 실행 결과&apos; title=&apos;&apos; src=&apos;/static/9e464e8f99ab0ed0880a7e35786a5f43/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_1.png&apos; srcset=&apos;/static/9e464e8f99ab0ed0880a7e35786a5f43/08678/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_1.png 190w,
/static/9e464e8f99ab0ed0880a7e35786a5f43/2edd7/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_1.png 380w,
/static/9e464e8f99ab0ed0880a7e35786a5f43/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_1.png 677w&apos; sizes=&apos;(max-width: 677px) 100vw, 677px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;화면 2 스레드 친화도 프로그램 실행 결과&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;그렇다면 이러한 친화도 값은 언제 사용할까? 윈도우 사용자들은 최적화를 위해서 친화도 값을 많이 사용한다. 방송을 하는 게이머들은 게임을 특정 CPU에 바인딩 시키고, 분리된 CPU에 방송 프로그램을 할당하는 방법을 사용한다. 일부 게임 최적화 유틸리티는 이러한 작업들을 자동으로 해주기도 한다. 물론 이 경우에 진짜 최적화가 될지는 조금 생각을 해보아야 한다.&lt;/p&gt;
&lt;p&gt;프로그래머가 친화도를 설정하는 경우도 크게 다르지는 않다. 프로그래머의 경우 자신이 작성한 프로그램의 스레드 구조를 완벽하게 알 수 있기 때문에, 병렬적으로 수행되어야 하는 스레드들에 대해서는 독립된 CPU를 설정함으로써 상호 컨텍스트 스위칭을 줄일 수 있다. IOCP도 그러한 식으로 최적화를 수행한 예로 생각할 수 있다.&lt;/p&gt;
&lt;p&gt;스레드 친화도 값은 최적화 작업 외에도 CPU와 관련된 특수한 작업을 하기 위해서 사용하는 경우도 있다. QueryPerformanceCounter 함수가 대표적이다. 해당 함수는 윈도우의 고해상도 타이머 값을 가져오는 역할을 한다. 이 함수는 CPU의 클럭과 밀접한 관련이 있는데 일반적인 경우에는 멀티 프로세서 환경에서 어떤 프로세서에서 호출되는지에 관계없이 정상적으로 동작하지만 BIOS에 버그가 있는 경우에는 호출되는 프로세서에 따라서 다른 값이 리턴되는 경우가 있다. 이러한 버그를 보정하기 위해서 SetThreadAffinityMask가 사용되기도 한다.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;리스트 5&gt;에 특정 코드의 수행 시간을 구하기 위한 전형적인 QueryPerformanceCounter 호출 구조가 나와 있다. 보통의 경우에 이 코드는 전혀 문제가 없지만 BIOS 등에서 처리가 잘못된 경우에는 1번 코드가 실행되는 프로세서와 2번 코드가 실행되는 프로세서가 다를 경우에 전혀 엉뚱한 두 값이 리턴되기도 한다. 이러한 부작용을 보정하기 위해서는 &amp;#x3C;리스트 6&gt;에 나타난 것과 같이 SetThreadAffinityMask 함수를 사용해서 QueryPerformanceCounter 함수가 하나의 프로세서에서만 호출되도록 만들어주어야 한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 5 QueryPeroformanceCounter 호출 예제&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;QueryPerformanceCounter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// … 1&lt;/span&gt;
특정 작업들
&lt;span class=&quot;token function&quot;&gt;QueryPerformanceCounter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// … 2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 6 QueryPerformanceCounter 함수가 특정 프로세서에서 호출되도록 지정한 예제&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;SetThreadAffinityMask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetCurrentThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;QueryPerformanceCounter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// … 1&lt;/span&gt;
특정 작업들
&lt;span class=&quot;token function&quot;&gt;QueryPerformanceCounter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// … 2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;앞서 스레드와는 별개로 프로세스 친화도 값이 있고, 스레드 친화도는 프로세스 친화도의 서브셋이 되어야 한다고 이야기했다. 이런 관점에서 살펴보면 &amp;#x3C;리스트 6&gt;와 같은 코드는 문제가 있다. 상수 1을 지정해서 0번 CPU에서만 실행하겠다고 지정했지만, 현재 실행되는 프로세스가 0번 CPU에서 실행되지 않도록 설정됐을 수 있기 때문이다. 이런 경우를 좀 더 유연하게 처리하기 위해서는 현재 프로세스의 친화도 값을 구해서 비교하는 약간 복잡한 과정을 거쳐야 한다. &amp;#x3C;리스트 7&gt;에는 이런 경우에 사용할 수 있는 간단한 헬퍼 클래스가 나와있다. 해당 객체를 생성하면 생성된 블록은 싱글 코어로 동작하게 만들어준다. &amp;#x3C;리스트 8&gt;에는 SingleCore 클래스를 사용해서 QueryPerformanceCounter의 동작을 보정하는 방법이 나와 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 7 SingleCore 스레드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SingleCore&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SingleCoreError&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    ULONG_PTR oam_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;SingleCore&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        ULONG_PTR pam&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sam&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetProcessAffinityMask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetCurrentProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;pam&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;sam&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SingleCoreError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        ULONG_PTR am &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; bits &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; CHAR_BIT &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;am&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;bits&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;am &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; pam&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                oam_ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SetThreadAffinityMask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetCurrentThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; am&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;oam_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SingleCoreError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

                &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

            am &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SingleCore&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;SetThreadAffinityMask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetCurrentThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; oam_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 8 SingleCore 클래스를 사용해서 QueryPerformanceCounter 동작을 보정한 예제&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;SingleCore s&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;QueryPerformanceCounter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// … 1&lt;/span&gt;
특정 작업들
&lt;span class=&quot;token function&quot;&gt;QueryPerformanceCounter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// … 2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;스레드 지역 저장소(Thread Local Sotrage)&lt;/h3&gt;
&lt;p&gt;GetLastError는 SetLastError로 설정된 오류 코드를 리턴해 주는 기능을 하는 윈도우 함수다. 신입 개발자에게 해당 함수를 직접 구현해 보라고 시키면 &amp;#x3C;리스트 9&gt;에 있는 코드와 같이 구현하는 경우가 많다. 이 코드는 기본적인 Set/GetLastError의 기능을 구현했지만 Set/GetLastError 함수가 스레드별로 독립적으로 오류코드를 관리되는 특징은 구현하지 않았다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 9 Set/GetLastError 구현 1&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;ULONG error_code &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MySetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG code&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    error_code &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

ULONG &lt;span class=&quot;token function&quot;&gt;MyGetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; error_code&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;원본 함수와의 차이점을 살펴보기 위해서 &amp;#x3C;리스트 10&gt;과 같은 프로그램을 만들어볼 수 있다. 두 개의 스레드를 만들어서 교차로 SetLastError, GetLastError를 호출하는 것이다. 이렇게 호출하면 원본 윈도우 함수와 우리가 구현한 버전의 차이를 발견할 수 있다. &amp;#x3C;리스트 10&gt;의 코드에서 MySetLastError, MyGetLastError 호출 부분을 우리가 작성한 버전과 윈도우 표준 함수로 변경해 가면서 결과를 관찰해 보도록 하자. &amp;#x3C;화면 3&gt;에는 윈도우 버전을 호출해서 결과를 출력한 화면이, &amp;#x3C;화면 4&gt;에는 우리가 구현한 버전을 호출해서 결과를 출력한 화면이 나와있다. 살펴보면 윈도우 버전을 호출했을 때에는 스레드별로 독립적으로 오류코드가 관리되고 있는 것을 볼 수 있다. 반면 MySetLastError, MyGetLastError를 호출했을 때에는 GetLastError를 호출 했을 때 다른 스레드가 덮어쓴 값이 반환되는 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 10 MySet/GetLastError 테스트 프로그램&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;ULONG CALLBACK &lt;span class=&quot;token function&quot;&gt;GleTestThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ULONG code&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        code &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetTickCount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%d] SetLastError %d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetCurrentThreadId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;MySetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;code&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%d] GetLastError %d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetCurrentThreadId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MyGetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_tmain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; argc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _TCHAR&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; argv&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    HANDLE threads&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ARRAYSIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;threads&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        threads&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; GleTestThread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;WaitForMultipleObjects&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ARRAYSIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;threads&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; threads&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; INFINITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ARRAYSIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;threads&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;threads&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./스레드_고급_활용법_우선순위,_친화도,_TLS,_APC.md_2.png&apos; data-alt=&apos;화면 3 Set/GetLastError 출력 결과&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 677px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/8c4f6ab77573d87d1f2eca1178c82cd6/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 65.26315789473685%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAABNklEQVR42mOYt3rH4o271u4+sXzL8UWbjyzefnr+7mvzd1/Hihbvu7Fiz4WlWw5tnLd40/wlDLHJGfLycurqmhoaWopKypJS0iysbGzsHDgRBycrGwePgFDv1NkMiWlZsjLSSkpKysrKcnKy4mJiDAwMjIyMDDgARIqNlWXS1JkMCSkZMtJS6urqGhoa8vLy4uLixGhmZWWdOWc+Q1hsioS4GFCziooKULO0tDQjGBCymXXyjHkM5vZuQA4XNzcbGHBwcDAzMxOr2cjSAchhYmJiIA6gaXYEaWZmJk8zRTZToNnYygnIYWZmYWRkAiEmHIgRipgYgR5kZGdnmzxzPszPJNrMzsY2YcoMBr/IVDkVbTVdE1UdY3U9U20jSx1jKyRkDUZWGvpmQDXqYARk6Jlad0yaDQDQNF7BScIK1QAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;화면 3 Set/GetLastError 출력 결과&apos; title=&apos;&apos; src=&apos;/static/8c4f6ab77573d87d1f2eca1178c82cd6/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_2.png&apos; srcset=&apos;/static/8c4f6ab77573d87d1f2eca1178c82cd6/08678/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_2.png 190w,
/static/8c4f6ab77573d87d1f2eca1178c82cd6/2edd7/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_2.png 380w,
/static/8c4f6ab77573d87d1f2eca1178c82cd6/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_2.png 677w&apos; sizes=&apos;(max-width: 677px) 100vw, 677px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;화면 3 Set/GetLastError 출력 결과&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./스레드_고급_활용법_우선순위,_친화도,_TLS,_APC.md_3.png&apos; data-alt=&apos;화면 4 MySet/GetLastError 출력 결과&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 677px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/cbd42ce4c92d0a58ec07bc82664ffbe5/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 65.26315789473685%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAABdklEQVR42mPIqp9R2jm/uHPhtCVbZ6/cMWnJtr4VhyesOd636mjfysNT1p8q6V3uEVvul1zvk1Dlm1CZVtrR2DNzQc+ERX2TGJy8guXl5ZRV1dTUNRQVFcUlJJmYWVjZ2IGIhRWEmFnYgHwgAgozMjEDZYEkNx9/x4SpDF4B4fKyMsrKSirKyrKysmJiYgwMDIyMjAw4AESKjZVl4tQZDF5BkbIyUurq6hoaGioqKhISEsRpZp0xex6DqaOvjJQE0NHKQNuVlKSlpYnSzMY6cdpsBnFVI2ZGBk4uLjYw4ODgYGZmJsbmSTPnMQgp6YOFmBiIA0g2z2EQUzEACTGRrnn6HAZhJV3ybJ40fS6DuApZzgb6ecY8BiUtYyAHGPVMMAA0COgLZIQMgMEJNICdnX3yzPkMwqqG5Dl7MtBmDZdwfkUdEQ0TLSMLAzNrPRNLHQNTbT1jHUMTHQMLXSNzTT0jPTNbAws7CDK0tNc2sjCytJsyfyUAm0xSQFbtiEAAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;화면 4 MySet/GetLastError 출력 결과&apos; title=&apos;&apos; src=&apos;/static/cbd42ce4c92d0a58ec07bc82664ffbe5/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_3.png&apos; srcset=&apos;/static/cbd42ce4c92d0a58ec07bc82664ffbe5/08678/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_3.png 190w,
/static/cbd42ce4c92d0a58ec07bc82664ffbe5/2edd7/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_3.png 380w,
/static/cbd42ce4c92d0a58ec07bc82664ffbe5/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_3.png 677w&apos; sizes=&apos;(max-width: 677px) 100vw, 677px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;화면 4 MySet/GetLastError 출력 결과&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;이러한 Set/GetLastError 함수의 특성을 이야기해 주면 똑똑한 신입 개발자들은 &amp;#x3C;리스트 11&gt;과 같은 코드를 작성한다. 스레드와 오류코드를 연결하는 맵을 만들어서 관리하는 것이다. 물론 이 코드는 멸티스레드 환경에서 사용하기에는 조금 부적절한 버전이다. 더 똑똑한 개발자는 여기에 동기화 처리를 덧붙여서 &amp;#x3C;리스트 12&gt;에 나와 있는 것처럼 실제로 써먹을 수 있는 코드를 만든다. 이쯤 되면 이제 기능적으로는 Set/GetLastError와 동일하다고 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 11 Map을 사용한 Set/GetLastError 구현&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;map&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;map ErrorCodeMap&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;map&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;iterator ErrorCodeMit&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

ErrorCodeMap error \_codes&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;MyThreadSetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG code&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ULONG tid &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetCurrentThreadId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ErrorCodeMit it &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; error \_codes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;it &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; error \_codes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		error \_codes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;make\&lt;span class=&quot;token function&quot;&gt;_pair&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tid&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		it&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;second &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

ULONG
&lt;span class=&quot;token function&quot;&gt;MyThreadGetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	ULONG tid &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetCurrentThreadId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ErrorCodeMit it &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; error \_codes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;it &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; error \_codes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; it&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;second&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 12 동기화 처리를 추가한 Set/GetLastError 구현&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;CRITICAL_SECTION gle_cs&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;InitSystem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;InitializeCriticalSection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gle_cs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CleanupSystem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;DeleteCriticalSection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gle_cs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SyncMyThreadSetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG code&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;EnterCriticalSection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gle_cs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;MyThreadSetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;code&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;LeaveCriticalSection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gle_cs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

ULONG &lt;span class=&quot;token function&quot;&gt;SyncMyThreadGetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ULONG ge&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;EnterCriticalSection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gle_cs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ge &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MyThreadGetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;code&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;LeaveCriticalSection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;gle_cs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; ge&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 모든 구현을 마치고 나면 한가지 의문이 떠오른다. 과연 이 방법뿐일까? 스레드별로 다른 저장소를 구현하기 위해서 우리는 매번 스레드와 자료를 연결하는 맵을 만들고 또 그 맵에 접근하기 위한 동기화 객체를 만들어야 할까? 구현의 번잡함을 차치하고서도 이 코드의 더 큰 문제점은 성능에 있다. 우리가 사용하려는 데이터의 논리적 특성은 전혀 공유적인 속성이 아니다. 하지만 우리는 구현상의 이유로 동기화 객체를 사용해서 직렬화를 시켰다. 이 말은 다시 표현하면 멀티 코어의 장점을 하나도 살리지 못한다는 의미가 된다.&lt;/p&gt;
&lt;p&gt;윈도우는 앞서 제기된 문제를 해결하기 위해서 스레드 지역 저장소(Thread Local Storage)라는 것을 제공해 준다. 이름에서 알 수 있듯이 지금까지 우리가 논의했던 모든 문제들을 한번에 해결해주는 기능이라고 생각하면 되겠다. 스레드 지역 저장소를 통해서 우리는 스레드별로 별도의 데이터를 동기화 객체 없이 저장하고 읽어올 수 있다.&lt;/p&gt;
&lt;p&gt;우선 스레드 지역 저장소를 조작하는 함수들을 살펴보자. &amp;#x3C;리스트 13&gt;에 TLS 조작 함수들의 원형이 나와 있다. TlsAlloc 함수는 스레드 별로 관리할 데이터의 인덱스를 할당하는 역할을 하는 함수다. 해당 함수를 호출하면 사용할 수 있는 TLS 인덱스를 반환해 준다. TlsFree 함수는 dwTlsIndex로 지정된 인덱스를 해제하는 역할을 한다. TlsGetValue 함수는 dwTlsIndex로 전달된 인덱스에 해당하는 값을 반환하는 역할을 한다. TlsSetValue 함수는 dwTlsIndex로 전달된 인덱스에 해당하는 값을 lpTlsValue로 설정하는 역할을 한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 13 TLS 조작 함수&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;DWORD WINAPI &lt;span class=&quot;token function&quot;&gt;TlsAlloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
BOOL WINAPI &lt;span class=&quot;token function&quot;&gt;TlsFree&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DWORD dwTlsIndex&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
LPVOID WINAPI &lt;span class=&quot;token function&quot;&gt;TlsGetValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DWORD dwTlsIndex&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
BOOL WINAPI &lt;span class=&quot;token function&quot;&gt;TlsSetValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DWORD dwTlsIndex&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPVOID lpTlsValue&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;여기까지 설명만 듣고는 어떻게 TLS가 우리가 제기했던 문제를 해결하는지 감이 잘 잡히지 않는다. 감을 잡기 위해서는 TLS의 구조에 대해서 알아야 한다. TLS가 동작하는 기본 원리는 운영체제가 스레드를 생성할 때에 스레드 스택을 만드는 것과 동일하게 TLS를 저장할 배열도 같이 만든다는데 있다. 물론 그 크기는 고정적이다. TLS로 할당할 수 있는 인덱스 개수는 그 배열의 개수만큼으로 한정된다. 이렇게 생성된 배열은 스레드의 컨텍스트 정보를 저장하는 곳에 기록돼서 스레드가 변경될 때마다 스레드가 생성될 때 같이 만들어진 TLS 배열을 가리키도록 설정된다. 따라서 우리는 표면적으로는 동일한 2번 인덱스의 값을 참조하지만 그걸 저장하고 있는 배열이 활성되는 스레드 컨텍스트에 따라서 변경되기 때문에 최종적으로는 다른 장조를 참조하게 되는 것이다.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;리스트 14&gt;에는 이렇게 TLS 함수를 사용해서 Set/GetLastError를 구현한 버전이 나와있다. 앞서 작성한 것보다 코드도 훨씬 적지만 동기화 객체가 없기 때문에 멀티 코어의 장점도 십분 활용할 수 있다는 특징이 있다. 이렇게 직접 TLS 함수를 호출하지 않고도 __declspec(thread) 지시어를 사용하면 &amp;#x3C;리스트 15&gt;에 나타난 것처럼 간단하게 TLS를 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 14 동적 TLS를 사용한 Set/GetLastError 구현&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;ULONG gle_index&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;InitSystem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    gle_index &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;TlsAlloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CleanupSystem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;TlsFree&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;gle_index&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MyTlsSetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG code&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;TlsSetValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;gle_index&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

ULONG &lt;span class=&quot;token function&quot;&gt;MyTlsGetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG_PTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;TlsGetValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;gle_index&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;리스트 15 정적 TLS를 사용한 Set/GetLastError 구현&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;__declspec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; ULONG error_code &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;MySetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG code&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    error_code &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

ULONG &lt;span class=&quot;token function&quot;&gt;MyGetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; error_code&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;유저모드 APC&lt;/h3&gt;
&lt;p&gt;APC란 Asynchronous Procedure Calls의 약자로 우리말로 하면 비동기 프로시저 호출 정도로 번역할 수 있다. 여기서 가장 중요한 말은 제일 앞에 있는 비동기란 말이다. 우리가 일반적으로 호출하는 함수 구조를 동기 방식이라고 한다. 그렇다면 비동기 방식은 무엇일까? 바로 함수 호출이 즉시 일어나지 않고 지연돼 있다가 특정 시점에 호출된다는 의미다.&lt;/p&gt;
&lt;p&gt;세부적인 내용을 살펴보기에 앞서 관련 함수들의 사용법에 대해서 먼저 알아보도록 하자. &amp;#x3C;리스트 16&gt;에 유저모드 APC와 관련된 함수 원형들이 나와있다. 제일먼저 보이는 QueueUserAPC 함수가 APC 큐에 함수를 추가하는 역할을 한다. pfnAPC로는 수행될 APC 함수를, hThread로는 해당 APC 함수가 추가될 스레드 핸들을, dwData로는 pfnAPC 함수로 전달될 컨텍스트 변수를 지정하면 된다. APCProc은 실제로 수행될 APC 함수 원형이다. 리턴 값은 없으며, dwParam은 QueueUserAPC 함수에서 설정한 컨텍스트 변수가 전달된다. 그 다음으로는 SleepEx라는 함수가 있다. 해당 함수는 Sleep과 동일한 기능을 하는데 추가적인 기능은 두 번째 파라미터인 bAlertable 값을 통해서 스레드를 통지 가능 상태로 만들 수 있다는 점이 특징적이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 16 유저모드 APC 관련 함수 원형&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;DWORD WINAPI &lt;span class=&quot;token function&quot;&gt;QueueUserAPC&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PAPCFUNC pfnAPC&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HANDLE hThread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ULONG_PTR dwData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
VOID CALLBACK &lt;span class=&quot;token function&quot;&gt;APCProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG_PTR dwParam&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
DWORD WINAPI &lt;span class=&quot;token function&quot;&gt;SleepEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DWORD dwMilliseconds&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; BOOL bAlertable&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이제 APC가 동작하는 세부 구조에 대해서 좀 살펴보자. 윈도우 스레드는 모두 APC 큐라는 것을 가지고 있다. 해당 큐에 값을 추가하는 함수가 QueueUserAPC 함수가 하는 역할이다. APC 큐에 추가된 함수들은 스레드가 통지 가능 상태(Alertable State)가 될 때에 일괄 수행된다. 스레드를 통지 가능 상태로 만드는 함수로는 SleepEx부터 WaitForSingleObjectEx, WaitForMultipleObjectsEx 등의 함수가 있다. 보통 스레드를 대기 상태로 만드는 함수의 Ex버전에 포함돼 있다고 생각하면 되겠다. 이렇게 스레드가 통지 가능 상태에 진입하면 윈도우는 APC 큐에 뭔가 추가된 것이 있거나 대기 중에 뭔가가 추가되면 해당 APC 루틴을 호출하고 대기를 종료한다.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;리스트 17&gt;에는 이렇게 유저모드 APC루틴을 사용한 예가 나와 있다. 실행 결과에서도 볼 수 있지만 동기 호출과 다르게 APC 루틴의 가장 큰 장점은 APC 루틴이 추가된 스레드 컨텍스트에서 호출된다는 점이다. 따라서 특정 스레드 컨텍스트에서 특정 함수가 호출되도록 만들어야 하는 경우라면 유용하게 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 17 유저모드 APC 사용 예제&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;ULONG
CALLBACK
&lt;span class=&quot;token function&quot;&gt;ApcThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;통지 상태 시작\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;SleepEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;통지 상태 끝\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;작업중...\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;
CALLBACK
&lt;span class=&quot;token function&quot;&gt;ApcProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG_PTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ApcProc %d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetCurrentThreadId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;ApcProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


    HANDLE thread&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    thread &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ApcThread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;QueueUserAPC&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ApcProc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; thread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;WaitForSingleObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; INFINITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 677px; margin-bottom: 16px;&apos; data-url=&apos;./스레드_고급_활용법_우선순위,_친화도,_TLS,_APC.md_4.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/0b4bc3dfdb78f6aae3d4c970eb91939e/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 65.26315789473685%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAABb0lEQVR42mPIqJpc0jKrsHl2YtmkkOxut6Q2RY8qWbcqeY9qec8aea8aee9aEPKpU/Fv0Alr88mdlN8yZ35V+dyqcgZHzyAFBXklZRU+fgEGJhYmZlZG3AioAEQysnDy8pU1dTPYOXtLS0nw8PIwMTExEAEYGRmBJDsba1f/ZAZHdz9ZGWkuLm4WFhbiNbOxsk6bOYfBwNpTTlZKRUWVh4eHFJvZeiZOZzBz9FNSkNXS1ubm5iZJc/eE6Qw6Fq7ystLCwiIkOZuDnb21s59Bw8RJUV6WhZUVIkq85vbuCQy6Vh4yUuKysnIkOpu1b9pMBlPnQEU5GU1NLVL93DttBoOOtaeigiy/gADQ5RA5RiYQYAQjNAASZGYGKuNk5wBp1jCxlxQVAoYW0EQmRkZmQkkFbnP/9BkMqvZhSnoWNs6eJtaOZjbOlg5uhhb2BuZ2usZWQKRnYg3k6hhb6RhbGlqCGUaWuiZWptZOXdPnAgCwwElwUCrAdgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                      TLS  APC md 4&apos; title=&apos;&apos; src=&apos;/static/0b4bc3dfdb78f6aae3d4c970eb91939e/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_4.png&apos; srcset=&apos;/static/0b4bc3dfdb78f6aae3d4c970eb91939e/08678/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_4.png 190w,
/static/0b4bc3dfdb78f6aae3d4c970eb91939e/2edd7/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_4.png 380w,
/static/0b4bc3dfdb78f6aae3d4c970eb91939e/3c503/%EC%8A%A4%EB%A0%88%EB%93%9C_%EA%B3%A0%EA%B8%89_%ED%99%9C%EC%9A%A9%EB%B2%95_%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84%2C_%EC%B9%9C%ED%99%94%EB%8F%84%2C_TLS%2C_APC.md_4.png 677w&apos; sizes=&apos;(max-width: 677px) 100vw, 677px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;화면 5 유저모드 APC 사용 예제 실행 결과&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[xfav 0.9.8: 탐색기에 즐겨찾기를 달아보아요~~]]></title><description><![CDATA[xfav 프로그램이 업데이트 되었습니다. 다음 사항이 변경되었습니다. 크래시 버그 수정. x키로 이어지는 연속기를 쓰실 수 있습니다. 탐색기 창 전부 닫기 (esc → x → k) 탐색기 창 전부 최소화 (esc → x → x…]]></description><link>https://jiniya.net/wp/archives/7599</link><guid isPermaLink="false">https://jiniya.net/wp/archives/7599</guid><pubDate>Wed, 04 Jul 2012 23:58:13 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/archives/2821&quot;&gt;xfav 프로그램&lt;/a&gt;이 업데이트 되었습니다. 다음 사항이 변경되었습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;크래시 버그 수정.&lt;/li&gt;
&lt;li&gt;x키로 이어지는 연속기를 쓰실 수 있습니다.
&lt;ul&gt;
&lt;li&gt;탐색기 창 전부 닫기 (&lt;strong&gt;esc → x → k&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;탐색기 창 전부 최소화 (&lt;strong&gt;esc → x → x&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;탐색기 창 전부 팝업 (&lt;strong&gt;esc → x → z&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;현재 창 항상 위 토글 (&lt;strong&gt;esc → x → t&lt;/strong&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;아래 경로에서 다운로드 받으실 수 있습니다. 그럼 모두 모두 즐탐하세욥 ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/bins/xfav/xfav32.0.9.8.zip&quot;&gt;xfav 0.9.8 32비트 버전&lt;/a&gt;&lt;a href=&quot;http://www.jiniya.net/bins/xfav/xfav64.0.9.8.zip&quot;&gt;xfav 0.9.8 64비트 버전&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; 1
 1&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[boost와 ABI, 그리고 ELF…]]></title><description><![CDATA[최근에 XIGNCODE…]]></description><link>https://jiniya.net/wp/archives/7543</link><guid isPermaLink="false">https://jiniya.net/wp/archives/7543</guid><pubDate>Tue, 03 Jul 2012 23:58:12 GMT</pubDate><content:encoded>&lt;p&gt;최근에 XIGNCODE3를 리눅스 게임 서버에 적용한 적이 있다. 뭐 리눅스 게임 서버야 여러 군데 적용을 했었는데 그 곳이 조금 특별했던 건 자바를 사용한다는 점이었다. 학부 때 자바 실험한 기억을 떠올리며 회사에 비치된 자바 책을 참고하여 난 뚝딱뚝딱 자바 인터페이스를 만들었다. 뭐 별로 어렵진 않았다. 그리고 적용도 잘 됐다. 적용하고 나서 한 가지 문제가 발생했다. 해당 게임 서버에 XIGNCODE3 기능을 ON/OFF 시키는 걸 만들면서 시작된 문제였는데 XIGNCODE3를 OFF 상태로 시작했다가 ON을 시키면 크래시가 난다고 했다. 자바 크래시 로그를 같이 보내 왔는데 XIGNCODE3 so 파일에서 다른 boost 공유 라이브러리에 있는 심벌에 바인딩되면서 오류가 발생했다.&lt;/p&gt;
&lt;p&gt;한동안 이 문제는 나를 굉장히 골치 아프게 만들었다. 그도 그럴것이 해당 게임 서버에서만 발생하는 문제이기 때문에 우리 쪽에서 재현하기가 쉽지 않았다. 모든 것을 동일하게 구축하고 해당 boost so 파일을 먼저 로드하고 고갱님 환경과 동일해 보이도록 만들고는 테스트를 해도 우리 쪽에서는 재현되지 않았다. 그래서 빌드할 때마다 고갱님께 테스트를 부탁 드려야 했기에 참 쉽지 않았다. 나와 같은 문제로 고통받는 개발자가 분명히 있을거란 생각에 내가 멘붕을 탈출했던 경로를 여기에다 조금 끄적여 본다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0. ABI가 뭔가요?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ABI라고 하면 뭔가 거창하고 있어보이는데 전산 약어들이 다 그렇듯이 아무거도 아닌 용어다. application binary interface의 약자로 바이너리 단계에서의 인터페이스를 의미한다고 보면 되겠다. 구조체가 메모라상에 실제로 어떻게 존재하는지 호출 규약이 어떻게 되는지를 나타내는 말이라고 생각하면 된다. 이렇게 말해도 참 어려운데 윈도우 프로그래머들이 더 쉽게 이해할 수 있게 말하자면 dll 버전 업이 되었을 때, 해당 dll을 사용하는 프로그램을 새로 컴파일할 필요없이 dll만 교체해서 실행이 되면 ABI 호환성을 지원한다고 하고, 재컴파일이 필요하다면 ABI 호환성을 지원하지 않는다고 말한다.&lt;/p&gt;
&lt;p&gt;어쨌든 장황하게 설명했는데 boost는 ABI 호환성을 제공하지 않는다. 버전 업이 되면 새로 컴파일을 해야 한다. 이건 여담이지만 여러분이 API 세트를 디자인해보면 알겠지만 ABI 호환성을 제공하는 것이 생각처럼 녹록한 일은 아니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1. ELF는 또 뭐죠?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ELF는 리눅스의 실행 파일 포맷이다. 난 이 포맷에 대해서 자세한 정보를 알진 못하는데 이번 사례를 통해서 아주 심각한 한가지 문제에 대해서 알게 되었다. 윈도우 dll은 export 시킨 심볼에 대해서만 외부로 노출시킨다. 근데 이 망할 ELF는 별도 설정을 하지 않으면 내가 가진 모든 심벌이 외부로 그대로 노출된다. 도대체 왜 이런지 모르겠다. 더 욱긴건 난 우리 so 파일에 boost를 정적으로 링크 시켰음에도 이 망할 시스템은 고객님의 게임 서버에 있는 다른 boost so 파일에 있는 심벌로 바인딩을 시도한다는 점이었다. 물론 그 다른 boost so 파일이 올라오기 전에 우리가 먼저 로딩되면 우리꺼를 쓴다. 근데 OFF로 시작해서 그 다른 버전의 boost so파일이 올라오고 우리 so 파일을 로딩하면 우리 so 파일 안에 정적으로 링크된 boost 심벌을 쓰는 것이 아니라 다른 버전의 boost so 파일에 있는 동일한 이름의 심벌에 바인딩을 한다는 점이었다. 그러니 크래시가 났다. ABI가 다르기 때문이다.&lt;/p&gt;
&lt;p&gt;ELF에 심벌 노출 정책을 설정하는 컴파일러 플래그들이 있는데 그걸 통해서 해당 심벌이 노출되지 않도록 설정해도 제대로 적용이 되질 않았다. 그 망할 문제가 생기는 심벌은 항상 공유됐다. 희한했다. 궁극의 ms-compatible 따위의 기능이 gcc 있었는데, 우리가 사용하는 버전에서는 지원되지 않았다. 그래서 더 골치 아팠다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2. 똑같은 boost를 쓴다면?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;온갖 컴파일 플래그 설정으로 문제를 해결하려 했지만 제대로 되지 않았기에 난 멘붕에 빠졌다. 그러다 결국 비굴하게 그냥 고객님께서 사용하시는 boost 최신 버전으로 우리 꺼를 컴파일하기로 했다. 그러면 ABI가 호환되니까 크래시는 발생하지 않을 것이라 생각한 것이다. 그렇게 온갖 것들을 다 바꿔서 새로 컴파일을 해서 테스트를 했는데 고객님께서 크래시가 발생하지 않는다고 했다. 근데 더 이상한 알 수 없는 온갖 문제들이 발생했다. 흙~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3. 심벌 이름 변경하기&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이 단계에서 이제 내가 선택할 수 있는 방법은 많은 선지자들이 갔던 길을 따르는 수 밖에는 없다. 심벌 이름이 바뀌도록 boost 소스 코드를 고치는 방법이었다. C++의 경우 이름 장식에 namespace가 포함되기 때문에 이 경우에 boost 네임스페이스 명을 boost2와 같이 변경하기만해도 심벌 이름이 모두 바뀌는 효과를 얻을 수 있다. 당연히 난 처음에 boost 라이브러리에서 ABI 호환성을 제공하지 않으니 이런 기능은 아주 자연스럽게 config.hpp 따위의 #define BOOST_NAMESPACE 값만 변경하면 싹 바뀌어서 컴파일이 될 줄 알았는데 그리 간단한 문제가 아니었다.&lt;/p&gt;
&lt;p&gt;똑똑한 우리 선배 개발자들은 파이썬 스크립트를 사용해서 네임스페이스를 변경하는 기능을 이미 만들어 두었다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://lists.boost.org/boost-build/2009/05/21911.php&quot;&gt;http://lists.boost.org/boost-build/2009/05/21911.php&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;나는 그냥 그걸 다운받아서 쓰기만 하면 되는 줄 알았다. 하지만 세상일이 모두 그리 간단하지만은 않다. 스크립트로 모든 네임스페이스를 변경하고는 boost를 컴파일 시키는데 당연한 이야기겠지만 제대로 동작하지 않았다. 멘붕, 멘붕, 멘붕… 난 어뜩하지?… 고객님 환경의 특성상 우리 라이브러리를 제일 처음 일단 로드만 시켜주세요. 이럴수는 없지 않겠는가? 핡~&lt;/p&gt;
&lt;p&gt;이제 난 어떡해야 하는가? boost 그 많은 파일들을 찾아서 모든 네임스페이스를 일일이 손으로 고쳐야 할까? 그 작업만 하는데도 올해가 다 지날지도 모른다. 그 전에 그 지겨운 일을 하다 내가 개발자를 그만둘지도 모른다. 그 때 생각났다. 그래 #define boost boost2 따위로는 안될까? 근데 config.hpp 처럼 모든 boost 파일이 공통으로 참고하는 헤더 따위를 알 수가 없었다. 그 때 떠올랐다. 그럼 gcc에 시키지 머. 그렇다. 이런 마법 같은 커맨드가 존재했던 것이다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;bjam cxxflags=-Dboost=boost2&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;bjam cxxflags=-Dboost=boost2&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;저렇게 할 경우에 include 경로도 모두 변경되기 때문에 boost 폴더에 있는 것을 boost2 폴더로 모두 복사한 다음에 컴파일을 시켜야 한다. 그렇게 하면 우리의 boost는 네임스페이스가 boost2로 변경돼서 멋지게 빌드된다. 당연한 이야기겠지만 이 경우에 boost를 사용하는 우리 모듈의 makefile에도 -Dboost=boost2를 넣어서 빌드를 해야한다.&lt;/p&gt;
&lt;p&gt;두둥 이렇게 네임스페이스를 변경했다. 그리고 고갱님께 한땀한땀 빌드한 so 파일을 제공하고는 테스트를 부탁한다. 그랬더뉘 마법같이 된단다. 살았다. boost 산을 넘었다.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[링크드 리스트를 추억하며…]]></title><description><![CDATA[중학교 2학년 때였다. 그 때까지 베이직만 배웠던 나에겐 실행 파일을 만들어보고 싶은 열망이 있었다. 그리고 실행 파일을 만들기 위해서는 컴파일러 언어라는 것을 배워야 한다는 것도 알게 되었다. 서점에 C…]]></description><link>https://jiniya.net/wp/archives/5610</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5610</guid><pubDate>Wed, 27 Jun 2012 23:58:11 GMT</pubDate><content:encoded>&lt;p&gt;중학교 2학년 때였다. 그 때까지 베이직만 배웠던 나에겐 실행 파일을 만들어보고 싶은 열망이 있었다. 그리고 실행 파일을 만들기 위해서는 컴파일러 언어라는 것을 배워야 한다는 것도 알게 되었다. 서점에 C언어 책이 많았던 시절이었다. 그 중에 내가 살 수 있는 책은 딱 두 종류 밖에 없었다. 무료 컴파일러가 번들로 끼워져 있던 책이 두 가지 밖에 없었기 때문이었다. 하나가 맥가이버 C언어였던가 그랬고, 다른 하나는 제목은 생각나지 않는데 PCC인가 하는 컴파일러가 들어있던 책이었다. 난 PCC가 들어있던 책을 샀다. 사실 맥가이버 C언어는 서점을 들락날락 하면서 거의 다 봐버렸고 좀 더 비싸기도 했기 때문이었다.&lt;/p&gt;
&lt;p&gt;PCC가 들어있던 그 책은 자료형에 대한 설명으로 시작하는 책이었다. 잠수함 게임을 만드는데 뭐 미사일의 공격력은 정수여야 하니깐 int를 써야 하고, 잠수함 이름은 문자라서 char를 쓴다는 식의 비유로 시작하는 책이었던 것 같다. 나중에 느낀 사실이지만 입문서 치고는 참 괜찮았던 책이었다.&lt;/p&gt;
&lt;p&gt;그 책으로 C언어를 좀 배우고는 만들고 싶은 게 하나 생겼는데 MDIR 같은 프로그램이었다. MDIR은 도스 시절 거의 국민 유틸리티로 통했던 파일 관리자였다. “C로 하드웨어 주무르기”라는 책을 통해서 나름 시스템 프로그래밍에 대해서도 눈을 떴던 나는 금방이라도 MDIR을 만들 수 있을 것 같은 느낌이었다. 그래서 거침없이 코딩을 시작했다. 하지만 안타깝게도 500줄을 타이핑 하기도 전에 코딩을 멈출 수 밖에 없었다.&lt;/p&gt;
&lt;p&gt;MDIR 짝퉁을 만들면서 한 가지 궁금한 게 생겼던 것이다. 디렉터리마다 파일 개수가 다 다른데 그걸 어떻게 저장할까, 라는 질문이었다. 그 당시 배열만 알고 있던 나에게는 무척 궁금한 질문이었다. 내가 3000개를 지정했는데 파일이 4000개가 있으면 어떡하지, 라는 생각이었다. 물론 malloc같은 동적 할당을 사용해서 복사를 하면 되는데 그건 또 답이 아닌 것 같은 느낌이었다. 난 그 질문을 한참을 가지고 있었다. 그리곤 500줄에서 진도는 더 나가지도 못했다.&lt;/p&gt;
&lt;p&gt;그 질문에 답을 찾기 위해서 대형 서점의 컴퓨터 코너에 있는 책은 정말 거의 다 읽다시피 했다. 그런데 그 어느 책에도 답이 나와 있질 않았다. 물론 사실 답은 지천으로 널려 있었지만 단지 내가 찾지 못했을 뿐이었다. 그 답을 중학생도 이해할 수 있게 써 놓은 책은 그리 많지 않았던 것이다. 그러다 한날 “PC Tools 따라하기”라는 책을 통해서 그 마법 같은 방법을 배웠다. 링크드 리스트였다. 충격과도 같은 방법이었다. 동시에 난 왜 이 방법을 생각하지 못했을까라는 자괴감이 들었다.&lt;/p&gt;
&lt;p&gt;링크드 리스트를 배우고 나서도 난 MDIR을 만들지 않았다. “PC Tools 따라하기”라는 책에 그 모든 것이 나와 있어서 재미가 없어졌기 때문이었다. 책의 예제 코드만 따라해도 반쪽짜리 MDIR은 만들 수 있을 정도로 굉장한 책이었다. 그러다 djgpp의 allegro라는 게임 라이브러리에 빠져서 한동안 게임 프로그래밍을 했었던 것 같다.&lt;/p&gt;
&lt;p&gt;난 여기서 반쯤은 위안을 얻기도 하고 반쯤은 좌절하기도 한다. 위안을 얻는 부분은 내가 배열이 정답은 아니라는 사실을 본능적으로 알았다는 점이다. 그럼에도 좌절하는 부분은 링크드 리스트를 절대로 내 머리로는 생각해 낼 수 없었다는 사실이다. 알고 나면 그렇게 어려운 내용이 아니기에 더 좌절감이 큰 것 같기도 하다.&lt;/p&gt;
&lt;p&gt;그 이후로도 난 상당히 오랜 시간 프로그래밍을 했는데 내가 가지는 장점과 단점은 그 일화에 거의 모두 다 들어있다는 느낌이 든다. 난 프로그래밍적인 문제에 대한 직관은 뛰어난 편이다. 답을 알진 못하더라도 답이 있을지 없을지, 내지는 이 방법이 옳은지 틀린지를 판단하는 능력은 좀 좋다는 말이다. 반면 역시 그리 똑똑한 편은 아니다.&lt;/p&gt;
&lt;p&gt;우습게도 나중에 알게 된 사실이지만 초창기 MDIR은 배열을 사용해서 디렉터리 목록을 관리했다고 한다. 그래서 지정된 배열의 원소 개수를 초과하면 해당 파일이 조회되지 않는 문제가 실제로 있었다는 이야기를 들은 적이 있다. 그 이야기를 듣고 난 큰 교훈 하나를 깨닳았는데, 바로 분야에 따라서는 오덕스런 꼼꼼함과 집요함보다는 느슨한 실용성이 더 중요할 수도 있다는 점이었다.&lt;/p&gt;
&lt;p&gt;덧) 가끔 뜨문뜨문 아빠 생각이 날 때가 있다. 중학교 때 이야기를 쓰고 나니 그 때 생각이 난다. 중학교 때 난 난생처음 내 컴퓨터를 가지고는 신나서 밤새 컴퓨터를 하곤 했었다. 종종 아빠는 내 방에서 같이 잠을 잤는데, 그런 날도 난 아랑곳하지 않고는 컴퓨터를 늦게까지 했다. 그러던 어느 날이었다. 새벽에 컴퓨터가 고장나서 디스크를 고치는 중이었다. 지금 생각해보면 진짜 욱긴데 scan disk같은걸로 치료를 하는데 백업을 디스켓에 하겠냐고해서 난 멍청하게 하겠다고 한 것이었다. 새벽 늦게까지 컴퓨터는 미친듯이 디스켓을 갈아 끼우라고 시켰고, 난 또 그걸 꼬박꼬박 했다. 컴퓨터가 새벽에 디스켓에 뭔가를 쓰는 소리는 분명 잠을 자는 아빠한테는 엄청 거슬리는 소리였을텐데 아빠는 나에게 아무 말도 하지 않았다. 내가 컴퓨터 프로그래머가 되는데 가장 큰 사건이 무엇이었냐고 물으면 난 이 이야기를 하곤 한다. 웃기지만 아마 그 때 아빠가 머라고 했다면 난 프로그래머가 안됐을 수도 있었을 것 같기 때문이다. ㅋㅋㅋ&lt;/p&gt;
&lt;p&gt;나이가 들어서도 그랬다. 엄마는 항상 말한다. 치대가라. 약대가라. 졸업할 때는 공무원 해라. 대기업 가라. 그래도 아빠는 항상 나의 편이었다. 내가 하는 일을 잘 아시진 않았지만 언제나 아들이 하는 일이 멋있어 보인다며 말이다. 글을 써놓고 보니 그런 아버지가 유난히 생각난다. 무에 그리 급하셨는지… ㅠㅜ~ 아버지, 좋은 곳에 잘 계시죠?&lt;/p&gt;
&lt;p&gt; 1
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[해킹툴 박멸 퀘스트에 참여하실 프로그래머/리버서 모집합니닷!!!]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/7276</link><guid isPermaLink="false">https://jiniya.net/wp/archives/7276</guid><pubDate>Mon, 04 Jun 2012 23:58:10 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;이 글은 온니 구인광고 목적으로 올린 글입니다. 몇 분께서 오픈 프로젝냐고 물어보셨는데요, 안타깝게도 오픈프로젝트는 아닙니다. 제가 대부분 다 별도로 회신을 드렸는데 부득이하게 회사 메일이 지메일에는 블록이 돼 있어서, 해당 메일로 보내주신 분들께는 회신을 못드렸습니다. 다음에 오픈 프로젝트로 뭔가를 진행하게 된다면 메일을 드리도록 하겠습니다. 개발자는 계속 채용 중이니까요. 관심 있으신 분들은 많이 지원해 주세요!!!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.wellbia.com&quot;&gt;(주)웰비아닷컴&lt;/a&gt;에서 해킹툴 박멸 퀘스트를 함께 진행할 참신한 엔지니어 분들을 모집합니다. 지구의 평화를 위협하며 개인의 의지를 무참히 짓밟는 해킹툴 세력에 맞서서 버티기가 가능하다, 라고 생각하시는 분들은 지원을 자제해 주시구요. 싸워서 이길 의지가 있으신 분들의 많은 지원부탁드립니다. 뭐 사실 장비는 그리 중요하지 않습니다. 이기겠다는 의지와 열정이 중요하죠. 물론 그래도 기본 장비는 좀 갖춰져야 싸움을 시작이라도 할 수 있다는 건 아시죠? 지원 방법은 어떻게 되냐구요? 간단한 이력서와 자기소개서를 codewiz at wellbia dot com으로 보내주시면 됩니다. 별도 양식은 없습니다. &lt;a href=&quot;http://jiniya.net/tt/694&quot;&gt;4년 만에&lt;/a&gt; 이런 글을 올리니 참 감회가 새롭네요. 내용을 새로 썼는데 찾아보니 그 때나 지금이나 별반 달라지진 않았군요. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;프로그래머&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;윈도우 시스템 프로그래밍 경력 2-3년 이상&lt;/p&gt;
&lt;p&gt;C/C++을 잘한다.&lt;/p&gt;
&lt;p&gt;Python도 할 줄 안다.&lt;/p&gt;
&lt;p&gt;Windows의 내부 구조를 쫌 안다.&lt;/p&gt;
&lt;p&gt;Visual C++을 다년간 사용해 봤다.&lt;/p&gt;
&lt;p&gt;프로그래머란 직업을 사랑한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;테스트 프로그래머&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;신입&lt;/p&gt;
&lt;p&gt;C/C++을 배웠다.&lt;/p&gt;
&lt;p&gt;Python도 배워볼 생각이 있다.&lt;/p&gt;
&lt;p&gt;Windows 프로그래밍 책을 몇 권 쯤은 읽었다.&lt;/p&gt;
&lt;p&gt;시스템 프로그래밍에 관심이 많다.&lt;/p&gt;
&lt;p&gt;프로그래밍이 정말 재밌어 죽겠다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;해킹툴 분석가&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;신입/경력&lt;/p&gt;
&lt;p&gt;진짜 리버싱을 할 줄 안다.&lt;/p&gt;
&lt;p&gt;C/C++을 할 줄 안다.&lt;/p&gt;
&lt;p&gt;Windows API도 쫌 안다.&lt;/p&gt;
&lt;p&gt;PoC 정도는 직접 구현할 수 있다.&lt;/p&gt;
&lt;p&gt;세상 모든 것들을 리버싱하고 싶은 욕구가 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;아래 사항에 부합하면 더욱 좋습니다. ^^;;&lt;/strong&gt;&lt;/p&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;
&lt;p&gt;블로거다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;미친듯이 해 본 온라인 게임이 하나 이상은 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;연애 경험이 좀 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;좋아하는 작가가 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</content:encoded></item><item><title><![CDATA[상수를 왼쪽에 쓰는 이유…]]></title><description><![CDATA[흔한 C언어 비교 구문입니다. C언어 코딩 컨벤션 중에 위와 같은 구문에서 if…]]></description><link>https://jiniya.net/wp/archives/7328</link><guid isPermaLink="false">https://jiniya.net/wp/archives/7328</guid><pubDate>Wed, 30 May 2012 23:58:09 GMT</pubDate><content:encoded>&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;A &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 뭔가 멋진 동작&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;흔한 C언어 비교 구문입니다. C언어 코딩 컨벤션 중에 위와 같은 구문에서 if문의 상수 위치를 변경해서 사용하는 것이 있습니다. 아래와 같이 말이죠.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; A&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 뭔가 멋진 동작&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이런 것을 강제하는 회사도 있는데, 전 개인적으로 이 표기법을 굉장히 증오합니다. 잘못 알려진 헝가리언 표기법 만큼이나 싫어합니다. 그런데 중요한 것은 위와 같은 방식에는 그 나름의 논리적인 이유가 있어서 저렇게 한다는 겁니다. 그런데 맥락도 모르고 그냥 상수를 왼쪽에다 쓰는 건줄 알고 사용하는 개발자들이 있습니다. 아래처럼 말이죠.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; A&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 뭔가 멋진 동작&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;정말 이건 아닙니다. 이건 아니예요. 우선 왜 if문의 상수를 왼쪽에다 쓰는지 그 이유를 알아봅시다. C언어의 경우 대입 연산자도 표현식으로 if문에 사용할 수 있습니다. 대입 연산자의 경우에 대입된 값이 if문 평가에 사용되죠. 즉, 아래 코드가 완전 합법적인 C 코드라는 말이죠.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;A &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 뭔가 멋진 동작&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;개발자가 의도한건 저런건 아니었겠죠. 왜냐하면 저건 사실 아래와 동일한 코드이기 때문에 if문을 쓸 필요가 없습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;A &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// 뭔가 멋진 동작&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;여기서 개발자가 한 실수는 사소한 타이핑 실수입니다. ‘==’ 를 써야 할 자리에 ‘=’를 쓴거죠. 그러면서 구문 자체가 완전 엉뚱해져 버린 겁니다. 엄청난 코드 더미에서 이런 실수가 하나 있다면 잡는게 쉽진 않겠죠. 그래서 앞서 말한 상수를 왼쪽에다 적는 컨벤션이 나온 겁니다. if(10 = A) 이렇게 실수로라도 쓰면 컴파일 오류가 나거든요. 이런 사소한 타이핑 실수를 방지하기 위해서 상수를 왼쪽에다 쓰는 겁니다.&lt;/p&gt;
&lt;p&gt;자 그럼 이제 if(10 &gt;= A)를 살펴봅시다. 이건 정말 의미 없는 짓입니다. if(10 &gt;= A)를 타이핑하려고 했던 개발자가 실수로 if(10 = A)로 타이핑을 할까요? 별로 가능성이 없습니다. 그러니 이런 표현식에는 애초에 굳이 상수를 왼쪽에다 쓸 필요가 없는거죠.&lt;/p&gt;
&lt;p&gt;끝으로 제가 이 표현식을 왜 증오하는지를 조금 설명드리겠습니다. 코드는 컴퓨터가 읽는게 아니라 사람이 읽는 겁니다. if(10 == A)라는 구문을 만난다고 생각해봅시다. 10은 A와 같다라고 보통은 읽힐 겁니다. 눈에 10이 먼저 들어오니까요. 그런데 우리가 원래 하려고 했던 생각은 대체로 A는 10과 같다일겁니다. 즉, 한번 꼬여서 머릿속에 들어온다는 거죠. if(10 &gt;= A)가 되면 좀 더 심해집니다. 당연히 원래 의도는 A는 10보다 작거나 같다를 의도했겠지만 실제 식은 10은 A보다 크거나 같다가 되었습니다. 머리에서 한번 더 생각해야하고 번역 작업이 들어간다는 거죠. 그래서 전 이런 표현식을 싫어합니다. 아주 많이.&lt;/p&gt;
&lt;p&gt;진짜 끝으로 한 가지 이야기만 더 하겠습니다. 이건 C언어 이야깁니다. 파이썬 코드를 if 10 == A:와 같이 작성할 필요는 정말 전혀 없습니다. 왜냐하면 파이썬에서는 if A = 10: 자체가 오류가 나는 구문이기 때문입니다. 그러니 머릿속에서 생각나는대로 구현하면 됩니다. 젭알 그걸 한번 더 꼬아서 쓸 필요는 없어요.&lt;/p&gt;
&lt;p&gt;진짜 진짜 끝으로 사족을 하나 더 달자면 요즘 컴파일러는 정말 기똥차게 좋습니다. if(A = 10) 같은 구문은 경고 레벨만 올려도 잡을 수 있고, 정적 분석 도구를 사용한다면 지나치다 싶을 정도로 친절한 설명을 들을 수 있습니다. 그러니 우리가 고생하면서 꼬아서 쓸 필요가 없습니다. 선조들이 돌도끼로 사냥했다고 우리도 돌도끼로 사냥할 필요는 없잖아요.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/05/1337995436-22.png&quot;&gt;&lt;img src=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/05/1337995436-22.png&quot; alt=&quot;&quot; title=&quot;1337995436-22&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;좋은 도구를 사용해야 레벨업이 편합니다. 현실 세계에서도 말이죠.&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[스레드 다루기 (기초편)]]></title><description><![CDATA[윈도우는 스레드를 관리하기 위해서 다양한 함수들을 제공해 준다. 그러한 함수들을 살펴보기에 앞서서 윈도우는 스레드를 위해서 어떠한 속성들을 저장하고 관리하는지를 먼저 살펴보도록 하자. <화면 1>에는 Process Hacker…]]></description><link>https://jiniya.net/wp/archives/7194</link><guid isPermaLink="false">https://jiniya.net/wp/archives/7194</guid><pubDate>Fri, 04 May 2012 23:58:08 GMT</pubDate><content:encoded>&lt;p&gt;윈도우는 스레드를 관리하기 위해서 다양한 함수들을 제공해 준다. 그러한 함수들을 살펴보기에 앞서서 윈도우는 스레드를 위해서 어떠한 속성들을 저장하고 관리하는지를 먼저 살펴보도록 하자. &amp;#x3C;화면 1&gt;에는 Process Hacker라는 유틸리티를 사용해서 특정 프로세스에서 생성한 스레드 목록을 살펴보고 있다. 이 화면에는 윈도우에서 저장하고 있는 스레드의 속성의 거의 대부분이 포함되어 있다. 각각의 항목이 어떤 의미를 나타내는지 먼저 살펴보도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/05/image001.png&quot;&gt;&lt;img src=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/05/image001.png&quot; alt=&quot;&quot; title=&quot;image001&quot;&gt;&lt;/a&gt;
&lt;strong&gt;화면 1 스레드 속성들&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;화면에서 제일 먼저 보이는 것은 TID라는 것이다. 이는 Thread Identifier의 약자로 스레드 아이디를 의미한다. 윈도우에서 동작하는 모든 스레드는 이 아이디를 통해서 다른 스레드와 구분된다. 다음으로는 Start Address가 보인다. 이는 스레드의 시작 주소가 된다. 스레드는 이 주소에서 시작해서 이 함수가 ExitThread를 호출할 때까지 수행을 이어나간다. 다음으로는 Priority가 있다. 이는 우선순위를 나타내는 것으로 해당 스레드가 얼마나 높은 빈도로 스케줄링 될 것인지를 나타낸다. 아래에 있는 Started라고 표시된 항목은 스레드의 시작 시간을 나타낸다. State는 현재 스레드의 상태를 나타낸다. Kernel Time은 스레드가 수행한 커널 코드의 시간을 나타내며, User Time이란 스레드가 수행한 유저 코드의 시간을 나타낸다. Context Switches는 컨텍스트 전환 횟수를 Cycles는 이 스레드가 사용한 CPU 클럭을 나타낸다.&lt;/p&gt;
&lt;p&gt;그러면 이제부터 스레드를 어떻게 생성하고 종료시키는지부터 개별 스레드의 이러한 속성들을 어떻게 프로그램 내에서 조작할 수 있는지에 대해서 알아보도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;스레드의 탄생&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;CreateThread와 CreateRemoteThread는 윈도우에서 스레드의 탄생을 책임지고 있는 함수다. 이 두 함수는 동일하게 스레드를 생성하는 역할을 한다. 단지 차이가 있다면 CreateThread는 호출한 프로세스에서 동작하는 스레드를 생성하는 역할을 하며, CreateRemoteThread는 파라미터로 넘어온 프로세스에서 수행되는 스레드를 생성하는 역할을 한다. 실제로 윈도우 내부에서 CreateThread는 GetCurrentThread를 사용해서 CreateRemoteThread를 호출하는 것으로 구현되기 때문에 CreateThread는 CreateRemoteThread의 서브셋이라고 보면 되겠다.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;리스트 1&gt;에는 이 두 함수의 원형이 나와 있다. CreateThread의 함수 원형을 살펴보면 6개의 파라미터를 받는 복잡한 함수라는 것을 알 수 있다. 하지만 주로 사용하는 파라미터는 몇 개 되지 않기 때문에 차근차근 사용 방법을 살펴보면 크게 어렵지는 않다. 첫 번째 파라미터는 스레드의 보안 속성이다. 보통은 NULL을 전달하면 된다. 두 번째 파라미터로는 스레드 스택 크기를 지정한다. 0을 넘겨주면 기본 스택 크기로 스레드가 생성된다. 세 번째 파라미터인 lpStartAddress로는 실제 스레드가 수행될 함수 포인터를, 네 번째 파라미터인 lpParameter로는 lpStartAddress로 전달될 파라미터를 넘겨주면 된다. dwCreationFlags는 생성 플래그를 지정한다. 0을 지정하면 기본 상태로 생성한다. 스레드를 정지된 상태로 생성하고 싶으면 이 플래그에 CREATE_SUSPENDED를 지정하면 된다. 끝으로 lpThreadId에는 스레드 아이디를 전달 받을 포인터를 넘겨주면 된다. 스레드 아이디가 필요 없다면 NULL을 지정하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 1 CreateThread, CreateRemoteThread 함수 원형&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DWORD&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__stdcall &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;LPTHREAD_START_ROUTINE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPVOID lpThreadParameter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

HANDLE WINAPI &lt;span class=&quot;token function&quot;&gt;CreateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    LPSECURITY_ATTRIBUTES lpThreadAttributes
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SIZE_T dwStackSize
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPTHREAD_START_ROUTINE lpStartAddress
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPVOID lpParameter
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DWORD dwCreationFlags
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPDWORD lpThreadId
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

HANDLE WINAPI &lt;span class=&quot;token function&quot;&gt;CreateRemoteThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    HANDLE hProcess
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPSECURITY_ATTRIBUTES lpThreadAttributes
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SIZE_T dwStackSize
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPTHREAD_START_ROUTINE lpStartAddress
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPVOID lpParameter
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DWORD dwCreationFlags
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPDWORD lpThreadId
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;윈도우에서 동일한 실행 파일을 가진 프로세스를 여러 개 동시에 실행할 수 있는 것처럼 스레드 또한 동일한 lpStartAddress를 가지는 것을 동시에 여러 개 만들 수 있다. 이렇게 만들어진 스레드 인스턴스를 구분하기 위해서는 스레드 아이디라는 것이 사용된다. 스레드 내에서 현재 자신의 스레드 아이디를 구하기 위해서는 GetCurrentThreadId라는 함수를 사용하면 된다. 파라미터는 없으며, 리턴 값은 현재 실행되고 있는 스레드의 아이디를 반환해 준다. 마찬가지로 GetCurrentThread를 사용하면 현재 실행되는 스레드의 의사 핸들을 반환 받을 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;리스트 2&gt;에는 이러한 스레드 함수를 사용해서 실제로 스레드를 생성하는 예제가 나와 있다. 프로그램은 PrintThread 함수를 시작 주소로 하는 스레드를 세 개 생성해서 해당 스레드가 종료될 때까지 기다리는 역할을 한다. 세 개의 스레드가 모두 종료되면 프로그램도 같이 종료된다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 2 PrintThread 프로그램&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;windows.h&gt;&lt;/span&gt;&lt;/span&gt;

DWORD
CALLBACK
&lt;span class=&quot;token function&quot;&gt;PrintThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID param&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ULONG_PTR id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG_PTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; param&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;[TID = %8d] [PARAM = %d] Running...\n&quot;&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetCurrentThreadId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token function&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    HANDLE threads&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ARRAYSIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;threads&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        threads&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PrintThread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;WaitForMultipleObjects&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ARRAYSIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;threads&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; threads&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; INFINITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Complete\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&amp;#x3C;화면 2&gt;에는 PrintThread 프로그램의 실행 화면이 나와 있다. &amp;#x3C;화면 2&gt;를 살펴보면 스레드가 생성 순서를 기준으로 0, 2, 1, 1, 2, 0, 0, 2, 1 순서대로 실행된 것을 볼 수 있다. 직접 입력해서 프로그램을 실행해보면 아마 화면의 순서와는 또 다른 실행 흐름을 볼 수 있을 것이다. 이렇게 스레드 프로그래밍은 운영체제 스케줄링 순서에 따라서 매번 실행 흐름이 바뀐다는 특징이 있다. 이런 비결정적인 특성 때문에 멀티 스레드 관련 버그들은 항상 재연이 쉽지 않고 재연이 된다 하더라도 그것을 관찰하려고 하면 버그가 사라지는 하이젠버그 같은 것들이 자주 만들어진다. 이런 특수한 성질이 있기 때문에 멀티스레드 프로그래밍에 있어서는 항상 머릿속으로 모든 실행 흐름을 염두에 두고 꼼꼼하게 따져보는 습관을 가지는 것이 좋다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/05/image002.png&quot;&gt;&lt;img src=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/05/image002.png&quot; alt=&quot;&quot; title=&quot;image002&quot;&gt;&lt;/a&gt;
&lt;strong&gt;화면 2 PrintThread 실행 화면&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;스레드 종료&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;스레드 생성 부분을 살펴보았으니 이번에는 스레드를 종료 시키는 방법에 대해서 살펴보도록 하자. 스레드 종료에는 ExitThread, TerminateThread, FreeLibraryAndExitThread등의 함수가 사용된다. &amp;#x3C;리스트 3&gt;에는 각 함수의 원형이 나와 있다. ExitThread는 가장 기본적인 함수로 해당 함수를 호출한 스레드를 종료하는 역할을 한다. 파라미터로는 스레드 종료 코드가 넘어간다. TerminateThread는 특정 스레드를 강제로 종료 시키는 역할을 한다. TerminateThread의 파라미터로는 종료시킬 스레드 핸들과 종료 코드가 넘어간다. 끝으로 FreeLibraryAndExitThread 함수는 스레드를 종료함과 동시에 특정 모듈을 FreeLibrary 시키는 역할을 한다. DLL 내에서 생성된 스레드에서 해당 스레드 종료와 동시에 모듈을 언로드 시키고 싶을 때 사용하기에 적합한 함수다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 3 스레드 종료 관련 함수 원형&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;VOID WINAPI &lt;span class=&quot;token function&quot;&gt;ExitThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DWORD dwExitCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
BOOL WINAPI &lt;span class=&quot;token function&quot;&gt;TerminateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE hThread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DWORD dwExitCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
VOID WINAPI &lt;span class=&quot;token function&quot;&gt;FreeLibraryAndExitThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HMODULE hModule&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DWORD dwExitCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
BOOL WINAPI &lt;span class=&quot;token function&quot;&gt;GetExitCodeThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE hThread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPDWORD lpExitCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;윈도우 환경에서 프로그래밍을 해본 독자라면 사실 이렇게 복잡한 함수를 직접 호출하지 않고도 그냥 스레드 함수가 리턴 함으로써 스레드가 종료된다는 사실을 알고 있을 것이다. 앞서 작성해본 &amp;#x3C;리스트 2&gt;의 프로그램도 그렇게 스레드를 종료했다. 또한 대부분의 책에서 그렇게 종료하는 것이 가장 좋은 방법이라고 강조하고 있다. 그렇다면 어떻게 스레드 함수가 리턴하는 것만으로도 스레드가 종료될 수 있을까? 그 마법의 비밀은 다름아닌 윈도우의 CreateThread 구현에 있다. CreateThread 함수는 사실 lpStartAddress를 시작으로 하는 스레드를 생성하지 않는다. 대신 &amp;#x3C;리스트 4&gt;에 나타난 것과 같이 BaseThreadStart라고 명명된 래퍼 함수를 시작 주소로 하는 스레드를 생성한다. 해당 래퍼 함수는 &amp;#x3C;리스트 4&gt;에 나와있는 것과 같이 개발자가 실제로 생성하려고 넘겨 주었던 lpStartAddress를 호출하고 해당 함수가 리턴하면 자동으로 ExitThread를 호출하도록 되어 있다. 이런 이유로 우리가 만든 스레드 시작 함수가 리턴 하는 것만으로도 자연스럽게 스레드가 종료될 수 있는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 4 BaseThreadStart 함수 의사 코드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;VOID
&lt;span class=&quot;token function&quot;&gt;BaseThreadStart&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    LPTHREAD_START_ROUTINE lpStartAddress&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    LPVOID lpParameter
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;ExitThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lpStartAddress&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lpParameter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;한 가지 더 살펴볼만한 내용은 TerminateThread 함수에 관한 오해다. 많은 책에서 TerminateThread를 사용하면 리소스 반환이 정상적으로 되지 않고 마치 큰 일이 생기는 것처럼 언급하고 있지만 이는 사실 잘못된 내용이다. TerminateThread를 호출한다고 해서 리소스 반환이 되지 않고 ExitThread를 호출한다고 해서 리소스 반환이 되는 것은 아니기 때문이다.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;리스트 5&gt;와 같은 스레드를 살펴보자. 이 스레드는 스레드 함수 내에서 메모리를 할당한 다음 리턴한다. 이 스레드 함수가 정상적으로 종료된다면 결국 궁극에는 ExitThread에 의해서 종료된다. 그렇다면 ExitThread 함수는 할당된 buffer를 자동으로 소거해 줄까? 당연히 하지 않는다. 이 스레드의 경우에는 ExitThread로 종료하던, TerminateThread로 종료하던 스레드가 종료되면 메모리 릭이 발생한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 5 메모리 할당 작업을 하는 스레드&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;DWORD
CALLBACK
&lt;span class=&quot;token function&quot;&gt;Thread1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;buffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;윈도우는 프로그램에서 사용하는 리소스와 관련해서 스레드 별로 할당 내용을 추적하지 않는다. 따라서 ExitThread나 TerminateThread 모두 리소스를 소거해 주는 역할을 가지고 있지는 않다. TerminateThread와 ExitThread 사이의 차이는 단지 누가 언제 스레드를 종료 시키느냐의 차이 밖에는 없다. &amp;#x3C;리스트 6&gt;를 살펴보면 그러한 차이를 알 수 있다. &amp;#x3C;리스트 6&gt;의 스레드 루틴은 buffer를 할당한 다음 작업을 하고 buffer를 삭제한 다음 종료한다. 이 경우에 있어서 ExitThread에 의해서 종료된다는 것은 항상 자신이 생성한 buffer 리소스에 대해서 해제 작업이 완료된 다음에 종료된다는 것을 알 수 있다. 하지만 외부에서 TerminateThread로 종료 시키는 경우에는 스레드 실행 시점에 따라서 buffer가 해제된 다음일 수도 있고, buffer가 사용 중인 도중일 수도 있다. 따라서 이 경우에는 실행 시점에 따라서 리소스 릭이 발생할 수도 있고, 아닐 수도 있게 되는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 6 리소스 해제가 추가된 스레드 루틴&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;DWORD
CALLBACK
&lt;span class=&quot;token function&quot;&gt;Thread2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;buffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token comment&quot;&gt;// buffer 관련 작업&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;    
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;결국은 ExitThread나 TermianteThread나 운영체제 내부적으로 리소스 해제와 관련된 작업을 해주는 것은 없다. 스레드 내에서 생성된 리소스에 대한 책임은 해당 리소스를 생성한 스레드 루틴에 있다. TerminateThread라고 무턱대고 사용하지 말아야 하는 함수라고 생각하기보다는 이러한 내부적인 차이점을 정확하게 이해하고 상황에 맞는 함수를 선택해서 사용하는 습관을 가지는 것이 좋겠다.&lt;/p&gt;
&lt;p&gt;끝으로 스레드의 종료 상태를 알아내는 방법에 대해서 살펴보자. 스레드의 종료 상태를 알아내기 위해서는 GetExitCodeThread 함수가 사용된다(&amp;#x3C;리스트 3&gt; 참고). hThread로 종료 상태를 알고 싶은 스레드를 전달하면 lpExitCode로 종료 상태가 넘어온다. 종료되지 않고 스레드가 실행중인 상태라면 lpExitCode로 STILL_ACTIVE가 전달되며, 종료된 상태라면 스레드 종료 코드가 넘어온다.&lt;/p&gt;
&lt;p&gt;실전에서는 GetExitCodeThread 함수보다는 WaitForSingleObject가 훨씬 더 많이 사용된다. 스레드 객체는 윈도우 운영체제에 의해서 종료 시에 시그널 상태로 설정된다. 따라서 WaitForSingleObject로 스레드 핸들을 전달해서 WAIT_OBJECT_0이 반환된다면 해당 스레드는 종료된 것이며, 다른 값이 반환된다면 여전히 실행 중인 상태로 판단할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;스레드 일시 정지와 재개&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;스레드는 언제든지 SuspendThread 함수를 통해서 일시 정지 시킬 수 있고, 또 ResumeThread를 통해서 실행을 재개할 수 있다. 각 함수의 원형은 &amp;#x3C;리스트 7&gt;에 나와 있다. 파라미터로 전달되는 hThread는 실행을 중지 하거나 재개시킬 스레드 핸들이며, 반환 값은 이전에 실행이 중지된 횟수를 반환한다. 중지된 횟수를 반환한다는 의미는 SuspendThread를 두 번 호출했다면 ResumeThread를 두 번 호출해야 스레드가 실제로 다시 수행된다는 것을 의미한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 7 SuspendThread/ResumeThread 함수 원형&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;DWORD WINAPI &lt;span class=&quot;token function&quot;&gt;SuspendThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE hThread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
DWORD WINAPI &lt;span class=&quot;token function&quot;&gt;ResumeThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE hThread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&amp;#x3C;리스트 8&gt;에는 SuspendThread와 ResumeThread를 사용해서 스레드를 정지 시키고 다시 재개시키는 프로그램이 나와 있다. 프로그램의 코드를 바꿔가면서 SuspendThread와 ResumeThread의 반환 값이 어떤 식으로 동작하는지 살펴보도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 8 SuspendResumeThread 프로그램&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    HANDLE thread&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ULONG count&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    thread &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ThreadFunc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SuspendThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;suspend count = %d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; count&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SuspendThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;suspend count = %d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; count&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ResumeThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;suspend count = %d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; count&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    count &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ResumeThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;suspend count = %d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; count&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;WaitForSingleObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; INFINITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;스레드 컨텍스트&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;하나의 CPU 상에서도 스레드를 동시에 실행시키기 위해서는 스레드를 중지시킨 이후에 다시 실행을 재개 시키기 위해서는 어디서부터 실행을 재개할지 저장해 두어야 한다. 이렇게 다시 실행 시킬 위치를 저장해 두는 것을 컨텍스트라고 표현한다. x86/x64 환경에서는 이러한 컨텍스트로 CPU 레지스터를 저장해둔다. 해당 레지스터만 있으면 언제든지 다시 실행을 재개할 수 있기 때문이다.&lt;/p&gt;
&lt;p&gt;윈도우에서는 특정 스레드의 컨텍스트를 구하기 위해서 GetThreadContext를 반대로 특정 스레드의 컨텍스트를 설정하기 위해서는 SetThreadContext라는 함수를 사용한다. &amp;#x3C;리스트 9&gt;에는 해당 함수의 원형이 나와 있다. GetThreadContext 함수는 hThread로 지정된 스레드의 컨텍스트를 lpContext에 저장하는 역할을 한다. 이 함수를 사용할 때 한 가지 주의해야 할 점은 lpContext의 ContextFlags는 함수 호출 전에 미리 설정해 두어야 한다는 점이다. GetThreadContext가 lpContext의 ContextFlags에서 지정한 것과 관계된 레지스터 값만 반환하기 때문이다. SetThreadContext 함수는 hThread로 지정된 스레드의 컨텍스트를 lpContext로 대체시키는 역할을 한다. 이 두 함수 모두 현재 스레드나 실행 중인 스레드에 대해서 함수 호출을 할 경우에는 정상적인 컨텍스트를 구할 수 없다. 따라서 이 함수를 호출하기 위해서는 항상 대상 스레드를 일단 SuspendThread로 중지 시킨 다음에 작업해야 한다는 점을 명심하자.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 9 스레드 컨텍스트 관련 함수들&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;BOOL WINAPI &lt;span class=&quot;token function&quot;&gt;GetThreadContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE hThread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCONTEXT lpContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
BOOL WINAPI &lt;span class=&quot;token function&quot;&gt;SetThreadContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HANDLE hThread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; CONTEXT &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;lpContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&amp;#x3C;리스트 10&gt;에는 GetThraedContext/SetThreadContext 함수를 사용해서 실행중인 스레드의 컨텍스트를 런타임에 변경하는 작업을 보여준다. SetThreadContext로 지정하기 전에 Eip를 Bypass로 바꾸었기 때문에 ResumeThread가 수행되면 스레드는 Bypass 함수부터 스레드 수행을 재개한다. &amp;#x3C;화면 3&gt;에는 DebugView를 통해서 프로그램 실행 중에 디버그 출력을 캡쳐한 화면이 나와 있다. 화면에 나타난 것을 살펴보면 정상적이라면 실행되지 않았을 Bypass 함수가 실행된 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 10 Bypass 프로그램&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;windows.h&gt;&lt;/span&gt;&lt;/span&gt;

ULONG
&lt;span class=&quot;token function&quot;&gt;Bypass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;OutputDebugStringA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Bypass\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;ExitThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

ULONG
CALLBACK
&lt;span class=&quot;token function&quot;&gt;MyThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ULONG ntick &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetTickCount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;OutputDebugStringA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        
        &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetTickCount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; ntick&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        ntick &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetTickCount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    HANDLE thread&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    thread &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MyThread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;SuspendThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    CONTEXT ctx&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ContextFlags &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; CONTEXT_FULL&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;GetThreadContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Eip &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG_PTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; Bypass&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;SetThreadContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;ResumeThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;WaitForSingleObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; INFINITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/05/image003.png&quot;&gt;&lt;img src=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/05/image003.png&quot; alt=&quot;&quot; title=&quot;image003&quot;&gt;&lt;/a&gt;
&lt;strong&gt;화면 3 Bypass 프로그램 실행 화면&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;#x3C;리스트 10&gt;의 프로그램에서는 Bypass 함수에서 ExitThread를 호출해서 스레드를 강제로 종료시킨다. 이렇게 하지 않고 Bypass 함수를 수행한 다음 원래 스레드 컨텍스트로 돌아가서 MyThread의 남은 코드를 마저 실행 시키도록 만들 방법은 없는지 생각해보자.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;스레드 실행 시간&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;스레드 실행 시간을 구하는 데에는 GetThreadTimes 함수가 사용된다. 함수 원형은 아래 나와 있는 것과 같다. hThread로는 실행 시간을 구하고 싶은 스레드의 핸들을 전달해 주면, lpCreationTime에는 해당 스레드가 생성된 시간이, lpExitTime에는 해당 스레드가 종료된 시간이, lpKernelTime에는 해당 스레드가 사용한 커널 영역 코드의 시간이, lpUserTime은 해당 스레드가 사용한 유저 영역 코드의 시간이 넘어온다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;BOOL WINAPI &lt;span class=&quot;token function&quot;&gt;GetThreadTimes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    HANDLE hThread
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPFILETIME lpCreationTime
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPFILETIME lpExitTime
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPFILETIME lpKernelTime
    &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPFILETIME lpUserTime
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 함수를 사용하면 특정 스레드의 CPU 점유율을 계산할 수 있다. CPU 점유율이란 “사용한 CPU 시간 / 전체 CPU 시간”으로 계산할 수 있고, 사용한 CPU 시간은 앞서 살펴본 GetThreadTimes 함수의 lpKernelTime과 lpUserTime을 합한 값으로 계산할 수 있다. &amp;#x3C;리스트 11&gt;에는 이러한 기본적인 원칙을 바탕으로 작성한 현재 스레드의 CPU 점유율을 출력해주는 CpuUsagePrinter 클래스 코드가 나와 있다. CpuUsagePrinter의 순간 점유율은 Reset 이후부터 Dump를 수행할 때까지의 점유율을 최근 1분은 최근 1분간 스레드의 CPU 점유율을 보여준다.&lt;/p&gt;
&lt;p&gt;CpuUsagePrinter에서 출력되는 CPU 점유율은 싱글 코어를 기준으로 한 점유율을 말한다. 멀티코어라면 이 점유율이 코어 개수에 대한 비율만큼 줄어들어야 한다. 예를 들어 CpuUsagePrinter가 100%의 점유율을 출력했는데 듀얼코어라면 실제로 듀얼코어 상의 점유율은 50%가 된다는 의미다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 11 CpuUsagePrinter&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; LPCWSTR xcwstr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; UINT64 xuint64&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CpuUsagePrinter&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    FILETIME fkt_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fut_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fft_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    FILETIME skt_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sut_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sft_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    FILETIME ekt_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; eut_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; eft_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    T &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;printer_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    xcwstr tag_&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;CpuUsagePrinter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;xcwstr tag&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; T &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;printer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;printer_&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;printer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;tag_&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tag&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;GetSystemTimeAsFileTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;sft_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        FILETIME ct&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; et&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;GetThreadTimes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetCurrentThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;ct&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;et&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;skt_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;sut_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token function&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;fft_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;sft_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fft_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;fkt_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;skt_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fkt_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;fut_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;sut_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fut_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    xuint64 &lt;span class=&quot;token function&quot;&gt;ToUInt64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;FILETIME &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;t&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        ULARGE_INTEGER u&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        u&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;HighPart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dwHighDateTime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        u&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;LowPart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dwLowDateTime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; u&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;QuadPart&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    xuint64 &lt;span class=&quot;token function&quot;&gt;GetDiff64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;FILETIME &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FILETIME &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ToUInt64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ToUInt64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Reset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;GetSystemTimeAsFileTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;fft_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        FILETIME ct&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; et&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;GetThreadTimes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetCurrentThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;ct&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;et&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;fkt_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;fut_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Dump&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;xcwstr tag &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        xuint64 lusage&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        xuint64 iusage&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;


        FILETIME ct&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; et&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;GetThreadTimes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetCurrentThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;ct&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;et&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;ekt_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;eut_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token function&quot;&gt;GetSystemTimeAsFileTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;eft_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        xuint64 ltime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetDiff64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sft_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; eft_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ltime &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        xuint64 lcpu &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetDiff64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;skt_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ekt_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetDiff64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sut_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; eut_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lcpu &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; ltime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            lusage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; lcpu &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10000&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; ltime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
            lusage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        xuint64 itime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetDiff64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fft_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; eft_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;itime &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        xuint64 icpu &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetDiff64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fkt_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ekt_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetDiff64&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fut_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; eut_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;icpu &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; itime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            iusage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; icpu &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10000&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; itime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
            iusage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        printer_&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%ls 순간: %3llu.%02llu%%    최근 1분: %3llu.%02llu%%\n&quot;&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tag &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; tag &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; tag_
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; iusage &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; iusage &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; lusage &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; lusage &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ltime &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10000000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;skt_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;ekt_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;skt_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;sut_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;eut_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sut_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;sft_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;eft_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sft_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CpuUsagePrinter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;Dump&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tag_&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&amp;#x3C;리스트 12&gt;에는 CpuUsagePrinter를 사용해서 간단한 스레드의 CPU 점유율을 측정하는 예제가 나와 있다. CalcThread를 실행하면 &amp;#x3C;화면 4&gt;에 나와 있는 것과 같이 스레드 동작 과정에서 CPU 점유율이 지속적으로 표시된다. CalcThread 코드를 바꿔가면서 CPU 점유율이 어떻게 변화하는지 살펴보도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;리스트 12 CalcThread 프로그램&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;windows.h&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;printer&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lpcstr fmt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        va_list ap&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token function&quot;&gt;va_start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ap&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; fmt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;vprintf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fmt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ap&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;va_end&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ap&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

DWORD
CALLBACK
&lt;span class=&quot;token function&quot;&gt;CalcThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID param&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    CpuUsagePrinter&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Printer&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cpu&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;L&lt;span class=&quot;token string&quot;&gt;&quot;CalcThread&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Printer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    ULONG_PTR id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG_PTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; param&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        cpu&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Reset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; k &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            k &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; k &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; k&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

        cpu&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Dump&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    HANDLE thread&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    thread &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; CalcThread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;WaitForSingleObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; INFINITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/05/image004.png&quot;&gt;&lt;img src=&quot;http://www.jiniya.net/wp/wp-content/uploads/2012/05/image004.png&quot; alt=&quot;&quot; title=&quot;image004&quot;&gt;&lt;/a&gt;
&lt;strong&gt;화면 4 CalcThread 실행 화면&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[내가 생각하는 장인, 그리고 장인이 되는 길…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/6917</link><guid isPermaLink="false">https://jiniya.net/wp/archives/6917</guid><pubDate>Wed, 02 May 2012 23:58:07 GMT</pubDate><content:encoded>&lt;p&gt;아는 녀석 중에 고기 굽기 달인이 한 명 있다. 우리끼리 만나면 항상 고기 굽는 일은 녀석이 전담하는데, 굽는 솜씨가 정말 일품이다. 토욜에도 만나서 고기를 먹었다. 셋이서 먹는데 당연히 고기 굽는 일은 녀석이 했다. 대충 다 굽고는 이제 먹어라, 하는데 나랑 옆에 있던 형이랑 둘이서 그냥 감동의 눈물을 흘렸다. 평소에도 고기를 잘 굽는다는 것은 알고 있었지만 그 날 따라 유달리 더 잘 구운 것 같아 보였기 때문이었다. 그래서 옆에 형이랑 둘이서 호들갑을 떨면서 인증샷을 찍었다. 맛은? 당연히 일품이었다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./내가_생각하는_장인,_그리고_장인이_되는_길.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/d1d558b6db9be60027a4a50936ea708c/e224a/%EB%82%B4%EA%B0%80_%EC%83%9D%EA%B0%81%ED%95%98%EB%8A%94_%EC%9E%A5%EC%9D%B8%2C_%EA%B7%B8%EB%A6%AC%EA%B3%A0_%EC%9E%A5%EC%9D%B8%EC%9D%B4_%EB%90%98%EB%8A%94_%EA%B8%B8.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 74.73684210526315%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAEDBf/EABUBAQEAAAAAAAAAAAAAAAAAAAID/9oADAMBAAIQAxAAAAHPq4RqyQj/AP/EABoQAAIDAQEAAAAAAAAAAAAAAAECAAMTISL/2gAIAQEAAQUCCM0ZeDIT1S9+hfRhP//EABcRAQEBAQAAAAAAAAAAAAAAAAEAEUH/2gAIAQMBAT8BXlpf/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAERIf/aAAgBAgEBPwFWmn//xAAdEAACAgEFAAAAAAAAAAAAAAAAAREhUSMxQXGB/9oACAEBAAY/Aq4M5LTY46NTcil4f//EABsQAQADAQADAAAAAAAAAAAAAAEAESFBMZHw/9oACAEBAAE/IWNYK2IksPABKHpmN2b6LlNgp4IAAgfOT//aAAwDAQACAAMAAAAQND//xAAXEQEAAwAAAAAAAAAAAAAAAAAAESFB/9oACAEDAQE/EKCDH//EABgRAAMBAQAAAAAAAAAAAAAAAAARQQGh/9oACAECAQE/EGtBavT/xAAdEAEBAAMAAgMAAAAAAAAAAAABEQAhMUFhcYGh/9oACAEBAAE/EDEgAioG+YtQWqHySX7cMaju2D10/cBD3InfE5g3VGMSeLNYAOIEK+7j/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                         md 0&apos; title=&apos;&apos; src=&apos;/static/d1d558b6db9be60027a4a50936ea708c/e224a/%EB%82%B4%EA%B0%80_%EC%83%9D%EA%B0%81%ED%95%98%EB%8A%94_%EC%9E%A5%EC%9D%B8%2C_%EA%B7%B8%EB%A6%AC%EA%B3%A0_%EC%9E%A5%EC%9D%B8%EC%9D%B4_%EB%90%98%EB%8A%94_%EA%B8%B8.md_0.jpg&apos; srcset=&apos;/static/d1d558b6db9be60027a4a50936ea708c/8ccab/%EB%82%B4%EA%B0%80_%EC%83%9D%EA%B0%81%ED%95%98%EB%8A%94_%EC%9E%A5%EC%9D%B8%2C_%EA%B7%B8%EB%A6%AC%EA%B3%A0_%EC%9E%A5%EC%9D%B8%EC%9D%B4_%EB%90%98%EB%8A%94_%EA%B8%B8.md_0.jpg 190w,
/static/d1d558b6db9be60027a4a50936ea708c/ea4c8/%EB%82%B4%EA%B0%80_%EC%83%9D%EA%B0%81%ED%95%98%EB%8A%94_%EC%9E%A5%EC%9D%B8%2C_%EA%B7%B8%EB%A6%AC%EA%B3%A0_%EC%9E%A5%EC%9D%B8%EC%9D%B4_%EB%90%98%EB%8A%94_%EA%B8%B8.md_0.jpg 380w,
/static/d1d558b6db9be60027a4a50936ea708c/e224a/%EB%82%B4%EA%B0%80_%EC%83%9D%EA%B0%81%ED%95%98%EB%8A%94_%EC%9E%A5%EC%9D%B8%2C_%EA%B7%B8%EB%A6%AC%EA%B3%A0_%EC%9E%A5%EC%9D%B8%EC%9D%B4_%EB%90%98%EB%8A%94_%EA%B8%B8.md_0.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;고기굽기 만렙의 위용. 어떤 분야든 우리는 장인의 작품을 대하면 감탄하게 된다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;사진을 찍어놓고는 집에와서 면면히 들여다보니 과연 녀석은 고기 굽기에 있어서는 장인이란 생각이 들었다. ㅋㅋ~ 그 크기의 균일성하며 절단면의 일관성. 섬세하게 발라낸 오도독뼈. 적당한 강도로 굽힌 고기 덩어리들. 그리고 완벽한 배치. 더 심각한건 녀석은 어느 정도는 자신의 고기 굽기에 대해서 철학을 가지고 있다는 점이다. 녀석이 제일 싫어하는 행위는 다 굽지 않았는데 먼저 먹는 것이다. 자신이 판단했을 때 익지 않았는데 손대면 심하게 혼난다 ㅋ~&lt;/p&gt;
&lt;p&gt;사진을 보면서 감탄하다가 문득 장인에 관한 이야기를 좀 해보고 싶다는 생각이 들었다. 장인이란 어떤 사람일까? 또 장인이 되려면 어떻게 해야 할까? 난 프로그래밍도 하나의 예술 행위로 간주하기 때문에 장인정신이 무척 중요하다고 생각한다. 그래서 이런 질문들은 나에게는 다소 엄숙하기도 하고 근엄하기도 한 질문들이다. 이 질문들이 정답이 있는 것도 또 정답을 찾는 것이 쉬운 문제들도 아니지만 편하게 요즘 내가 생각하는 장인에 대한 이야기를 좀 해볼까 한다. 맞다. 모두 다 개똥 철학이다. ㅋ~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;XIGNCODE 로그 파일을 설계할 때였다. 로그 파일을 만드는 일이 뭐 대단한 일이냐고 생각할 수 있다. 사실 뭐 정말 아무것도 아닌 일이다. 숙련된 개발자라면 한두 시간 코딩하면 쓸만한 로그 파일 구조를 만들어 낼 수 있다. 더욱이 난 많은 업체에서 다양한 형태의 로그 파일을 수도없이 만들어 보았다. 그렇게 늘 반복적으로 했던 일임에도 XIGNCODE 로그 파일을 설계할 때는 정말 많은 생각을 했다. 그리고 그 생각들은 그 전까지는 내가 전혀 해보지 않은 것들이었다.&lt;/p&gt;
&lt;p&gt;가장 고민을 많이 한 생각은 이거였다. 과연 로그 파일의 크기는 얼마여야 하는가? 어느 정도 크기면 사용자들이 부담없이 로그 파일을 전송할 수 있을까? 압축이란 과정을 통하지 않고도 보내기에 적당한 크기는 얼마일까? 또 어느 정도 크기여야 우리가 그 로그 파일로부터 의미있는 정보들을 충분히 얻을 수 있을까? 사용자의 심리적 바운더리와 우리가 체험하게 될 유용성의 바운더리 사이에서 최대 값을 찾고 싶었던 것이다. 난 로그 파일을 설계하는 것보다 이 아무것도 아닌 문제에 대해서 더 오랜 시간 고민했다.&lt;/p&gt;
&lt;p&gt;그렇게 많이 고민했음에도 로그 파일에는 빈틈은 많다. 난 틈만나면 로그 파일을 새롭게 설계하고 싶은 욕망에 휩싸이곤 하지만 다른 바쁘고 중요한 일들에 치여 로그 파일은 늘 제자리다. 그런 실수들 중에서도 명백하게 내가 가장 제일 잘못했다고 생각하는 한 가지 실수가 있다. 명백히 잘못했지만 아마 영원히 바로 잡긴 힘들것 같은 실수다. 뭘까? 바로 확장자다. 난 로그 파일이라 별 생각없이(&amp;#x3C;= 장인이 되기엔 아직 한 십만년 더 멀었다는 사실에 대한 고백) log라는 확장자를 채택했다. 그런데 이게 왜 문제일까?&lt;/p&gt;
&lt;p&gt;윈도우 정책과 결합하면 놀라운 문제가 된다. 확장자가 숨겨지기 때문이다. 윈도우 탐색기 기본 옵션은 알려진 확장자 숨김이기 때문이다. 따라서 그 옵션을 끄기 전까지 사용자들은 xigncode.log 파일을 보내 주세요, 라고 말해도 그 파일이 없어요, 라고 대답하게 되는 것이다. 치명적이다. 근데 그 확장자가 더 치명적인 두 번째 사실은 윈도우 기본 옵션이 log 파일을 노트패드에다 연결해 놨다는 점이다. 당연히 우리 파일은 암호화된 바이너리 파일이다. 흙~ 노트패드로 열었다. 실수로라도 고쳐서 저장하는 경우에는 말짱 황이다. 유저들이 그런 로그를 보내는 경우도 종종있다.&lt;/p&gt;
&lt;p&gt;로그 파일 설계에 대한 이야기를 하고 싶었던 건 아니다. 내가 이야기하고 싶었던 것은 이전에 다른 제품을 만들 때에는 전혀 신경 쓰지도 않았던 것들에 대해서 많은 부분 신경을 쓰게 됐다는 점이다. 또 이전에 만든 제품들이라면 전혀 문제라고 생각지도 않았을 것들에 대해서도 문제라고 인식한다는 점이다. 누구도 말하지 않았고, 누구도 신경쓰지 않는데도 말이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 333px; margin-bottom: 16px;&apos; data-url=&apos;./내가_생각하는_장인,_그리고_장인이_되는_길.md_1.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/3130569c8142bdca4adc705c532f2e41/7bf32/%EB%82%B4%EA%B0%80_%EC%83%9D%EA%B0%81%ED%95%98%EB%8A%94_%EC%9E%A5%EC%9D%B8%2C_%EA%B7%B8%EB%A6%AC%EA%B3%A0_%EC%9E%A5%EC%9D%B8%EC%9D%B4_%EB%90%98%EB%8A%94_%EA%B8%B8.md_1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 150%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAeABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAMEBQb/xAAXAQADAQAAAAAAAAAAAAAAAAAAAgMB/9oADAMBAAIQAxAAAAGyeZ9JPM81UaNrlpzJ0Yx//8QAHRAAAgICAwEAAAAAAAAAAAAAAQIDEgAhBBETFP/aAAgBAQABBQJ3WaOOsbHlAFH23VbWyFbt89hlAhA15Jn/xAAXEQEBAQEAAAAAAAAAAAAAAAAAARES/9oACAEDAQE/AW1kcv/EABgRAQADAQAAAAAAAAAAAAAAAAABAhES/9oACAECAQE/AWJs7f/EAB8QAAIBBAIDAAAAAAAAAAAAAAABEQIQEiExMkFhcf/aAAgBAQAGPwJpSZJ+DoYzr0bqX2CbOXbVNJwjqf/EAB4QAQACAgEFAAAAAAAAAAAAAAEAESExQVFxgZHh/9oACAEBAAE/IRLptUg4qioJ9yiwUcK3L2EK21lVzvxB7UALgxncTPyCITriAhlddif/2gAMAwEAAgADAAAAEKTZgP/EABsRAQACAgMAAAAAAAAAAAAAAAEAERAxIYHw/9oACAEDAQE/EN8u4i1Z7qDNuH//xAAZEQADAAMAAAAAAAAAAAAAAAAAAREhQVH/2gAIAQIBAT8QkxoStWMbIieH/8QAHxABAAMAAgIDAQAAAAAAAAAAAQARITFRQWFxgaHB/9oACAEBAAE/EA/2HQ3xHSOhQu/H5EiD3n+S2qi3AuvGRUUBqGmzh9MskdHFM42CC2jbSfUdoWmx1WZ8z3BMfaWrp4Vs8x3bl4QUhqq1Zs//2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                         md 1&apos; title=&apos;&apos; src=&apos;/static/3130569c8142bdca4adc705c532f2e41/7bf32/%EB%82%B4%EA%B0%80_%EC%83%9D%EA%B0%81%ED%95%98%EB%8A%94_%EC%9E%A5%EC%9D%B8%2C_%EA%B7%B8%EB%A6%AC%EA%B3%A0_%EC%9E%A5%EC%9D%B8%EC%9D%B4_%EB%90%98%EB%8A%94_%EA%B8%B8.md_1.jpg&apos; srcset=&apos;/static/3130569c8142bdca4adc705c532f2e41/8ccab/%EB%82%B4%EA%B0%80_%EC%83%9D%EA%B0%81%ED%95%98%EB%8A%94_%EC%9E%A5%EC%9D%B8%2C_%EA%B7%B8%EB%A6%AC%EA%B3%A0_%EC%9E%A5%EC%9D%B8%EC%9D%B4_%EB%90%98%EB%8A%94_%EA%B8%B8.md_1.jpg 190w,
/static/3130569c8142bdca4adc705c532f2e41/7bf32/%EB%82%B4%EA%B0%80_%EC%83%9D%EA%B0%81%ED%95%98%EB%8A%94_%EC%9E%A5%EC%9D%B8%2C_%EA%B7%B8%EB%A6%AC%EA%B3%A0_%EC%9E%A5%EC%9D%B8%EC%9D%B4_%EB%90%98%EB%8A%94_%EA%B8%B8.md_1.jpg 333w&apos; sizes=&apos;(max-width: 333px) 100vw, 333px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;XIGNCODE의 기반 구조를 변경시킨 드라마, 브레인&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;언젠가 브레인이란 드라마에 심취해서 본방 사수하면서 보던 때가 있었다. 히로인으로 나온 최정원씨도 이뻤지만 신하균씨의 연기가 정말 일품인 드라마였다. 발연기 하는 장면을 연기하는 모습이 얼마가 간지던지 ㅋㅋ~ 여튼 그 드라마를 다 보고는 그런 생각이 들었다. 어쩌면 내가 만드려고 하는 시스템이 뇌랑 비슷한 건 아니었을까, 라는 생각. 소프트웨어로 구성된 독립적인 시스템은 모두 그렇지만 게임보안도 하나의 완성된 계를 이룬다. 각각의 기능들이 있고, 그 기능들은 서로 협력해서 하나의 큰 기능을 만들어 낸다. 그래서 그런 생각을 했다. 아, 뇌를 만들어야겠다. 마치 뇌의 뉴런들이 신경 전달 물질을 통해서 정보를 주고 받는 그것처럼 말이다.&lt;/p&gt;
&lt;p&gt;브레인이 끝나던 밤에 난 우리 코드에 IBrain이란 객체를 추가했다. 또 INeuron을 추가했다. 그리곤 일부 핵심 기능들을 그 INeuron으로 대체했고 IBrain에 추가했다. 그랬더니 놀라운 일이 벌어졌다. 그 300줄로 안되는 코드로 이전에는 아주 복잡하고 지저분하게 구현했던 것들이 깔끔해지는 놀라운 현상을 목격한 것이다. 뉴런 간 크로스 체크를 더욱 은밀하게 할 수 있었고, 동일한 기능을 하는 뉴런이 여러 개 있다면 가장 우수한 뉴런을 선택해서 기능을 수행할 수도 있게 되었다.&lt;/p&gt;
&lt;p&gt;300줄도 안되는 객체를 만든 것을 두고 호들갑을 떨려던 것은 아니다. 내게 이 사건이 놀라웠던 이유는 드라마를 보면서 내가 그런 생각을 했다는 점이다. 단지 그게 신기했다. 어쩌면 난 드라마를 보는 동안에도 우리 제품을 어떻게하면 더 좋게 만들지를 고민하고 있었는지도 모른다. 무의식이 의식을 지배하는 그것처럼 말이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;미켈란젤로에 관한 일화 중에 이런 이야기가 있다. 그가 천장 벽화 작업을 하고 있을 때 였다. 아래에서는 보이지도 않는 구석까지 그가 신경써서 다듬는 것을 보고는 조수가 그에게 잘 보이지도 않는 부분까지 왜 그렇게 신경을 쓰냐고 물었다. 미켈란젤로가 말한다. 내가 보잖아.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./내가_생각하는_장인,_그리고_장인이_되는_길.md_2.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/e08f48a6c558297ae440fb90fcebc56e/e224a/%EB%82%B4%EA%B0%80_%EC%83%9D%EA%B0%81%ED%95%98%EB%8A%94_%EC%9E%A5%EC%9D%B8%2C_%EA%B7%B8%EB%A6%AC%EA%B3%A0_%EC%9E%A5%EC%9D%B8%EC%9D%B4_%EB%90%98%EB%8A%94_%EA%B8%B8.md_2.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAEDBf/EABYBAQEBAAAAAAAAAAAAAAAAAAEAAv/aAAwDAQACEAMQAAABy6ReVkRv/8QAGRAAAgMBAAAAAAAAAAAAAAAAAQIQESES/9oACAEBAAEFAkGutQGzuP/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEABj8CX//EABoQAAIDAQEAAAAAAAAAAAAAAAABESExQVH/2gAIAQEAAT8hpxpvfUJJaRoNH6TNn//aAAwDAQACAAMAAAAQuM//xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPxBX/8QAFhEBAQEAAAAAAAAAAAAAAAAAABEh/9oACAECAQE/ENR//8QAGhABAAMAAwAAAAAAAAAAAAAAAQARITFBUf/aAAgBAQABPxBGqawZeHMLr2GaJrBscWO7bEB6Zfmn/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                         md 2&apos; title=&apos;&apos; src=&apos;/static/e08f48a6c558297ae440fb90fcebc56e/e224a/%EB%82%B4%EA%B0%80_%EC%83%9D%EA%B0%81%ED%95%98%EB%8A%94_%EC%9E%A5%EC%9D%B8%2C_%EA%B7%B8%EB%A6%AC%EA%B3%A0_%EC%9E%A5%EC%9D%B8%EC%9D%B4_%EB%90%98%EB%8A%94_%EA%B8%B8.md_2.jpg&apos; srcset=&apos;/static/e08f48a6c558297ae440fb90fcebc56e/8ccab/%EB%82%B4%EA%B0%80_%EC%83%9D%EA%B0%81%ED%95%98%EB%8A%94_%EC%9E%A5%EC%9D%B8%2C_%EA%B7%B8%EB%A6%AC%EA%B3%A0_%EC%9E%A5%EC%9D%B8%EC%9D%B4_%EB%90%98%EB%8A%94_%EA%B8%B8.md_2.jpg 190w,
/static/e08f48a6c558297ae440fb90fcebc56e/ea4c8/%EB%82%B4%EA%B0%80_%EC%83%9D%EA%B0%81%ED%95%98%EB%8A%94_%EC%9E%A5%EC%9D%B8%2C_%EA%B7%B8%EB%A6%AC%EA%B3%A0_%EC%9E%A5%EC%9D%B8%EC%9D%B4_%EB%90%98%EB%8A%94_%EA%B8%B8.md_2.jpg 380w,
/static/e08f48a6c558297ae440fb90fcebc56e/e224a/%EB%82%B4%EA%B0%80_%EC%83%9D%EA%B0%81%ED%95%98%EB%8A%94_%EC%9E%A5%EC%9D%B8%2C_%EA%B7%B8%EB%A6%AC%EA%B3%A0_%EC%9E%A5%EC%9D%B8%EC%9D%B4_%EB%90%98%EB%8A%94_%EA%B8%B8.md_2.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;strong&gt;미켈란젤로의 서명이 있는 유일한 작품이자 그의 처녀작, 피에타&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;지금까지 이야기하려던 장인의 모습이 바로 미켈란젤로다. 난 어떤 기능의 숙련됨의 정도가 장인을 나타내는 지표는 아니라고 생각한다. 진정한 장인이냐 아니냐는 어떤 행위를 얼마냐 잘하느냐가 아닌 그 행위를 하는 그의 태도에 달려 있다고 생각한다. 어떤 창조물이 사람들을 감동시키는 것 또한 그것이 얼마나 잘 만들어졌냐 아니냐를 떠나서 그걸 만드는 동안에 그걸 만든 사람의 태도가 어땠느냐에 따른다고 생각한다. 모든 창조물에는 반드시 창작자의 애티튜드가 반영될 수 밖에 없다고 믿기 때문이다. 사람들이 말하는 혼이 담긴 작품이란 말도 그런 맥락일 것이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;프로그래머를 시작하던 그 시절 난 장인은 아니었다. 그 때 난 지금보다 훨씬 더 유명한 제품을 만들기도 했었고, 훨씬 더 돈을 많이 버는 제품을 만들기도 했었고, 훨씬 더 기술력이 뛰어난 제품을 만들기도 했었다. 하지만 난 장인은 아니었다. 그저 한 명의 회사원이었고, 프리랜서였다. 그랬던 내가 지금은 장인이라고 떳떳하게 말하고 다닌다. 어떻게 그럴 수 있는 것일까? 단지 경력이 좀 됐기 때문일까? 절대 아니다. 그렇게 말할 수 있는 이유는 바로 지금 만드는 제품이 제품이 아닌 작품이 돼 버렸기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/tt/164&quot;&gt;세상이 좀 더 편평하고 공정해져야 한다&lt;/a&gt;고 생각한다. 하지만 오프라인 세계에서 그런 세상을 만들기 위해서 내가 할 수 있는 일은 솔직히 거의 없다. 거대한 권력을 가진 것고, 큰 힘을 가진 것도, 많은 부를 축적한 것도 아니기 때문이다. 하지만 온라인 게임 세상에서는 다르다. 난 온라인 게임 세계에서 공정성을 해치는 많은 장애물들을 제거할 수 있고, 또 온라인 게임 세계를 경험하는 많은 이들에게 오프라인 세상보다는 공정한 세상을 보여줄 수 있는 힘이 있다. 그래서 난 이 일이 재미있고, 또 더 잘하고 싶다. 좋은 게임보안 제품을 만들고 싶고, 당당하게 그 제품에 내 크레딧을 달고 싶다. 부끄럽지 않은 제품을 만들고 싶다. 그러니 당연히 남들이 신경쓰지 않는 부분도 내가 본다는 생각으로 만들 수 밖에는 없다. 이건 내 꿈이고, 내 작품이기 때문이다. 이게 바로 내가 스스로 장인이라 떳떳하게 말할 수 있는 이유다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#4&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;좋아하는 학교 선배가 한 명 있다. 마계촌 온라인을 개발하면서 이제는 너무 &lt;a href=&quot;http://www.bloter.net/archives/99093&quot;&gt;유명해져 버린&lt;/a&gt; 형이다. &lt;a href=&quot;http://www.jiniya.net/wp/archives/5451&quot;&gt;지난 마계촌 글&lt;/a&gt;에도 썼었지만 그 형은 내가 아는 사람들 중에 몇 안되는 진짜 장인이다. 왜냐하면 그 글에도 나타난 것처럼 형은 자신이 만드는 작품을 학교 수업시간에도 들고와서 진지하게 고민했기 때문이다. 장인이 아니라면 절대 그렇게 할 수 없다. 선우 형이 몇 해 전 쓴 글 중에 &lt;a href=&quot;http://megarex.tistory.com/19&quot;&gt;내가 참 좋아하는 글이 있다.&lt;/a&gt; 아래 글은 그 글에서 발췌한 것인데 다시 읽어도 정말 멋있는 문장이다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;다시 돌아와서 간단히 말하자면&lt;br&gt;
&lt;br&gt;
회사에서의 자기 업무가 곧 자신의 작품이자 자신의 꿈이라면&lt;br&gt;
&lt;br&gt;
업무시간이라는 것은 아무 의미가 없습니다.&lt;br&gt;
&lt;br&gt;
저의 인생 모든 시간이 곧 제 작품을 만들기 위한 시간이니까요.
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;저의 팀원 모두가 같은 생각이었으면 좋겠습니다.&lt;br&gt;
&lt;br&gt;
게임 개발자도 creator 입니다.
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;– 마계촌 온라인 개발자 황선우&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;우리는 태어날 때 모두 장인이었는지도 모른다. 단지 사는 동안 하루 살이에 치여 모두가 장인이었다는 사실을 잊어버린 것이다. 그러니 우리가 장인이 되는 법은 복잡하거나 어렵지 않다. 단지 그 잊어버렸던 꿈을 다시 찾기만 하면 된다. 자신의 꿈을 향해 가는 동안 우리 모두는 저절로 장인이 될 수 밖에는 없기 때문이다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 게임 보안: 허들 넘기…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/6414</link><guid isPermaLink="false">https://jiniya.net/wp/archives/6414</guid><pubDate>Fri, 27 Apr 2012 23:58:06 GMT</pubDate><content:encoded>&lt;p&gt;사용자들은 언제 게임보안 제품을 느낄까? 해킹툴을 잘 잡아서 게임 내 해킹이 줄었을 때? 아니다. 사실 일반 게이머들은 게임보안 제품이 해킹툴을 잡는다는 사실을 모르는 경우가 대부분이다. 그들이 게임보안 제품을 느끼는 대표적인 순간은 바로 잘되던 게임이 안되기 시작하는 순간이다. 게임보안 제품이 게임 구동을 방해하는 허들이 되는 그 지점인 것이다. 이 순간이 되면 모든 게이머들이 안티치트 솔루션 이름에 대해서 알게된다. 더불어 그 게임이 진짜 인기있는 게임이라면 네이버 실시간 검색어 1위에서 10위까지 휩쓰는 기염을 토하기도 한다. 이 모든 일들과 함께 안티치트 솔루션에 대한 욕과 비방이 범람한다. 한마디로 아찔한 순간이다.&lt;/p&gt;
&lt;p&gt;XIGNCODE라는 제품을 처음 만들 때 사실 별 생각이 없었다. ㅋㅋ~ 후에 제품의 틀을 잡으면서는 크게 두 가지 다짐을 했다. 하나는 아이러니하게도 진짜 해킹툴을 잡는 제대로 된 솔루션을 만들자는 생각이었고, 다른 하나는 절대로 게임의 허들이 되는 제품을 만들지는 말자는 생각이었다. 하지만 시간이 흘렀고, 우리 제품도 게임에 속속 탑재되기 시작했고, 해킹툴과 전쟁도 뻘짓나게 많이 하면서 자연스럽게 허들이 되는 순간도 생기게 됐다. 그렇게 장애물은 되지 말자고 했는데 애물단지가 되는 순간이 발생한 것이다. 그럴때면 나 또한 똑같은 한명의 게이머로서 한없이 죄송함을 느끼곤 한다. 그리곤 또 다짐한다. 정신차리고 똑바로 만들자고 말이다.&lt;/p&gt;
&lt;p&gt;그렇다면 왜 그렇게 모든 게임보안 제품은 하나같이 다 허들이 되는 것일까? 또 그 허들은 왜 생기는 것일까? 피할 순 없는 것일까? 또 반대로 게이머 입장에서는 조금이라도 허들을 피하기 위해서는 어떤 점들에 주의해야 할까? 역설적이게도 게임보안 제품이 허들이 되는 이유는 그들에게 봉착한 허들을 제대로 넘지 못했기 때문이다. 여기서는 게임보안 제품 개발을 하면서 겪게 되는 허들에 대해서 살펴보고 작게나마 앞선 질문들에 대한 해답을 찾아보는 시간을 가져보도록 하자.&lt;/p&gt;
&lt;h3&gt;#0 운영체제 허들&lt;/h3&gt;
&lt;p&gt;일단 게임보안 제품에게는 운영체제 하나가 거대한 산맥으로 다가온다. 왜 그럴까? 게임도 똑같이 다양한 운영체제 위에서 구동되는 프로그램이고 게임보안 프로그램도 그럴 뿐인데 왜 게임보안 제품에게는 운영체제 자체가 허들이 되는 것일까? 그 이유는 게임보안 제품의 특성상 운영체제에서 공개하지 않은 다양한 기능들을 사용하기 때문이다. 왜? 도대체 왜? 많은 이유가 있는데 주된 이유만 들어보자면 하나는 해킹툴이 그런 기능을 사용하기 때문에 탐지하기 위해서 부득이하게 사용하는 경우고, 다른 하나는 해킹툴로부터 자신을 보호하기 위한 목적으로 사용한다. 이렇게 공개되지 않은 부분들을 사용하는 것이 호환성을 떨어뜨리는 대표적인 요인이다. 여러분이 생각하는 그 모든 호환성 이슈는 다 이 하나의 사실에 기인한다고 할 수 있다. 그렇다면 이건 어떻게 해결해야 할까? 테스트만 열심히 한다고 해결될까? 물론 문제가 그렇게 쉽진 않다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_허들_넘기.md_0.png&apos; data-alt=&apos;우리가 생각하는 것 이상으로 게임이 실행되는 운영체제는 게임 종류와 국가에 따라 천차만별이다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/95d9694335b7b2a8f7b90ff151864aea/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 31.578947368421055%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABc0lEQVR42j2RO0/CUBiGuxgH/R+OLv4SNxMnf4OLt8TFwWjUSRkgDiZumjiog8b7BYzEGAEDonJtCy1NLZTWlvJ4KMRvOZfvzfN+7zkS3QC6XcLq7UXpqX2UQhq9YeL7fr9HZ7CG2sBpZLtK5gRVMzGMxr9O6vUDrulUlkG+Dy+Vr0Wy6QsKRSUU931aFI0TPPk81DT1Kz5eVvj81jDNBp1OMADKl/iZYbxHwY6MgPFGLBchkbmjUqjwkc9j264wneI0J2FtS5DaIvPzwuHbJnr1h6pcRlVVApFUIr4AMQFLzRPsCHF6g6WjMvfJFHqtSqlcw21+EZQl7Pok/sEEHI5xmS2xehynqdUolkq4rjuYsHoG0SGICOjuqMjyxN76N6+JHHVdwW45QiYmvB2H3eG+6dM0yQeL6FqSipxHq+u4jhu+oxRie9DnOVDvwqNdb+OImJ7n/X8UxjvczAjYLHgajhmg5Q1a7SZtu41lWWLKX/4AVtqppcO6PdsAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;우리가 생각하는 것 이상으로 게임이 실행되는 운영체제는 게임 종류와 국가에 따라 천차만별이다.&apos; title=&apos;&apos; src=&apos;/static/95d9694335b7b2a8f7b90ff151864aea/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_0.png&apos; srcset=&apos;/static/95d9694335b7b2a8f7b90ff151864aea/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_0.png 190w,
/static/95d9694335b7b2a8f7b90ff151864aea/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_0.png 380w,
/static/95d9694335b7b2a8f7b90ff151864aea/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_0.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;우리가 생각하는 것 이상으로 게임이 실행되는 운영체제는 게임 종류와 국가에 따라 천차만별이다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;XIGNCODE는 기본적으로 Windows 2000 SP4, Windows XP SP2, Windows XP SP3, Windows Vista SP1, Windows Vista SP2, Windows 7 RTM, Windows 7 SP1, Windows 8 CP에서 게임 구동 테스트를 거친다. 우와 장난 아니다. 그런데 여기서 놀라면 안된다. 저 모든 운영체제를 한중일영으로 테스트 한다. 보면 알겠지만 서팩별로도 많이 사용되는 것들은 분리해서 테스트 한다. 그 이유가 서팩별로도 많은 차이를 가지기 때문이다. 이런 복잡한 테스트를 몇 시간씩 하고, 일주일 내내하고, 또 하고, 또 하고, 제품 릴리즈를 함에도 문제는 발생한다. 왜 그럴까?&lt;/p&gt;
&lt;p&gt;그 이유는 바로 우리가 기대고 있는 언덕이 그만큼 부실하기 때문이다. 공개되지 않은 부분이라는 그 사소하지만 절대 사소하지 않은 사실 때문이다. 즉, 오전까지는 잘되다가 오후에는 안되도 전혀 이상할 이유가 없는 단서들에 제품이 기반하고 있기 때문이다. 우리가 이 사실에 대해서 어떤 불평을 한다면 운영체제를 만든 MS에서는 이렇게 대답할 것이다. “야, 그건 우리가 그래서 공개안한거야. 니네들 쓰라고 만든건 아니거든.” 이라고 말이다. 어쨌든 그래서 테스트 만으로는 이 허들을 넘기가 쉽지 않다. 우리가 관찰한 100시간 동안은 운영체제가 A라는 방식으로 동작했겠지만 그건 단지 우리가 관찰한 100시간 동안만 그랬기 때문일 수도 있기 때문이다.&lt;/p&gt;
&lt;p&gt;이 허들을 넘기 위해서는 테스트 보다는 운영체제에 대해서 보다 더 정확하게 알 수 있는 방법이 필요하다. 즉, 100시간의 관찰보다는 실제로 그렇게 돼 있는지 안 돼 있는지를 판단할 수 있어야 한다는 말이다. 그래서 운영체제를 직접 리버싱 하는 것이 더 도움이 된다. 맞다. 그런데 리버싱도 한계가 있다. 그래서 이 허들을 넘는 궁극의 도구는 MS 소스 코드 라이선싱 프로그램이다. 바로 그 놈이 답지고 그 놈이 갑이기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_허들_넘기.md_1.png&apos; data-alt=&apos;내가 곧 진리요. 답이고, 갑이다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 400px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a58de23b943e20cdd9965207a4b9f240/d9f49/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 74.73684210526315%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAERUlEQVR42h2Pa0yTBxSGm+yH2Z/NReemiBBRBuJlOoegE5niBJFMiYKRxSnO6cxQbi2gIFOoMK61tJWLoVYugihUQNhADAjaYkWQAN7m5mVMp3yoFIFCy7Mv+/Hm5D3Jec77SiaMpVjvVGHtvizOOia66hjvrMNyuwaL6C29ou+tZeJuDeN9tYx1XmS0vZzRFh3vfstjuPYU7xq0jLWUMdF2Fsl4+wUmOvSMmy4xaqjgXVspZkM55lsXGO6uYrhHL6oac2cF5vYSRq5qGb6kYrAsjYESOW8rs7HUKKBBhaU2DclIaxmjRhFkOM+bazoGmgt5ea2QF61a/rlexLPWUvqbCum/ouNBvQ69sZ4jT/7gRl059xuqeaRLp7dSR1vjVRTZeUiGmkt43XyGF2L8x3olD8WPdysy6L2kpEd/kt5qNddaL6P6+zmHhkaQjY2z3wY/DY5xZcTKxZ5nJDW/5XgXnK+oRPKiSsWj0gx6tHI6Tx+jo/A4Rl0yXUWJGOoL0HTfI+SOwO5hK8esE0RZLARN2tgkgjMf/0vriI1MwwClxTUMFicjeViQTG9+Ih2qOG4oZbRrYriuiOB0QjhByVo2GF7y7Z03/Gy2sMVqw3cSttomCWaS0Fdm9MIoTbf7uKs8yqtiOZI+dQJdOTG0K6Npy46kKlPKD3EJLM9twLP5KV9qGnGWX8DruRlfK2wctbFZBAeO2/A224h/8BpjXQPdBWk81qYi6ciKwaSQYsqNw5D6IwnFOtYOQrB4uOYvmLrtBB8GyHHV9uBuHMTrCXw9IEKHrOw1g0/bEOeyNbQoUuhSn0BiUhzhpghsTA7jonQHOfF78NK341bfz6L6VzjFFjE3y8RHB7Q4pN7Eo3WSLffG2NsPAU0DhOS1clahoTEnk47cX5E0JkVR/8sBauJ3UyYLIj/UE5+QvcxIrGV2lA6nrBu4lv3JJ4drWJzexPaHsEo/gEdaI36bAkmPiOBcloJ6pQJjjlj5qjyCuqM7KY/YjHrXGlICP2dfgCcfLNjE9KAE5uX34ZBuYNqhM8zLuMUKpQmPwH34LXPhe4/5ZMXFUJKWwe+qk5gKFEiK9m8m97tVKLctJzVgIYl+rsi85/CZvSPvb4/FPruOKQHhfLzUj7W7ZPh/5Y6/4xRCFk/j4PqFqGMOUqnIoilPze1CDZIUXzfS/F3/V7KvM7HejkjXzGHrMjves3NnqsMXrHBxYOui6ex0n8melbM5tN6FyHXORHk7kRW6haqUY7SosunOy0RyxGMmSWsdSP5mPsc3OJPg40TkSjvCPGcRvHgWe5bNQCruov3ckPouIM5/CYf9lohNFpG0wY38XRtpkEfTlZ/G0+IMJDL3T4XDq+2FmFV2gnSlvRAtKnK1oxDuNVeQ+bgIUetchDCveUKkt6sgXb9UkO/YKJwKCxXOhocKJQeDherYnUJbukzoVMcL9zVxwn+vmTDbEWt/yAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;내가 곧 진리요. 답이고, 갑이다.&apos; title=&apos;&apos; src=&apos;/static/a58de23b943e20cdd9965207a4b9f240/d9f49/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_1.png&apos; srcset=&apos;/static/a58de23b943e20cdd9965207a4b9f240/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_1.png 190w,
/static/a58de23b943e20cdd9965207a4b9f240/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_1.png 380w,
/static/a58de23b943e20cdd9965207a4b9f240/d9f49/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_1.png 400w&apos; sizes=&apos;(max-width: 400px) 100vw, 400px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;내가 곧 진리요. 답이고, 갑이다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;이 허들과 관련해서 사용자가 겪게 되는 또 다른 불편 중에 하나는 다양한 환경에서 게임을 즐기지 못한다는 요소다. 우리 제품도 종종 불만사항으로 올라오는 내용 중에 하나가 와인에서 실행되지 않는다는 것들이다. 이럴때면 늘 우리는 갈등한다. 사실 와인에서 실행되도록 만들어주는 것은 전혀 어려울 게 없다. (&amp;#x3C;== 어려울 수도 있다 ㅋㅋ) 그런데 문제는 와인을 통해서 해킹을 한다면 문제가 복잡해지기 시작한다. 물론 나는 선량한 리눅서가 와인을 통해서 게임을 즐기기 위함이지 절대 해킹을하기 위해서 리눅스를 깔고 와인을 올려서 게임을 구동하리라곤 생각하지 않는다. 그래도 만에 하나의 경우 그래 버린다면 문제가 될 수도 있다는 것이다. 어쨌든 우리는 이 옵션에 대해서 심각하게 고민하고 있다. 벤더 정책에 따라서 옵션으로 와인 호환성을 제공할까도 고려중이다.&lt;/p&gt;
&lt;h3&gt;#1 시스템 허들&lt;/h3&gt;
&lt;p&gt;다음으로 우리가 넘어야 할 허들은 게임 시스템이다. 이 또한 정말 다양한 시스템들이 있다. 이제는 우리가 시중에서 구하기도 힘든 시스템으로 게임을 하는 유저들이 적지 않다. 특히 오래된 게임들은 더 그렇다. 이 부분은 사실 테스트도 어렵다. 우리는 다양한 환경이라고 테스트 시스템 수십대를 구비해 놓지만 정작 유저들이 사용하는 시스템에 비한다면 그 수십대는 샘플 수량조차 되지 못한다. 그만큼 다양한 환경이 존재한다. 그리고 그 다양한 시스템을 게이머들은 우리가 상상도 못한 방식으로 변형시켜 사용한다.&lt;/p&gt;
&lt;p&gt;여튼 이런 다양한 시스템이 문제가 되는 주된 요소들은 시스템 버그에 대한 패치를 사용자가 하지 않는다는 점이다. 대표적인 예를 들어보자면 AMD CPU의 Cool’n Quiet 기능 버그가 있다. 해당 기능을 사용하면 특정 운영체제에서는 시간을 측정하는 함수가 비정상적으로 동작하는 문제가 있다. 이건 패치를 해야 하는데 사용자들이 그러한 패치를 알리가 만무하고 또 그 패치를 하지 않더라도 일반 프로그램 사용에는 문제가 없기 때문에 하지 않는 경우가 많다.&lt;/p&gt;
&lt;p&gt;하지만 우리에게는 그러한 것들이 굉장히 크리티컬하게 다가온다. 게이머가 해킹툴을 설치해서 시간이 이상한지 아니면 패치를 안해서 이상한지를 구분해야 하기 때문이다. 그래서 온갖 꼼수들이 동원된다. 당연히 그 꼼수들로 인해서 프로그램의 호환성은 더 떨어지고, 테스트는 더 힘들어지고, 제품은 더 쉽게 부서진다.&lt;/p&gt;
&lt;h3&gt;#2 오진 허들&lt;/h3&gt;
&lt;p&gt;여기부터는 이제 우리가 우리 발목을 잡기 시작하는 허들이다. 해킹툴 차단 방식은 크게 나누자면 패턴 방식과 로직 방식으로 나눌 수 있다. 패턴 방식은 사람 지문으로 누군가를 구분하는 것처럼 해킹툴의 특정 시그니처로 해당 해킹툴을 차단하는 방식을 말한다. 지문이 데이터베이스에 없다면 인식이 안되는 것처럼 이 경우도 수집이 안 된 해킹툴에 대해서는 차단을 하지 못한다는 문제가 있다. 그래서 도입된 개념이 로직 방식이다. 이건 이렇게 행동하는 사람은 A 밖에는 없다고 우리가 추론하는 것과 똑같은 원리로 해킹툴을 진단한다. 즉, 어떤 프로그램이 a, b, c라는 동작을 하면 해킹툴로 간주하는 것이다. 당연히 우리가 인식하는 세계처럼 여기에는 맹점이 생길 수 밖에 없다. 그 사람이 아닌데, 내지는 해킹툴이 아닌데도 a, b, c라고 동작을 하는 경우가 있기 때문이다. 이게 우리 발목을 잡는다. 물론 대놓고 난 정상 프로그램이라고 말하면 문제는 한결 가벼워 지는데 그 정상 프로그램이 각종 꼼수 꼼수에 꼼수를 사용해서 마치 해킹툴처럼 판단하기 어렵게 만든 경우에는 허용 처리가 안드로메다로 가버린다.&lt;/p&gt;
&lt;p&gt;그럼 어떤 프로그램이 주로 오진 케이스에 말려들까? 가장 대표적인 프로그램들은 아이러니하게도 게임 유틸리티다. 게임 동영상 촬영 도구라던지, 게임 내에서 채팅 기능을 구현한 메신저 프로그램이 대표적이다. 이들 프로그램은 게임과 동시에 동작한다는 것이 특징인 것들이지만 내부 구현 방식은 해킹툴의 그것과 상당히 유사하기 때문이다. 또 이 프로그램들이 진화하면서 이 프로그램들 나름대로 탐지를 회피하기 위해서 각종 테크닉을 사용하기 때문에 요즘은 허용 처리도 참 쉽지 않은 경우가 많다.&lt;/p&gt;
&lt;p&gt;그 다음 대표적인 유틸리티 들로는 가상화 유틸리티들 SandBox, Vmware, Virtual PC부터 네트워크 프록시 도구들이 있다. 이런 프로그램들은 해킹툴과 동작 방식이 유사히진 않지만 벤더 요청으로 차단하는 경우가 있다. 그렇게 차단된 것임에도 사용자 입장에서는 정상 프로그램을 오진한다고 생각하기도 한다.&lt;/p&gt;
&lt;p&gt;벤더 정책으로 누명을 쓰는 또 하나의 대표적인 프로그램으로는 또 JoyToKey가 있다. 이름에서 볼 수 있듯이 조이스틱을 컴퓨터에서 매핑해서 사용할 수 있게 해주고, 또는 매크로 기능을 사용할 수 있게 해주는 프로그램이다. 그런데 이게 왜 문제인고 하면 게임 벤더에 따라서 어떤 쪽은 이 프로그램을 허용처리하고 어떤 곳은 차단 처리를 하기 때문이다. 유저들의 반응은 딱 갈리게 된다. 저걸 해킹툴로 많이 사용하는 게임인데 벤더에서 허용을 해주면 어떤 반응이냐면 우와 XIGNCODE는 쓰레기다. JoyToKey도 차단이 안된다. 이런 반응들이 올라온다. 사실 우리가 못 막아서 안 막는 경우는 아님에도 말이다. 또 반대로 이 프로그램을 별로 해킹툴로 사용하지도 않는 게임인데 벤더 정책상 차단하게 되면 와 이런 정상 프로그램을 왜 차단하냐. 미친거 아니냐. 라는 반응들이 올라온다. 마찬가지로 우리가 차단하고 싶어서 차단한건 아님에도 말이다. 즉, 가끔은 중간에 끼여서 욕을 먹는 경우에는 조금 억울한 생각이 들 때도 있다.&lt;/p&gt;
&lt;h3&gt;#3 충돌 허들&lt;/h3&gt;
&lt;p&gt;충돌은 정말 장난아닌 문제다. 게임보안 제품은 그 모든 것들과 충돌을 일으키지만 특히 안티바이러스 이슈가 많다. 가장 최근에 겪었던 충돌 문제를 한 번 살펴보자. 이 문제는 안티바이러스의 코드 에뮬레이션 기능과의 충돌이었다. 처음 보고가 들어온 제품은 AVAST였다. 이런 문제의 99.8971234%는 서로 같은 포인트를 후킹하거나 후킹하려고 하는 것이 문제이기 때문에 그 체크를 먼저 했다. 어라? 근데 깨끗하다. 아무 문제가 없어 보였다. 근데 게임이 크래시가 난다. 그래서 AVAST의 이 옵션, 저 옵션 조정하면서 왜 크래시가 나는지를 관찰했다. 그랬더니 아니나 다를까 AVAST의 코드 에뮬레이션 기능을 켜면 크래시가 발생하는 것이었다. 게임이!!! 도대체 왜? 아마 우리의 코드가 그 코드 에뮬레이터가 이해하기는 힘들었는지도 모르겠다. 여튼 QA팀에게 AVAST에 충돌 보고를 하라고 했다. 내가 보기에는 AVAST에서 봐야 할 문제였기 때문이었다. 그러고 끝일까? 당연히 아니다. 게이머한테 이건 AVAST 버그니 코드 에뮬레이션 끄고 게임하세요. 이렇게 말할수는 없기 때문이다. 그래서 우리는 그 코드를 AVAST가 켜진 경우에는 AVAST가 딱 이해할만한 수준으로 낮춰서 동작시키도록 했다.&lt;/p&gt;
&lt;p&gt;이 문제가 억울한 이유는 사실 이런 경우는 우리쪽 버그가 아니다. AVAST 코드 에뮬레이터 버그지 않겠는가? 결국 AVAST에서 해당 기능을 고쳤다는 보고를 해왔다. 하지만 게임사나 유저들은 우리 잘못으로 오인하는 경우가 많다. 안타까운 현실이다. AVAST만 거론해서 그렇는데 동일한 이슈를 겪은 다른 3종의 백신이 더 있었다. MS SE, ESET Smart Security, McAfee였다. 물론 다른 벤더엔 귀찮아서 오류 보고도 하지 않았다.&lt;/p&gt;
&lt;p&gt;그렇다면 우리는 왜 AVAST 코드 에뮬레이터도 이해하지 못하는 그런 코드를 써야 했을까? 첨부터 그냥 다 평이한 걸 사용했으면 문제가 없지 않을까라고 생각할 수도 있겠다. 근데 이게 딜레마다. 우리 제품은 해커로부터 우리 코드를 보호해야 한다. 또 해커가 우리 코드를 이해하는 것을 막아야 한다. 그러니 당연히 복잡하게 꼬아 놓을 수 밖에는 없는 것이다. 그게 경쟁력이니 포기할 수가 없는 것이다. 충돌을 감수하더라도 그 코드를 계속 써야만 하는 이유다.&lt;/p&gt;
&lt;p&gt;그리고 이런 충돌 이슈는 충돌을 넘어서 좀 더 복잡한 문제들을 야기 시킨다. 충돌때문에 작성한 특수 코드가 우리 발목을 잡는 경우가 생기는 것이다. 해커가 만약 백신 때문에 작성한 특수한 코드에 대한 사실을 눈치채면 그걸 이용해 먹을 수 있다는 말이다. 그런 방법을 공유한다고 사용자들이 백신을 설치할까라고 생각할 수 있다. 근데 뻥안치고 방법만 있다면 게임핵을 사용하고 싶은 모든 사용자는 어디서 구하든 다 구해서 그 백신을 설치한다. 그 정도로 게임핵의 유혹은 강하기 때문이다. 실제로 예전에 중국에서 KAV를 이용해서 해킹 시도를 하는 사례가 있었다. 그래서 귀찮더라도 보고하고 무조건 백신을 고쳐야 한다.&lt;/p&gt;
&lt;p&gt;여기까지 생각하면 이제 게임보안 1-2년 정도 해본 사람이라고 할 수 있겠다. 좀 더 해보면 알겠지만 저거 고쳤다고 원래 코드를 쓸 순 없다. 세상이 그렇게 순수하진 않은 탓이다. 백신 업체가 고쳤다고 그걸 업데이트하는 유저도 있지만 하지 않는 유저도 부지기수기 때문이다. 우리가 백신 업체가 고쳤다는 소리만 듣고 순진하게 원래 코드로 원복시켰다가는 다시 똑같은 문제가 생긴다는 소리만 듣는다. 모든 사용자는 업데이트를 하지 않는다고 생각하는게 속편하다. 그래서 그 특수 코드를 이용하는 놈들이 나타나면 다시 그 특수 코드에 대한 특수 코드를 만들어야 한다. 이렇게 소스 코드는 걸레가 되고 로직은 38.7차원 어딘가에 위치하게 된다.&lt;/p&gt;
&lt;h3&gt;#4 버그 허들&lt;/h3&gt;
&lt;p&gt;이거야말로 우리가 피해야 할 허들이다. 그런데 가장 많으면서 제일 피하기 힘든 허들이다. 누구 말처럼 이건 명백히 프로그래머의 실수다. 그런데 버그라는 말을 만들어서 책임 회피를 하는 것처럼 보일 수 있다. 어쨌든 맞다. 명백한 우리 실수, 잘못이다. 인정한다.&lt;/p&gt;
&lt;p&gt;그럼에도 변명을 좀 대보자면 이렇다. 우선 게임보안 제품은 생각보다 빌드가 굉장히 많이 있다. 왜냐하면 해킹툴이 자주 나오기 때문에 그 취약점도 고쳐야 하고 새로운 방식에 대응도 해야 하기 때문이다. 심한 시기에는 풀빌드가 일주일에 두세 번씩 되기도 한다. 이런 경우에는 머 QA팀은 초죽음이 된다고 보면 된다. 또한 이러한 풀빌드가 전혀 계획되지 않은 상황에서 발생하기도 한다. 왜? 해킹툴을 막아야 하기 때문이다. 자잘한 빌드는 말도 못 할 정도로 많다. 하루 밤에 24번 모듈을 빌드하고 업데이트 한 적도 있었다. 당연히 그 해킹툴 제작자는 그 다음주에 학교로 돌아갔다. 그래서 때로는 이런 어처구니 없는 실수들도 자주 발생한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_허들_넘기.md_2.png&apos; data-alt=&apos;이렇게 아무 문제도 없어 보이는 배열 속에…&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/4219a15013e725feb5aa16d0f9c7b004/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 65.78947368421053%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAByElEQVR42m2S627jIBCF8yrdxkls4ytg7mAMvidV3/9pdtxspd1spWEEP47mO4c5pXVLlaFSN0xUlFWkqzv+vBSYFC2pCCsxuRUoQUWSlxdUJnlxTrNft+z0dr314zSu+/rxOe+PuO7L42OY12l/hHmxIcT1PsyT0KKmNK+btGquZZXkX2I4zDgVIu8HNUTuPO99Zx01llmHJS/wIbjk6P2WvV3T7/oWI0IbZVooY2ul4VJy8exQFROoxReUv3+h/l2HuOWCaSudVzBTGeUGKjQ3jkrVSSWt50aXLVjNfxBDVEAunNdD6LSBS6cd5gILqfqBG4uaIsn+oL6KmbE2jGHZbJzidvfzAoH5adZ+cHHSvqeSFUCev5IfYiB04ww5+3EO6z5u935cph36ZEMM62a8xZymVX3J/xVDhkRIMAxjZQ/kESiAFqrTGrIwx9NjRrKqSrL/Jle0o0qD7aNrCwVr0zIBto/9UQaCaBlHTfk6GY6wzk8LYMd1A+cAbIYI8GBb9f3hf16kEaguz9kPXyXBtvIBsIXr5ZG21T50SoMj7SPTCtUIVvIl8NM5y0tCiVCw3lBEalDCz0MnUgEtFgrz53oXL5N/A0mnoUZtWpPFAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;이렇게 아무 문제도 없어 보이는 배열 속에…&apos; title=&apos;&apos; src=&apos;/static/4219a15013e725feb5aa16d0f9c7b004/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_2.png&apos; srcset=&apos;/static/4219a15013e725feb5aa16d0f9c7b004/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_2.png 190w,
/static/4219a15013e725feb5aa16d0f9c7b004/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_2.png 380w,
/static/4219a15013e725feb5aa16d0f9c7b004/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_2.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;이렇게 아무 문제도 없어 보이는 배열 속에…&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_허들_넘기.md_3.png&apos; data-alt=&apos;NULL이 하나 빠진 이런 말도 안 되는 버그가 숨어있는 상황. 때로는 깔맞춤이 필요한 이유.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/2a2208ca8aaa47d90a3b186141782656/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 58.42105263157894%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAB8ElEQVR42lWSWZbaMBBFWUm6A3jUZM22bHkETAMh6aRP9r+UPPOXHx1JVa/q1pN2pmlVHcpKYi2EpMoo3zBtE8IyxitX4xJ7rFybyvqcV8eSZpQcS7IzTeiXM0o8/3zpOgyny3p/4ngoCTdufTx106aU1TFOl/V8e6D0oaDSkJzRHdXGxIFZ1y4nZr3pIrdun5fvaV5KLVElJzgK520cAHLIy+9ZQSqWELpDhqgDNS4sZ269DJ2LAzghzivZTEvBK4i586qNth9BsYkl38RMG1U3TJnxvNZxcG3s5iVj4i3JidLCOEDui1L5GtH+dOHaoi6TJCXkJfYBK6YV1tf9GMYpJRwZMM+GDvZALL1v+rGbllJIdGaSbmKUxK309f3zN6qOl+v91yep1Ldjilo/v/7CMGC/DLs+thwDKGlYRukOlsJb4J0+7lTqMM7z+oEjBETq4cWJvW7CFrreXm4TrsgmJlKhA1W6m+aUcttG1/UYL+cqDrQfyFtSIFsYa9vOI9QPGKcUJAG2sM6GCP3l/gPhMMwbggJbpry5Pe/S1ehs27abTsv1hvz3tBCabp3/E4euGSZg4z9BTKWd1xseYp8XNoR22iYCKbwU6iXGx0QfZAMYm82C0OVcwFI8GC7LSqEz5sLfRKgQFUIFI0lJ/gFJQ5Hdi8sfUwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;NULL이 하나 빠진 이런 말도 안 되는 버그가 숨어있는 상황. 때로는 깔맞춤이 필요한 이유.&apos; title=&apos;&apos; src=&apos;/static/2a2208ca8aaa47d90a3b186141782656/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_3.png&apos; srcset=&apos;/static/2a2208ca8aaa47d90a3b186141782656/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_3.png 190w,
/static/2a2208ca8aaa47d90a3b186141782656/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_3.png 380w,
/static/2a2208ca8aaa47d90a3b186141782656/dface/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_3.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;NULL이 하나 빠진 이런 말도 안 되는 버그가 숨어있는 상황. 때로는 깔맞춤이 필요한 이유.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;물론 당연하다. 똑똑하다면, 진짜 실력이 있다면 빨리 만들면서도 잘 만들어야 하고, 또 문제가 없어야 한다. 우리가 항상 이런 버그 앞에서 한없이 초라해지고 숙연해지는 이유이기도 하다. 그럼 우린 어떻게 해야 하는가? 프랙티스, 프랙티스, 프랙티스… practice makes perfect를 외치며 항상 연습하는 수 밖에는 없다. 빨리 고치고, 급하게 고치고, 막 바꾸면서도 실수하지 않도록 말이다. 라이브는 말 그대로 전쟁터다.&lt;/p&gt;
&lt;h3&gt;#5 필요악???&lt;/h3&gt;
&lt;p&gt;문제가 한두 가지가 아니다. 한 게임보안 프로그램은 국내 대형 MMORPG에 탑재됐다가 북미에서는 유저들 원성으로 제거되는 굴욕을 겪기도 했었다. 사람들은 늘 말한다. 100% 막지도 못하고, 그렇다고 문제가 0%인 것도 아닌데 왜 필요한가라고 말이다.&lt;/p&gt;
&lt;p&gt;하지만 정작 실제 내용을 살펴보면 그런 이야기를 하기는 힘들다. 왜냐하면 게임보안 솔루션을 사용해서 유통되는 유료핵툴 한두 개만 차단하더라도 연간 구독료 값어치는 하고도 남기 때문이다. 특히 MMORPG같이 컨텐츠가 생명인 게임은 더 그렇다. 아래는 한 게임에 오토 유료핵이 나온 경우의 상황을 보여주고 있다. 여러분이 보는 그대로 전체 게이머의 60%가 그 핵툴을 사용하는 시간대도 있다. 이 정도로 말도 안 되게 온라인 게임의 핵은 심하고, 또 게임보안 제품은 여러분이 생각하는 것보다 훨씬 더 쓸모있다. 저 오토들이 컨텐츠 소모에 들어갔다면 어땠을까? 단순히 유저들이 느끼는 불균형의 문제가 아니다. 비싼 돈주고 개발한 컨텐츠가 유저가 아닌 기계에 의해서 순식간에 소모되는 말도 안 되는 일이 벌어질 수 있는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_허들_넘기.md_4.png&apos; data-alt=&apos;가로축은 시간이고, 세로축은 해킹툴 유저 비율(%)이다. 유료핵의 파괴력은 생각보다 훨씬 심하다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 467px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/e1c1196cae62eb6480b029ea4d1cfa6e/128f7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 45.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABpklEQVR42kVPy27TQBTNX7JBQlBSKvWxJpsKVQRaqMSOH2DBgiWrSiwRTRM/EI9YSuNHCiqx41dsjx9zZzwcGwFXozN3zpxz58yAMZamafu3ZCukFF0jZX/EJrlIQXZ9T/6rQZ5ltm0LAY8Ugjo3EVoiUCDbhtLv0fGGfVKt4lRDI/rqzGVZup5H0EIqREXrmhLoegazlJe+mazvLJJXUsLG4flvLorCcV3qXms5FV/D0ZdwhBF4FyOS+vNsfd/cHJjBkRWPV9u3UTWFkpARZvzZcRxODaQ323eavzNd37st3iupENiKn2n+0AgOdH9PDx5d/bo7j56ILjoiyM7seR7ixZWp+btmcAi0ojGnch6NZ/4DOI1gX/f3cWX4iHDImp8YjfgDVlTW8nIen5jhnr55aIS7xmZohEMreQo0cexw+Af7ZudbPLKz1371YaCUWvy4mCyPNed85pzp3our5XNjdX55faK7L2fOKZbmnk2ux3qP0Ezt04+Lx6vwojPnOSPeMlZjcXw0LaRQ27Tgjci2LM/LuqYoSkmoMEyamvKM5VnVSvUbT9zY7j/2qEsAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;가로축은 시간이고, 세로축은 해킹툴 유저 비율(%)이다. 유료핵의 파괴력은 생각보다 훨씬 심하다.&apos; title=&apos;&apos; src=&apos;/static/e1c1196cae62eb6480b029ea4d1cfa6e/128f7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_4.png&apos; srcset=&apos;/static/e1c1196cae62eb6480b029ea4d1cfa6e/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_4.png 190w,
/static/e1c1196cae62eb6480b029ea4d1cfa6e/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_4.png 380w,
/static/e1c1196cae62eb6480b029ea4d1cfa6e/128f7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_4.png 467w&apos; sizes=&apos;(max-width: 467px) 100vw, 467px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;가로축은 시간이고, 세로축은 해킹툴 유저 비율(%)이다. 유료핵의 파괴력은 생각보다 훨씬 심하다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;해킹툴로 서비스되는 게임을 내려본 게임사는 게임보안 솔루션의 필요성에 대해서 절절하게 실감한다. 몇 백억이 투입된 게임도 해킹으로 난장돼서 서비스가 불가능할 수도 있기 때문이다. 여러분이 생각하는 것 이상으로 반드시 필요하고, 또 좋은 솔루션이 필요하다. 그래야 문제는 낮추고, 탐지율은 높아지기 때문이다.&lt;/p&gt;
&lt;h3&gt;#6 허들을 넘어서&lt;/h3&gt;
&lt;p&gt;참 문제도 많고 탈도 많다. 프로그래머는 어떨까? 이런 수많은 허들을 마주하면 게임보안 프로그래머는 위축될 수 밖에 없다. 공격적인 탐지 방식보다는 느슨한 탐지 방식을 사용할 수 밖에 없다. 좀 더 복잡한 숨김 방식보다는 노멀한 방식을 사용할 수 밖에 없다. 자신감이 없어지기 때문이다. 하지만 이런 것들에 위축돼서 쪼는 순간 게임보안 프로그래머로써의 생명은 끝이고, 그 제품 생명도 끝이다. 왜냐하면 그런 자신감이 없어지는 순간 제품과 코드의 경쟁력은 순식간에 사라지기 때문이다. 진짜 프로라면 이 모든 허들을 웃으면서 사뿐히 뛰어넘으면서도 위험한 방법을 과감하게 선택하는 강단이 필요하다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;게이머에게 유쾌한 느낌을 주는 게임보안 솔루션이고 싶다. 물론 쉽진 않다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;적어도 XIGNCODE를 사용하는 게임에게 짐이고 싶진 않다. 또 적어도 XIGNCODE가 탑재된 게임을 하는 게이머들에겐 공정하다는 느낌을 주고 싶다. XIGNCODE 팀은 매 순간 그 시소의 양 극단에서 갈등하고 고민한다. 지금까지 우리는 항상 가장 위험한 방법에 과감하게 도전했고, 그걸 제일 안전하게 구현했다. 또 실수를 최소화하기 위해서 매일 연습했다. 그것만이 우리 제품을 사용하는 모든 이들에게 신뢰를 줄 수 있는 방법이고, 또 우리가 이 수많은 허들을 뛰어넘은 방법이기 때문이다.&lt;/p&gt;
&lt;p&gt;새로운 기능이 잔뜩 준비됐다. QA팀은 긴장한다. 그 쏘 쿨한 기능들은 늘 그랬듯이 허들을 하나씩 넘을 것이고, 그걸 다 넘으면 게임에 탑재돼서 새로운 핵들에 대한 대응력을 강화해 나갈 것이다. 이렇게 우리는 매일 조금씩 전진한다. 제품도, 팀도, 회사도 말이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_허들_넘기.md_5.png&apos; data-alt=&apos;가장 공격적인 방법을 선택하되 가장 안전하게 구현해야 한다. 왜? 우리는 프로니까.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/dc41bc1baab2d05dd6d4c60e540054d6/984b6/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_5.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 5.7894736842105265%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAABCAIAAABR8BlyAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAO0lEQVR42h3GOxYAEAwFUfvfFhryEnJ0QsU+fO6ZYpxqBaiIUCZ8zAx6X1OWEOD9jWM01dna6N2+tfYBvz0w2mII1KIAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;가장 공격적인 방법을 선택하되 가장 안전하게 구현해야 한다. 왜? 우리는 프로니까.&apos; title=&apos;&apos; src=&apos;/static/dc41bc1baab2d05dd6d4c60e540054d6/984b6/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_5.png&apos; srcset=&apos;/static/dc41bc1baab2d05dd6d4c60e540054d6/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_5.png 190w,
/static/dc41bc1baab2d05dd6d4c60e540054d6/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_5.png 380w,
/static/dc41bc1baab2d05dd6d4c60e540054d6/984b6/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%ED%97%88%EB%93%A4_%EB%84%98%EA%B8%B0.md_5.png 630w&apos; sizes=&apos;(max-width: 630px) 100vw, 630px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;가장 공격적인 방법을 선택하되 가장 안전하게 구현해야 한다. 왜? 우리는 프로니까.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 게임 보안: 커플링에 관한 오해들…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/5823</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5823</guid><pubDate>Tue, 24 Apr 2012 23:58:05 GMT</pubDate><content:encoded>&lt;p&gt;게임사 미팅을 해보면 흔하게 겪는 일 중에 하나가 커플링에 관한 오해들입니다.&lt;/p&gt;
&lt;p&gt;반지는 아니구요. ㅋㅋ 게임과의 결합도가 높은 보안 코드에 대한 이야깁니다.&lt;/p&gt;
&lt;p&gt;소프트웨어 공학에서는 모듈간의 의존도 내지는 결합도를 나타내는 척도로 커플링이란 단어를 쓰거든요. 결합도가 낮으면 느슨한 결합이라고 하고 결합도가 높으면 강한 결합이라고 한답니다. 어떤게 좋을까요? 당연히 소프트웨어 공학에서는 커플링이 낮은 수준이 닥치고 갑입니다. 결합도가 높다는 건 덜 모듈화 됐고, 고치기 쉽지 않으며, 수정할 때 오류가 발생하기 쉽고, 유지보수 하기가 까다롭다는 그 모든 것을 의미합니다. 그래서 커플링을 피해야 할 그것으로 간주하죠.&lt;/p&gt;
&lt;p&gt;하지만 요사이 많은 부분에서 게임보안 제품과 게임은 커플링이 높아지는 것이 필연적일 수 밖에 없다는 주장이 제기되는 것 같아서 몇 가지 사례별로 생각을 정리해 보았습니다. 자 그럼 과연 커플링이 높아야 해킹툴을 잘 잡는다는 말이 진실인지 아닌지 한 번 살펴볼까요? ㅎㅎ~&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;언제부턴가 게임보안 업체들 사이에서 서버에 게임보안 코드를 탑재하는 것이 일반화 됐습니다. 저희가 XIGNCODE라는 제품을 개발하던 초기만 해도 서버 쪽에 코드를 탑재하는 것을 두고 게임 서버 개발자들 사이에서 반감이 굉장히 많았습니다. 그랬던 것이 요즘은 대부분 다 기본적으로 코드를 탑재해야 된다고 생각하시니 감사할 따름입니다. 격세지감도 좀 느끼고 그래요. 여튼 이러한 서버 코드 탑재와 함께 따라온 잘못된 관습(?!) 중에 하나가 클라이언트가 빌드될 때마다 서버에 클라이언트 해시 데이터를 업로드하는 것입니다. 보안 코드에서는 서버 쪽과 클라이언트를 비교해서 다른 경우에 끊겠다는 것을 목표로 개발된 기능인 것 같습니다. 매우 강한 결합 중에 하나죠.&lt;/p&gt;
&lt;p&gt;이 경우에 실수가 발생할 소지는 굉장히 다분합니다. 관리자가 서버 쪽에 해시 데이터를 업로드 하는 것을 빼먹거나, 서버에 올린 해시 데이터와 다른 클라이언트가 패치 된다거나 하는 등의 실수 개입 요지가 많습니다. 근데 뭐 실수는 안한다고 차치하더라도 이 방법이 그다지 좋지 않은 이유는 대부분의 게임에서는 이런 조치가 전혀 필요하지 않기 때문입니다. 도둑이 모두 창문으로 넘나드는데 창문은 지키지 않고 정문을 유지보수 한다는 느낌일까요? 이런 이야기를 하면 꼭 그럼 정문은 안지켜도 되는거냐? 라고 물으시는 분들이 계신데 현실 세계에서 리소스는 항상 제한적입니다. 따라서 그 정문 지키는 리소스로 도둑이 드나드는 다른 곳을 지키는 것이 백배 더 현명하다는 이야기입니다.&lt;/p&gt;
&lt;p&gt;그렇다면 게임 서버에 탑재되는 코드에서 해야 하는 일은 무엇일까요? 바로 실행 보장입니다. 게임보안 제품은 외부 라이브러리 형태로 제공되기 때문에 인터페이스가 노출되면 손쉽게 바이패스될 수 있습니다. 이런 경우를 검증하기 위함입니다. 즉, 모든 것들이 다 제거되고 우회되고 변경되더라도 단 하나 이거는 그래도 실행된다고 보장할 것이 필요하다는 것이죠. 그게 바로 서버에 적용된 코드가 해야 하는 일입니다. 실행 보장만 되면 변경된 지점을 찾아내는 것은 언제든지 할 수 있거든요. 하지만 실행 보장이 되지 않으면 백날 변경 지점을 찾는 코드를 넣어봐야 효과도 없습니다. 변경 지점을 찾는 그 코드가 변경될꺼거든요.&lt;/p&gt;
&lt;p&gt;그리고 뭔가를 변경한다는 자체가 굉장히 오래된 발상입니다. 요즘 트렌드는 노모디피케이션입니다. 즉 아무것도 바꾸지 않고 바꾼 것과 동일한 효과를 내는 방법들이라는 것이죠. 왜냐면 해커들도 이제는 다들 알거든요. 뭔가를 바꿔서는 너무 쉽게 탐지된다는 사실을요.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;오토, 매크로 프로그램과 특정 기술을 무한대로 사용하게 하는 핵들은 게임 내 특정 함수를 불법적으로 호출하는 기능을 통해서 많이 구현됩니다. 예를 들어서 레이싱 게임이라면 부스터 가속을 시키는 함수를 들 수 있습니다. 외부 해킹툴은 그런 함수를 불법적으로 계속 호출합니다. 이렇게 만들어진 것이 무한 부스터 핵입니다. 이런 기법이 게임 개발자들 사이에도 많이 퍼져서 요즘 흔하게 나오는 질문 중에 하나가 보안 프로그램이 특정 함수를 보호할 수 있는 기능을 제공하는가 물어보십니다. 이 기능이 제공되면 게임 개발자가 생각하기에 위험하다고 생각하는 함수 주소를 전달해서 불법 호출을 막겠다는 생각인거죠.&lt;/p&gt;
&lt;p&gt;과연 효과적인 전략일까요? 솔직히 무용지물입니다. 게임 내 랙만 증가시킨다고 보시면 됩니다.&lt;/p&gt;
&lt;p&gt;일단 기본적으로 반환 주소 체크 기법은 return address morphing이란 테크닉에 의해서 너무 쉽게 무력화됩니다. 그런 기법을 방어하기 위해서는 코드를 트레이싱해서 추적해야 하는데 해당 게임 함수 런타임에 이런 체크를 깊이 하게 되면 부하가 증가됩니다. 따라서 일정 범위 밖에 체크를 못하죠. 즉 우리가 N Depth를 추척하는데 상대가 N+1 Depth를 사용하면 그냥 우회된다는 겁니다. 참고로 이런 것들을 인식하고 N Depth를 검사하도록 넣은 보안제품도 잘 없답니다. 안타까운 현실이죠.&lt;/p&gt;
&lt;p&gt;근데 더 안타까운 사실은 이러한 체크 기법이 후킹이란 방식에 의존하는데 제작자 입장에서는 해당 후킹 포인트를 지나서 함수를 호출하는 것 또한 너무 쉽다는 겁니다. 물론 이것도 방어하기 위해서 동적 코드 분석을 한 다음에 애매한 위치에 알박기를 할 수도 있지만 소프트웨어의 견고성만 떨어질 뿐 크게 효과적이진 못합니다.&lt;/p&gt;
&lt;p&gt;진짜 최고로 안습한 사실은 해당 함수 주소를 차단하면 해커는 다른 함수를 찾아낸다는 겁니다. 100% 말이죠. 그래서 효과적이지 않습니다. 여러분이 해커와 같은 속도 내지는 해커보다 빠른 속도로 해커가 다시 찾아낸 그 함수를 찾아낸다 해도 효과는 없습니다. 그냥 하나의 경쟁 루프를 만들어낼 뿐이거든요. 상호 패치 공방 밖에는 벌어질 수 없는 방식이란 거죠.&lt;/p&gt;
&lt;p&gt;저희도 중국 유료 해킹툴에 이 기법을 몇 차례 적용했었는데 별 재미를 못 봤습니다. 왜 재미를 못봤냐구요? 우리는 일주일이 걸려 겨우 그 함수를 찾았습니다. 그래서 이제 막으면 원천 차단이 되겠다 생각했죠. 근데 넣고 하루만에 다른 함수를 호출하더군요. 다시 일주일을 분석하느니 그냥 그런 방법은 개나 주는 편이 낫겠다고 생각했습니다. 저희는 다른 방법을 선택했고 그 해킹툴은 3월 2일부로 영원한 수면에 들어가셨습니다. ㅋㅋ~ 이 사례를 통해서 전 교과서에 나오는 방법들이 생각보다 훨씬 더 실전에서 쓸모가 없다는 저의 생각을 좀 더 굳히게 됐습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_커플링에_관한_오해들.md_0.png&apos; data-alt=&apos;XINGCODE로 인하여 3월 2일부로 영면하신 그 비운의 해킹툴…&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 507px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/1ca6771485881f6e9380392d33c89636/f03ec/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%BB%A4%ED%94%8C%EB%A7%81%EC%97%90_%EA%B4%80%ED%95%9C_%EC%98%A4%ED%95%B4%EB%93%A4.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 36.31578947368421%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAIAAACHqfpvAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABDUlEQVR42m2Qy07DMBBF/cP8BOInYIXEmg17BAvEAqmiKqFKW1LivOzYjh+x3UTYaTBFgrZwNBpdjebOjAZcPVbn9/npzfphycdxdH4IbHcMw6/+F3BxC8+u45PL6O6VBfOwHY86QvEnH5uFMklBrTXdRhtjGWNqh9ZaStW2bRDW2lDp+z4c4vcAOVWTFRKtkbwxWpMaKyk456FbSiEDQnQbizEO5vEQwCiFMF1CvCoI5jJKcU54gcoFLOYZwY1AQq4rYo2WX+MOAMZoShAijGNqUM1gqUqkYMaT9waWuiZtXinCwtruD8C7jtO0KKuPLPeLxD+/uGnkotg9Tf1s7uM3N5kNuN5+PyzkvfgErJWJn6T98KIAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;XINGCODE로 인하여 3월 2일부로 영면하신 그 비운의 해킹툴…&apos; title=&apos;&apos; src=&apos;/static/1ca6771485881f6e9380392d33c89636/f03ec/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%BB%A4%ED%94%8C%EB%A7%81%EC%97%90_%EA%B4%80%ED%95%9C_%EC%98%A4%ED%95%B4%EB%93%A4.md_0.png&apos; srcset=&apos;/static/1ca6771485881f6e9380392d33c89636/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%BB%A4%ED%94%8C%EB%A7%81%EC%97%90_%EA%B4%80%ED%95%9C_%EC%98%A4%ED%95%B4%EB%93%A4.md_0.png 190w,
/static/1ca6771485881f6e9380392d33c89636/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%BB%A4%ED%94%8C%EB%A7%81%EC%97%90_%EA%B4%80%ED%95%9C_%EC%98%A4%ED%95%B4%EB%93%A4.md_0.png 380w,
/static/1ca6771485881f6e9380392d33c89636/f03ec/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%BB%A4%ED%94%8C%EB%A7%81%EC%97%90_%EA%B4%80%ED%95%9C_%EC%98%A4%ED%95%B4%EB%93%A4.md_0.png 507w&apos; sizes=&apos;(max-width: 507px) 100vw, 507px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;XINGCODE로 인하여 3월 2일부로 영면하신 그 비운의 해킹툴…&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;저희가 커플링 높은 인터페이스를 게임 개발자들에게 권하지 않는 이유는 이런 겁니다. 첫째는 게임 개발자가 스터디를 해야하는 보안 제품을 만들어서는 안 된다고 생각하기 때문입니다. 여려분이 자동차를 사는데 그 엔진 구조를 모르고는 시동도 걸 수 없는 차라면 사시겠습니까? 저같으면 그런 건 개나 줄 것 같거든요. 다른 하나는 이러한 테크닉의 경우 자칫 남용되거나 내부 구현을 모르고 사용했다가는 게임 내 부하만 증대 시키고 해킹툴을 막는대는 하나도 보탬이 되지 않기 때문입니다. 결국 출혈을 감수해 가면서까지 가져간 높은 커플링으로 볼 수 있는 재미는 하나도 없다는 이야기입니다.&lt;/p&gt;
&lt;p&gt;물론 잘 아시겠지만 여러분이 모르는 그런 곳에 이 반환 주소 체크 기법을 사용해서 재미를 볼 수 있는 곳은 많이 있습니다. 당연히 그런 건 여기다 적진 않겠죠? 단물 좀 더 빼먹고 누구나 알게 될 즈음에 마치 제가 처음 발견한 마냥 교과서에다 공개하겠습니다. ㅋㅋ~&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;끝으로 요즘 가장 핫한 데이터 중에 하나인 DirectX 인터페이스 주소를 좀 살펴보겠습니다. DirectX 가상 함수 변조를 체크하기 위해서 해당 인터페이스의 포인터를 전달 받는 것이 이 커플링 높은 방식의 골격같습니다. 하지만 이 또한 안타깝게도 큰 의미는 없습니다. 우선 전달받지 않고도 주소를 획득할 수 있고, 무조건 전달을 받아야만 막을 수 있는 방식이 한가지 있긴 한데 그 방식은 속도 상의 이유로 실전에서 거의 사용되지 않습니다. 또한 사용한다 하더라도 다른 루트를 통해서 검출할 수 있습니다.&lt;/p&gt;
&lt;p&gt;전 이런 방식을 사용해 본 업체들에게 페르미의 역설처럼 한 번 여쭤보고 싶습니다. 달라고 하는 DirectX 인터페이스 주소를 가르쳐 주셔서 재미 좀 보셨습니까? 라구요. 아마 그닥 재미를 못 보셨을 겁니다. 인터페이스를 조작하는 해킹 방식은 제가 지난 번에 썼던 것처럼 Visual C++ 일주일 배우고 게임 커뮤니티에서 DirectX Hook Toolkit을 받아서 월핵 샘플따라 코딩하는 경우 외에는 잘 없거든요. 참 올드 패션드한 테크닉이란 이야기죠. 요즘은 저런 방식 자체가 전문 해커들에게는 거의 사용되지 않습니다. 물론 사용하는 해커가 있다면 그건 B급 해커겠죠. 그리고 그런 B급 해커가 조작하는 것들은 인터페이스를 받지 않아도 다 차단할 수 있답니다. 그러라고 비싼 돈주고 솔루션 사서 쓰는 것 아니겠습니까?&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;게임보안 제품을 왜 사용하는 걸까요? 해킹툴을 막기 위함일겁니다. 그런데 요 근래에 몇몇 게임 업체와 미팅을 하면서 느낀 점은 보안 제품을 해킹툴을 막는 본연의 목적이 아니라 보안 제품한테서 컨설팅을 받고 계시더군요. 그것도 잘못된 보안 컨설팅을요. 그럴 때 마다 정말 안스러움을 느낀답니다.&lt;/p&gt;
&lt;p&gt;해킹툴을 막는 데에는 여러 수천가지 방법이 있습니다. 제가 생각하는 가장 상책은 개발사나 운영사 모두가 전혀 신경 쓸 필요가 없는 방법입니다. 중책은 개발사에서 뭔가 정보를 알려줘야 하는 방법이고, 가장 하책은 게임 업데이트를 보안 업체에 신고해야 하는 방법입니다. 왠만하면 상책을 사용하는 업체와 일을 하세요. 그게 여러분에게도 보안 업체에게도 정신 건강에 이롭습니다. 물론 저희도 과거에 ‘나는 보안이다’라면서 하책을 남발했던 경험이 있습니다. 결과는요? 상호 멘붕상태가 오더군요. 그 때 깨달았습니다. ‘아 진짜 이거 없이는 답이 없겠다 하는 경우를 제외하고는 절대로 하책을 써서는 안되겠다’라고 말이죠.&lt;/p&gt;
&lt;p&gt;다시 한 번 기억하세요. 여러분이 사용하는 솔루션은 해킹툴을 차단하기 위한 솔루션입니다. 게임의 보안 결함을 찾아서 나열해 주는 솔루션이 아니라는 이야기죠. 더 나아가서는 해킹툴 분석 보고서를 그럴듯하게 쓰는 솔루션도, 특허를 나열하는 솔루션도 아닙니다. 단지 여러분의 그 지긋지긋하게 골치아픈 해킹툴들을 알아서 잘 차단해 줄 솔루션을 선택하세요. 그럼 게임 내 보안 결함을 찾을 필요도, 해킹툴 분석 보고서를 쓸 필요도, 특허를 나열할 필요도 없거든요. 맞습니다. 카드를 쥐고 있는 한 여러분이 갑입니다. 이제는 갑의 권리를 다시 찾아 올 때 입니다. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_커플링에_관한_오해들.md_1.png&apos; data-alt=&apos;right now는 빼도 된다는 거 아시죵? ㅎㅎ~&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 612px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/725058a7a4527f814c8db6c709a82b67/dbf98/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%BB%A4%ED%94%8C%EB%A7%81%EC%97%90_%EA%B4%80%ED%95%9C_%EC%98%A4%ED%95%B4%EB%93%A4.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 13.684210526315791%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAYAAACTWi8uAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAkklEQVR42qWLORbCMAxEcw9IghfJduKKJpsbCMHH5QZU1NwIBmGOQDHvz/sjVV3XIcaIPvb49n8SQkDlnYcx5kHEzxA8rKW3NQRrGEweZH2h1hZGk3QnjuWOhU5+CSTu5x0qZkZd725KqTuzw3FsX/PWYFpbpKyxXDWSZDjvMZzq4ubtgOnSyqYwrk1hygpLVvgAU9VY0j5RKk0AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;right now는 빼도 된다는 거 아시죵? ㅎㅎ~&apos; title=&apos;&apos; src=&apos;/static/725058a7a4527f814c8db6c709a82b67/dbf98/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%BB%A4%ED%94%8C%EB%A7%81%EC%97%90_%EA%B4%80%ED%95%9C_%EC%98%A4%ED%95%B4%EB%93%A4.md_1.png&apos; srcset=&apos;/static/725058a7a4527f814c8db6c709a82b67/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%BB%A4%ED%94%8C%EB%A7%81%EC%97%90_%EA%B4%80%ED%95%9C_%EC%98%A4%ED%95%B4%EB%93%A4.md_1.png 190w,
/static/725058a7a4527f814c8db6c709a82b67/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%BB%A4%ED%94%8C%EB%A7%81%EC%97%90_%EA%B4%80%ED%95%9C_%EC%98%A4%ED%95%B4%EB%93%A4.md_1.png 380w,
/static/725058a7a4527f814c8db6c709a82b67/dbf98/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%BB%A4%ED%94%8C%EB%A7%81%EC%97%90_%EA%B4%80%ED%95%9C_%EC%98%A4%ED%95%B4%EB%93%A4.md_1.png 612w&apos; sizes=&apos;(max-width: 612px) 100vw, 612px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;right now는 빼도 된다는 거 아시죵? ㅎㅎ~&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 게임 보안: 인력에 관한 불편한 진실…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/6174</link><guid isPermaLink="false">https://jiniya.net/wp/archives/6174</guid><pubDate>Mon, 23 Apr 2012 23:58:04 GMT</pubDate><content:encoded>&lt;p&gt;국내 게임보안 업체 중에서 &lt;a href=&quot;http://wellbia.com/&quot;&gt;우리 회사&lt;/a&gt;가 가장 영세하다. 가장 후발 주자다. 그러다보니 업체 미팅을 하다보면 으례 듣는 이야기가 있다. 그 인력을 가지고 지원이 되겠냐는 이야기다. 그런데 아이러니한 사실은 그렇게 이야기 했던 많은 업체들이 사용하고 난 다음에는 지원이 참 좋다는 이야기를 한다. 해킹툴을 잘 잡는다는 이야기도 한다. 왜 그럴까?&lt;/p&gt;
&lt;p&gt;여기에는 게임 업체에서는 전혀 생각하지 못하는 정말 불편한 진실이 숨어있기 때문이다. 바로 MPS다. MPS가 뭐냐고? Man Per Site다. 사이트당 몇 명의 인력이 대응하는지를 나타내는 수치라고 생각하면 되겠다. 과연 이 수치가 얼마일까? 1정도는 될까? 당연히 안된다. 1이면 게임보안 업체는 아마 한 십년 전에 모두 망했을 것이다. 그렇다면 어느 정도일까? 여러분이 생각하는 것보다 훨씬 낮다. 0.1이 되는 업체가 잘 없다. 즉, 게임 10개 사이트에 한 명이 채 되지 않는다는 말이다. 반대로 말하면 한 사람이 열 개 이상의 사이트를 커버해야 한다는 말이다. 이러니 무슨 보안이되고 무슨 해킹툴 컨트롤이 되겠는가? 당연히 되지 않을 수 밖에 없다. 메이저 업체들이 그렇게 해킹툴을 못막는 이유가 바로 여기 있는 것이다. 관심이 없어서가 아니다. 사람이 없는데 무슨 수로 해킹툴을 막겠는가? 당연히 우리는 0.1은 넘는다. 아직까지는. 그러니 다른 업체보다는 잘 할 수 밖에 없는 것이다.&lt;/p&gt;
&lt;p&gt;그렇다면 이 MPS 수치가 어느 정도면 해킹툴 제어가 가능할까? 내가 생각하는 최소 수치는 0.57이다. 무슨 근거로 그런 이야기를 하느냐고? 바로 4명이서 7개 사이트를 커버하는 수준이다. 그렇다면 그 4명과 7개 사이트는 어디서 나왔을까? 우선 해킹툴이 출몰하는 정도로 인기있는 온라인 게임의 경우 통상 수출하면 7개국 정도는 깔고 가는 경우가 많다. 따라서 7개 사이트라는 말은 하나의 게임을 4명이서 컨트롤 한다는 말과 동일하다. 그렇다면 4명은 어떤 사람일까? 검색 한명, 분석 한명, 개발 한명, QA 한명이다. 이걸로 될까? 뻥안치고 저정도 인력 투입하면 거의 모든 해킹툴 사이트를 다 다운시킬 수 있다. 물론 기반 시스템은 모두 갖추어져 있다는 전제 하에서다. 기반 시스템 없이 4명이서 무얼 하겠는가? 또 물론 그 4명이 겁나 똑똑하다는 전제하에서다.&lt;/p&gt;
&lt;p&gt;그런데 정말 안타까운 현실은 많은 게임 업체들이 해킹툴 차단에 관심은 많다고 하지만 MPS 0.57에 대한 투자 조차도 인색한 경우가 많다. 국내 게임보안 업체들은 모두 연간 구독(annual subscription) 형태로 제품을 판매한다. 그런데 이 구독료가 십년 전이나 지금이나 별반 차이가 없기 때문이다. 지금 시세로 따져보면 그 일년 구독료가 통상 MPS 0.1에서 0.2 사이다. 그러니 회사 입장에서 차떼고 포떼고 하면 MPS 0.1 이상 투입하기가 힘든 것이다. 흙. 상황이 이러면 메이저 게임보안 업체에서라도 인식을 바꾸도록 테이블을 새로 구성해야 함에도 현실은 그렇지가 못하다. 같이 치킨 게임을 하는 경우가 다반사다. 이러니 게임보안 제품이 좋아지고 싶어도 좋아질 수가 없는 환경인 것이다.&lt;/p&gt;
&lt;p&gt;자자. 여기저기서 웅성 거리는 소리가 들려오는 것 같다. 맞다. 규모의 경제가 있다. 일정 규모를 넘어서면 깔고가는 인력이 당연히 생기게 마련이다. 하지만 그 깔고가는 수많은 인력 중에서 여러분의 게임 게시판 내지는 해킹툴 포럼을 모니터링해주는 인력이 있다고 생각하면 정말 큰 오산이다. 안한다. 왜냐고? 그 깔고가는 수많은 인력은 말 그대로 공유인력이기 때문이다. 그들은 그런 일외에도 할 일이 너무도 많기 때문이다. 그러면 스스로 알아서 한 번은 하지 않을까? 라고 생각할 수도 있는데. 뻥안치고 안한다. 사람이기 때문이다. 잠깐 짬나면 나가서 담배펴야지 그거 모니터링 하겠는가? 난 다른 일도 많이 했는데, 라고 생각하면서 신나게 나가서 담배피게 돼 있다. 그러니 공유인력을 계산에 넣는다는 자체가 넌센스다.&lt;/p&gt;
&lt;p&gt;그러면 다음으로 나오는 이야기들이 있다. 기술을 개발해서 원천 차단을 하면 되지 않겠냐는 것이다. 근데 이게 진짜 정말 골때리는 이야기다. 아니면 게임 업체들이 하는 오해일 수도 있겠다. 그런 오해를 하는 많은 분들을 위해서 조금 원천차단이라는 말의 실제 의미를 풀이해보자면 이렇다. 모든 게임보안 업체에서 말하는 원천차단이라는 말은 Visual C++을 일주일 배우고 나서 해킹툴 커뮤니티에서 소스를 퍼다가 변수 오프셋을 조금 수정해서 해킹툴을 만드는 경우에 대한 대응을 자동으로 할 수 있는 기술이라고 이해하면 되겠다. 물론 어러분도 잘 알고 있는 것처럼 안타깝지만 이것 조차도 잘 안되는 경우도 많이 있긴 하다. 그러니 어떤 업체와 미팅을 하는데 원천차단에 대해서 이야기를 한다면 ‘아 이건 코흘리게들을 막는 기술인데 다른 업체는 이것도 안되나 보구나’라고 이해하면 되겠다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_인력에_관한_불편한_진실.md_0.png&apos; data-alt=&apos;저 수많은 초록색 Undetected!!! 현기증이 ㅠㅜ~&lt;br&gt;&lt;br&gt;하지만 MPS 0.57에 좋은 게임보안 제품을 사용한다면 저 목록에서 빠지는 것도 불가능 한 일은 아니다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 516px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/1eef6f027671f48dedadc1efbde41bc2/fbb32/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 48.42105263157895%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABz0lEQVR42kWLa2+bMBSG+TipkbYFGIECxjaXJMXcCbmAwU4w6XVat2qTpqr//18Msk6TXj1+z3OOpe8v7d1Lc3zt+t9MvLXd10eEA2BpCBge1F3HGMuNp3twHA3sGI6t+2j0+jqAUpi7fuUB6sN6iWgQbHcksFb2hxDOUvdq7VytwZSVM1vaM4JmS3Dl27PR74kiadj8Etjy0lF9rKygTQobuJb2GZuqZylAU01NxWCkYi0UbCj2QgULFepK5FmSBpHmYx0G12g1BkXVrl6RzacwXiSlVp7mVS3vHblkSlHqOZVJJVcnJW3meW1KBvDHPyZeW15kudGybJ++Jc3Dx/3BFPfX57f5w7P8Y63c/lLOt6D/OaeP8t2rzJ/n7MmUaMu6jrFj3zHe8Z73gzgPYuiFOA1jEcfzMIjjaZS9OAohhn+r04lLbVNUe9J25XYX12122Ke7OqZ1PklabHaEtkWxiS6r5NCkzSHdHuKW5ml1IxUJDIm/Kdww9MoCR8TPczdL/Dj1yswNI29TumQ6wHHsl8W0yjK3zDySYAkACyOEEUQIYuhMvHQE34MnMwrnL9FEONFxJEop55wxziayqfwne++cd5enmyZ+Ae869gfuT22dhUcVlgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;저 수많은 초록색 Undetected!!! 현기증이 ㅠㅜ~&lt;br&gt;&lt;br&gt;하지만 MPS 0.57에 좋은 게임보안 제품을 사용한다면 저 목록에서 빠지는 것도 불가능 한 일은 아니다.&apos; title=&apos;&apos; src=&apos;/static/1eef6f027671f48dedadc1efbde41bc2/fbb32/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_0.png&apos; srcset=&apos;/static/1eef6f027671f48dedadc1efbde41bc2/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_0.png 190w,
/static/1eef6f027671f48dedadc1efbde41bc2/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_0.png 380w,
/static/1eef6f027671f48dedadc1efbde41bc2/fbb32/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_0.png 516w&apos; sizes=&apos;(max-width: 516px) 100vw, 516px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;저 수많은 초록색 Undetected!!! 현기증이 ㅠㅜ~&lt;br&gt;&lt;br&gt;하지만 MPS 0.57에 좋은 게임보안 제품을 사용한다면 저 목록에서 빠지는 것도 불가능 한 일은 아니다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;그럼 게임 업체들을 고민에 빠뜨리는 진짜 해킹툴들은 어떤 것들일까? 저런 꼬맹이들이 코흘리면서 만드는 장난감일까? 당연히 아니다. 게임 업체를 고민에 빠뜨리고, 게임 서비스 자체를 종료시키게 만드는 유료핵들은 수년간 Visual C++을 갈고 닦았고 (&amp;#x3C;== 해킹툴 소스가 더럽다고 생각하면 오산이다.) 어셈블리에도 능통하면서, 리버싱도 잘하는 그런 애들이 알바해서 돈을 벌려고 만드는 것들이다. 물론 심한 경우에는 기업에서 하는 경우도 있다. 심지어는 보안회사, 게임회사보다 그 기업이 더 클 수도 있다. 여기에다 원천 차단이란 말을 쓴다는 건 내년까지 단 한번도 비가 오지 않을 거라는 걸 보장하는 것과 주식이 5000까지 쭉 갈거라는 걸 보장하는 것과 똑같은 의미다. 미래에 일어날 일에 대한 보장이란 것이다. 당연히 말도 안되는 소리라는 것을 알 수 있다. 여기엔 원천 차단이란 있을 수도 없고, 그런 말을 쓰는 것도 넌센스다.&lt;/p&gt;
&lt;p&gt;그렇다면 무슨 차이가 있는가? 단지 해킹툴이 나왔을 때 얼마나 신속하고 정확하게 대응하느냐의 차이 밖에는 없다. 당연히 여기서 대응한다는 말은 그 지겹도록 매일 올라와 있는 초록색 Undetected라는 말을 적어도 이틀 이상은 빨간색 Detected라는 말로 바꾸는 경우를 말한다. 이 정도 억제력을 우습게 생각할 수 있다. 그렇다면 여러분이 사용하는 보안 제품 업데이트 이후에 해킹툴 페이지를 꼭 방문해 보길 바란다. 그러면 이 이틀이란 시간이 얼마나 영겁의 시간인지를 금방 알 수 있을 것이다. 물론 여러분이 선택한 보안 제품이 진짜 탁월하다면 그 목록에서 여러분의 게임이 영원히 제거되는 기적을 경험케 해 줄 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_인력에_관한_불편한_진실.md_1.png&apos; data-alt=&apos;누구나 공정한 게임을 하고 싶어한다. 그래야 재미있기 때문이다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 418px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/980d3ee10e7cc499c7a2c22254cf750f/2bbac/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 26.31578947368421%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAIAAADKYVtkAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAArklEQVR42n2PzQqDMBCE8/4P5qW9iFSsgtGDRARR87tmE+020lNpv8MwDMMsy/w4urqGrvNCAOf28dD3mykKXNag9YF4Jo4vKGRxWVye+77HYYC2hbI0WeabJiodrT1COH/DfAiAaAB270OMDkA7p6y1jizsCWOM1lopRUpeJRCRzfPccc7blnSaJtJnVQkhtk0qKa0xV1tKua7rRmkyBI2ya5guUSM130fw8+p/Xp4LHlG71S0LAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;누구나 공정한 게임을 하고 싶어한다. 그래야 재미있기 때문이다.&apos; title=&apos;&apos; src=&apos;/static/980d3ee10e7cc499c7a2c22254cf750f/2bbac/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_1.png&apos; srcset=&apos;/static/980d3ee10e7cc499c7a2c22254cf750f/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_1.png 190w,
/static/980d3ee10e7cc499c7a2c22254cf750f/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_1.png 380w,
/static/980d3ee10e7cc499c7a2c22254cf750f/2bbac/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_1.png 418w&apos; sizes=&apos;(max-width: 418px) 100vw, 418px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;누구나 공정한 게임을 하고 싶어한다. 그래야 재미있기 때문이다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;게임 시장은 점점 더 커져가고 있다. 당연히 이러한 블랙마켓도 점점 커지고 있다. 더불어 요즘 온라인 게임의 출시에는 항상 이런 질문이 따라 다닌다. 안티 치트 솔루션은 무엇을 사용하는가? 치트 대책은 무엇인가? 이런 것들이 이제는 일반화 됐다는 이야기고 또 온라인 게임에 있어서는 굉장히 중요한 이슈라는 의미일 것이다. 자 이제 결론을 내려보자. 그렇다. 회사에 직원이 많다는 이야기가 여러분의 게임에 관심을 가지는 사람이 많다는 것을 의미하는 건 아니다. 또 해킹툴을 더 잘 막고 관리하기 위해서는 MPS 0.57이라는 최소한의 투자는 이루어져야 한다. 이런 것들이 이루어진다면 클린한 온라인 게임 환경을 만드는 일이 결코 불가능한 일은 아니다.&lt;/p&gt;
&lt;p&gt;아직 이 모든 이야기의 맥락을 눈치채지 못한 분들을 위해서 딱 한 마디만 더 하자면, ㅋㅋ~&lt;/p&gt;
&lt;p&gt;게임보안 하면 &lt;a href=&quot;http://wellbia.com&quot;&gt;XIGNCODE, XIGNCODE&lt;/a&gt;하면 게임보안이라는 거. 답 딱 나온다. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 569px; margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_인력에_관한_불편한_진실.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f1a1d39632ad98f8e1568aa605ea97e5/7ca0c/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 20.52631578947369%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAnklEQVR42iWPCw7DIAxDe46qUiFh4w9pKLv/0eZSC0WQWH5hI+KcS4oJJy7lnFFLKajee0wLDAntmpdCCLlUsnYLIY4lEVEdrXWRa96ztaaX6vVo6N17H+PGFE/YYkzmPLev97XWF4gLCDFEJIIJ4AMBpTbvw7sCtGzpOI6H/JsTcSJ9KDaYfcUjy1pLRM45fM0xG2OImYk/aDHv+/4Hdw8oAITqu48AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                    md 2&apos; title=&apos;&apos; src=&apos;/static/f1a1d39632ad98f8e1568aa605ea97e5/7ca0c/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_2.png&apos; srcset=&apos;/static/f1a1d39632ad98f8e1568aa605ea97e5/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_2.png 190w,
/static/f1a1d39632ad98f8e1568aa605ea97e5/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_2.png 380w,
/static/f1a1d39632ad98f8e1568aa605ea97e5/7ca0c/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_2.png 569w&apos; sizes=&apos;(max-width: 569px) 100vw, 569px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 562px; margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_인력에_관한_불편한_진실.md_3.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a54dc3484f0f7f9bebb83bfcb31aebfd/a4f00/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 6.315789473684211%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAABCAIAAABR8BlyAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAANUlEQVR42mMwN7ewsrLS1dXV09XRhQF9PX0dHV0DAwM9PT1dPT0DfRBDSxsEIFLGJibq6uoAVFYK55RK46IAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                    md 3&apos; title=&apos;&apos; src=&apos;/static/a54dc3484f0f7f9bebb83bfcb31aebfd/a4f00/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_3.png&apos; srcset=&apos;/static/a54dc3484f0f7f9bebb83bfcb31aebfd/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_3.png 190w,
/static/a54dc3484f0f7f9bebb83bfcb31aebfd/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_3.png 380w,
/static/a54dc3484f0f7f9bebb83bfcb31aebfd/a4f00/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_3.png 562w&apos; sizes=&apos;(max-width: 562px) 100vw, 562px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 620px; margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_인력에_관한_불편한_진실.md_4.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/2533ab7b4ef612cd6c6379b0d64a2bab/abf7b/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 5.263157894736842%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAABCAIAAABR8BlyAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAMklEQVR42g2KQQoAMAzC9v9nNrb2tH1hoiiEHIGk9WZbnU6SlyhshwAhHndP9AhU3fs+Y9s1tm5BT34AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                    md 4&apos; title=&apos;&apos; src=&apos;/static/2533ab7b4ef612cd6c6379b0d64a2bab/abf7b/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_4.png&apos; srcset=&apos;/static/2533ab7b4ef612cd6c6379b0d64a2bab/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_4.png 190w,
/static/2533ab7b4ef612cd6c6379b0d64a2bab/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_4.png 380w,
/static/2533ab7b4ef612cd6c6379b0d64a2bab/abf7b/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_4.png 620w&apos; sizes=&apos;(max-width: 620px) 100vw, 620px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_인력에_관한_불편한_진실.md_5.jpg&apos; data-alt=&apos;고기도 먹어 본 놈이 잘 먹고, 연애도 해 본 놈이 잘 하고, 해킹툴도 막아 본 놈이 잘 막는다.&lt;br&gt;&lt;br&gt;우리는 최고의 팀을 가지고 있다. 그게 바로 우리가 이런 이야기를 들을 수 있는 이유다.&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 620px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/88ccc10b29aff0e767354c74152c9904/e28f5/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_5.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIDBf/EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAHRSjS3JCf/xAAZEAEBAQEBAQAAAAAAAAAAAAACAQMRAAT/2gAIAQEAAQUC2XdvoqEF6NYUoTr7Fyj/xAAVEQEBAAAAAAAAAAAAAAAAAAAQIf/aAAgBAwEBPwGH/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAHRAAAgIBBQAAAAAAAAAAAAAAAAECESEiUmGBof/aAAgBAQAGPwKEOxO82JnhJtcFbdJ//8QAHBABAAMBAAMBAAAAAAAAAAAAAQARITFBUWFx/9oACAEBAAE/If0PUMABh8sa6uy4EXEdfYSn2t9lGPds9T//2gAMAwEAAgADAAAAEA//AP/EABYRAQEBAAAAAAAAAAAAAAAAAAEAEf/aAAgBAwEBPxARjN//xAAWEQEBAQAAAAAAAAAAAAAAAAABADH/2gAIAQIBAT8QRYy//8QAHRABAAMAAgMBAAAAAAAAAAAAAQARITFBcZGhwf/aAAgBAQABPxCn8KtKaXX7kdpQJwec6Ir7DTMGAzbtvzZdLWSqAOSvKxZfVQQL29VP/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;고기도 먹어 본 놈이 잘 먹고, 연애도 해 본 놈이 잘 하고, 해킹툴도 막아 본 놈이 잘 막는다.&lt;br&gt;&lt;br&gt;우리는 최고의 팀을 가지고 있다. 그게 바로 우리가 이런 이야기를 들을 수 있는 이유다.&apos; title=&apos;&apos; src=&apos;/static/88ccc10b29aff0e767354c74152c9904/e28f5/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_5.jpg&apos; srcset=&apos;/static/88ccc10b29aff0e767354c74152c9904/8ccab/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_5.jpg 190w,
/static/88ccc10b29aff0e767354c74152c9904/ea4c8/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_5.jpg 380w,
/static/88ccc10b29aff0e767354c74152c9904/e28f5/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EC%9D%B8%EB%A0%A5%EC%97%90_%EA%B4%80%ED%95%9C_%EB%B6%88%ED%8E%B8%ED%95%9C_%EC%A7%84%EC%8B%A4.md_5.jpg 620w&apos; sizes=&apos;(max-width: 620px) 100vw, 620px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;고기도 먹어 본 놈이 잘 먹고, 연애도 해 본 놈이 잘 하고, 해킹툴도 막아 본 놈이 잘 막는다.&lt;br&gt;&lt;br&gt;우리는 최고의 팀을 가지고 있다. 그게 바로 우리가 이런 이야기를 들을 수 있는 이유다.&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[클라우드 서비스!!! 과연 저렴할까?]]></title><description><![CDATA[CBT가 시작하던 날이었다. 날씨도 꿉꿉하던 그 날. 기어이 사고가 터졌다. 회사 홈페이지와 메일 서버를 운영하는 서버에 이상이 생긴 것이다. 멀쩡하다가 접속이 안돼서 IDC…]]></description><link>https://jiniya.net/wp/archives/6103</link><guid isPermaLink="false">https://jiniya.net/wp/archives/6103</guid><pubDate>Sat, 21 Apr 2012 23:58:03 GMT</pubDate><content:encoded>&lt;p&gt;CBT가 시작하던 날이었다. 날씨도 꿉꿉하던 그 날. 기어이 사고가 터졌다. 회사 홈페이지와 메일 서버를 운영하는 서버에 이상이 생긴 것이다. 멀쩡하다가 접속이 안돼서 IDC에 전화해서 재부팅을 요청했다. 소식이 없길래 재차 전화했더니 하드가 나갔다는 것이었다. 물론 그 사이에 IDC에서 무슨 일이 있었는지는 아무도 모른다. 단지 하드가 노후해서 맛이 갔다는 이야기. IDC를 찾아갔다. 겉은 멀쩡해 보이는 SATA 하드디스크를 가져오면서도 내심 우리 PC에 연결하면 잘 될 거란 생각을 했다. 하드디스크가 고장 난다니 설마? 설마? 했다. 그랬는데 그 하드는 진짜 맛탱이가 갔다. 부팅을 시키려고 하자 끼릭끼릭 거리며 고주파 음을 울리며 우리를 나락으로 보냈다. 남자라면 백업을 하지 않는다는 토발즈의 말을 철썩 같이 믿었기에 우리에겐 어떠한 데이터도 없었다. 운영중인 서비스는 회사 홈페이지에 FAQ 페이지뿐이라 천만 다행이었다. IDC 직원이 그랬다. 서버도 하드웨어에 신경을 써야 한다고. 멀쩡하다고 하더라도 3-4년에 한번씩 서버 업그레이드도 하고 아니면 하드는 반드시 교체해 주는 것이 좋다고 말이다. 그렇겠지.&lt;/p&gt;
&lt;p&gt;그날의 일을 교훈 삼아서 클라우드 서비스를 찾아보기 시작했다. 서버 관리할 사람도 없는데 서버 하드웨어까지 신경 쓸 필요는 없지 않을까라는 생각에서였다. 예전부터 구글 앱엔진 이야기를 많이 들어서 살펴봤는데 우리 목적에 쓸만한 서비스는 아니었다. 거기다 앱엔진 홈페이지는 온통 불투명한 사항뿐이었다. 뭔가 고객들에게 제품을 파는 사이트가 아니라 개발자 놀이터를 만들어 놓은 느낌이었다. 그래서 접었다. 그리고 이후 가장 많은 클라우드 서비스를 운영한다는 아마존을 찾았다. AWS 계정을 만들고 접속했다. 이거다. 무엇이 어떻게 진행되는지 명확했고 내가 무엇을 사용할 수 있고 돈은 얼마가 지불되는지 확실했다. 직관적이었고 쓰기 편했다.&lt;/p&gt;
&lt;p&gt;그러면서 나는 막연하게 서버를 직접 운영하는 것보단 아마존이 응당 쌀것이라 생각했다.&lt;/p&gt;
&lt;p&gt;그런데 그건 정말 오해였다. 진짜로.&lt;/p&gt;
&lt;p&gt;우선 기존 서버를 살펴보자. 서버를 임대하는 비용은 얼마일까? 공짜다. 요즘은 회선 비용만 주면 공짜로 주는 서버도 많기 때문이다. 우리가 사용하는 서비스에는 공짜 서버를 써도 전혀 지장이 없었다. 지출하는 비용은 IDC 회선 비용. 10Mbps에 대한 10만원이 전부다. 10Mbps 회선이면 얼마를 전송할 수 있을까? 초당 1.25메가 바이트, 분당 75메가바이트, 시간당 4.5기가바이트, 하루당 108기가 바이트를 전송할 수 있다. 그닥 나쁘진 않다.&lt;/p&gt;
&lt;p&gt;그럼 이제 아마존 클라우드 서비스를 생각해보자. 난 처음에 멋모르고 서비스할 지역이 싱가폴이랑 가까워 싱가폴에 서버를 만들었다. 기존에 우리가 가진 공짜 물리 하드웨어와 유사한 성능을 가진 인스턴스는 m1.xlarge였다. 그거보다 낮은 단계의 인스턴스는 모두 서비스가 불가능할 정도로 성능이 나빴다. 그 인스턴스는 시간당 무려 0.45달러가 들어간다. 이게 참 웃긴데 이렇게 보면 굉장히 싸 보이는데 곱하기를 하면 장난이 아니다. 해볼까? 0.45*24*30 = 324달러가 나온다. 한 달에 서버 비용으로만 33만원 가량을 지출해야 한다는 의미다. 물론 m1.xlarge가 기존의 공짜 서버 보다는 좋을 것이다. 그러리라 굳게 믿는다. 하지만 가격은 여기서 끝이 아니다. 데이터 요금이 추가되기 때문이다. 아마존 클라우드 서비스는 밴드 기준이 아니라 트래픽 기준으로 과금을 한다. 싱가폴 지역의 데이터 요금은 10TB까지 기가바이트당 0.19달러다. 역시 싸 보인다. 그런데 우리는 어제 하루 서비스를 오픈했는데 벌써 30기가 바이트를 사용했다. 0.19*30=5.7달러, 6-7천원 가량을 썼다는 의미다. 30을 곱하면 재미있어진다. 171달러가 된다. 자 이제 우리가 한 달에 아마존에 상납해야 하는 비용을 계산해보면 인스턴스 비용과 데이터 비용만 합해도 무려 495달러가 나온다. 50만원 가량이다. 기존 서버보다 5배나 많은 돈을 지불해야 한다는 의미다. 그런데 이게 끝이 아니다. IP비용, 하드디스크 비용, 무슨 비용, 무슨 비용… 서비스를 신청하면 당연한 이야기겠지만 모두 비용이다. 딱 보고 드는 느낌은 한솥도시락이다. 계란 후라이도 팔아먹는 그 느낌? ㅋㅋ~&lt;/p&gt;
&lt;p&gt;과연 싼 걸까? 우리가 아마존에서 서버를 운영하면서 누릴 수 있는 프리미엄은 두개 뿐이다. 하나는 250Mbps의 회선, 다른 하나는 하드웨어는 신경 꺼도 된다는 거. 물론 서버를 복사해서 바로 생성할 수 있는 이점도 있지만 직접 세팅하나 복사하나 별 차이는 없다. 단지 하드웨어에 신경을 쓰지 않기 위해서 한대당 40만원 가까운 추가 비용을 지출해야 하는 것이다. 과연 싼가? 글쎄다. 한대는 40만원, 두 대는 80만원, 세 대면 120만원 벌써 이쯤 되면 하드웨어 관리자를 고용하는 게 더 싸지 않을 까란 생각이 들기 시작한다. 클라우드 서비스는 결코 싸지 않다. 더욱이 우리처럼 밴드는 전혀 중요하지 않은 서비스는 더더욱 그렇다. 밴드가 중요한 서비스라면 다시 고려해볼 필요가 있다. 왜냐하면 글로벌 100Mbps 밴드가 가비아의 경우 월 800만원 정도 하기 때문이다. 250Mbps면 장난 아닌 밴드다. 물론 가비아는 데디 방식이라 아마존 보다는 좀 더 좋을 수도 있다.&lt;/p&gt;
&lt;p&gt;이런 모든 사항에도 불구하고 난 아마존을 쓰겠다. 난 아마존의 모든 클라우드 서비스가 필요하다는 사람들에게 하고 싶은 몇 가지 팁을 써보면 이렇다. 일단 절대 32비트 운영체제는 설치하지 말지어다. 확장이 불가능하다. 큰 걸 쓰던 작은 걸 쓰던 64비트를 써라. 그래야 나중에 쉽게 큰 걸로 바꿀 수 있다. 또한 윈도우도 절대 쓰지 말아야 한다. 훨씬 비싸다. 곱하기 하면 추가 비용이 장난이 아니다. 다른 한 가지는 절대 지역을 선택하지 마라. 가깝다고 일본, 동남아 서비스한다고 싱가폴 이랬다간 망한다. 왜냐하면 해당 지역이 결코 싸지 않기 때문이다. 가격 테이블보고 제일 싼 지역을 선택하는 것이 좋다. 내가 멋모르고 싱가폴에 서버를 세팅했다고 했는데 미쿡에 세팅했을 때와 비교하면 데이터 요금이 한 달에 7-8만원 차이 난다. 장난 아니다. 트래픽이 더 많으면 더 커진다. 그리고 진짜로 쓸 생각이 있다면 무조건 약정해야 한다. 그것만이 살 길이다.&lt;/p&gt;
&lt;p&gt;난 비용은 하나도 중요하지 않은데 서비스는 괜찮냐고 물어본다면 절대 그냥 아마존 쓰라고 강추해주고 싶다. 진짜 편하고 잘 돼 있다. 그 모든 것이. 국내 업체들이 아마존보다 속도도 빠르고 더 저렴한 서비스들을 내놓겠다고 한다. KT의 유클라우드도 그랬고, SKT도 상품을 준비한다고 한다. 나름 써 본 입장에서 비교해 보자면 비싸도 아마존이다. 안정성 및 검증은 둘째 치고라도 웹 인터페이스만 봐도 진짜 애와 어른이 아니라 세포 덩어리와 사람을 비교하는 수준으로 차이 난다. 나도 개발자지만 아마존 웹서비스를 사용하면서 느낀 건 진짜 토나올 정도로 잘만들어 놨다는 거다. 저런거 만든 개발자 한 명만 데려와도 울 웹 서비스도 진짜 뽀대날 거 같은 느낌. 근데 이랬든 저랬든 그 모든 게 다 결코 싸진 않다. 우리가 신경 쓰지 않아도 되고 편한 만큼 그 비용을 지불하고 있다는 거다. 세상에 절대로 네버 공짜 점심은 없다. 진짜 이 글은 한 30만원 짜리는 되는것 같다. 왜냐하면 나는 이 모든 사실을 아마존에 한 30만원은 상납하고 배웠기 때문이다. 큭~&lt;/p&gt;
&lt;p&gt;멋도 모르고 로그 서버 주소를 죄다 변경했는데 월요일 다시 모두 롤백 업데이트를 해야 할 것 같다. 애꿎은 지원팀 식구들만 고생하게 생겼다. 헤드가 멍청하면 직원들이 고생한다는 말이 괜한 말이 아니다. 흙~&lt;/p&gt;
&lt;p&gt;끝으로 사족을 하나만 더 달자면 국내 서버 임대는 가비아가 좋다. 예전에 싸다고 닷네임코리아를 쓴 적이 있었는데 완전 왓더헬이었다. 전화도 안받고, 관리도 안되고 싼 게 비지떡이란 교훈을 그 때 깨달았다. 가비아는 항상 전화도 받았고, 우리 하드디스크가 맛탱이가 간 그 순간에도 우리가 가장 빠르게 서비스를 복구 할 수 있도록 도와 주었다. 괜히 코스닥 상장 업체가 아니다. 가비아를 안쓰더라도 절대로 닷네임코리아는 쓰지 말길 바란다. 이건 뭐. 헬이다. 헬게이트 ㅋ~&lt;/p&gt;
&lt;p&gt; 10
 34&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[스레드 개념과 원리]]></title><description><![CDATA[컴퓨터에서 무엇인가를 동시에 실행시킨다는 개념은 초창기부터 있었다. 실제로 1970년대 유닉스 구현에는 이미 멀티태스킹이라는 개념이 포함되어 있었다. 하지만 이런 방식이 범용적으로 사용되기 까지는 오랜 시간이 걸렸다. 1995년 Windows 9…]]></description><link>https://jiniya.net/wp/archives/5856</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5856</guid><pubDate>Tue, 20 Mar 2012 23:58:02 GMT</pubDate><content:encoded>&lt;p&gt;컴퓨터에서 무엇인가를 동시에 실행시킨다는 개념은 초창기부터 있었다. 실제로 1970년대 유닉스 구현에는 이미 멀티태스킹이라는 개념이 포함되어 있었다. 하지만 이런 방식이 범용적으로 사용되기 까지는 오랜 시간이 걸렸다. 1995년 Windows 95가 나오기까지 PC 운영체제를 거의 독점했던 DOS 시절에는 한번에 하나의 프로그램이 실행되는 것이 상식이었고, 다른 프로그램과 동시에 실행되는 프로그램을 만드는 것이 대단한 테크닉으로 취급 받았다. Windows 3.1의 등장과 함께 멀티태스킹이란 개념이 일반인들에게 본격적으로 소개되었다. Windows 3.1은 DOS 위에서 구동되는 프로그램이었지만 여러모로 현재 Windows의 기틀을 다진 운영체제였다. 비선점형 멀티태스킹 방식을 지원했고 현재 사용되는 GUI의 기본 개념을 소개한 운영체제였다. 이런 시기를 거쳐 Windows 95가 등장하면서 DOS 시절에 굳어졌던 일반인들의 상식은 완전히 뒤집혔다. 이제 프로그램은 원래 당연히 동시에 실행되는 것이고, 운영체제에서 멀티태스킹이란 당연히 지원해야 되는 기능이 돼버렸다. Windows 95의 선점형 멀티태스킹은 일반인들에게 그런 인식을 심어주기에 충분했다.&lt;/p&gt;
&lt;p&gt;하지만 모든 일이 항상 좋은 점만 있는 것은 아니다. 일반인들에게 당연한 기능 내지는 축복이 시선을 달리해서 개발자의 입장으로 바라보면 재앙과도 같기 때문이다. 단순히 동시에 실행된다는 사실 만으로는 그렇게 많은 문제가 발생하진 않지만 동시 상황에서 무엇인가를 공유하기 시작하면 지옥 문을 여는 것과 동일한 효과를 가져온다. 단순히 하나만 공유해도 이런데 프로세스 내에서 모든 자원을 공유하는 스레드는 문제 발생의 정도가 더 심각하다. 이런 환경은 개발자에게 엄청나게 많은 문제들을 안겨주었고, 더불어 기존에는 고민할 필요도 없었던 문제들에 대해서 고려하도록 만들었다. 그리고 이 시점부터 더 이상 프로그램은 결정론적으로 동작하지 않게 되었다. 이는 달리 표현하면 재현 불가능한 무수한 버그들이 스레드라는 판도라의 상자를 통해서 세상으로 출현했다는 것이다.&lt;/p&gt;
&lt;p&gt;이런 여러 이유로 멀티 스레드 프로그래밍은 윈도우 프로그래밍 중에서도 매우 어려운 부분에 속한다. 그럼에도 점점 더 PC의 코어 수는 늘어가고 멀티 스레드 프로그래밍은 점점 더 당연한 일이 되어가고 있다. 왜 멀티 스레드 프로그래밍이 어려운 것일까? 아마도 우리의 생각 자체가 병렬적으로 동시 처리하는 것에 익숙하지 않은 점에 그 근본적인 원인이 있을 것 같다. 이번 시간에는 컴퓨터에서 멀티태스킹을 구현하는 기본적인 구조와 멀티태스킹이 가져오는 동기화 문제에 대해서 살펴보도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;시분할&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;요즘은 CPU가 여러 개 달린 컴퓨터가 일반적이다. 스마트폰에도 듀얼 코어가 탑재되는 세상이니 PC는 두 말하면 잔소리다. 이렇게 CPU가 여러 개 달린 컴퓨터에서는 동시에 실행하는 것이 하나도 이상하지 않다. 장치 개수만큼 동시에 실행할 수 있는 것은 누가 봐도 당연한 일이기 때문이다. 하지만 Windows가 인기를 끌듯 말듯했던 Windows 3.1 시절부터 Windows XP가 등장하던 시점까지는 이러한 멀티 코어가 일반적인 PC 환경은 아니었다. 그 당시 컴퓨터에는 CPU가 하나라는 것이 거의 고정적이었던 시절이었다. 그렇다면 어떻게 이 CPU가 하나인 환경에서 여러 개의 프로그램을 동시에 실행할 수 있었던 것일까? 여기에는 약간의 눈속임이 있다.&lt;/p&gt;
&lt;p&gt;눈속임을 쉽게 이해하기 위해서 우리가 공부를 하는 과정에 비유를 들어서 먼저 살펴보도록 하자. 텅 빈 책상이 있고, 책상 앞 의자에 우리가 앉아 있는 상황이다. 책상에는 국어, 영어, 수학 문제집이 놓여 있다. 이 문제집을 다 푸는 것이 오늘 우리의 할 일이다. 이 미션을 달성하는 방법에는 크게 두 가지 전략이 존재한다고 볼 수 있다. 하나는 국어 문제집을 다 풀고, 영어 문제집을 다 풀고, 수학 문제집을 다 푸는 형태로 순차적으로 하나씩 작업을 완료해 나가는 방식이고, 다른 하나는 국어, 영어, 수학 문제집을 번갈아 가면서 조금씩 풀어 나가는 방식이다. 멀티태스킹의 비밀은 바로 두 번째 방법에 있다. 문제집을 번갈아 가면서 푸는 상황에서 문제집을 교체하는 시간을 단축시키다 보면 어느 순간부터는 마치 우리가 세 개의 문제집을 동시에 풀고 있는 것처럼 느껴진다는 사실을 이용한 것이다.&lt;/p&gt;
&lt;p&gt;운영체제는 여러 개의 프로그램을 동시에 실행하기 위해서 우리가 문제집을 풀었던 것과 동일한 방식으로 CPU에 프로그램 코드를 할당한다. 탐색기, 계산기, 그림판이 실행되어 있다면 Windows는 탐색기 코드를 조금 실행하고 계산기 코드를 또 조금 실행하고 이어서 그림판 코드를 실행하고는 다시 탐색기 코드를 실행하는 식으로 동시에 실행된 프로그램의 코드들을 잘게 나누어서 반복적으로 실행함으로써 마치 우리 눈에는 여러 개의 프로그램이 동시에 실행되는 것처럼 보이도록 만든다.&lt;/p&gt;
&lt;p&gt;문제집을 번갈아 가면서 풀려면 문제집을 바꿀 때에 자신이 마지막으로 풀었던 문제가 어디인지를 기록해 두어야 한다. 그래야 나중에 다시 그 문제집을 풀 때에 어디서부터 풀어나가야 할지 기억할 수 있기 때문이다. 이렇게 마지막으로 풀었던 문제가 어떤 것이었는지를 기억하는 것과 마찬가지로 멀티태스킹에서도 이러한 것들이 필요하다. 작업을 이어가기 위해서는 중지했던 작업을 어디서부터 이어가야 할지를 알아야 하기 때문이다. 이렇게 작업을 이어가기 위해서 중단했던 시점의 기록을 “컨텍스트”, 작업들을 전환하는 것을 두고는 “컨텍스트 스위칭”이라고 표현한다.&lt;/p&gt;
&lt;p&gt;문제집을 번갈아 가면서 푼다는 이 방법을 좀 더 살펴보면 재미있는 현상이 있다. 문제집을 너무 띄엄띄엄 번갈아 풀 경우에는 세 개를 동시에 푼다는 느낌이 없어지고, 문제집을 자주 번갈아 풀다 보면 특정 시점 이상부터는 문제집을 푸는 시간보다 문제집을 바꾸는 시간이 더 많아진다는 점이다. 이는 시분할을 사용한 멀티태스킹 시스템에서는 모두 발생하는 문제로 컨텍스트 교체 비용이 공짜가 아니라는 점을 보여준다. 따라서 운영체제는 멀티태스킹의 품질과 교체 비용을 고려해서 작업 교체 빈도를 적절하게 결정할 필요가 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;협력형 vs 선점형&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;앞선 국영수 문제집 풀이 예를 다시 생각해 보자. 여기서 우리가 문제집을 번갈아 푼다고 생각했을 때 이를 통제하는 방식 또한 크게 두 가지 형태로 나뉠 수 있다. 문제집을 푸는 당사자가 자유롭게 일정시간 한 문제집을 풀다가 다음 문제집을 푸는 형태로 번갈아 가면서 푸는 방식이 있을 수 있고, 다른 하나는 선생님이 일정시간마다 들어와서 다음 문제집을 풀도록 지시하는 방법이 있을 수 있다.&lt;/p&gt;
&lt;p&gt;그렇다면 이 두 방식에는 각각 어떤 장단점들이 있을까? 우선 스스로 관리하는 방법을 생각해 보자. 이 방법의 장점은 효율성의 극대화에 있다. 문제를 푸는 당사자가 스스로 문제집을 교체하기 때문에 언제 교체하는 것이 가장 유리한지를 알 수 있다는 점이다. 다른 부가적인 장점으로는 선생님이라는 외부 존재가 필요하지 않다는 점을 들 수 있겠다. 이는 다시 말하면 비용이 절감된다는 말이다. 이에 반해서 두 번째 방법은 선생님이라는 추가 비용이 발생하지만 문제집 교체가 일정시간마다 반드시 발생하기 때문에 문제집 세 개에 할당되는 시간이 비슷해 진다. 멀티태스킹의 관점에서 보자면 일정 수준 이상으로 멀티태스킹 품질을 유지할 수 있다는 것을 의미한다.&lt;/p&gt;
&lt;p&gt;이게 바로 협력형과 선점형 멀티태스킹의 차이다. 협력형 멀티태스킹이란 멀티태스킹 작업들이 협력해서 동시에 실행되는 구조를 말한다. 프로그램 실행 중간에 스스로 컨텍스트 전환을 해도 되는 시점이라고 판단이 된다면 다음 작업에게 CPU를 양보해주는 형태로 멀티태스킹이 진행된다. Windows 3.1이 이러한 방식을 채택했었다. 하지만 앞서도 언급했듯이 이 방식의 단점은 특정 작업이 지나치게 오래 CPU를 독점할 경우 전체 멀티태스킹의 품질이 떨어질 수 있다는 점에 있다. 더욱 치명적인 문제는 특정 작업의 버그로 인해서 CPU 자원을 다른 작업에게 양보하지 않을 경구 운영체제 자체가 다운될 수 있다는 점이다.&lt;/p&gt;
&lt;p&gt;선점형 멀티태스킹이란 협력형과는 반대로 작업 제어 권한을 커널이 가지는 구조를 말한다. 이는 모든 작업이 임의의 시점에 커널에 의해서 선점될 수 있음을 의미한다. 선점된다는 말은 CPU 자원이 커널에게로 다시 넘어간다는 것이다. 여기에선 특정 작업이 CPU를 독점할 수도 없으며, CPU를 독점하려 한다고 해도 커널이 원하면 언제든지 CPU 제어권을 뺏어올 수 있다. 즉, 커널이 선생님의 역할을 한다고 할 수 있다. 이 방식의 장점은 앞에서도 설명한 것과 같이 안정적으로 멀티태스킹을 수행할 수 있으며, 작업들의 버그로 시스템다운이라는 치명적인 결과가 나타나진 않는다는 점이 있다. Windows 95 이후의 모든 Windows 운영체제는 이러한 선점형 멀티태스킹 방식으로 멀티태스킹을 구현하고 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;스레드&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;전통적으로 운영체제에서 작업이란 프로세스란 개념으로 표현된다. 따라서 운영체제는 앞서 설명한 것처럼 이런 프로세스를 동시에 여러 개 실행할 수 있도록 만들기 위해서 프로세스의 코드를 번갈아 가면서 수행한다. 이렇게 멀티태스킹 운영체제를 만들어놓고 보니 만들어진 프로세스들 중에는 다른 프로세스와 대규모의 자료를 공유해야 하는 것들이 있었다. 이런 프로세스들은 단순히 자료를 공유하기 위해서 운영체제의 IPC라는 복잡하고 비싼 메커니즘을 사용하고 있었다. 여기에서 이런 의문을 품은 사람들이 생겨난다. 왜 이렇게 멍청하게 하고 있지? 처음부터 모든 것을 자동으로 공유하도록 해준다면 어떨까? 이런 생각이 스레드라는 개념의 초기 발상이다. 많은 유닉스 운영체제는 이 개념의 생각대로 스레드를 특수한 형태의 프로세스로 처리한다. 실제로 리눅스의 경우에는 스레드라는 별도의 커널 객체를 두기 보다는 단순히 동일한 커널 구조체를 참조하는 특수한 프로세스로 구현했다.&lt;/p&gt;
&lt;p&gt;하지만 Windows는 이러한 방식이 아닌 좀 다른 방식으로 스레드와 프로세스의 관계를 정리했다. 일단 기존의 스케줄링 단위를 프로세스에서 스레드로 바꾸어 버렸고, 프로세스는 스레드가 수행될 때 참조하는 컨테이너 역할로 만들어버렸다. 이렇게 만들어버리자 Windows에서는 스레드가 없는 프로세스란 아무런 의미가 없어졌다. 그래서 Windows에서 모든 스레드 종료란 프로세스의 종료를 의미한다.&lt;/p&gt;
&lt;p&gt;다시 정리하면 이렇다. Windows 환경에서 프로세스란 실행 환경을 제공해주기 위한 컨테이너 역할을 한다. 여기에는 주소 공간과 접근 권한 같은 것들이 포함된다. 프로세스 자체로는 수행 가능한 객체가 아니며 내부에서 하나 이상의 스레드를 수행시킬 수 있는 환경에 불과하다. 스레드는 스케줄링의 기본 단위이며 하나의 실행 흐름을 나타낸다. 스레드는 수행되기 위해서는 해당 스레드가 수행될 프로세스 정보가 있어야 한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;동기화&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;스레드가 이야기가 나오면 기본 안주로 함께 등장하는 메뉴가 동기화 문제다. 왜 그럴까? 그 답을 알기 위해서는 “동기화란 무엇인가?” 라는 질문에 대한 답을 먼저 찾아야 한다. 동기화란 바로 코드가 실행되는 순서를 정하는 일을 말한다. 어떤 코드를 먼저 실행할지 어떤 코드를 나중에 실행할지 순서를 정하는 일이다. “프로그램은 항상 프로그래머가 정해둔 순서대로 실행되는 것 아닌가요?”라는 의문을 가질 수 있다. 맞다. 프로그램은 항상 프로그래머가 정해둔 순서대로 실행된다. 하나만 실행될 때에는 말이다. 하지만 동시에 실행되기 시작하면 문제가 달라진다. 개별 실행 흐름들은 기존과 마찬가지로 순차적으로 수행되지만 그 흐름들이 섞이면 전혀 생각지도 못한 문제를 발생시킨다. 이를 방지하기 위해서 섞여서 실행되는 코드들 사이에 순서를 정하는 일이 필요해진 것이다. 그래서 동기화 문제란 항상 동시성과 같이 나올 수 밖에 없다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;동시성 vs 병렬성&lt;/p&gt;
&lt;p&gt;비슷해 보이는 이 두 말은 큰 차이를 가지고 있다. 우선 동시성이란 우리에게 동시에 실행되는 것처럼 보이는 것들을 모두 나타내는 말이다. 따라서 단일 CPU 상에서 시분할 기법을 사용해서 여러 개의 프로그램을 수행하는 것도 동시성에는 포함된다. 반면 병렬성이란 복수의 CPU를 통해서 코드가 진짜 동시에 실행되는 상황을 나타낸다. 이런 의미에서 병렬성이란 물리적인 동시성을 나타낸다고 생각하면 되겠다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;#x3C;리스트 1&gt;에는 동기화 문제를 보여주는 간단한 코드가 나와 있다. PinGame 함수는 핀을 서로 하나씩 가져가면서 마지막 핀을 가져가는 사람이 이기는 게임을 묘사한 코드다. 이제 이 함수가 스레드로 여러 개가 동시에 실행된다고 가정해보자. 그러면 개별 스레드는 이 하나의 코드를 순차적으로 실행하겠지만 운영체제 관점에서 보자면 이 코드들이 섞여서 동시에 실행되는 셈이 된다. 이렇게 동시에 실행되면 하나만 실행될 때에는 전혀 생각지도 못했던 문제가 발생하는데 이렇게 동시에 실행되면서 발생하는 문제를 동기화 문제라고 말한다.&lt;/p&gt;
&lt;p&gt;우선 동기화 문제를 보다 효과적으로 설명하기 위해서 간단한 표현식을 정의하자. “(숫자)”는 숫자에 해당하는 스레드로 컨텍스트가 변경됐음을 나타낸다. a, b와 같은 기호는 코드 상의 주석에 나타나 있는 지점이 실행됐음을 의미한다. 따라서 “(1)ab”라는 것은 1번 스레드가 a, b라는 코드를 실행했음을 나타낸다. 마찬가지로 “(1)ab(2)a”라는 것은 1번 스레드가 a, b를 수행하고 2번 스레드로 컨텍스트 전환돼서 a라는 코드가 실행됐음을 나타낸다.&lt;/p&gt;
&lt;p&gt;리스트 1 동기화 문제를 가진 코드&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; pin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;PrintWinner&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;                                 &lt;span class=&quot;token comment&quot;&gt;// ... a&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pin &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                  &lt;span class=&quot;token comment&quot;&gt;// ... b&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;pin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;                    &lt;span class=&quot;token comment&quot;&gt;// ... c&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;you win\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;      &lt;span class=&quot;token comment&quot;&gt;// ... d&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;pin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;                    &lt;span class=&quot;token comment&quot;&gt;// ... e&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;자 그렇다면 앞서 정의한 표현식을 토대로 &amp;#x3C;리스트 1&gt;의 코드에서 동기화 문제가 발생하는 흐름을 찾아보도록 하자. 바로 “(1)abea(2)ab(1)bcd(2)cd”가 그것이다. 문제는 결국 “you win”이라는 문자열이 화면에 두 번 출력된다는 것이다. 이런 코드들을 보여주고 여기까지 설명하면 대부분의 학생들은 &amp;#x3C;리스트 1&gt;의 코드를 고침으로써 문제를 해결할 수 있다고 생각한다. 그리고는 거의 대부분 코드를 &amp;#x3C;리스트 2&gt;와 같이 고친다.&lt;/p&gt;
&lt;p&gt;리스트 2 동기화 문제를 가진 코드&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; pin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;PrintWinner&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pin &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;pin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;           &lt;span class=&quot;token comment&quot;&gt;// … a&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pin &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;     &lt;span class=&quot;token comment&quot;&gt;// … b&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;you win\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그렇다면 과연 &amp;#x3C;리스트 2&gt;의 코드는 문제가 없을까? 언뜻 보기에는 뭔가 좀 더 명확해 보여서 문제가 없어 보이지만 좀 깊이 생각해보면 &amp;#x3C;리스트 2&gt;의 코드도 문제가 생기는 흐름을 찾아낼 수 있다. “(1)a(2)abc(1)bc”가 그것이다. 이 코드는 동기화 문제가 어디에서 비롯되는지 보다 명확하게 보여준다. 바로 값의 변경과 비교 사이에 발생하는 컨텍스트 전환이다. 이 말은 pin의 값 변경과 0과 비교하는 부분이 하나의 덩어리로 뭉쳐서 연산이 되지 않고서는 절대로 이 문제를 해결할 수 없다는 걸 의미한다.&lt;/p&gt;
&lt;p&gt;여기까지 이야기하면 “if(--pin == 0)”과 같은 코드를 쓰면 된다고 생각하는 사람들이 있다. 하지만 “if(--pin == 0)”과 같은 표현식도 C언어 상으로는 한 줄로 표기되기 때문에 한번에 실행된다고 생각하기 쉽지만 컴파일러가 생성해낸 기계어는 &amp;#x3C;리스트 2&gt;의 코드와 마찬가지로 여러 개의 기계어로 구성되어 있기 때문에 실행하는 사이에 컨텍스트 스위칭이 발생할 수 있고, 최종 프로그램에서는 동일한 문제가 발생한다.&lt;/p&gt;
&lt;p&gt;이를 해결하기 위해서는 앞에서 우리가 내린 결론, 값의 변경과 비교가 한 덩어리가 되어서 실행되도록 만들어줄 어떤 도구가 필요하다. 이런 기능을 제공해주는 도구가 바로 운영체제에서 지원해주는 동기화 객체다. &amp;#x3C;리스트 3&gt;에는 이러한 도구 중 하나인 크리티컬 섹션을 사용해서 문제를 해결한 코드가 나와있다.&lt;/p&gt;
&lt;p&gt;리스트 3 크리티컬 섹션을 통한 동기화 문제 해결&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;CRITICAL_SECTION cs&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;EnterCriticalSection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;                   &lt;span class=&quot;token comment&quot;&gt;// … a&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;pin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;                                       &lt;span class=&quot;token comment&quot;&gt;// … b&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pin &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;                                 &lt;span class=&quot;token comment&quot;&gt;// … c&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;LeaveCriticalSection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;               &lt;span class=&quot;token comment&quot;&gt;// … d&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;you win\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;                      &lt;span class=&quot;token comment&quot;&gt;// … e&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;LeaveCriticalSection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;cs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;                   &lt;span class=&quot;token comment&quot;&gt;// … f&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;크리티컬 섹션은 해당 객체를 진입한 상태에서 다른 스레드가 다시 진입하지 못하도록 만드는 기능을 한다. “(1)a(2)”는 가능하지만 “(1)a(2)a”는 불가능하다는 말이다. “(1)a(2)(1)b(2)(1)c(2)”와 같이 1번 스레드가 a를 수행하고 나면 1번 스레드가 d를 수행하기 전까지 다른 스레드로의 컨텍스트 스위칭은 발생할 수 있지만 해당 스레드가 a를 수행 시키는 것은 불가능하다. 결국 실행 흐름의 입장에서는 중간 중간 잡음이 섞이긴 하지만 결과론적으로 b와 c가 항상 한번에 수행되는 것과 동일한 효과를 나타낸다.&lt;/p&gt;
&lt;p&gt;그렇다면 운영체제는 어떻게 이런 것들을 만들 수 있었을까? 운영체제가 만든 코드라고 하더라도 결국 CPU 상에서 동작하기는 우리가 만든 코드와 다를 수 없기 때문이다. EnterCriticalSection 내부에서도 언제든지 컨텍스트 전환이 발생할 수 있지 않을까? 당연한 이야기다. 이 문제를 해결하기 위해서는 크게 두 가지 종류의 해법이 있다. 하나는 운영체제 스케줄러를 특수하게 만들어서 EnterCriticalSection과 같은 함수의 수행 도중에는 절대로 컨텍스트 전환이 발생하지 않도록 만드는 것이다. 다른 하나는 보다 낮은 단계에서 값의 변경과 비교를 한번에 수행하는 연산을 사용하는 것이다. x86/64 계열의 CPU에는 이러한 목적을 위해서 cmpxchg라는 명령어를 제공한다. 비교와 변경을 한번에 수행하는 명령어다. Windows는 결국에는 이러한 명령어를 사용해서 동기화 객체를 구현한다. 이런 맥락에서 우리가 처음에 만든 프로그램도 cmpxchg라는 명령어를 사용하도록 만든다면 동기화 객체를 사용하지 않고도 문제를 해결할 수 있다.&lt;/p&gt;
&lt;p&gt;지금까지의 논의는 단일 CPU 상에서 동시에 실행되는 코드들에 대한 것이었다. 멀티코어가 되면 문제가 좀 더 복잡해진다. 멀티코어란 CPU가 두 개 이상인 시스템을 말한다. 이런 시스템에서는 진짜 동시 실행이 가능해진다. 이 말은 지금까지 논의했던 방식으로는 멀티코어 환경에서 문제를 해결할 수 없다는 것을 의미한다. 앞서 동기화 문제를 해결하는데 일등 공신이었던 cmpxchg라는 명령어를 생각해보자. n개의 CPU가 있다고 가정한다면 n개의 CPU에서 동시에 cmpxchg가 실행될 수 있다. 결국 문제를 해결하기 위해서는 cmpxchg라는 명령어가 n개의 CPU가 아닌 한번에 하나의 CPU에서만 실행될 수 있도록 만들어주는 메커니즘이 필요하다. x86/64 계열의 CPU에서는 lock이라는 접두어가 이런 역할을 한다. lock cmpxchg를 하면 해당 시점에는 한 녀석만 메모리에 접근하도록 만들어준다. 재미있는 사실은 동시성에서 비롯된 동기화 문제를 해결하기 위해서는 결국 동시에 실행되지 않는 무엇인가가 필요하다는 점이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;컨텍스트, 컨텍스트, 또 컨텍스트&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;스레드 이야기에는 필연적으로 다양한 종류의 컨텍스트라는 말이 등장한다. 의미는 다른데 이를 표현하는 말은 모두 컨텍스트이기 때문에 처음 접하는 개발자는 상당히 혼란스러울 수 있다. 여기에서 잠깐 이런 컨텍스트라는 말의 정체에 대해서 알아보고 넘어가도록 하자. 컨텍스트를 우리 말로 번역하면 문맥이라는 말이 된다. 문맥이란 무엇인가? 우리가 일상생활에서 접하게 되는 문맥이라는 말의 의미는 다음과 같은 간단한 대화 속에서 쉽게 파악할 수 있다.&lt;/p&gt;
&lt;p&gt;영희: 너 밥 먹었니?&lt;/p&gt;
&lt;p&gt;철수: 응. 먹었어.&lt;/p&gt;
&lt;p&gt;일반적으로 구두 표현은 상황을 통해 유추할 수 있는 정보는 대부분 삭제된다. 우리는 철수의 대답에는 포함되지 않았지만 상황을 통해 ‘먹었어’라는 말을 철수가 밥을 먹었다라는 사실로 자연스럽게 확장시킬 수 있다. 이렇게 유추의 근거를 제공하는 말이 놓인 상황을 우리는 문맥이라고 부른다. 프로그래밍에서 말하는 것 또한 이와 별반 다르지 않다. 일반적인 프로그래밍 환경에서 말하는 컨텍스트라는 말은 해당 코드가 바인딩되어 실행되는 환경을 일컫는다. 물론 이렇게 이야기를 하더라도 바인딩되어 실행되는 환경이라는 것이 무엇인지 감이 잡히지 않는다. 이를 좀 더 구체적으로 살펴보기 위해서 &amp;#x3C;리스트 4&gt;의 코드를 살펴보자.&lt;/p&gt;
&lt;p&gt;리스트 4 콜백 함수를 사용한 프로그램&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;std&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;list GlobalList&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Callback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    GlobalList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push_back&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetTickCount&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;RegisterCallback&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Callback&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;GlobalList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
       &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
           cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; GlobalList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;front&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
           GlobalList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;pop_front&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
       &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&amp;#x3C;리스트 4&gt;의 코드에서 RegisterCallback 함수는 입력으로 들어간 콜백 함수가 랜덤 주기로 호출되도록 등록하는 함수다. 만약 RegisterCallback 함수 설명에 ‘입력으로 들어온 콜백 함수는 등록한 스레드 컨텍스트에서 호출된다’라는 말이 있다면 위 코드는 아무런 문제 없이 동작한다. 하지만 이와는 다르게 ‘입력으로 들어온 콜백 함수는 시스템 스레드 컨텍스트에서 호출된다’는 말이 있다면 위 코드는 잘못 동작한다. 이유는 Callback이 호출되는 스레드와 main이 실행되는 스레드가 다르기 때문이다. 서로 다른 스레드가 GlobalList를 동시에 접근함에도 동기화 처리가 되어 있지 않기 때문에 최악의 경우에는 프로그램 크래시가 발생한다. 이와 같이 Callback이라는 코드가 바인딩되어 실행되는 스레드를 우리는 컨텍스트라는 말로 표현한다.&lt;/p&gt;
&lt;p&gt;여기서 더불어 살펴보아야 할 표현이 하나 있다. 바로 “임의의 스레드 컨텍스트”라는 표현이다. 대부분의 콜백 함수 설명에는 등록한 콜백 함수는 임의의 스레드 컨텍스트에서 호출된다라는 말이 있기 때문이다. 여기서 “임의의”라는 말은 정해지지 않았음을 나타내는 말이다. 그러니 “임의의 스레드 컨텍스트”라는 말은 달리 표현하면 “정해지지 않은 스레드 컨텍스트”가 된다. 그렇다면 도대체 정해지지 않은 스레드 컨텍스트라는 표현이 개발자에게 해주고 싶은 속내는 무엇이었을까? “정해지지 않았음”이 프로그래머에게 해주고 싶은 진짜 이야기는 이 말이다. “네 멋대로 특정 스레드 컨텍스트에서 호출된다고 생각하지 말아라. 이 코드는 네가 생각지도 못한 스레드 컨텍스트에서도 호출될 수 있다.”&lt;/p&gt;
&lt;p&gt;“해당 콜백 함수는 임의의 스레드 컨텍스트에서 호출된다”는 문장을 보는 순간 여러분이 베스트 개발자라면 다음과 같은 생각을 반드시 해야 한다. “아, 이 함수가 실행되는 스레드는 정해지지 않았구나. 콜백 함수가 전역 데이터에 접근하는 경우에는 반드시 동기화 처리를 해줘야 하겠구나.” 반대로 “해당 콜백 함수는 콜백을 등록한 스레드와 같은 컨텍스트에서 호출된다”는 문장을 보게 되면 역으로 콜백과 등록한 스레드에서만 사용하는 공유 데이터가 있다면 동기화 처리를 생략해서 최적화 작업을 할 수 있겠다라는 생각을 하는 것이 정석이다.&lt;/p&gt;
&lt;p&gt;지금까지 특정 함수가 수행되는 컨텍스트에 대해서 알아보았다. 이와 마찬가지로 특정 스레드도 해당 스레드가 수행되는 컨텍스트가 존재한다. 바로 프로세스다. 앞서 Windows에서 스레드의 개념을 설명할 때 특정 프로세스 내에서 수행되는 실행 흐름이라고 표현했다. 따라서 스레드가 동작하기 위해서는 반드시 어떤 프로세스 컨텍스트에서 동작할지를 알아야 한다는 말이다. 일반적으로 프로그램에서 생성하는 모든 스레드는 그 코드를 수행하는 스레드가 참조하는 프로세스 컨텍스트로 생성된다. 하지만 커널 모드 코드들의 경우에는 이 참조하는 프로세스 컨텍스트를 임의의 변경할 수 있다. 따라서 코드가 호출되는 스레드 컨텍스트와 마찬가지로 스레드가 수행되는 프로세스 컨텍스트도 변경될 수 있음을 알아야겠다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 게임 보안: 광클릭 개론]]></title><description><![CDATA[광클릭이란 말 그대로 빛 광자에 클릭을 붙인 말로 빛처럼 빠르게 클릭을 한다는 의미입니다. 그렇다면 게임에서 빛처럼 빠르게 클릭해서 어떤 이득이 있는 것일까요? 이득이 있으니까 그런 일들을 하는 거겠죠. 바로 FPS…]]></description><link>https://jiniya.net/wp/archives/5740</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5740</guid><pubDate>Mon, 12 Mar 2012 23:58:01 GMT</pubDate><content:encoded>&lt;p&gt;광클릭이란 말 그대로 빛 광자에 클릭을 붙인 말로 빛처럼 빠르게 클릭을 한다는 의미입니다. 그렇다면 게임에서 빛처럼 빠르게 클릭해서 어떤 이득이 있는 것일까요? 이득이 있으니까 그런 일들을 하는 거겠죠. 바로 FPS 게임에서 이득을 볼 수 있습니다. 모든 FPS 게임에 통용되는 것은 아니지만 일부 FPS 게임의 경우 클릭 속도가 일정 간격 아래로 떨어질 경우 총기 반동이 왜곡되는 구간이 생깁니다. 동일한 지점에 클릭을 두 번 할 때에는 첫 번째 샷과 두 번째 샷이 총기 반동으로 인해서 다른 곳에 각각 발사됩니다. 하지만 광클릭을 사용해서 굉장히 빠르게 같은 지점에 두 번 클릭을 하게되면 두 샷 모두 동일한 지점에 발사되는 놀라운 현상을 경험할 수 있죠. 이말은 즉, 헤드샷이 아니더라도 한 방에 보내는 것이 가능해 진다는 겁니다. 속도 조절에 따라서 한 지점에 세 방, 네 방 등등을 한 큐에 발사할 수 있습니다. 굉장하죠? 조준이 아예 되지 않는 초보 게이머의 경우에는 별 효과가 없지만 중수 정도만 되더라도 광클릭을 사용하면 굉장한 실력 상승의 효과를 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;다음으론 이 광클릭의 진화 역사를 좀 살펴보겠습니다. 초창기 광클릭은 대부분 소프트웨어 매크로 형태였습니다. 매크로를 이용해서 특정 키나 마우스의 특정 버튼에 더블 클릭 내지는 특수한 빠른 입력의 매크로를 작성해서 사용하는 형태였죠. 하지만 아시겠지만 이런 소프트웨어 매크로 방식의 경우에는 한계가 있습니다. 탐지하기 쉽고 무력화 되기는 더 쉽죠. 이후 등장한 광클릭은 마우스 자체를 개조한 형태였습니다. 기계적으로 사용자들이 개조한 것도 있고 중국 등지에서 만든 개조 마우스가 유행했죠. 기계적인 방식의 경우에는 만들어진 형태를 소프트웨어 적으로 가공하는 것이 불가능한 경우가 대부분입니다. 하지만 소프트웨어 방식이 아니라 이 시기부터 사실상 광클릭 탐지가 불가능해지기 시작했습니다. 이후에 거대한 변화가 닥쳐옵니다. 게이밍 마우스라는 이름으로 메이저 벤더들에서 매크로 기능이 탑재된 마우스를 내놓기 시작한 것이죠. 로지텍이 대표적입니다. 로지텍도 초창기 게이밍 마우스의 경우 소프트웨어 방식으로 에뮬레이션하는 형태였으나 최근에 나오는 시리즈 상위 버전의 경우 놀라운 기능이 탑재됩니다. 바로 마우스 하드웨어 내부에 별도 메모리를 두고 해당 메모리에 매크로를 입력했다가 사용하는 기능이죠. 로지텍 소프트웨어를 사용해서 매크로를 마우스 내부 메모리에 입력 시킨 다음에 다른 컴퓨터에 들고가도 바로 사용이 가능하다는 이야깁니다. 추가적인 드라이버나 소프트웨어 설치 없이 말이죠. 기계식 개조의 조악함을 넘어섬과 동시에 소프트웨어 방식의 손쉬운 탐지를 회피한 것이죠. 이 때 부터 게이머들 사이에서는 이러한 마우스의 사용이 우후죽순 늘어납니다.&lt;/p&gt;
&lt;p&gt;이 문제가 심각한 사실은 분명한 부정행위 임에도 메이저 벤더들이 게이밍 마우스라는 이름으로 제품을 출시하고 해당 제품들이 게임에서 차단되지 않기 때문에 해킹이라는 사실을 별로 인식하지 않는 문제가 발생했다는 점 입니다. 일부 사용자의 경우 매크로 게이밍 마우스를 사용해서 게임 대회에 참가하는 것 또한 문제될 것이 없다고 생각한다는 점에서 이러한 상황의 심각성을 엿볼 수 있습니다. 더 안타까운 사실은 게이머들 사이에서 실력으로 게임을 하는 시대는 지나갔다. 이제는 돈으로 게임을 하는 시대라는 인식이 퍼지고 있다는 사실입니다(로지텍 게이밍 마우스 상위 기종은 상당히 고가입니다). 뭔가 현실 세계의 불균형이 온라인 세계로까지 이어지는 것 같지 않습니까? 이러한 공정하지 못한 현실을 바로잡기 위해서 최근 몇 달 동안 저희 XIGNCODE(라고 쓰고 싸인코드라고 읽습니다) 개발팀에서는 광클릭에 대한 연구를 진행했습니다. 그 결과 이 이슈가 제기되었던 게임 내에서 상당 수의 광클릭 유저를 몰아냄과 동시에 광클릭 사용이 부정행위라는 인식을 심어주고 있습니다. 물론 아직 끝은 아니죠. 이 이슈를 발본색원하기 위해서 지금도 새로운 아이디어, 알고리즘, 그리고 대안을 연구하고 있습니다. 이어지는 내용은 그간 저희가 겪은 시행 착오와 생각들을 정리해본 내용입니다.&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;우리의 초기 접근은 하드웨어에 대한 탐지였습니다. 사용자들이 주로 사용하는 메이저 벤더의 게이밍 마우스가 한정적이기 때문에 해당 벤더의 마우스 내부에 탑재된 메모리의 내용물을 읽어서 차단할 수 있지 않을까란 생각이었죠. 참 재기 발랄한 생각이 아닐 수 없습니다. 그래서 저희는 불철주야 게이밍 마우스를 분석했습니다. 당연히 로지텍 마우스가 일순위였죠. 그런데 안타까운 사실이 벌어졌습니다. 저희 예상과는 달리 로지텍 마우스 소프트웨어 자체에서도 게이밍 마우스에 담겨진 매크로 내용을 읽어오는 부분이 없었기 때문이었죠. 로지텍 전용 소프트웨어 조차도 마우스에 쓰는 기능은 있어도 읽는 기능은 없다는 이야기입니다.&lt;/p&gt;
&lt;p&gt;어쨌든 그래도 아쉬운대로 저희는 해당 소프트웨어의 기록하는 부분만 리버싱을 한 다음 샘플 프로그램을 만들어서 똑같이 기록해 봤습니다. 그랬더니 놀라운 일이 발생했습니다. 해당 로지텍 마우스는 영원히 매크로를 기록할 수 없는 불능 상태가 돼버렸지요. ㅋㅋ 개발팀에서는 이 세상 모든 게이밍 마우스를 매크로 불능으로 만드는 것도 나쁘지 않겠다고 생각했지만 광클릭 외의 목적으로 그 비싼 마우스를 구매하신 분들에게는 큰일날 소리라는 생각과 함께 이 방식에 대한 연구를 중단했습니다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;이후 저희는 속도에 집착했습니다. 광클릭이란 말에서도 알 수 있듯이 이 문제의 핵심 쟁점은 속도에 있다고 생각한 것이죠. 당연히 매크로 마우스의 클릭 속도는 인간이 범접할 수 없는 영역의 속도로 설정할 것이란 생각이었습니다. 사람이 할 수 있는 속도라면 그 속도로 설정하진 않을 것이란 생각이었죠. 하지만 이런 생각을 토대로 속도를 측정하는 것 또한 쉽지는 않습니다. 매크로 설정을 통한 자동 입력되는 마우스 클릭도 있지만 거기에 더불어 사용자가 해당 매크로나 일반 버튼을 통해서 입력 시키는 이벤트도 존재하기 때문입니다. 즉, 우리가 구하려고 하는 매크로 입력의 속도만 차용할 수는 없다는 점이죠. 노이즈가 섞여 있다는 이야기 입니다. 더불어 이 문제를 좀 더 어렵게 만드는 또 한 가지 요인은 FPS 게임의 경우에 항상 클릭 이벤트를 강요하지는 않는다는 점입니다. 대부분의 시간을 적을 찾는데에 보내고 실제로 전투 중 발발하는 클릭 이벤트는 그렇게 많지 않습니다. 이렇게 적을 서치하는 시간 또한 같이 계산해버리면 엄청난 노이즈가 됩니다.&lt;/p&gt;
&lt;p&gt;이렇게나 복잡하고 어려운 문제를 똑똑한 XIGNCODE 개발 팀에서 아주 심플하게 모델링 해서 놀랍게도 노이즈를 상당수 줄이는데 성공했습니다. 그리곤 그 결과를 측정해 보았죠. 참고로 XIGNCODE 개발팀에는 정말 똑똑한 사람들이 많습니다. 진짜로요 ㅋㅋ~~&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 619px; margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_광클릭_개론.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/eb15879c06badfc741df34a111049d97/80833/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 45.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAp0AAAKdAGYYj8ZAAABf0lEQVR42mNgAIKcnBxFZ2dnYSCTw1hSkktGRoaTVCwuLs4N1M8OMo8hNzdX2d7eXqK+vp6lfv9+FiDNBsMzZ85kBWEYG5d4aGgo2GCwgcVAF9p4eIj+d3Xl/qKhIbnq/3/mM2fOgDWAaGQME0OW+///P0t8fDwH3ECQl419fET+a2gIf5OUlFuF5AJi8H6grzAMtHR1FfsvJSX8QUtL6J2xMX8o0JVkG5iWlibn5Osr/hFo4F2gYU/V1ETsgYquIIXlKjz4DNBQFAOTsrOlpunqKv2XkREC8f8rKYntByqo//+fCRSeIAwMJyZkPkwMihlBlsIN9K+vF5ippKS7lptbDBjl7NPk5AT3SkjIr5KQEAVaJNgvLy8AYs9WVBRfpaICoYH8RUCLQfRaIG0PVANNOgwMoOTiGhPDbWxszBUdHS3pCoztNHd3ycmGhlKlLi5SJcAk1WdsLNlnY6PUoq8vXW9vrzJBR0e8ycVFda6BgWiTl5emh5kZX2xsrBwAyYfurbmQWfIAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;             md 0&apos; title=&apos;&apos; src=&apos;/static/eb15879c06badfc741df34a111049d97/80833/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_0.png&apos; srcset=&apos;/static/eb15879c06badfc741df34a111049d97/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_0.png 190w,
/static/eb15879c06badfc741df34a111049d97/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_0.png 380w,
/static/eb15879c06badfc741df34a111049d97/80833/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_0.png 619w&apos; sizes=&apos;(max-width: 619px) 100vw, 619px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
이 그래프는 사용자들의 평균 입력 속도를 나타냅니다. 앞에서 설명한 것처럼 복잡한 연산 후에 노이즈를 제거하고 뭔가 의미있는 값들로 구한 평균입니다. 가로축은 속도를 ms단위로 세로는 해당 구간에 포함된 사용자 숫자를 의미합니다. 알흠답게도 200ms를 기점으로 정규 분포를 보여주고 있습니다. 저희 내부 테스트에 의하면 보통 사람이 생각없이 더블 클릭을 하면 100-200ms 정도가 나오는 것으로 나타났습니다. 저희는 이 데이터 구간에서 100ms 아래에 있는 사용자들이 광클릭을 사용하고 있는 것이 아닌가라는 추론을 하기 시작했습니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 621px; margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_광클릭_개론.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f196fee2ce687148b5b7aa2c47532452/41b39/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 45.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAApNAAAKTQG1k+TGAAABoUlEQVR42pWSMWvCQBTHz2g1RqO1MSZnrQEbEJyEIDgUDnQwQ3ETIg6Cg4oQKF0KLhm6dO0o/QYZSunULV+gn6DQsUPbobX9ANf3grYObWkDP97LvXf/XP7vCIFnPB7nLcvKQioaAMQ4ssr/CyGu66qNRkPxPC+G3Fcq2TtdV89tO7Fe+wuapqVCwclksttutxW/14tySvOv5XLu4fBQ4oah3y4WWz7nUQ4EQRBbx+8EKaVSKDidTgtHlkWXsqy8GMY24TyCPDKWfjNN1eNcQJFNfhW0PS9zpeu1J0mi+B5AEUHRZbGoPFerMua45vt+9Cc+BQeum5mXy5TXanHcCF8T1gSMxd5TKQ0j1tCWTTZ7QSr5NRTwEPwR+MqvDQQ+HIq8UNC458Xx99dgLTwd9CGfJ5zNZumDel3FsTebzWSpVEoahhHmGAlj4khR5BtR3PNVVb8Er324BReZzM4J3IizXC47RjFVTYeCPTh6t9uVIRX6/X6ewTBQbDAYoKeRkeMUe2AH9sxbrV2fkPSpbe9fEyIddTr0mLG8bZoJx3G0D0et2ZCFeK15AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;             md 1&apos; title=&apos;&apos; src=&apos;/static/f196fee2ce687148b5b7aa2c47532452/41b39/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_1.png&apos; srcset=&apos;/static/f196fee2ce687148b5b7aa2c47532452/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_1.png 190w,
/static/f196fee2ce687148b5b7aa2c47532452/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_1.png 380w,
/static/f196fee2ce687148b5b7aa2c47532452/41b39/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_1.png 621w&apos; sizes=&apos;(max-width: 621px) 100vw, 621px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
평균만으론 뭔가 심심해서 표준 편차를 구해봤습니다. 매크로 입력을 사용한다면 당연히 표준 편차가 낮을 거라는 생각이었죠. 이 그래프도 앞선 그래프와 마찬가지로 x축은 속도를 y축은 사용자 숫자를 나타냅니다. 저희는 앞쪽 데이터 0-20ms 정도의 편차를 가지는 사용자들을 광클릭 사용자라고 판단하고 있습니다. 사람이 클릭 이벤트를 발생 시켰다면 이렇게 편차가 낮기는 쉽지 않을테니까 말입니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 619px; margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_광클릭_개론.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f7038487ccd5a8e4cd0da1aa6005bed5/80833/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 50%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAzDAAAMwwFTdG0jAAAB4UlEQVR42nWSv24TQRDG5/bOd/5zviQ2lmVhdDKyFHGNi1Miy80iRTZU7q7AMqIJjf0ASKa4B6CDNBFtinCiiBSJlhdImSpNJDqUiAIlghCH5ZvlzmBEik87Ozv725mdoTiOrcFgUCGiHGRDTqrbbMcnyt8akySJ2el0VgEWSimheM3sKDK1pLSWxD4kopXdUcogfijCoWQgkdBQ7I/CMMc69f3851rNzXReqXhn1Wr5U7NZ4DOO+YgHkt8PCA2cTqdVBu6i5Ax00m47X9bWVi6KxcY3x2l9t+3gq20/gN1mH58xlGPTbHUyGjiZTPwMqFOv10u4eP+HZcm5EE+UENtYp1dCjODrXRYKdzlTFQT237AFcDabNcIwXMHGQCbrP4V4fmMYb26I3kGH0B6AL69N8xFgTYXSk39AS0Ducntz07si2gbo/dwwDgDZh17PiV5cE21xVlzi/0Dcg2UguvR0Y6OKiw+VaW6pcnld5fP3lOvWVKNRPI4iW2V/hYnQXUVHF1PxxzbS8SF6hj98RVT6QOS9bbXqiedVdojcOAzvxIAGmLF+v19KZy3X6/XKmT0cDhe2lHJVA2Nk8Rh0SWRFUrr4Ux5yE+W4HBigAaPRyO92u4XMn8ZYKVDb4/G49AtKw9unmeCoXgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;             md 2&apos; title=&apos;&apos; src=&apos;/static/f7038487ccd5a8e4cd0da1aa6005bed5/80833/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_2.png&apos; srcset=&apos;/static/f7038487ccd5a8e4cd0da1aa6005bed5/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_2.png 190w,
/static/f7038487ccd5a8e4cd0da1aa6005bed5/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_2.png 380w,
/static/f7038487ccd5a8e4cd0da1aa6005bed5/80833/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_2.png 619w&apos; sizes=&apos;(max-width: 619px) 100vw, 619px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
두 데이터에 대한 상관 관계입니다. 가로축이 평균, 세로 축이 표준편차입니다. 뭔가 소행성같은 느낌이 나죠. 저희는 이 소행성에서 떨어져 나온 분진들 중에서도 y축값이 낮고 x축의 값도 낮은 데이터에 집중하고 있습니다. 평균 50ms, 표준 편차 50ms를 설정할 경우에 전체 사용자의 1% 정도가 나왔습니다. 그리고 더욱 놀라운 사실은 그 데이터에 포함된 사용자들이 기존 매크로 검출률이 높은 사용자였다는 점이죠. 이쯤되면 감 잡으셨죠.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;물론 광클릭외에도 게이밍 마우스를 통해서 얻을 수 있는 이득은 무궁무진합니다. 인간의 입력을 기계가 대체한다는 점만을 놓고 볼 때 게임 상에서 허용되지 않는 방식을 통한 모든 종류의 매크로 입력은 사실상 부정행위입니다. XIGNCODE 개발팀에서는 이러한 다양한 매크로 방식에 대해서도 자동적으로 식별할 수 있는 새로운 방법을 연구하고 있습니다.&lt;/p&gt;
&lt;p&gt;지금은 일정 구간의 모든 입력을 레코딩한 다음 해당 구간에서 공통적으로 반복되는 가장 긴 부분 집합을 찾는 작업을 하고 있습니다. 물론 이 방법의 가장 큰 취약점은 타이밍 오차인데 그 부분만 근사할 수 있게 만든다면 굉장히 강력한 방법이 될 거라고 생각합니다. 하지만 이 작업의 가장 큰 걸림돌은 잘 아시겠지만 이 내용이 말로하면 쉽지만 동작하는 코드로 만들어 내기에는 그렇게 녹록한 작업이 아니라는 점이죠. 어쨌든 XIGNCODE 개발팀은 이 세상 모든 하드웨어 입력 방식의 매크로를 원천 차단하겠다는 신념 하나로 오늘도 불철주야 불꽃 코딩을 하고 있습니다. ㅋㅋㅋ~&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;어때요? 잘 보셨죠. XIGNCODE 개발팀은 단순히 해킹툴을 잡은 일만 하는 건 아니라는 거, 게임에 대한 모든 부정 행위에 대해서 깊이 있는 생각을 하고 그 대안을 찾아준다는거 꼭 기억하세요. 뉴요커 게임 개발자라면 당연히 보안 제품은 XIGNCODE를 선택한다는 것도 잊지 마시구욥 흐흐~~&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_광클릭_개론.md_3.png&apos; data-alt=&apos;probably는 빼도 된다는거, 까먹지 마세요!!! ㅋ~&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 636px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/53c726b9d892cee99c11f60af88bb9dc/44bb2/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 16.315789473684212%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAIAAAAcOLh5AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAtUlEQVR42gXBuw6CMBQAUH7IwahAvFLsLS1QhSYFLGkkPmJ8YNTFn3HSQeOgi3/oOY5LPeA+SQGnEOTReK3ppsJtLVqbnOasXbDDkm1n0WGRXlbiuGT7hrcWbN2BidMjroe+h0OIIZwSkkdEJYHKaKmELYqdUWuT2kw2KmkMmooZjVWOWnbDxHHDPkSDkXBD6RMJLA+EHgsd8wL31/Pz+3u8P7f7q1yVvJJxrWQ94UWKitOM/gFzzTheOPmtOAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;probably는 빼도 된다는거, 까먹지 마세요!!! ㅋ~&apos; title=&apos;&apos; src=&apos;/static/53c726b9d892cee99c11f60af88bb9dc/44bb2/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_3.png&apos; srcset=&apos;/static/53c726b9d892cee99c11f60af88bb9dc/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_3.png 190w,
/static/53c726b9d892cee99c11f60af88bb9dc/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_3.png 380w,
/static/53c726b9d892cee99c11f60af88bb9dc/44bb2/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_%EA%B4%91%ED%81%B4%EB%A6%AD_%EA%B0%9C%EB%A1%A0.md_3.png 636w&apos; sizes=&apos;(max-width: 636px) 100vw, 636px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;probably는 빼도 된다는거, 까먹지 마세요!!! ㅋ~&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[개발자에게 독이되는 말, 말, 말, …]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/5735</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5735</guid><pubDate>Fri, 09 Mar 2012 23:58:00 GMT</pubDate><content:encoded>&lt;p&gt;인간은 말을 통해서 의사 소통을 한다. 서로 의견을 교환하고, 자신의 생각을 표현하고, 설득을 하고. 사랑을 표현한다. 그래서 회사 생활에도 말은 참 중요하다. 오죽하면 말 잘하는 사람이 성공한다는 이야기도 있겠는가? 그런 말 중에도 신입 개발자들에게 참 독이 되는 말이 있다. 독이 되는 말임에도 하나같이 신기하게도 신입 개발자들은 이 말을 입에 달고 사는 것 같다. 새해에는 이런 말을 하지 않는 신입 개발자들이 좀 늘었으면 하는 바램이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0. 안 됩니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;무슨 이야기만 하면 찾아보지도 않고 안 된다는 답변을 먼저 해버리는 개발자들이 있다. 사실 좀 어처구니 없는 대답이긴 하다. 왜냐하면 회사에서 높은 비용을 지불해가면서 똑똑한 개발자를 쓰는 유일한 이유는 남들이 못하는 것을 하기 위해서지, 남들도 다하는걸 하기 위해서는 아니기 때문이다. 사사건건 하는 것마다 안 된다는 이야기를 한다면 과연 어떤 회사가 당신에게 높은 비용을 지불하겠는가?&lt;/p&gt;
&lt;p&gt;더 안타까운 사실은 개발자에게 주어지는 요구 사항 중에 안 되는 것은 사실 거의 없다는 점이다. 나도 사회 초년생 시절에는 회사에서나 커뮤니티에서 답변을 달 때에 ‘안 된다’라는 이야기를 자주 했다. 하지만 지나고 보니 안 된다고 생각했던 건 그 당시 지식이 부족했거나 아이디어가 없었던 경우가 대부분이었다. 논리적으로 안 되는 이유를 증명할 수 있는 이야기가 아니라면 가급적 안 된다라는 말을 하는 것은 피하는 것이 좋다. 차라리 정직하게 자신이 아는 한도 내에서는 방법이 없는 것 같다고 말하고, 긍정적으로 방법을 찾아 보자고 이야기 하는 것이 좋은 방법이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1. 팀장님이 작성한 코드예요.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;대다수 신입 개발자들이 회사에서 처음 맡아서 하게 되는 일은 기존 코드의 유지 보수 작업이다. 선임들의 코드 뭉치를 한 덩이 받아 들고는 시작하는 경우가 태반이라는 말이다. 상황이 이렇다 보니 자신이 만든 코드가 아니라는 알량한 생각에 문제가 생기거나 기존 코드에 잘못을 지적 받으면 자연스럽게 방어기제가 발동한다. 책임 회피가 나오는 것이다. “팀장님이 작성한 코드예요”, “그 부분은 원래 이렇게 돼 있었습니다”라는 말들은 이러한 방어기제의 대표적인 형태다. 하지만 안타깝게도 이 답변은 질문에 대한 0점짜리 대답이다. 왜냐하면 이 답변은 지적 받은 문제가 제대로 된 지적인지 아닌지에 대한 생각도 없고, 또 그것을 어떻게 고쳐야 하는지에 대한 생각은 더더욱 없으며, 일말의 책임감이라고는 하나도 찾아볼 수 없는 아주 비겁한 답변이기 때문이다.&lt;/p&gt;
&lt;p&gt;여러분이 어떤 코드 뭉치를 받았건 그것을 받아 들고 해당 코드를 관리하는 순간부터 그 코드는 여러분의 것이고, 직접 책임져야 하는 것들이다. 그 코드를 누가 만들었는지, 기존 코드가 처음부터 문제가 있었는지 없었는지는 하나도 중요하지 않다. 여러분이 알아야 할 것은 지금 문제가 있는지, 문제가 있다면 그것을 고칠 수 있는지 없는지가 중요하다.&lt;/p&gt;
&lt;p&gt;많은 신입 개발자들이 선임의 코드를 받으면서 그 코드는 완전 무결할 것이라는 막연한 환상을 가진다. 하지만 그걸 만든 선임 개발자도 나름의 사정이 있었고, 일정에 쫓겼고, 더욱이 신은 아니다. 그는 자신의 아내가 출산을 하는 날에도 야근을 하면서 해당 코드를 작성해야 했을 수도 있고, 어처구니 없는 일정에 쫓겨가면서 급하게 코드를 만들었을지도 모른다. 상황이 이런데도 신입 개발자들은 코드가 돌아간다면 가급적 고치지 않으려는 습성이 있다. 일종의 관성이라고 할 수도 있는 이 문제는 고치다가 문제가 발생할지도 모른다는 두려움이 그 원인이다. 하지만 반드시 기억해야 할 사실은 항상 새로운 것들은 기존의 것들을 파괴하는 데서 출발한다는 점이다. 기존의 것을 변경하지 않고는 절대로 새로운 것이 탄생할 수 없다. 맡은 코드에 대해서 잘 돌아가는 것 이상을 생각할 필요가 있다. 그게 처음부터 만들지 않은 사람이 해야 할 일이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2. 잘되는데요.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;신입 개발자들의 코드를 보다가 문제를 지적하면 흔히 듣게 되는 대답이다. 물론 똑똑한 개발자라면 기초적인 실수는 하지 않았을 것이기 때문에 이런 실수는 아주 드물게 나타나는 현상에 대한 것이거나 이론적으로는 가능하지만 현실 세계에서 재현은 되지 않는 문제인 경우가 많다. 특히 이번 시간에 언급할 멀티 스레드 문제들도 이 범주에 속한다. 재현이 쉽지 않기 때문에 자신의 코드가 잘 동작한다는 착각에 빠지는 것이다.&lt;/p&gt;
&lt;p&gt;하지만 코드가 잘 돌아간다고 모두 제대로 동작하는 것은 아니다. 완전한 논리로 설명할 수 없다면 불충분한 코드다. 언제든지 안될 수 있다는 말이다. 잘못을 정확하게 판단하기 위해서는 지금까지 잘됐는지 안됐는지가 아니라 그 코드의 논리가 제대로 된 논리인지 아닌지를 해명하는 것이 우선이다.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 게임 보안: VIP 해킹툴 대처 방안 A to Z…]]></title><description><![CDATA[블로그가 진짜 말그대로 거의 개점 휴업 상태였네요. 바쁘다는 말을 별로 좋아하진 않는데 정말 바빴습니다. 제 머릿속에서 날 것 그대로 방출된 무수한 버그들, 겹겹이 겹친 CBT 일정, 그리고 각종 요구 사항, 이슈 사항, 거기에다 VIP…]]></description><link>https://jiniya.net/wp/archives/5657</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5657</guid><pubDate>Wed, 29 Feb 2012 23:57:59 GMT</pubDate><content:encoded>&lt;p&gt;블로그가 진짜 말그대로 거의 개점 휴업 상태였네요. 바쁘다는 말을 별로 좋아하진 않는데 정말 바빴습니다. 제 머릿속에서 날 것 그대로 방출된 무수한 버그들, 겹겹이 겹친 CBT 일정, 그리고 각종 요구 사항, 이슈 사항, 거기에다 VIP 핵툴까지… 헉. 이런 것들에 파묻혀서 정말 숨도 못쉬다가 이제 조금 호흡을 가다듬고 있습니다. 후훗~ 간만에 XIGNCODE(라고 쓰고 싸인코드라고 읽습니다) 깔때기나 좀 댈겸 VIP 핵툴에 대한 이야기를 좀 해볼까 합니다. ㅋㅋ&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./게임_보안_VIP_해킹툴_대처_방안_A_to_Z.md_0.png&apos; data-alt=&apos;가장 최근에 등장한 모 해킹툴 그룹의 GG 제스쳐.&lt;br&gt;&lt;br&gt;해킹툴 제작자만 이런 사실을 안다는게 안타깝습니다 ㅋ~&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 584px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/1e4ad12424a94ff748fb79d5d30c32e7/f5818/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_VIP_%ED%95%B4%ED%82%B9%ED%88%B4_%EB%8C%80%EC%B2%98_%EB%B0%A9%EC%95%88_A_to_Z.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 26.31578947368421%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAIAAADKYVtkAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABDUlEQVR42hWNW3KCMAAAOYyKaKSAESU8FBIS3hKCpmKpWh9t73+B0pmdnf1bJREFbS65vJXdq+5/q/4nk/eqe1TnZ3l6YP5JxBU3V0gOVlgDN5ttqGYTFYZjM1B2+T4sT5T3rL3E/IPwMxV9kEmHtl4qvfSIqHCYQMkRscPcSTQ7nsJoYm3Hhq8EaR0W0sZ70091l5lBBneV7uUzZ5iwgakdT2A0tkJ1Rf57OTy3I8Mf6a6Cy4NLa8ujqrVTVzFAubZmwC2sUCzczPArI6iAk8zXZG6HYEMWDgVrrC23kzekREUUlxJnTXPiXy9+/25vz3rw+6XmkjYyFl3WdolPmYGoiTD0qYUi3Q4A9P4AdsNPBpMDCagAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;가장 최근에 등장한 모 해킹툴 그룹의 GG 제스쳐.&lt;br&gt;&lt;br&gt;해킹툴 제작자만 이런 사실을 안다는게 안타깝습니다 ㅋ~&apos; title=&apos;&apos; src=&apos;/static/1e4ad12424a94ff748fb79d5d30c32e7/f5818/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_VIP_%ED%95%B4%ED%82%B9%ED%88%B4_%EB%8C%80%EC%B2%98_%EB%B0%A9%EC%95%88_A_to_Z.md_0.png&apos; srcset=&apos;/static/1e4ad12424a94ff748fb79d5d30c32e7/08678/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_VIP_%ED%95%B4%ED%82%B9%ED%88%B4_%EB%8C%80%EC%B2%98_%EB%B0%A9%EC%95%88_A_to_Z.md_0.png 190w,
/static/1e4ad12424a94ff748fb79d5d30c32e7/2edd7/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_VIP_%ED%95%B4%ED%82%B9%ED%88%B4_%EB%8C%80%EC%B2%98_%EB%B0%A9%EC%95%88_A_to_Z.md_0.png 380w,
/static/1e4ad12424a94ff748fb79d5d30c32e7/f5818/%EA%B2%8C%EC%9E%84_%EB%B3%B4%EC%95%88_VIP_%ED%95%B4%ED%82%B9%ED%88%B4_%EB%8C%80%EC%B2%98_%EB%B0%A9%EC%95%88_A_to_Z.md_0.png 584w&apos; sizes=&apos;(max-width: 584px) 100vw, 584px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;가장 최근에 등장한 모 해킹툴 그룹의 GG 제스쳐.&lt;br&gt;&lt;br&gt;해킹툴 제작자만 이런 사실을 안다는게 안타깝습니다 ㅋ~&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;VIP 핵툴이란 유료 핵툴이라고 생각하면 됩니다. 근데 그냥 유료 핵툴은 아니고 해킹툴 제작 그룹에서 퀄리티를 보장하는 해킹툴이라는 게 특징이죠. 즉 비싼 돈을 받는 대신에 QA를 해주는 핵툴이라고 생각하면 되겠습니다. 그래서 흔히들 보안 업체가 계약을 할 때에 최대 몇 시간 내에 대응을 해줄 것인지에 대한 보장을 하는데 이런 VIP 해킹툴도 사용자들에게 그런 조항을 달아 줍니다. 예를들면 72시간 동안 해킹툴이 다운될 경우에는 보너스 기간을 준다거나 하는 식이죠. 즉, 쉽게 생각하면 목숨걸로 핵툴 만드는 애들이 판매하는 핵툴이 VIP라고 생각하면 됩니다.&lt;/p&gt;
&lt;p&gt;그러다보니 자연스럽게 VIP 핵툴의 경우 대응이 까다로운 점이 있습니다. 사실 대응이라고 하기도 좀 힘든 실정입니다. 대부분의 경우 VIP 핵툴은 게임 패치와 동시에 업데이트 돼서 거의 항상 오픈된 상태를 유지하기 때문입니다. 어쨌든 요번 글에서는 이런 VIP 해킹툴을 대응하면서 느꼈던 점, 팁(?!)들을 몇 가지 써볼까 합니다.&lt;/p&gt;
&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;테크닉, 기술. 사실 가장 중요한 요소입니다. 이게 안되면 이후에 진행하는 모든 것들이 애초에 불가능하기 때문입니다. 따라서 게임 보안 제품을 만든다면 반드시 해커보다는 똑똑한 개발자와 분석가를 뽑아야 합니다. 그게 안되면 싸움 자체가 성립이 안되기 때문입니다.&lt;/p&gt;
&lt;p&gt;이 말이 의미하는 바는 이런 겁니다. 커널 모드 핵툴이 나왔는데 우리는 유저 모드 기술 밖에는 없을 때. 같은 레벨에서 싸우지 않고서는 답이 없는 경우가 존재합니다. DirectX 후킹만 알고 있는데 핵툴 제작자는 WDDM 후킹을 하고 있을 때, 함수 진입 부분 훅 체크만 하는데 함수 중간 부분을 후킹하는 기법일 때, 코드 오버라이트 방식의 훅만 생각하는데 예외 처리기를 통한 후킹 방식일 때, 등등… 즉, 일부 영역에서는 해당 테크닉을 모르고는 영원히 대응이 불가능한 지점이 생깁니다. 따라서 일정 수준 이상의 기술력을 갖추는 것은 필수 사항입니다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;도구. 두 번째로 중요합니다. 보안 제품에 반드시 특정 싸움에 대해서는 종결 시킬 수 있는 이론적 근간이 있는 코드들이 있어야 한다는 것을 의미합니다. 논클라이언트 봇이나 바이패스 툴이 나왔을 때 해당 툴들을 사전에 차단은 하지 못하더라도 사후 대응은 가능한 이론적 근간은 있어야 한다는 겁니다. 그런 게 없으면 싸움을 이어 나갈 수가 없습니다. 이런게 없으면 그냥 단순하게 바이패스 등장, 끝이기 때문입니다.&lt;/p&gt;
&lt;p&gt;더불어서 알려진 범용 핵툴 기법에 대해서는 해당 접근 루트를 완전히 차단할 정도로 완전한 도구가 필요합니다. 특정 API를 후킹할 때 우리가 해당 API를 체크하면 더 이상 해당 API를 후킹하면서 우리 코드를 우회할 방법은 없어야 한다는 것, 특정 게임 함수를 불법 호출할 때 해당 게임 함수를 보호하면 더 이상 불법 호출을 하면서 우리 코드를 우회할 방법은 없어야 한다는 것을 의미합니다. 그런데 이 정도로 완성도 높은 코드들을 만들기는 쉽지 않습니다. 하지만 이런 코드들 없이는 절대로 싸움을 끝낼 수가 없습니다. 반드시 어느 지점까지 몰아갔을 때에는 해커들을 막다른 골목으로 인도할 수 있는 도구가 있어야 싸움을 끝낼 수 있습니다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;이런 기본기가 갖추어진 다음 진짜 중요한 것은 업데이트 입니다. 핵툴은 제작이 끝나는 순간 바로 배포합니다. 몇몇 운영체제에서 크래시가 나는 것은 중요하지도 않습니다. 선배포 후에 테스트를 진행한다고 보면 되겠습니다. 이렇게만 해도 일부 핵툴이 동작하는 사용자들은 환호하면서 그들에게 돈을 지불하고도 칭찬을 아끼지도 않죠.&lt;/p&gt;
&lt;p&gt;하지만 보안 제품은 상황이 다릅니다. 모든 PC에서 정상 동작을 해야 하며, 다른 제품들과 충돌 테스트도 거쳐야 하고, 내부 QA에서 게임사 QA, 또는 게임사에 따라서는 게임사의 자체 보안팀의 QA를 거쳐야 합니다. 이러한 복잡한 단계를 거치더라도 최소한 해킹툴과 속도전을 할 수 있을 정도의 업데이트 속도는 갖추어야 합니다. 보안 제품 한 번 업데이트로 해킹툴을 하루 다운(down) 시킨다면 적어도 매일 업데이트가 이루어져야 한다는 겁니다. 대응을 해보면 알겠지만 사실 추가 업데이트 없이 하루를 다운시키는 것도 거의 불가능할 정도로 긴 시간입니다.&lt;/p&gt;
&lt;p&gt;물론 이런 업데이트 주기를 가지기 위해서는 보안 제품을 개발하는 쪽에서도 많은 부분을 신경 써야 합니다. 우선은 코드가 아닌 데이터만 교체함으로써 핵툴을 차단할 수 있는 구조를 많이 만들어 두어야 합니다. 데이터 교체는 빌드를 새로 하는 것보다는 훨씬 문제가 덜 발생하기 때문이죠. 또한 검증할 것도 적어지기 때문에 QA 시간도 단축됩니다. 더불어 절대로 핵툴이 새로 나왔다고 그걸 분석하고 있어서는 안됩니다. 나오는 즉시 일단 막고 봐야 합니다. 그 후에 분석해도 늦지 않습니다. QA 시간을 고려해서 최대한 빨리 대응할 수 있도록 해주어야 한다는 의미입니다.&lt;/p&gt;
&lt;p&gt;속도전입니다. 핵툴이 새롭게 업데이트 되자 마자 바로 문제가 발생한다는 인식을 해킹툴 사용자와 해킹툴 제작 그룹에 인지시켜 주어야 합니다. 이런 인식이 없으면 마치 깨진 유리창 이론처럼 우후죽순 유사 해킹툴들이 등장합니다.&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;시스템 가변성. 이 싸움을 잘 살펴보면 해킹툴 그룹은 아주 소수이며 그것을 사용하는 사람은 절대 다수라는 점을 알 수 있습니다. 따라서 이 싸움에서 이기기 위한 영리한 생각 중에 하나는 시스템 가변성을 두는 것입니다. 즉 우리가 만든 보안 제품이 해킹툴 제작자의 PC와 다른 사람들의 PC에서 다르게 동작한다면 해킹툴 제작자 입장에서는 굉장히 골치 아픈 문제가 될 수 있다는 겁니다. 해커가 자기 PC에서 되는 것 같아서 배포했는데 사용자들은 모두 동작하지 않는다고 아우성을 치는 상황을 만들 수 있다는 것이죠. 이런 상황이 몇 번 연출되면 해킹툴 제작자 입장에서는 클레임에 골치 아파서라도 그냥 GG치게 됩니다.&lt;/p&gt;
&lt;h3&gt;#4&lt;/h3&gt;
&lt;p&gt;느린 탐지. 아주 간단하지만 의외로 굉장히 효과적인 방법입니다. 해킹툴 배포 시간을 늦추고 싶다면 해당 해킹툴 탐지 시간을 늦추는 단순한 행위로도 효과를 볼 수 있다는 말입니다. 물론 아무리 길어지더라도 해킹툴 사용자 입장에서는 핵툴을 이용한 효용이 없는 시간 정도여야겠지요. 예를 들어 FPS 게임이라면 핵툴을 가동하고 게임을 실행하고 방을 찾아 들어가서 이제 한 번 시작해볼까 할 때에 탐지하는 것을 말합니다. 그런데 보통은 빠른 탐지가 좋은 줄 알고 게임 구동 시에 알려진 핵툴에 대해서는 바로 탐지해 버립니다. 이게 문제입니다.&lt;/p&gt;
&lt;p&gt;이 방법이 효과적인 이유는 해킹툴 제작자의 테스트 시간을 늘린다는 점과 굉장히 피로하게 만든다는 점입니다. 게임을 구동해서 방에까지 들어가야 뭔가 결과를 알 수 있기 때문이죠. 즉, 자신이 수정한 것이 우회됐는지를 확인하기까지 시간이 늘어난다는 점입니다. 더불어 탐지 시간이 가변적이라면 더 효과적입니다. 해킹툴 제작자 입장에서는 얼마 정도를 테스트해야 하는지를 알기가 힘들어지기 때문입니다.&lt;/p&gt;
&lt;h3&gt;#5&lt;/h3&gt;
&lt;p&gt;복잡한 내부 IPC 구조. 여러분이 반드시 숨겨야 하는 것은 어떤 기준으로 해킹툴을 탐지 했냐는 겁니다. 따라서 탐지하는 부분과 사용자에게 핵툴이 탐지 됐다고 보고하는 부분 사이에는 거리가 있어야 합니다. 절대로 탐지 했다고 바로 그것을 보고하는 멍청한 짓을 해서는 안됩니다. 왜냐하면 해커들은 당연히 탐지 지점부터 우리를 추적해 오기 때문입니다. 그 사이에 엄청 복잡한 단계의 IPC 통로를 만들어 두세요. 그 IPC 메커니즘이 일정 수준 이상 복잡해지면 어느 순간부터는 해커들이 우리 코드를 분석해 패치하기 보다는 그냥 자기 코드를 고치는 것이 빠르다는 생각을 하게 됩니다.&lt;/p&gt;
&lt;h3&gt;#6&lt;/h3&gt;
&lt;p&gt;VIP 핵툴의 경우 절대로 진단 루틴이 제너레이터를 통해서 우회할 수 있는 수준이어서는 안됩니다. 해킹툴 개발자가 코드를 보고 어디를 고쳐야 할지 생각하고 다시 컴파일을 강요할 수준은 되어야 합니다. 이런 게 되지 않으면 업데이트 한 트럭이 주어져도 전혀 효과가 없습니다. 무조건 우리가 업데이트를 한 번 할 때에는 해킹툴 개발자도 적어도 컴파일을 새로할 정도는 되는 진단 루틴을 추가해야 합니다. 물론 해커가 고민을 많이 해야 알 수 있는 루틴이라면 더 좋습니다.&lt;/p&gt;
&lt;h3&gt;#7&lt;/h3&gt;
&lt;p&gt;구구절절 설명했지만 솔직히 정말 복잡하고 골치 아프고 신경쓰기 싫은 문제들입니다. 그럴 땐 그냥 &lt;a href=&quot;http://www.wellbia.com&quot;&gt;웰비아닷컴의 XIGNCODE를&lt;/a&gt; 사용하시면 됩니다. 합리적인 가격에 우수한 게임 보안 서비스를 제공한답니다. 어쨌든 게임 보안하면 XIGNCODE, XIGNCODE하면 게임 보안 딱 답 나오잖아요 ㅋㅋㅋ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[키보드 눌렀는지 비동기 방식으로 검사하기]]></title><description><![CDATA[프로그래밍을 하다보면 동기/비동기라는 말이 자주 등장합니다. 동기 방식이란 해당 I/O…]]></description><link>https://jiniya.net/wp/archives/5598</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5598</guid><pubDate>Tue, 03 Jan 2012 23:57:58 GMT</pubDate><content:encoded>&lt;p&gt;프로그래밍을 하다보면 동기/비동기라는 말이 자주 등장합니다. 동기 방식이란 해당 I/O 작업이 완료될 때까지 프로그램이 블록된다는 것을 의미합니다. 소켓 통신에서 수신을 한다면 데이터가 올 때까지 프로그램이 정지한다는 말이죠. 키보드 입력을 받는다면 사용자가 키보드에서 데이터를 입력할 때까지 프로그램이 정지하는 겁니다. 그렇다면 비동기는 어떻게 동작하는 것일까요? 동기 방식과 정반대로 동작하는 것을 말합니다. I/O가 완료되지 않아도 바로 리턴하며, I/O가 완료됐을 때 이벤트를 받는 형태로 동작하는 방식입니다. 따라서 프로그램은 계속 다른 작업을 할 수 있다는 장점이 있습니다.&lt;/p&gt;
&lt;p&gt;… 작성 중 (나용 추가 필요) …&lt;/p&gt;
&lt;p&gt;아래 프로그램은 지속적으로 “Happy New Year!!!”을 출력하다가 사용자가 q를 누르면 종료하는 프로그램입니다. _kbhit 함수는 사용자가 키보드를 입력했는지 하지 않았는지를 검사하는 함수 입니다. 키보드를 입력했으면 0이 아닌 값을, 입력하지 않았다면 0을 리턴하죠. getch는 키보드 입력 버퍼에서 한 글자를 입력 받아서 해당 키 값을 리턴해 주는 함수입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;tchar.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;conio.h&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_tmain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; argc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _TCHAR&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; argv&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_kbhit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token char&quot;&gt;&apos;q&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Happy New Year!!!\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;아래 프로그램과 동작을 비교해 보시면 어떤 차이가 있는지 금방 알 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;stdio.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;tchar.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;conio.h&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_tmain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; argc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _TCHAR&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; argv&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token char&quot;&gt;&apos;q&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

		&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Happy New Year!!!\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[여러분의 DllMain이 예외를 발생시키면 어떻게 될까요?]]></title><description><![CDATA[#0. 이 내용은 최문혁 MVP 햄님께서 친히 제보해 주신 xfav…]]></description><link>https://jiniya.net/wp/archives/5253</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5253</guid><pubDate>Wed, 21 Dec 2011 23:57:57 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;#0.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이 내용은 &lt;a href=&quot;http://dotnetpower.kr/&quot;&gt;최문혁 MVP 햄님&lt;/a&gt;께서 친히 제보해 주신 xfav 프로그램 버그를 찾다가 알게 된 사실입니다. 이 자리를 빌어서 다시한번 감사의 마음을 전합니다. 여러차례 덤프를 떠서 전달해 주시는 수고를 마다하지 않으셨습니다. 흙~ 눈물날라 그러는군요. 좀 오래된 이야긴데 바빠서 그간 정리를 못하고 있다가 인제서야 올리게 되는군요. 수정된 프로그램은 다음에 시간날 때 빌드해서 올리도록 하겠습니다. ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;증상은 간단했습니다. xfav.exe에서 인젝션하는 DLL이 explorer.exe에 주입되면서 explorer.exe가 크래시가 발생하는 현상이었습니다. 덤프는 explorer.exe가 종료되려고 하는데 엉뚱하게도 언로드된 xfav.exe의 _freefls를 가리키고 있더군요. 뭐 그런 상황이었습니다. 원인이 무엇이었는지는 제목이 암시하고 있는 거겠죠. 애니웨이, 시작해 봅시다!!!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;제일 먼저 DllMain에 대해서 운영체제가 어떤 정책을 취하고 있는지 알아보아야 합니다. 우리가 아무리 잘 만들어본들 우리는 그저 O/S 위에서 돌아가는 일개 프로그램일 뿐이잖아요. ㅋ~ MSDN을 찾아보면 아래와 같이 설명이 나와있습니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If the DLL’s entry-point function returns FALSE following a DLL_PROCESS_ATTACH notification, it receives a DLL_PROCESS_DETACH notification and the DLL is unloaded immediately. However, if the DLL_PROCESS_ATTACH code throws an exception, the entry-point function will not receive the DLL_PROCESS_DETACH notification.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx&quot;&gt;http://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;영어를 잘하는 제가(ㅋㅋ) 짧게 요약을 해보면 이렇습니다. DLL_PROCESS_ATTACH에서 FALSE를 리턴하면 DLL_PROCESS_DETACH 호출을 받을 것이고, DLL_PROCESS_ATTACH에서 예외가 발생했다면 DLL_PROCESS_DETACH를 받을 생각 따위는 아예 하지도 말아라. 헉. 그렇습니다. 기본적으로 예외가 발생하면 DLL_PROCESS_DETACH 호출을 받지 못합니다. 우리가 운영체제를 만든다고 하더라도 그러겠지요? 생성자에서 예외가 발생하면 소멸자가 호출되지 않는 것과 동일한 원리 아니겠습니까? ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;다음으로 우리는 그 지긋지긋한 CRT에 대해서 다시 살펴보는 시간을 가져야 겠습니다. CRT는 멀티스레드 환경을 지원하기 위해서 FLS(Fiber Local Storage)라는 것을 사용합니다. CRT 초기화 루틴에서 FlsAlloc(_freefls)를 호출해서 등록하죠. 이는 다시 CRT가 종료될 때 회수됩니다. 일반적인 DLL을 만들면 우리의 DLlMain이 호출되기 전에 FlsALloc으로 flsindex를 할당 받고, DLL_PROCESS_DETACH가 호출되면 CRT가 그것을 정리하는 원리로 돌아갑니다.&lt;/p&gt;
&lt;p&gt;즉, 코드로 살펴보면 다음과 같은 구조가 되는 겁니다. OurDllMain이 우리가 작성한 것이고, 실제 DLL의 엔트리는 CrtDllMain이 되는 구조입니다. 머 심플하죠.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;BOOL CALLBACK &lt;span class=&quot;token function&quot;&gt;CrtDllMain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HINSTANCE instance&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ULONG reason&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PVOID reserved&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reason &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; DLL_PROCESS_ATTACH&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        flsindex &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;FlsAlloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_freefls&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;OurDllMain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;instance&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reason&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reserved&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;reason &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; DLL_PROCESS_DETACH&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        BOOL r &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;OurDllMain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;instance&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reason&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reserved&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;FlsFree&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;flsindex&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; r&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;#3.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;그런데 이 CRT가 싸지른 FlsCallback이 문제입니다. 앞선 코드에서 _freefls가 되겠죠. 이 FlsCallback은 운영체제에서 필요한 경우, 스레드 종료, 파이버 종료, fls 해제와 같은 상황이 되면 호출을 합니다. 이런 복잡한 처리를 하기 위해서 운영체제는 이놈을 운영체제의 테이블, 리스트같은 곳에 등록을 해놓습니다. 뭐 PEB같은 곳에 말이죠. 그리고는 필요한 때에 그 루틴을 불러서 호출한답니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#4.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;자 이제 다왔습니다. 그렇다면 우리가 만든 DllMain의 DLL_PROCESS_ATTACH에서 예외가 발생하면 어떻게 될까요? DLL_PROCESS_ATTACH가 실패했으니 일단 DLL은 로드되지 않겠죠. 여기까지는 문제가 없습니다. 그냥 DLL이 로드되지 않고 기능이 동작하지 않을 뿐이죠. 문제는 프로세스가 종료할 때 발생합니다. FLS를 정리하기 위해서 운영체제는 우리 DLL의 CRT 코드가 싸지른 FlsCallback을 호출하려고 시도합니다. 비극은 여기서 시작됩니다. DLL은 로드에 실패했기 때문에 메모리에 존재하지 않고, 운영체제는 그 바운더리에 있는 FlsCallback을 호출하려고 하는 겁니다. 결과는 머 당연하죠. 크래시가 발생합니다.&lt;/p&gt;
&lt;p&gt;이유는 우리가 예외를 발생시켰고, 예외가 발생한 경우에 운영체제는 DLL_PROCESS_DETACH를 호출하지 않고, 그러니 CRT는 자신이 싸지른 FlsCallback을 회수할 기회가 없었던 겁니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#5.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;결론을 요약하면 이렇습니다. DllMain에서는 절대로 예외를 발생시켜서는 안됩니다. 왜냐하면 그 예외가 CRT의 코드에 영향을 미칠 수 있기 때문입니다. 모든 예외를 봉쇄하고 발생한 경우에는 그냥 FALSE를 리턴하는 것이 현명합니다. 그러면 적어도 다른 프로그램에 민폐는 안끼칠 수 있겠죠. 그렇지 않다면 민폐를 끼치고 엉뚱한 프로그램이 크래시가 발생하는 문제가 생길 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;다시 처음으로 돌아와서 그렇다면 xfav.exe에서 주입했던 DLL의 DllMain은 왜 크래시가 발생했던 걸까요? 궁금하시죠? 이유는 제가 예전에 썼던 글들에 답이 있습니다. DllMain과 관련된 글을 두 개를 썼더랬습니다. 하나는 &lt;a href=&quot;http://jiniya.net/tt/788&quot;&gt;DllMain에서는 절대로 하지 말아야 할 것&lt;/a&gt;이고, 다른 하나는  &lt;a href=&quot;http://www.jiniya.net/wp/archives/4457&quot;&gt;DLL_PROCESS_DETACH 시점에서 주의해야 할 점&lt;/a&gt;이었습니다. 그런데 제가 그 DllMain에서는 절대로 하지 말아야 할 것을 해버린 것이었죠. user32.dll의 함수를 DLL_PROCESS_ATTACH에서 호출한 겁니다. user32.dll이 아직 초기화가 되어있지 않아서 예외가 발생해버린 겁니다. 하지 말라는데에는 다 이유가 있는 거겠죠. 흙~~&lt;/p&gt;
&lt;p&gt;그래서 어떻게 했냐구요? 초기화를 지연 시켰습니다. DLL_PROCESS_ATTACH에서 하지 않고 말이죠.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[마계촌 온라인 클베 두둥~]]></title><description><![CDATA[이 게임의 역사를 말하자면 좀 유서가 깊은데요. 한 6-…]]></description><link>https://jiniya.net/wp/archives/5451</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5451</guid><pubDate>Wed, 14 Dec 2011 23:57:56 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./마계촌_온라인_클베_두둥~.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/0411bbcc601dd6d68d1eedd8ff7f280e/e224a/%EB%A7%88%EA%B3%84%EC%B4%8C_%EC%98%A8%EB%9D%BC%EC%9D%B8_%ED%81%B4%EB%B2%A0_%EB%91%90%EB%91%A5~.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 62.63157894736842%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAIBAwX/xAAWAQEBAQAAAAAAAAAAAAAAAAAAAQL/2gAMAwEAAhADEAAAAcdoMqhyv//EABkQAAIDAQAAAAAAAAAAAAAAAAABAhASEf/aAAgBAQABBQKmjbQ5Gun/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAYEAADAQEAAAAAAAAAAAAAAAAAATEQQf/aAAgBAQAGPwKEzhERH//EABsQAQADAAMBAAAAAAAAAAAAAAEAESExUXGB/9oACAEBAAE/ITAdRpoqeRB4nQfpNSFt0fJ//9oADAMBAAIAAwAAABDDD//EABURAQEAAAAAAAAAAAAAAAAAAAAR/9oACAEDAQE/EEf/xAAWEQADAAAAAAAAAAAAAAAAAAAAARH/2gAIAQIBAT8QjKz/xAAcEAEAAwEAAwEAAAAAAAAAAAABABEhMUFRceH/2gAIAQEAAT8QIKAd+1sdMp5TsQgsgkvJFxsjxWRY+io/U//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;               md 0&apos; title=&apos;&apos; src=&apos;/static/0411bbcc601dd6d68d1eedd8ff7f280e/e224a/%EB%A7%88%EA%B3%84%EC%B4%8C_%EC%98%A8%EB%9D%BC%EC%9D%B8_%ED%81%B4%EB%B2%A0_%EB%91%90%EB%91%A5~.md_0.jpg&apos; srcset=&apos;/static/0411bbcc601dd6d68d1eedd8ff7f280e/8ccab/%EB%A7%88%EA%B3%84%EC%B4%8C_%EC%98%A8%EB%9D%BC%EC%9D%B8_%ED%81%B4%EB%B2%A0_%EB%91%90%EB%91%A5~.md_0.jpg 190w,
/static/0411bbcc601dd6d68d1eedd8ff7f280e/ea4c8/%EB%A7%88%EA%B3%84%EC%B4%8C_%EC%98%A8%EB%9D%BC%EC%9D%B8_%ED%81%B4%EB%B2%A0_%EB%91%90%EB%91%A5~.md_0.jpg 380w,
/static/0411bbcc601dd6d68d1eedd8ff7f280e/e224a/%EB%A7%88%EA%B3%84%EC%B4%8C_%EC%98%A8%EB%9D%BC%EC%9D%B8_%ED%81%B4%EB%B2%A0_%EB%91%90%EB%91%A5~.md_0.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이 게임의 역사를 말하자면 좀 유서가 깊은데요. 한 6-7년은 된 이야기 같습니다. 대학교 수업 시간이었죠. 수업 시간에 형이 연습장에 막 뭔가를 끄적이면서 고민을 하고 있었습니다. 그 때 셋이서 수업을 같이 들었던 것 같은데 저랑 다른 형은 어떻게 하면 출석 부르고 나가서 스타나 할까라는 생각을 하고 있었죠. 밖으로 나가기는 애매한 분위기가 되서 무슨 고민을 그리도 하냐고 물어 봤습니다. 그 때 형이 그러더군요. 마계촌이란 게임을 온라인으로 만드는데 횡스크롤을 3D로 어떻게 매핑을 해야 할지를 모르겠다고 말이죠. Z축이 생기면 여러모로 원작 마계촌의 횡스크롤 느낌을 살리기는 힘드니까요. 그런 심도 있는 고민을 연습장에 맵을 그려가면서 막 했답니다. 다른 날은 또 와서는 월드 클래스를 어떻게 만들어야 좋을지를 고민하기도 했었죠. 그렇게 시간이 흘러 흘러 우리는 졸업을 했고, 열심히 고민을 했던 형은 졸업을 하고도 계속 마계촌 온라인을 만들었고, 저는 어찌 흘러 흘러 게임 보안 제품을 만들게 되었답니다.&lt;/p&gt;
&lt;p&gt;우왕 사설이 너무 길었네요. 새벽에 감상에 젖어서 그만… ㅋㅋ 각설하구요. 어쨌든 그랬던 마계촌 온라인이 지난 주 목요일부터 일요일까지 장장 4일에 거쳐서 클로즈 베타 테스트라는 엄청한 테스트를 진행했습니다. 지난 시간 옆에서 들은 이야기가 있어서 그런 걸까요? 게임을 보는데 제가 다 뿌듯하더군요. 물론 형이 고맙게도 보안 제품으로 우리 회사 제품인 XIGNCODE3를 전격 기용하는 용단을 발휘했기 때문에 그런건 절대 아닙니다. 아니고요. ㅋ~&lt;/p&gt;
&lt;p&gt;클베 이야기를 좀 해야겠네요. 이번 클베는 26렙까지 컨텐츠를 오픈했다고 하는데 전 그마저도 모두 즐기지를 못했습니다. 시간만 있었어도 만렙을 찍는 기염을 토하려고 했으나 진행하는 과제 완료 발표가 이번주로 잡혀서 주말 내도록 발표 자료 만드느라 제대로 게임을 즐기질 못했습니다. 뭐 핑계죠 ㅋㅋ~ 어쨌든 그래도 조금은 즐겨 봤는데요. 기사 6렙, 아처 3렙, 기사 11렙 이렇게 했봤습니다. 첨에 하던 기사가 클베 시작하니 삭제되고 없드라고요. 흙~&lt;/p&gt;
&lt;p&gt;마계촌을 처음 마주한 느낌은 딱 두 가지였습니다. 배경 음악, 마계촌 고유의 배경음악을 듣는데 왠지 오싹하더군요. 저도 어렸을 때 마계촌을 했었거든요. 난이도 탓에 늘 초반에 죽곤 했었지만 말입니다. 그리고 다른 한 가지 느낌은 그래픽이 뭔가 요즘 게임같지 않게 후지다는 느낌이었습니다. ㅋㅋ~ 근데 클베 마지막 날 알게된 사실인데 그래픽이 그랬던건 해상도 탓이더군요. 제 모니터 해상도가 1680×1050인데 디폴트로 1280x???로 잡혀서 그랬더라고요. 해상도 맞추고 게임을 하니 몰입도가 100배 증가 부왘. 마치 해골 분쇄기가 모니터에서 튀어나오는듯한 느낌이었습니다. 그래픽 좋습니다.&lt;/p&gt;
&lt;p&gt;앞서 기사와 궁수를 해봤다고 했는데 전 여러모로 기사가 재밌었습니다. 타격감도 좋고, 써는 맛도 있고, 뭔가 내가 하려는 의지대로 캐릭터가 움직인다고 할까요? 손에 착착 감기는 ㅋㅋ~ 반면 궁수는 허구헌날 그 놈에 언덕 때문에 화살이 언덕에 박히는 몹쓸 장면이 많이 연출되더군요. 물론 제가 발컨이라 그렇기도 합니다. 같이 테스트 했던 직원도 기사가 재밌다고 하는걸로 봐서는 확실히 기사가 대세인것 같아요 ㅋㅋ~&lt;/p&gt;
&lt;p&gt;초반에는 x키로 닥썰만 하면 돼서 사실 좀 심심한데요. 제가 재밌다고 느낀 건 그 불타는 농장인가 거기를 가면서부터였습니다. 막 바퀴 날라오고 불덩이 날라오고 하는데 뭔가 이제는 약간 컨트롤 아닌 컨트롤이 필요한 듯한 느낌, 또 해골 분쇄기 앞에 이상한 놈 두 놈 나오는 데 왠지 그것들을 처리하고 나면 뿌듯하더군요. 발컨이라 해골 분쇄기는 죽지 않곤 못잡겠드라고요. 후반 컨텐츠가 더 재밌을 것 같은데 해보질 않아서 논하기가 곤난하네요. 2차 클베때는 반드시 만렙을 찍겠습니다. 그리고 해보면서 느낀 건데 기사는 진짜 타격감이 좋습니다. 특히 초반에 그 무덤 나오는 데서 해골 때릴 때 그 독특한 타격감은 잊을 수가 없네요.&lt;/p&gt;
&lt;p&gt;한 가지 건의 사항이 있다면 물약을 단축키로 지정했을 때, 물약 다 먹고 나면 단축키에서 사라져서 다시 물약 주으면 또 끌어다 놔야 하는 불편함이 있는데요. 한번 물약 단축키는 영원한 물약 단축키가 됐으면 좋겠다는 소소한 바램이 ㅋ~ 저희 같은 발컨은 물약이 생명이거든요. 흙~&lt;/p&gt;
&lt;p&gt;어쨌든 구구절절 느낌점을 풀어봤는데요, 총평을 하자면 재밌습니다. 게임이 재밌으면 그만이죠. 특히 자투리 시간 킬링 타임용으로는 정말 괜찮을것 같다는 생각이 팍팍 들었습니다. 뭔가 지금도 불타는 농장을 들어가서 다시 해골 분쇄기와 맞짱을 뜨고 싶은데 서버와 연결이 되지 않아 많이 안타깝네요. 스샷을 좀 찍어둔다는게 정신이 없어서 못찍었네요. 그나마도 클베 끝나고 드가서 시작 화면 하나 찍었습니다. ㅠㅜ~ 클베 끝날 때 GM이랑 애들이랑 막 밖에서 댄스타임하길래 그 때 나중에 글 올리려고 스샷을 찍어 둔다고 찍었는데 Print Screen 누른다는게 그만 Pause를 계속 연타해서 하나도 못건졌습니다.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[아버지와 나…]]></title><description><![CDATA[#0 일요일 저녁. 술을 한 잔 하고는 집으로 들어왔다. 11시쯤 됐던가? 이른 시간이었지만 피곤했는지 집에 와서는 그 길로 잠들어 버렸다. 일어나니 새벽 3시. 한참을 고민했다. 이상하게 안가던 떼목욕이 가고 싶었기 때문이다.…]]></description><link>https://jiniya.net/wp/archives/5518</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5518</guid><pubDate>Tue, 13 Dec 2011 23:57:55 GMT</pubDate><content:encoded>&lt;h3&gt;#0&lt;/h3&gt;
&lt;p&gt;일요일 저녁. 술을 한 잔 하고는 집으로 들어왔다. 11시쯤 됐던가? 이른 시간이었지만 피곤했는지 집에 와서는 그 길로 잠들어 버렸다. 일어나니 새벽 3시. 한참을 고민했다. 이상하게 안가던 떼목욕이 가고 싶었기 때문이다. 4시쯤이 돼서는 기어코 목욕 가방을 챙기고 길을 나섰다. 4시부터 5시까지 탕을 청소한다는 말에도 아랑곳하지 않고 들어가서는 신나게 목욕을 했다. 간만에 탕에 몸을 담그고 떼를 밀고나니 한 결 머리가 가벼워진 느낌이었다.&lt;/p&gt;
&lt;p&gt;어린 시절 아빠는 목욕을 끝내곤 곧잘 삼육두유를 마셨다. 나도 그런 그의 취향을 물려받아 떼목욕을 하고 나면 으레 삼육두유를 하나씩 먹곤 했다. 그날도 냉장고를 뚫어져라 뒤졌다. 하지만 삼육두유는 없었다. 순두유를 마셨다.&lt;/p&gt;
&lt;p&gt;백팩을 가지러 회사에 들렸다 집으로 돌아왔다. 내일은 과제 완료 발표가 있었고, 다음주 토요일에는 엄마 CT 촬영이 있었다. 보고서도 써야 했고 집 청소도 해야 했다. 귀찮은 생각이 들어서 그냥 다 잊고 침대에 몸을 뉘였다. 그때 핸드폰 벨이 울렸다. 엄마다. 전화를 받고는 엄마, 하는데 반대편에서 “느그 아버지가…”하는 광란에 빠진 한 마리 짐승의 절규만 들리고는 전화가 끊어졌다. 다시 전화를 하려는데 작은 누나에게 전화가 먼저 왔다. 울고불고 정신 없는 상태에서 누나는 나에게 재차 아버지 부고를 전했다.&lt;/p&gt;
&lt;p&gt;멍했다. 처음에는 마치 이 모든 사실이 농담처럼 느껴졌다. 그것도 잠시 주섬주섬 아무 옷이나 챙겨 입고는 뒤도 돌아보지 않고 집을 나왔다. 택시를 타고는 공항으로 향했다. 눈물이 났다. 너무 슬프면 눈물도 나지 않는다고 했는데 내 평생에 그렇게 구슬프게 모르는 사람 앞에서 처절하게 울었던 적은 처음이었다. 이상한 듯 쳐다보는 택시 아저씨의 시선도 무시한 채 엉엉 울었다. 너무 슬펐다. 뭔지 모를 감정이 내 머릿속을 헤집고 다녔고, 내 심장에서는 뭔가 대단한 덩어리가 빠져나간 느낌이었다.&lt;/p&gt;
&lt;p&gt;그의 죽음은 나에게 이렇게 어처구니 없이 갑작스럽게 차가운 바람처럼 다가왔다.&lt;/p&gt;
&lt;h3&gt;#1&lt;/h3&gt;
&lt;p&gt;부산에서 친구 결혼식이 있던 날이었다. 역시나 난 늦잠을 잤고 늘 그렇듯이 부리나케 서울역으로 가서는 아무 기차나 올라탔다. 입석이었다. 11월임에도 날씨가 무던 덥던 날이었다. 부산 양정에서 결혼식이 있었는데 양정에 도착하자 정말 애매모호한 시간만 남았다. 집에 가서 정장을 갈아입고 오기엔 시간이 너무 촉박해 그냥 근처 커피숍을 찾아 들어갔다. 부산 날씨는 그야말로 7월 장마철 날씨였다. 습하고, 더웠고, 불쾌지수는 상상을 초월했다.&lt;/p&gt;
&lt;p&gt;결혼식이 끝나고 친구들과 술을 한 잔 하고는 저녁쯤 본가 기습을 단행했다. 동래부터 온천천을 호기롭게 걸어가며 엄마한테 전화를 건다. 별 일 없냐는 나의 질문. 엄마는 대뜸 아빠가 입원했다가 어제 퇴원했다는 이야기를 한다. 종합 검진을 받았는데 장기들 기능이 떨어져서 그렇지 관리만 잘하면 큰 문제는 없다는 이야기를 의사가 했다고 전해준다. 그러다 배터리가 다돼서 전화가 끊겼다.&lt;/p&gt;
&lt;p&gt;집에 도착했다. 1302호. 내가 고등학교를 다니던 무렵부터 이 곳에 살았다. 이제는 익숙하지 않은 비밀번호를 누르고는 들어가면서 신나게 소리친다. 사랑하는 아들이 왔노라고. 쇼파에 앉아서 TV를 보고 있던 아빠는 늘 그랬듯이, “영지~ 왔나?”라는 말을 하며 아주 반갑게 맞아 주셨다.&lt;/p&gt;
&lt;p&gt;다음날 아침. 아빠는 목욕을 가고 싶어 했다. 그렇게 엄마가 가라고 할 때는 가지 않다가 교통사고가 난 불편한 발을 이끌고 기어코 목욕을 가겠다고 고집을 부리신 것이었다. 고집을 이기지 못한 엄마가 나에게 같이 가라고 했다. 그러겠다고. 그렇게 집을 나와서는 거의 20년 만에 처음으로 목욕탕 가는 길을 함께 걸었다. 하필 옆 상가에 목욕탕이 없어져서 먼 길을 걸어서 가야 했다. 비는 여전히 추적추적 내리고 있었다. 5m를 가다가 잠시 앉아 쉬고, 또 열 걸음을 가다 쉬곤 했다. 그러기를 5-6회 기어코 아빠는 다리 한 가운데서 주저 앉았다. 저혈당이 온 것이다. 평소 가지고 다니시던 사탕이 없어 부리나케 근처 구멍가게에서 사탕을 사왔다. 그러고도 수습이 되질 않았다. 결국 엄마를 불러서 차에 태워서 집으로 다시 돌아갈 수 밖에 없었다.&lt;/p&gt;
&lt;p&gt;집에 와서는 한참 동안 아빠를 타박한다. “왜 엄마 말을 듣지 않느냐?”부터 시작해서 갖은 타박을 다했다. 아픈 것도 야속한데 하나 있는 아들이 그랬으니 그 심정이 오죽했을까? 그런데도 아빠는 싫은 내색 한 번 하지 않고 아들이 자신을 살렸다는 이야기를 하시며 해맑게 웃으셨다.&lt;/p&gt;
&lt;p&gt;이 장면이 내가 기억하는 그의 마지막 모습이다. 물론 이렇게 되리란 걸 상상도 못했지만 그렇게 돼 버렸다. 야속하게도 말이다. 물론 내가 그의 마음을 야속하게 한 것에 비하면 이 일은 아무 것도 아닌지도 모르겠다. 그럼에도 너무 슬프고, 애통하고, 비통하고, 원통하다. 또 그가 너무 원망스럽다. 그는 평생 자신을 이해해 주지 않았던 나를 한번도 원망하지 않았지만, 난 단 한 차례 그가 나의 바램을 꺾었다는 이유만으로 그를 원망한다는 사실이 비겁하다는 생각이 들었지만, 마음은 어쩔 수가 없었다. 이제는 그의 모습을 볼 수 없다. 목소리도 들을 수 없으며, 체취를 느낄 수도 없다. ‘영원’이란 단어가 허용된다면 단 한 곳, 바로 이 상황에 쓸 수 있다는 생각이 들었다. 그는 영원히 우리 곁을 떠났다.&lt;/p&gt;
&lt;h3&gt;#2&lt;/h3&gt;
&lt;p&gt;2년 전 크리스마스였다. 여자친구와 파르나서스 박사의 상상극장이라는 내 생애 최악의 영화로 꼽을 만한 영화를 이브 날에 보고는 술을 마시며 밤을 보냈다. 그리곤 크리스마스 날 오후에 눈을 떴을 때 엄마에게 전화가 왔다. 아빠가 쓰러져서 대학병원에 입원했다는 전화였다. 부리나케 비행기를 예약하고는 전화 받고 한 시간도 안되어서 공항에서 비행기를 탔다. 참 시트콤같은 크리스마스였다.&lt;/p&gt;
&lt;p&gt;택시를 타고 도착한 대학병원. 엄마와 작은 누나가 있었고, 머지 않아서 큰 누나도 왔다. 아빠는 의식이 없었다. 우리는 의식이 없는 아빠를 쳐다보면서 황당하게 크리스마스 당일에 가족이 다 모인 게 정말 얼마 만인지 모르겠다는 이야기를 했다. 실로 큰 누나가 20살이 된 이후로는 단 한 차례도 없었던 것 같았기 때문이다. 아마 올해도 아빠가 스러지지 않았다면 우리는 모두 따로 각자의 크리스마스를 보냈을 것이다.&lt;/p&gt;
&lt;p&gt;병원에서는 아버지께서 돌아가실 수도 있다는 말을 하면서 마음의 준비를 하라는 이야기를 했다. 하지만 아빠는 우리의 바램을 저버리지 않고 다시 일어났다. 그가 깨어났을 때 난 정말 우리 아빠라는 생각을 했다. 그가 깨어나고 처음 한 말이 저기 간호사가 이쁘다면서 나보고 꼬셔보라는 농이었기 때문이었다. 난 아빠가 농을 하는 걸 보니 다 나은 것 같다고 너스레를 떨었다.&lt;/p&gt;
&lt;p&gt;그렇게 우리는 그 해 크리스마스를 병원에서 함께 보냈다. 작은 누나는 다음 해 아빠가 퇴원하기가 무섭게 그때 병문안을 왔던 남자와 결혼을 했다. 돌이켜보니 누나 나이도 있겠지만 아빠의 건강 때문에 결혼식이 더 빨리 진행됐던 것 같다.&lt;/p&gt;
&lt;h3&gt;#3&lt;/h3&gt;
&lt;p&gt;장례식장, 상주 자리에 앉아서 그의 영정 사진을 멍하니 쳐다보고 있다. 지난 2년여의 시간이 스펙트럼처럼 머릿속을 뒤지고 돌아다닌다. 신성태라는 아빠 이름 앞에 붙은 ‘고’라는 한자를 볼 때면 이상하게 눈물이 났다. 그 한 글자가 아빠의 영면을 부인하는 나에게 그의 죽음을 계속 강요하는 느낌이 들었기 때문이었다.&lt;/p&gt;
&lt;p&gt;당연한 이야기겠지만 이 모든 슬픔과 아픔에도 시간은 하염없이 흘러갔고 장례식도 끝이 났다. 한 평생을 싸웠던 엄마는 장례식이 끝나고 그래도 그는 따뜻한 사람이었다는 이야기를 생전 처음으로 자식들에게 들려줬다. 엄마의 타박도 그는 항상 묵묵히 받아 줬으며, 야망을 가진 한 평생을 살지는 않았지만 적어도 그는 살아생전 누구에게도 피해를 주지 않으려는 착한 사람이었다고 말했다. 우리 모두는 눈물을 훔쳤다.&lt;/p&gt;
&lt;h3&gt;#4&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;세상은 요지경 속이다.&lt;/p&gt;
&lt;p&gt;이 다음에 무슨 일이 닥쳐올지 알 수 있다면&lt;/p&gt;
&lt;p&gt;물이 막혀 넘치는 주방, 옻이 올라 가려운 피부&lt;/p&gt;
&lt;p&gt;그리고 죽일 듯이 싸우던 순간들이&lt;/p&gt;
&lt;p&gt;앞으로 다가올 일에 비하면&lt;/p&gt;
&lt;p&gt;우리 생애 최고의 순간이라는 것을 깨닫게 도와줄 수 있을까?&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;– Grey’s Anatomy S08E09&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;사람들은 늘 어리석다. 많은 사람들이 자신은 예외라고 생각하지만 큰 착각이다. 나 또한 예외는 아니었다. 화장실이 고장 난 통에 물바다가 된 주방에서 밤새 고생했던 날, 보일러가 갑작스레 고장 난 월요일 아침, 코딩할 게 너무 많다고 투덜거렸던 새벽, 쓰기 싫은 보고서에 치여서 한숨 쉬던 날들을 돌아 본다. 힘들다고 생각했던 그 순간들 조차도 지금 생각해보니 정말 아름다운 시간이 아니었나 하는 느낌이 들었다. 단지 그와 내가 같은 하늘 아래에서 함께 숨쉬고 있다는 그 사실, 아주 사소하게 생각했지만 전혀 사소하지 않았던 그 사실 하나만으로 말이다.&lt;/p&gt;
&lt;p&gt;우리는 소중한 것들을 잃어버린 후에야 그것이 얼마나 소중했는지를 깨닫는다.&lt;/p&gt;
&lt;p&gt;똑같은 실수를 두 번 하지는 말자.&lt;/p&gt;
&lt;p&gt;절대로!!!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Unicode Windows Internals]]></title><description><![CDATA[There are many developers in Windows environment who are well aware of the Unicode function but not specifically with the Unicode Windows…]]></description><link>https://jiniya.net/wp/archives/5532</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5532</guid><pubDate>Mon, 12 Dec 2011 23:57:54 GMT</pubDate><content:encoded>&lt;p&gt;There are many developers in Windows environment who are well aware of the Unicode function but not specifically with the Unicode Windows. One could argue that this is because the majority of books do not directly demonstrate it as the first reason, and secondly because it’s concealed by Windows API. This post explores the principles of Unicode Windows for those rookie developers who are not yet familiar with this system.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In order to understand the Unicode Windows, we need the full understanding of activity structure of Unicode function that Windows support. The Windows provides two primary versions of Unicode for most functions that handle the string. Multi-byte version with A is attached to, and the Unicode version which W is attached to. In other words, there’s ‘GetWindowTextA’ and ‘GetWindowTextW’. The performance of the two functions are equal, with the difference that A function gets char pointer as the parameter, while W gets ‘wchar-t’ as the parameter.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;_UNICODE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;GetWindowText&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;GetWindowTextW&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;GetWindowText&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;GetWindowTextA&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In other words, if our build environment is under Unicode, GetWindowText becomes GetWindowTextW, while GetWindowTextA is resulted when it’s under multi-byte. This allows us to use the T typed neutral character with the system, with the neutral API which is redefined with the Macro without A and W. Moreover, the T typed neutral function on character string handling gets redefined by the macro, which allows us to generate the code regardless of the multi-byte build.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;TCHAR buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;MAX_PATH&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;GetWindowText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hwnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ARRAYSIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;_tcscat_s&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ARRAYSIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;$&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Although development process is done with no such issues with programs adequately compiling according to the build due to the well-structured Window Subsystem, it is difficult to know the root of the issue if the conversion problem breaks out.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We will now cover our main subject, the Unicode Window. One can define the Unicode Window as the Window that uses the Unicode when processing a message, which makes sense to have the ’ansi window’ on the other hand, which processes the message via multi-byte message.&lt;/p&gt;
&lt;p&gt;If you were a developer with a little more insights, you could question what exactly it means to proceed by ‘unicode’. Here is a simple example with WM_GETTEXT message. Its WParam appoints the number of letters, while IParam appoints the buffer pointer that can save the letters. The question in this case is, Should one deliver the Unicode buffer via Iparam? Or multi-byte buffer? In other words, in the identical code as mentioned, is it right to use StringCchCopyW? Or StringCchCopyA?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;LRESULT CALLBACK &lt;span class=&quot;token function&quot;&gt;MyWindowProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HWND hwnd
                              &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; UINT msg
                              &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WPARAM w
                              &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPARAM l&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; WM_GETTEXT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
         &lt;span class=&quot;token comment&quot;&gt;// StringCchCopyW((LPWSTR) l, w, L&quot;MyWindowText&quot;);&lt;/span&gt;
         &lt;span class=&quot;token comment&quot;&gt;// or&lt;/span&gt;
         &lt;span class=&quot;token comment&quot;&gt;// StringCchCopyA((LPSTR) l, w, &quot;MyWindowText&quot;);&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DefWindowProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hwnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; w&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; l&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Most of the developers wouldn’t have wondered such issue, as Window subsystem does an excellent job of hiding it. Ultimately, we should handle ‘ansi window’ by multi-byte buffer, and Unicode window by Unicode buffer in dealing with ‘WM-GETTEXT’. In other words, you will result having an abnormally functioning window if you have multi-byte pointer handling Unicode Window, and vice versa with ansi-window.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Now, we’re going to cover how Unicode Window is created. Developing the Unicode Window involves the ‘RegisterClass’ function. Although no parameter of this function has the function of categorizing the new Window into the Unicode or not, it is decided automatically depending on the type of function it’s calling out. A window becomes a Unicode window when one uses the Unicode class is&lt;/p&gt;
&lt;p&gt;We can also identify if a particular Window is Unicode window or not by ‘Spy++ utility’. When we search through the Window and its property using Spy++, it shows ‘Unicode’ on Window Proc section. If it doesn’t have it, we can understand that it’s the ansi window.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 458px; margin-bottom: 16px;&apos; data-url=&apos;./Unicode_Windows_Internals.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5a51fcbc4aa4a4b538ccce81a702e55e/e5e51/Unicode_Windows_Internals.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 61.05263157894737%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAAsTAAALEwEAmpwYAAACDUlEQVR42m1Sa4+aQBTl//+EfmjSJk2atummxqRttnHXXdRVHgLyFBAY3iAvEVwDSi/YL5t0cnKZOeHcOXNmMJwUcFrqKyUsJftFzZ7kdCICsokEyB+V4kHOH6V0tk2XWkrtUgaVvB7++PAR2wiKpuuapvOCSK8Zes0tXlYsJ1A0w3I8RbMEScmK6gWh5wc3uJ6fpMliSWKqbu7jOIpj23F4XoiiyDDReiMiL0RuYPvRDjleuM/LOj1UWVkDkqJ8bVqa2WCaYZqmoes6fCRJapomzfI1wziu2zZt13XX67WvXXergPZygTnNcJis7kzDkGVF07Qsy4CN45gkSUVRtoDtNvD98/lcHY9VXQ8dussgJtcbTNzqjm2zLKuq6uFwABYqKC3L4nkevIAj6AteoNFbMYdJqhEEPvwHzouiADbPc1mWYYkQAoFt29ACmPrtzgTNYbykWpapDA6hgsMkSWazmSiKbdvCgS/DuJ38P2Lfc0EIF1ZVFbAgxnEctroO46a8DPgXWNsHuQLbG0n1XLePfLdL9zGwp/oIl5cXRX06lUcIqoIJpAW4LWEC+iXF9oE153NxKPW04py9HOZ6dgqT1EbIMk24dtd10TAcx4EHEQQBBLSPIwJ2vp/ORUmhOeE7Ib//Q7z7Nf+6VKYLYjT++e1u9ITPH6bPd6MxAJjZYjWZPn/6/KUnx7//AoHOfq9En977AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Unicode Windows Internals md 0&apos; title=&apos;&apos; src=&apos;/static/5a51fcbc4aa4a4b538ccce81a702e55e/e5e51/Unicode_Windows_Internals.md_0.png&apos; srcset=&apos;/static/5a51fcbc4aa4a4b538ccce81a702e55e/08678/Unicode_Windows_Internals.md_0.png 190w,
/static/5a51fcbc4aa4a4b538ccce81a702e55e/2edd7/Unicode_Windows_Internals.md_0.png 380w,
/static/5a51fcbc4aa4a4b538ccce81a702e55e/e5e51/Unicode_Windows_Internals.md_0.png 458w&apos; sizes=&apos;(max-width: 458px) 100vw, 458px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;However, one could wonder, why is it so important to know whether it’s a Unicode window or not? First of all, it’s because there could be an error with the handler if we didn’t know about it. As seen below, Window class registration is left under Unicode window and the particular window message procedure: for eg; ‘WM_GETTEX’ is processes via multi-byte, which will obviously cause an error.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;WNDCLASSEXW wcex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
wcex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lpfnWndProc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; WndProc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;RegisterClassExW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;wcex&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

LRESULT CALLBACK &lt;span class=&quot;token function&quot;&gt;WndProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HWND wnd
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; UINT message
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WPARAM w
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPARAM l&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;message &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; WM_GETTEXT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;StringCchCopyA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPSTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; l&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; w&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lstrlenA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPSTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; l&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DefWindowProcW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; message&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; w&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; l&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Secondly, this is one of the most important effect for any action related to the Window, which can complicate the system if you’re not fully aware of the system. Say for example, we are sub-classing a particular window. In this case also, we neede to use ‘SetWindowLongW’ for a Unicode, and ‘SetWindowLongA’ for multi-byte. If it were done in an opposite way, the original window message will be dealt with by the Unicode, with the procedure which sub-classes it using multi-byte system. Moreover, even when the original window is the Unicode window, it will turn into the ansi-window once the sub-classing is done via ‘SetWindowLongA’. Using the sub-classing function without the internal mechanisms as noted could cause a complicated conversion issues.&lt;/p&gt;
&lt;p&gt;Here is another example. Most message procedure consists of creating only the critical parts, leaving the rest upto the ‘DefWindowProc’ function, which could either be ‘DefWindowProcA’ or DefWindowProcW, which is where the problem could occur with the system not responding as expected in some cases. The window below shows the similar case. The case below refers to the similar case, when ‘defWindowProcW’ is called for after creating the ANSI window using ‘RegisterClass’ A function. If it were processed correctly, it would show Hello on the title bar, but you can notice something else instead below.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 337px; margin-bottom: 16px;&apos; data-url=&apos;./Unicode_Windows_Internals.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/501c1c5256bcfaa44ff76af6cbe0ca80/f57f1/Unicode_Windows_Internals.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 50.526315789473685%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAAsTAAALEwEAmpwYAAABVElEQVR42mPonLZw2oKVHd29nb0TSqvq2rv7qxuaU7MLHLyDtczsdMwdrJx9XP3CcooqOnsntfZOntLaujorfntFbnd6EsPMhStXrd+xat2WhUtWzV+6euGyNbMWLOvsn5Zf3piaX5FWUJldXFtc3dLYMbFn8uyJMxZMn7UAiFfOX9je1sWwcevuS5fv33nw5tDhcw+efnjx9ufz19+B5Ov3v998+ANGv4Hsl29/vnjzA0S+/fnk9Y8P3/5v2LaP4dSZc//////9+/e/f//+IoE/qABZ4tevn0Athw4fZdi1dz+QBZT8TzQAmgUkN2/bwbB91144nyTNm7ZsZ9i0bQd5mtdu2Mywet1GIOvXr19/iQZAxUAty1etZVixZj2pNv8GK166YjVDRV3z1h27Vq3bAHTG+k1bN2zehoaAgus2bVmzYdPq9ZvWgNHKtRuAWkqrGwDot/b+W6nK/wAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Unicode Windows Internals md 1&apos; title=&apos;&apos; src=&apos;/static/501c1c5256bcfaa44ff76af6cbe0ca80/f57f1/Unicode_Windows_Internals.md_1.png&apos; srcset=&apos;/static/501c1c5256bcfaa44ff76af6cbe0ca80/08678/Unicode_Windows_Internals.md_1.png 190w,
/static/501c1c5256bcfaa44ff76af6cbe0ca80/f57f1/Unicode_Windows_Internals.md_1.png 337w&apos; sizes=&apos;(max-width: 337px) 100vw, 337px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;To avoid the mistakes mentioned previously, all we need is to have the understanding of the existence of Unicode and its procedure. Its procedure is that it uses W function for Windows, and A type for the multi-byte window. And lastly, that the related windows deal with messages by either Unicode or multi-byte.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#4&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Knowing the existence of Unicode window and being aware of what kind of disasters you might face, one could probably wonder how we could find out whether the window we are working on is a Unicode or not. There is a very simple function for it, called “IsWindowUnicode”. If you receive a false message after you type in “IsWindowUnicdoe(hwnd), it means that you’re working on an ansi-window, while if you have other answers instead of FALSE, your Window turns out to be a Unicode.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#5&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Lastly, I would like to cover a few things. For those developers who have already tested the codes, you will notice that you end up getting ‘WM_GETTEXT’ no matter which one you type in out of ‘DefWindowProcA’ or ‘DefWindowProcW’ out of the Unicode or ansi. The reason for this is simple. If its coded as protectively as shown, it can solve the character string no matter the type of window that’s used.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WM_GETTEXT&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;IsWindowUnicode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hWnd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;StringCchCopyW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPWSTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; lParam&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; wParam&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lstrlenW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPWSTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; lParam&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;StringCchCopyA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPSTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; lParam&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; wParam&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lstrlenA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPSTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; lParam&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Some of those who are reading this post might think that one should stick to ‘SendMessageW’ for Unicode, and ‘SendMessageA’ for ansi even when sending the message in a particular window. It is smart, but the reality is not as inconvenient as it seems. Through the test, you would notice the system delivering the correct answer no matter whether if you’ve used ‘SendMessageA’ or ‘SendMessageW’, as long as you have delivered the adequate buffer. In other words, ‘SendMessage’ function does all the hard work of appointing the adequate buffer or conversing the ‘IsWindowUnicode’ into ‘WideeCharToMultibyte’ etc. Moreover, other than WM_GETTEXT, ‘sendMessage’ functions as to adequately change the messages that we need the conversion on. All we need to remember is to use ‘SendMessage A’ for ansi, and ‘SendessageW ‘for the Unicode.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[저장소 업적 놀이… ㅋㅋ~]]></title><description><![CDATA[어제는 또 사고를 쳤습니다. 뭐냐구요? 버그죠 ㅋㅋ~ 반성하는 마음으로 디버깅을 밤새 하고는 이전 글에 적었던 충돌 문제도 해결했습니다. QA…]]></description><link>https://jiniya.net/wp/archives/5361</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5361</guid><pubDate>Fri, 25 Nov 2011 23:57:53 GMT</pubDate><content:encoded>&lt;p&gt;어제는 또 사고를 쳤습니다. 뭐냐구요? 버그죠 ㅋㅋ~ 반성하는 마음으로 디버깅을 밤새 하고는 &lt;a href=&quot;http://www.jiniya.net/wp/archives/5339&quot;&gt;이전 글에 적었던 충돌 문제&lt;/a&gt;도 해결했습니다. QA팀이 출근할 때에 맞춰서 따끈따끈한 빌드를 만들어 놔야겠다는 생각에 빌드를 돌려 놓고는 기다리다 심심해서 간만에 저장소 통계를 돌려 봤습니다. 예전에는 재미삼아 한 달마다 돌려서 개발팀끼리 업적 놀이도 하곤 했었는데 말이죠… ㅋㅋ~ 먹고 사는게 바쁘다보니 그런 것도 해본지가 한 백만년은 된 듯 하네욤. 절대로 우리 회사는 이런 걸로 개발자를 압박하거나 그러진 않습니다. ㅋㅋㅋ~ 여튼 랭킹 한 번 볼까요?&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 540px; margin-bottom: 16px;&apos; data-url=&apos;./저장소_업적_놀이_ㅋㅋ~.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/7ad7824300d29fc11a2cf55d5e163957/03ec9/%EC%A0%80%EC%9E%A5%EC%86%8C_%EC%97%85%EC%A0%81_%EB%86%80%EC%9D%B4_%E3%85%8B%E3%85%8B~.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 40.526315789473685%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAA7DAAAOwwHHb6hkAAABf0lEQVR42hWQ6W7bMBCE9f6PUiB2LFEUKR46HOiKLYu6r8hJkKAtULQJGqB/OwYIYrHkzHy71rfjJTCrLKdD0p/GbZ/0OOI8PfZrWi+pmfP2KWsWL87uuAoLkzdr1q6pWfJpsMQoH97S6BrLWWffc7FoFOFTFG4Ra5malByl6H0xCN4xr/bUpNUo1azzH4XFe65m/BCs8eLnWAzc7zjvOOq7dMcadl/svcZzK0IqisI+H3b5Pn45Nn8bi3VMLVovtwQI4CJn5fciukZO6SDcH3wo7bONghoabdHp17n8XVYfxsKzXgNoXEPj5yO8XOOy1iOlvct2vOWkJE5JQL4v7knpYEA0k7fEQIyc4+tDfI2CNUjeUzVJvQTBEoAFGj0rWlE5KczMOp6+J8XPovlqhn8Dbgs5N84OCQ4fBK1dDEZrGm7h4WRjQ0ClxkW+W7nUEN77lz+X6rMCuSWn26jYKviBHaxaTLdlRltILgR9sMAaFmIUvGVAMJ91+9WaD/Mf9Vl1UGxoWR0AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;              md 0&apos; title=&apos;&apos; src=&apos;/static/7ad7824300d29fc11a2cf55d5e163957/03ec9/%EC%A0%80%EC%9E%A5%EC%86%8C_%EC%97%85%EC%A0%81_%EB%86%80%EC%9D%B4_%E3%85%8B%E3%85%8B~.md_0.png&apos; srcset=&apos;/static/7ad7824300d29fc11a2cf55d5e163957/08678/%EC%A0%80%EC%9E%A5%EC%86%8C_%EC%97%85%EC%A0%81_%EB%86%80%EC%9D%B4_%E3%85%8B%E3%85%8B~.md_0.png 190w,
/static/7ad7824300d29fc11a2cf55d5e163957/2edd7/%EC%A0%80%EC%9E%A5%EC%86%8C_%EC%97%85%EC%A0%81_%EB%86%80%EC%9D%B4_%E3%85%8B%E3%85%8B~.md_0.png 380w,
/static/7ad7824300d29fc11a2cf55d5e163957/03ec9/%EC%A0%80%EC%9E%A5%EC%86%8C_%EC%97%85%EC%A0%81_%EB%86%80%EC%9D%B4_%E3%85%8B%E3%85%8B~.md_0.png 540w&apos; sizes=&apos;(max-width: 540px) 100vw, 540px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
역시 codewiz라는 감탄사가 절로 나오죠? 이건 어느 나라 깔때긴지? ㅋㅋ 무려 7개월 동안 연속 1등을 놓치지 않는 기염을 토했습니다. 4월에 zippolook에게 습격 받지만 않았어도 좀 더 장기간 집권할 수 있었는데 아쉽군요. 물론 이거보다 더 기가막힌 통계 자료가 있긴 하지만 그건 너무 심한 깔때긴것 같아서 자체 검열했습니다. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;저장소 업적을 좀 살펴볼까요? 돈 좀 벌자는 우리의 염원을 담아서 GoldRush라 지었답니다. 실제로 캘리포니아로 골드러시를 갔던 분들의 말로가 어떻게 됐는지는 미처 고려하지 못했습니다. 흠흠. 작년 1월 22일에 저장소를 만들었네요. 무려 672일이나 됐군요. 하루 평균 3.6개를 커밋했습니다. 장난 아니죠? 우리 회사 개발자들이 참 열심히 합니다. 개발자가 13명이라고 나와있는데 실제로 이 저장소를 거쳐간 개발자는 6명입니다. zippolook이 어찌나 줏대 없이 아무 아이디나 막 쓰는지 혼자 4-5개를 썼더군요 헐~ ㅋㅋㅋ~&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Project name: GoldRush&lt;br&gt;
&lt;br&gt;
Generated: 2011-11-25 08:37:59 (in 227 seconds)&lt;br&gt;
&lt;br&gt;
Generator: GitStats (version d2b5b32)&lt;br&gt;
&lt;br&gt;
Report Period: 2010-01-22 17:02:59 to 2011-11-25 08:25:23&lt;br&gt;
&lt;br&gt;
Age: 672 days, 382 active days (56.85%)&lt;br&gt;
&lt;br&gt;
Total Files: 3482&lt;br&gt;
&lt;br&gt;
Total Lines of Code: 1220952 (1678694 added, 457742 removed)&lt;br&gt;
&lt;br&gt;
Total Commits: 2397 (average 6.3 commits per active day, 3.6 per all days)&lt;br&gt;
&lt;br&gt;
Authors: 13&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 620px; margin-bottom: 16px;&apos; data-url=&apos;./저장소_업적_놀이_ㅋㅋ~.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/67c0f6ba68fb5907f2fbca7330605536/abf7b/%EC%A0%80%EC%9E%A5%EC%86%8C_%EC%97%85%EC%A0%81_%EB%86%80%EC%9D%B4_%E3%85%8B%E3%85%8B~.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 45.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsTAAALEwEAmpwYAAABeElEQVR42o2RzWrCQBDH168mmmhTo6WplkDryYMXIXjbi8qCQb0siogLHlQUUQ895zk895aXyAv02JOXglBKn2I7E1ooQUgXfkwmM/vf+SAEjhDCmM1mFfjUARXI/hP1giVkt9sZ4/H4vtVqZaWUSd/3U3F4kCcZU2SzmZO2rUrOr0i1iqIksV6v9clkYjchGCZ7XjqOz0ZDe6vX9dfFIoME8K+KgqvV6na5XFZA8NGGl+IEOcTP0Mk7pSqP5FqWlSOHw6Gy3++t0Wj0gIJxLWM1X1DZpVgoOJ/P85vNxsQZQvsKzgBEE1ECStOnWk35gEswtwwkJaCq5F9+FkMIVghbfqrBBXk8Zs6cZ6UQash2q0jXzYWAfwLflzIVBEE6SlghHlwKF+Juoeull2Kx8GyaecQrl3W0LiTiYwiOBYePNgpIaeT3TKdTjTNW7vV6N5RSgw4GhsNYYTgcmp1OR2u329cY63a7RbToI67rlhjkOY5T6Pf7+W9eQNi/0Atr/AAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;              md 1&apos; title=&apos;&apos; src=&apos;/static/67c0f6ba68fb5907f2fbca7330605536/abf7b/%EC%A0%80%EC%9E%A5%EC%86%8C_%EC%97%85%EC%A0%81_%EB%86%80%EC%9D%B4_%E3%85%8B%E3%85%8B~.md_1.png&apos; srcset=&apos;/static/67c0f6ba68fb5907f2fbca7330605536/08678/%EC%A0%80%EC%9E%A5%EC%86%8C_%EC%97%85%EC%A0%81_%EB%86%80%EC%9D%B4_%E3%85%8B%E3%85%8B~.md_1.png 190w,
/static/67c0f6ba68fb5907f2fbca7330605536/2edd7/%EC%A0%80%EC%9E%A5%EC%86%8C_%EC%97%85%EC%A0%81_%EB%86%80%EC%9D%B4_%E3%85%8B%E3%85%8B~.md_1.png 380w,
/static/67c0f6ba68fb5907f2fbca7330605536/abf7b/%EC%A0%80%EC%9E%A5%EC%86%8C_%EC%97%85%EC%A0%81_%EB%86%80%EC%9D%B4_%E3%85%8B%E3%85%8B~.md_1.png 620w&apos; sizes=&apos;(max-width: 620px) 100vw, 620px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
LOC 그래프입니다. 뭔가 좀 경이롭지 않나요? 도대체 5-8월에 무슨 일이 있었던 걸까요? 사실 저 시기가 거의 죽음의 시기이긴 했습니다. 진짜 밥만먹고 코딩했던 것 같네요. 밥도 안먹고 코딩했었나? ㅋㅋ 그래도 거품이 좀 심하죠. 사실 저 기간에 늘어난 LOC 중에 거의 대부분은 IP 지역을 저장하고 있는 SQL 파일이 주범입니다. 500k나 되더군요. 헐. 네 맞습니다. 전체 LOC 거의 절반이 그겁니다. 그래도 이전 버전에서 가져온 코드가 180k 정도니 그 사이에 정말 많이 늘긴 했네요.&lt;/p&gt;
&lt;p&gt;프로그래머라는 명함을 판지 한 10년 돼 가는것 같은데, XIGNCODE를 5년 동안 개발했으니 제 경력의 절반은 XIGNCODE와 함께 했다고 해도 과언이 아니네요. 당연히 이리 오래 걸린다는 걸 알았다면 시작도 안했을 겁니다. 겁나서요 ㅋ~ 그래도 오랜 기간 한 제품을 만들어 본다는 건 정말 무엇과도 바꿀 수 없는 멋진 경험인 것 같습니다. 누가 알아주지 않더라도 말이죠. ㅋㅋ~ 5년간 저의 세계는 XIGNCODE였습니다. 내년에도 그랬으면 좋겠네요. 세상의 모든 해킹툴을 잡아내는 현자의 알고리즘(?!)을 찾는 그날까지 달리고 또 달려야죠. 빌드가 끝났네요. 테스트하러 가야겠습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] Collision Hell…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/5339</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5339</guid><pubDate>Fri, 25 Nov 2011 23:57:52 GMT</pubDate><content:encoded>&lt;p&gt;프로그래머로 밥 벌어 먹고 살면서 제일 싫어하는 단어가 생겼다. ‘크래시’, 밥 먹다가도 이 말만 들으면 먹던 내용물이 올라오는 느낌이 든다. 그만큼 듣기 싫은 말이고 짜증나는 말이며, 피하고 싶은 대상이다. 보안이라는 전문 분야를 정하고 나서는 싫어하는 단어가 하나 더 생겼는데 바로 ‘충돌’이다. 좋은 보안 프로그램을 만든다는 것은 달리 말하면 얼마나 많은 충돌을 피했는가로 귀결된다고 할 수 있다. 많은 보안 업체에서 자사 제품의 장점으로 내세우는 게 바로 다름아닌 충돌이 얼마나 없는가라는 사실도 이를 반증해 준다고 할 수 있겠다. 진짜 우습지 않은가? 보안 제품의 성능을 첫 번째 장점으로 말하는 것이 아니라 충돌이 없다는 것을 장점으로 말한다는 것이, 그런데 더 웃긴 건 고객들이 그걸 더 우선시한다는 점이다. 그만큼 실전에서 충돌은 아주 굉장히 중요한 요소다.&lt;/p&gt;
&lt;p&gt;5년간 게임 보안 제품을 만들면서 정말 온갖 충돌이란 충돌은 다 겪어 봤다고 생각했다. 유사 게임 보안 제품과의 충돌은 기본 안주고, 각종 타사 보안 제품들과의 충돌들이 있었다. 심지어는 게임 핵툴과의 충돌도 있었다. 커널 모드 게임 핵툴이 있었는데 그놈이 어설프게 작성하는 바람에 게임을 실행한 다음 그 핵툴을 실행하고, 그 상태에서 게임을 종료하면 블루스크린이 발생하는 문제가 있었다. 우습게도 우리는 충돌이 없다는 장점을 부각시키기 위해서 그 핵툴을 위해서 전체 훅 코드를 죄다 변경했다. 물론 지금 생각해보면 굉장한 오버 센스인데, 그 때는 그래야 하는 줄 알았다. 대단한 작업이었다. 훅코드를 죄다 변경했더니 이번에는 중국 방화벽 제품과 충돌이 발생했다. 그래서 해당 방화벽 제품을 위한 특수한 코드를 추가했다. 이런 식이다. 이 곳에는 신호등도 없고, 교통 법규도 없다. 그냥 무법 천지 세상에서 온갖 충돌을 피해야 한다. 그래서 이 세상에서는 경험이 닥치고 갑이며, 충돌을 피한다는 아무것도 아닌 사실이 우리의 가장 든든한 진입 장벽이 되어준다. 참 우스운 사실이다.&lt;/p&gt;
&lt;p&gt;이렇게 온갖 충돌을 겪었고, 그 온갖 충돌을 피하는 코드를 추가하다 보니 나름 이 바닥에서는 산전수전 다 겪었다고 생각을 했었다. 그랬는데. 오늘 진짜 핵폭탄 같은 충돌을 목격하고 말았다. 우리가 만드는 제품은 다름아닌 게임 보안 제품이다. 게임 프로그램이 동작하는 동안 부정 행위를 막아주는 그런 제품이다. 그런데 이런 게임 보안 제품이 게임 그 자체와 충돌이 발생하는 것이 아닌가? 좀 더 정확하게 말하자면 게임에 포함된 자체 보안 코드와 충돌이 발생하는 것이었다. 핡~ 게임 내 보안 코드가 게임 보안 제품을 잡는 우스운 상황. 정말 보고 어처구니가 없었다. 이렇게 말하고 보니 그 게임이 아주 큰 잘못을 한 것 같은데 사실은 전혀 그렇지 않다. 요즘은 워낙 해킹 이슈가 부각되다 보니 큰 게임 업체에서는 다들 자체 보안팀을 가지고 있고, 해당 보안팀에서도 게임의 보안을 향상 시키기 위한 모듈을 개발하기도 한다. 매우 바람직한 현상이며, 외부 보안 업체에게도 큰 힘이 되어준다. 왜냐하면 외부 보안 제품의 경우 게임과의 결합도가 일정 수준 이상으로 높아지기 힘들다는 단점이 있고 게임 개발팀과의 이야기를 하는데 한계가 있을 수 밖에 없는데 내부 보안팀은 그런 것들이 가능하기 때문이다. 어쨌든 해당 보안 코드는 자신의 의무를 다했다. 단지 우리는 다른 필요한 기능을 수행하기 위해서 그 코드의 사각 지대를 찾아야 할 뿐이다.&lt;/p&gt;
&lt;p&gt;여기까지만 딱 읽으면 우리가 항상 충돌을 당하는 입장처럼 보인다. 하지만 사실은 우리가 더 많은 충돌을 야기시키는 주범이기도 하다. 그런 불이익을 당하는 대부분의 프로그램은 게임 유틸리티다. 그런 유틸리티 중에 유명한 프로그램으로 반디캠이 있다. 게임 동영상을 촬영하는 유틸리티인데, 나도 한 때 와우 동영상을 찍기 위해서 애용하던 제품이었다. 프랩스보다 훨씬 강력한 유틸리티다. 그런 반디캠도 게임 보안 제품과 충돌이 잦은 편이다. 물론 우리 제품과도 다소 충돌이 있었다. 그래서 허용 처리를 해주었다. 이런 허용 처리를 하다 보면 반디캠의 신묘한 후킹 코드에 놀라곤 한다. 왜 당췌 이런 정상적인 유틸리티가 이리도 복잡한 방식으로 후킹을 하는 것일까, 라는 생각이 들었던 적이 한두 번이 아니었다. 대놓고 나는 반디캠 후킹 코드요, 라고 우리한테 말해 준다면 우리가 한결 허용 처리 하기가 쉬웠을 것이기 때문이다. 하지만 실상은 반디캠 개발자 분도 똑같은 고민이 있었음에 틀림이 없다. 보안 제품과의 충돌을 피하는 것이 그 제품에는 하나의 장점이 될 수도 있었을 것이기 때문이다. 그래서 보안 제품에 탐지되면 그걸 피하기 위한 보다 복잡한 방식을 생각해내다 보니 거기까지 가신 것이 아닐까?&lt;/p&gt;
&lt;p&gt;어쨌든 이쯤되면 한 가지 생각이 들 것이다. 사실 이 모든 게 정말 바보 같다는 사실이다. 충돌을 당하는 입장에는 그 충돌을 피하기 위해서 더 복잡한 코드를 작성하고, 충돌을 야기시킨 입장에서는 그 복잡해진 코드를 허용하기 위해서 더 복잡한 코드를 작성한다는 점이다. 즉, 여기엔 기본적으로 엔트로피를 증가시키는 악순환의 피드백 루프가 내장되어 있는 것이다. 이런 맥락에서 오늘밤 내가 작성할 코드도 언젠가는 그 게임에 내장된 자체 보안 코드를 작성한 분에겐 애물단지가 될 것이다. 내가 충돌을 피하기 위해서 작성한 복잡한 코드가 그걸 작성한 사람에게 다시 충돌이 되어 돌아가는 정말 요지경 같은 구조, 보고 있으면 그저 웃음 밖에는 나오질 않는다.&lt;/p&gt;
&lt;p&gt;예전에 어떤 TCP/IP 책인지 모르겠는데 CSMA/CD 설명이 나와 있는 책을 읽었던 적이 있었다. CSMA/CD 설명을 읽고는 참 심플하면서 신묘한 방법이라는 생각이 들었다. 오늘 밤, 또다시 충돌을 피하기 위한 코드를 작성하보니 CSMA/CD의 Collision Detect라는 말이 생각난다. 우리에겐 이 악순환의 피드백 루프를 끊고 자동으로 충돌을 탐지할 수 있는 방법이란 없을까?&lt;/p&gt;</content:encoded></item><item><title><![CDATA[디버깅 0교시: 절차대로]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/3997</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3997</guid><pubDate>Fri, 04 Nov 2011 23:57:51 GMT</pubDate><content:encoded>&lt;p&gt;요즘 여기 저기 다른 일들로 불려 다니는 경우가 많다 보니 회사에서 진득하게 앉아서 코딩을 해 본 적이 거의 없는 것 같다. 난 개발이 좋고, 개발 일을 할 때가 가장 행복하고, 가장 잘하는 것도 개발이지만, 그렇다고 개발만하고 살수는 없는 거니까. 현실 세계에서 살아남으려면 결국 손에 물을 묻히기도 해야 하는 법이다. 어쨌든. 그러다 어제 조금 한 숨 돌릴 짬이 났다. 신규 업체에 SDK 파일들을 전달해 주기에 앞서서 이번에 새로 추가된 기능도 있고, 매뉴얼도 업데이트된 부분이 있어서 개발팀 막내에게 숙제를 하나 내주게 되었다. TCP/IP로 간단한 소켓 통신 프로그램을 만들고, 거기다 매뉴얼보고 그대로 적용을 해보라는 것이었다. 개밥 먹기라고 했던가? 우리가 만든 것들이 제대로 되는지 확인해보고자 하는 심산이었다.&lt;/p&gt;
&lt;p&gt;뭐 어쨌든 돌아가는 놈들이니 다소 우여곡절이 있었지만 적용은 되었고 테스트가 진행이 되었다. 그런데 이상한 문제가 하나 발생했다. 이상하게 먼가가 정상적으로 돌아가지 않는 것이었다. 딱 2시간 걸린 것 같다. 막내가 매뉴얼에 적혀 있는 초기화 함수를 호출하지 않았던 것이었다. 로그 파일만 봐도 알법한 이 문제를 찾는데 2시간이나 걸리다니. 하지만 이건 복선에 불과했다.&lt;/p&gt;
&lt;p&gt;그 아주 가벼운 문제를 해결하고 심층 테스트로 넘어가려고 하는 순간 정말 요상한 문제가 발생했다. 이상하게 새로 만든 클라이언트와 서버 사이의 통신이 안되는 것이었다. 그것도 아주 통신이 안되는 것이 아닌 우리가 전달하려고 하는 일부 패킷만 이상해지는 문제였다. 이 문제가 좀 더 심오하게 보이는 이유는 새로운 서버에 기존 클라이언트로 접속하면 잘 되었고, 기존 서버에 새로운 클라이언트로 접속하면 잘되기 때문이었다. 정말 희한하게 새로운 서버와 새로운 클라이언트만 통신을 하면 이상해지는 문제였다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; margin-bottom: 16px;&apos; data-url=&apos;./디버깅_0교시_절차대로.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/c07e2711441dcf43aaed37ca9bc5408a/56d4e/%EB%94%94%EB%B2%84%EA%B9%85_0%EA%B5%90%EC%8B%9C_%EC%A0%88%EC%B0%A8%EB%8C%80%EB%A1%9C.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAQCAwX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAB0bVJjIoJ/8QAGhAAAgMBAQAAAAAAAAAAAAAAABIBAhETIf/aAAgBAQABBQL0aTR648HWp//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABcQAQEBAQAAAAAAAAAAAAAAAAAxECH/2gAIAQEABj8C5tVX/8QAGxABAAICAwAAAAAAAAAAAAAAAQARECFBcdH/2gAIAQEAAT8hUhrgQsqHLqFMNvif/9oADAMBAAIAAwAAABBXH//EABURAQEAAAAAAAAAAAAAAAAAABAR/9oACAEDAQE/EKf/xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPxCH/8QAHBABAAMBAAMBAAAAAAAAAAAAAQARITFBUbHR/9oACAEBAAE/EFJq014HuXaNm0eWXZ7AigAFW/IzDa3jDU+k/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;    0        md 0&apos; title=&apos;&apos; src=&apos;/static/c07e2711441dcf43aaed37ca9bc5408a/56d4e/%EB%94%94%EB%B2%84%EA%B9%85_0%EA%B5%90%EC%8B%9C_%EC%A0%88%EC%B0%A8%EB%8C%80%EB%A1%9C.md_0.jpg&apos; srcset=&apos;/static/c07e2711441dcf43aaed37ca9bc5408a/8ccab/%EB%94%94%EB%B2%84%EA%B9%85_0%EA%B5%90%EC%8B%9C_%EC%A0%88%EC%B0%A8%EB%8C%80%EB%A1%9C.md_0.jpg 190w,
/static/c07e2711441dcf43aaed37ca9bc5408a/ea4c8/%EB%94%94%EB%B2%84%EA%B9%85_0%EA%B5%90%EC%8B%9C_%EC%A0%88%EC%B0%A8%EB%8C%80%EB%A1%9C.md_0.jpg 380w,
/static/c07e2711441dcf43aaed37ca9bc5408a/56d4e/%EB%94%94%EB%B2%84%EA%B9%85_0%EA%B5%90%EC%8B%9C_%EC%A0%88%EC%B0%A8%EB%8C%80%EB%A1%9C.md_0.jpg 640w&apos; sizes=&apos;(max-width: 640px) 100vw, 640px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;br&gt;
새벽 4시였던가? 우리는 김밥천국에 앉아서 이 요상한 문제에 대해서 이야기를 했다. 김밥천국 주문서 쪽지에 그림을 그려가며, 떡볶이 국물을 튀겨가며, 이 이해할 수 없는 문제의 원인에 대해서 토론을 했다. 그 때가 디버깅하고 한 6시간은 지났던 시간이었던 것 같다. 그리곤 김밥을 먹고는 올라가서 디버깅을 이어갔다. 이 알 수 없는 문제를 해결하기 위해서 한 10가지 프로젝트를 열었고, 여기저기 단서를 추적하기 위한 내용들을 추가했다. 그리곤 결국 10시간 정도 지나서 문제를 찾았는데 다름 아닌 새로 만든 서버가 엉뚱한 내용을 클라이언트에 전달하고, 그 클라이언트가 그 내용을 우리 SDK에 바로 전달해서 발생한 문제였다. 로그 파일에 선명하게 남아있는 PacketError, 사실 로그 파일만 열어봤어도 이렇게 오랜 시간 디버깅을 할 필요가 없었을 텐데. 그 절차를 아무도 따르지 않았던 것이었다.&lt;/p&gt;
&lt;p&gt;디버깅을 할 때면 ‘말렸다’는 표현을 쓸 때가 있다. 엉뚱한 곳에 휘말려서 정작 중요한 부분을 보지 못하고 헤매는 경우에 쓰는 말이다. 이렇게 ‘말리는’ 상황을 미연에 방지하기 위해서는 항상 침착하게 절차대로 디버깅을 진행해야 한다. 더불어 자신이 가진 모든 증거를 차근차근 나열해서 꼼꼼하게 생각하는 습관을 들여야 한다. 절대로 증거가 아닌 현상에 휩싸여서는 안된다. 그럼 지는 거다.&lt;/p&gt;
&lt;p&gt;힘겨웠던 디버깅 세션을 마치고 집으로 돌아가는 길. WoW에 미쳤던 시절이 떠올랐다. 공대에서 불타는 성전의 거의 마지막 던전인 검은 사원을 트라이 하고 있었던 때였다. 나는 주말 공대였지만 평일에 다른 레이드 던전을 재미 삼아 다니다 보면 으레 지쳐서 5인 던전은 엄두도 못 낼 때가 많았다. 이런 상황임에도 우리 공대에는 하루도 거르지 않고 5인 영던을 꼬박꼬박 다니는 두 놈이 있었다. 한 날 그 녀석들과 영던 나들이를 갔다가 궁금해서 물었다. 지치지도 않냐고, 무슨 재미도 없는 영던을 그리 맨날 다니냐, 라는 질문. 대답이 가관이었다. 감각을 잃지 않으려면 매일 수련을 해야 한다는 것이었다. 레이드 던전을 매일 갈수는 없으니 영던에서 수련을 한다는 대답이었다. 게임 훼인스런 대답이긴 하지만 여기서 우리가 배울 점이 하나도 없는 것은 아니다. 녀석들의 말은 사실 게임을 떠나서 어떤 분야에든 적용될 수 있는 말이기 때문이다.&lt;/p&gt;
&lt;p&gt;“숙련됨은 연습을 중단하는 그 시점부터 퇴보하기 시작한다.” 당신이 프로그램을 짜지않는 하루하루마다 숙련공으로 가는 길은 점점 더 멀어져 간다. – 프로그래머의 길, 멘토에게 묻다.&lt;/p&gt;
&lt;p&gt;수련을 게을리하는 순간 우리는 퇴보한다. 그런 수련을 게을리한 나에게 일침을 놓는 디버깅 세션이었다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[05. 무한 루프를 다스려라, 2001]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/5333</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5333</guid><pubDate>Tue, 01 Nov 2011 23:57:50 GMT</pubDate><content:encoded>&lt;p&gt;안녕하세요~ 요즘 몇일동안 강좌 올리는 플그램을 만드느라 강좌를 못 올렸음당. 지금은 거의 반쯤 완성된 단계라서, 일케 편하게 강좌를 올릴 수 있게 되었네요. 앞으로는 틈틈히 남는 시간을 이용해서 이렇게 강좌를 올리도록 하겠습니다. 그럼 오늘은 while을 이용한 무한루프의 세계로 한번 가 보도록 합시다~&lt;/p&gt;
&lt;p&gt;우선 간단하게 while문의 문법을 알아보도록 하겠습니다. 지난 시간에 배운 for문은 그 구조가 상당히 복잡한 반면에 while문은 문장 구조 자체가 단순하므로 배우기가 수월 하실겁니다. 그럼 아래 소스를 보도록 하죠~&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
   cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; 

&lt;span class=&quot;token comment&quot;&gt;// 위에것과 같은 for문 루틴 &lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
   cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위의 예제를 보면 금방 이해가 가실 겁니다. 지난 시간에 배운 for문에 대해서 확실하게 숙지하고 계시는 분들은 훨씬 더 이해하기가 쉽겠죠~ 그럼 while문을 잠시 살펴보도록 합시다. while다음에 오는 괄호에 인자로 들어가는 것은 조건문 입니다. 그 조건문인 참인 동안 아래있는 반복할 문장을 실행 시키는 거죠. 아주 쉽죠?! 그럼 오늘 배울 무한루프의 세계로 한번 날아가 봅시다~&lt;/p&gt;
&lt;p&gt;A Book On C라는 책의 첫머리에 이런 말들이 나옵니다. C언어에서 0은 매우 다양하고 특이한 의미들로 사용된다. 0은 모든 숫자의 시작이며, 문자열 배열의 끝을 알리는 기호이며, 또한 메모리 가비지 값을 초기화 시키는 값으로 사용된다. 뿐만 아니라 모든 배열의 시작또한 0에서 한다. 그리고 0은 거짓을 의미하는 기호이기도 하다. 제가 대충 생각나는대로 적었는데, 아마도 말은 틀리지만 의미는 비슷한 글이었을 것 입니다. 그렇습니다. C언어에서 0그렇게 다양한 의미로 사용되고, 그 중에 오늘 배울 의미중의 하나가, 바로 거짓을 나타내는 기호입니다. 그럼 다음 문장을 보도록 합시다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 거짓이다... &lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 참이다... &lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 무엇일까? &lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// 무엇일까? &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위에서 서술한 것을 보면 0은 거짓으로 나와있고 1은 참이라고 나와있다. 다른 것은 무엇일까?! 여러분은 어떻게 생각하나요?! 위의 글을 충분히 읽었다면 당연하게 상상을 해 낼 수 있을 겁니다. 0은 특별한 의미의 기호로 사용되고 있다는 것을 여러분들은 아실 수 있을 겁니다. 그러니 당연히 거짓의 0도 특별한 의미겠죠. 그럼 0이외의 다른 값들은 바로 다 참인 것 입니다. 그럼 아래있는 구문은 어떻게 될까요?!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
   cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;이건 볼 수 없습니다...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위에 있는 소스는 한줄도 실행되지 않습니다. 왜 일까요?! 바로 whlie안의 조건문이 처음부터 거짓이기 때문입니다. 반면에 다음 예제는 어떤가요?!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
   cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;이건 계속 볼 겁니다...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위의 프로그램을 실행하면 여러분들은 끝없는 문장을 보게 될 겁니다. 헤헤. 이런 프로그램을 어디다 써 먹을려고 작성을 하냐구요~ 그럼 다음 프로그램을 한 번 봅시다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
   cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;yes&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위의 예는 끝없이 yes를 출력하는 프로그램입니다. 이것두 쓸모없어 보이나요?! 하지만 매우 가치있는 프로그램임을 여러분들은 곧 알게 될 겁니다. 실제로 Unix에는 yes라는 프로그램이 있습니다. 바로 위와 같은 기능을 하는 프로그램이죠~ 어디다 써먹냐 하면, 몇몇 성가신 명령어들 | yes 이렇게 하면 계속 반복된 질문을 하는 프로그램들에게 yes라고 타이핑 할 필요없이 자동으로 넘어가게 되는 것 입니다. 아마도 유닉스를 사용해 보신 분들은 알겠지만 사용해 보지 않으신 분들은 그냥 그런게 있다 하는 정도로 넘어 가도록 하죠~&lt;/p&gt;
&lt;p&gt;그럼 이제 그 무한 루프를 제어하는 두가지 비밀병기를 알아보도록 하겠습니다. 하나는 break라는 넘이고 또 하나는 continue라는 넘입니다. 이제 설명할 내용들은 while문을 중심으로 설명하지만, for문에서도 똑같이 적용된다는 사실을 알았으면 합니다. 그럼 그 두 넘이 무슨 일을 하는지 알아보기 위해서 간단한 소스코드를 보면서 이해해 보도록 합시다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ............. 1번 &lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
      &lt;span class=&quot;token keyword&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// ............ 2번 &lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
      &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;번 

   cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;번 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;츨력 결과가 어떻게 될까요?! 다들 지금 한번 실행시켜 보십시요. 아마도 화면에는 이렇게 출력이 될 겁니다. 1, 3만 출력 될 겁니다. 왜 그렇게 될까요?! 궁금하죠?! 위에서 continue라는 키워드를 만나게 되면 루프의 조건문 i에게로 다시 돌아갑니다. 그러니 뒤에 있는 것들은 무시가 되는 것이죠~ 반면에 break를 만나면 루프를 탈출해 버리는 겁니다. 실제로 위에 있는 예제는 무한루프입니다. 왜 그럴까요? i가 1부터 계속 증가하기때문에 영원히 거짓은 될수가 없는 겁니다.(추신 : 하지만 실제 시스템 상에서는 종료 될수도 있습니다. 정수의 한계를 넘어서서 오버플로우 되어 다시 0이 되는 경우에 그런 가능성이 있습니다). 그러면 어떤 순서로 수행되었는지 한번 알아봅시다.&lt;/p&gt;
&lt;p&gt;처음에 1번이 실행될 겁니다. 그러면 i값이 1이 되니까 참이 되겠죠. 여기서 여러분들이 한가지 상기하셔야 할 것은 ++이라는 연산자 입니다. 이 ++이라는 넘은 단순하게 변수를 1 증가 시키는 역할을 하지만, 변수의 앞에 쓰이는 것과 뒤에 쓰이는 것은 천지 차이가 있습니다. 위의 while(++i)는 참이 되지만. while(i++)은 거짓이 됩니다. 왜 그런가 하면 을 앞에서 쓰게 되면 변수의 값을 먼저 증가시킨 다음에 식에 반영을 합니다. 하지만 뒤에 쓰게 되면 식을 해석하고 난 다음에 나중에 변수값을 증가시키는 거죠. 하여튼 그래서 i는 1이 되고 1번은 참이므로 블록안에 있는 것들이 실행됩니다. 그러면 조건문을 만나게 되는데, i % 2 == 0는 무엇을 의미하는 조건문 입니까?! i를 2로 나누어서 나머지가 0과 같으냐를 묻는 조건문 입니다. 당연히 실행이 안 되겠죠. 그 다음것도 실행이 안됩니다. 그래서 4번이 실행되고 다시 1번으로 돌아가서 i값은 2가 됩니다. 역시 참이죠. 그래서 또 블록안의 것이 실행이 되고, i % 2가 참이 되게 됩니다. 그러면 continue를 만나게 되고. 그렇게 되면 다시 바로 1번으로 돌아가는 겁니다. 지금까지의 순서를 한번 정리 해 볼까요?!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1번 — 4번(1출력) — 2번 — 1번 — 4번(3출력) — 1번 — 2번 — 1번 — 3번 — 종료&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;위의 순서대로 되는 겁니다. break는 이해가 가죠. 바로 루프를 타출하는 기능입니다. 그러면 오늘 강좌는 여기까지 하도록 하겠습니다. 다들 충분히 이해하셨죠. 처음 배우는 분들은 continue의 개념을 잘 이해하지 못하는데. 그 부분을 집중적으로 한번 살펴보세요~ 그럼 다들 좋은 하루 되세요.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;숙제!!!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;뭐물래?! 를 출력해서 사용자가 먹고 싶은 것을 입력 받는다. 사용자가 99를 입력하면 프로그램이 종료되도록 하여라. 99를 입력하기 전까지는 무한대로 입력받을 수 있다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[유니코드 윈도우의 정체]]></title><description><![CDATA[윈도우 환경에서 개발 경험이 있는 많은 개발자들이 유니코드(Unicode…]]></description><link>https://jiniya.net/wp/archives/4760</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4760</guid><pubDate>Tue, 01 Nov 2011 23:57:49 GMT</pubDate><content:encoded>&lt;p&gt;윈도우 환경에서 개발 경험이 있는 많은 개발자들이 유니코드(Unicode) 함수에 대해서는 잘 알고 있는데, 정작 유니코드 윈도우에 대해서는 잘 모르는 경향이 있다. 왜 그럴까? 대다수 책에서 이를 직접적으로 설명하지 않기 때문이 그 첫 번째 이유고, 이 내용이 윈도우 API에 의해서 잘 감춰져 있기 때문이 그 두 번째 이유다. 이런 내용을 모르고 고통 받는 많은 루키 개발자들을 위해서 유니코드 윈도우에 대해서 알아보도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;유니코드 윈도우를 이해하기 위해서는 기본적으로 윈도우에서 제공하는 유니코드 함수들의 동작 구조에 대해서 잘 이해하고 있어야 한다. 윈도우는 문자열을 취급하는 대부분의 함수에 대해서 A가 붙은 멀티바이트(multi-byte) 버전과 W가 붙은 유니코드 버전을 제공한다. GetWindowTextA가 있다면 GetWindowTextW가 있는 셈이다. 물론 각 함수의 기능은 동일하며 A 함수는 파라미터로 char 포인터를, W 함수는 파라미터로 wchar_t 포인터를 전달받는 차이점이 있다. 그렇다면 GetWindowText는 무엇인가? 그건 아래와 같이 매크로로 재정의된 함수다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;_UNICODE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;GetWindowText&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;GetWindowTextW&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;GetWindowText&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;GetWindowTextA&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;즉, 우리의 빌드 환경이 유니코드라면 GetWindowText는 GetWindowTextW가 되고, 멀티바이트라면 GetWindowTextA가 되는 것이다. 그래서 이 시스템에서는 다음에 나오는 코드와 같이 T형 중립(neutral) 문자형을 사용하고, A, W가 없는 매크로로 재정의된 중립 API를 사용하고, 문자열 처리에도 매크로로 재정의된 T계열 중립 함수를 사용하면 유니코드, 멀티바이트 빌드에 상관 없는 코드를 만들 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;TCHAR buffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;MAX_PATH&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;GetWindowText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hwnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ARRAYSIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;_tcscat_s&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ARRAYSIZE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;$&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;윈도우 하부 시스템이(window subsystem) 모든 것을 잘 포장하고 있기 때문에 유니코드, 멀티바이트에 대한 고려 없이 프로그램을 작성해도 빌드에 따라서 적절하게 컴파일되고 잘 동작하지만, 정작 변환(conversion) 문제가 발생하면 내부 구조를 모르고는 어디서, 왜 문제가 발생했는지를 알 수 없는 구조라 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이제 본론으로 들어가서 유니코드 윈도우에 대해서 알아보자. 유니코드 윈도우란 무엇인가? 메시지(message) 처리에 유니코드를 사용하는 윈도우를 말한다. 그러니 당연히 안시(ansi) 윈도우도 있고, 그건 멀티바이트로 메시지를 처리하는 윈도우를 말한다.&lt;/p&gt;
&lt;p&gt;똑똑한 개발자라면 메시지를 멀티바이트, 유니코드로 처리한다는 것은 무엇을 의미하는 거지, 라는 새로운 의문이 들 것이다. 간단한 예를 통해서 살펴보도록 하자. WM_GETTEXT라는 메시지를 보자. 이 메시지의 wParam은 글자 개수를, lParam은 글자를 저장할 수 있는 버퍼의 포인터를 지정한다. 문제는 여기서 시작된다. 그렇다면 lParam으로는 유니코드 버퍼를 전달해야 할까? 아니면 멀티바이트 버퍼를 전달해야 할까? 다음과 같은 코드에서 StringCchCopyW를 쓰는 것이 옳은지, StringCchCopyA를 쓰는지가 옳은지를 묻는 것이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;LRESULT CALLBACK &lt;span class=&quot;token function&quot;&gt;MyWindowProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HWND hwnd
                              &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; UINT msg
                              &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WPARAM w
                              &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPARAM l&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;msg &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; WM_GETTEXT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
         &lt;span class=&quot;token comment&quot;&gt;// StringCchCopyW((LPWSTR) l, w, L&quot;MyWindowText&quot;);&lt;/span&gt;
         &lt;span class=&quot;token comment&quot;&gt;// or&lt;/span&gt;
         &lt;span class=&quot;token comment&quot;&gt;// StringCchCopyA((LPSTR) l, w, &quot;MyWindowText&quot;);&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DefWindowProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hwnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; w&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; l&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;아마 대부분의 개발자가 이런 것에는 신경 써 본 적이 없을 것이다. 윈도우 하부 시스템이 이를 굉장히 잘 감추고 있기 때문이다. 결론부터 말하면 WM_GETTEXT의 버퍼를 유니코드 윈도우는 유니코드 버퍼로, 안시 윈도우는 멀티바이트 버퍼로 취급해야 한다. 유니코드 윈도우가 멀티바이트 포인터로 이를 처리하고, 반대로 안시 윈도우가 유니코드 문자열로 처리하면 이상하게 동작하는 윈도우가 만들어진다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;그럼 이제 유니코드 윈도우는 어떻게 생성되는지에(created) 대해서 알아보자. 유니코드 윈도우의 생성에는 RegisterClass라는 윈도우 클래스(class) 등록 함수가 개입한다. 물론 이 함수의 어떤 파라미터도 생성될 윈도우가 유니코드인지 아닌지를 결정하는 것은 없다. 그렇다면 어떻게 결정되는 것일까? 바로 호출하는 함수의 종류에 따라서 자동으로 결정한다. RegisterClassW 함수를 사용해서 윈도우 클래스를 등록하면 해당 클래스로 생성되는 윈도우는 유니코드 윈도우가 된다. 반대로 RegisterClassA 함수를 사용해서 윈도우 클래스를 등록하면 해당 윈도우는 멀티바이트 윈도우가 되는 것이다. 이렇게 생성 과정이 감추어져 있기 때문에 많은 개발자가 윈도우가 유니코드인지 아닌지에 대해서 잘 모르고 지나치게 된다.&lt;/p&gt;
&lt;p&gt;화면에 존재하는 특정 윈도우가 유니코드 윈도우인지 아닌지는 Spy++ 유틸리티를 통해서 살펴볼 수 있다. Spy++을 사용해서 해당 윈도우의 속성을 살펴보았을 때 다음 그림에 나타난 것처럼 Window Proc 부분에 Unicode라는 말이 있다면 해당 윈도우는 유니코드 윈도우인 것이고, 이런 표시가 없다면 안시 윈도우라고 생각하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 458px; margin-bottom: 16px;&apos; data-url=&apos;유니코드_윈도우의_정체.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5a51fcbc4aa4a4b538ccce81a702e55e/e5e51/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C_%EC%9C%88%EB%8F%84%EC%9A%B0%EC%9D%98_%EC%A0%95%EC%B2%B4.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 61.05263157894737%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAAsTAAALEwEAmpwYAAACDUlEQVR42m1Sa4+aQBTl//+EfmjSJk2atummxqRttnHXXdRVHgLyFBAY3iAvEVwDSi/YL5t0cnKZOeHcOXNmMJwUcFrqKyUsJftFzZ7kdCICsokEyB+V4kHOH6V0tk2XWkrtUgaVvB7++PAR2wiKpuuapvOCSK8Zes0tXlYsJ1A0w3I8RbMEScmK6gWh5wc3uJ6fpMliSWKqbu7jOIpj23F4XoiiyDDReiMiL0RuYPvRDjleuM/LOj1UWVkDkqJ8bVqa2WCaYZqmoes6fCRJapomzfI1wziu2zZt13XX67WvXXergPZygTnNcJis7kzDkGVF07Qsy4CN45gkSUVRtoDtNvD98/lcHY9VXQ8dussgJtcbTNzqjm2zLKuq6uFwABYqKC3L4nkevIAj6AteoNFbMYdJqhEEPvwHzouiADbPc1mWYYkQAoFt29ACmPrtzgTNYbykWpapDA6hgsMkSWazmSiKbdvCgS/DuJ38P2Lfc0EIF1ZVFbAgxnEctroO46a8DPgXWNsHuQLbG0n1XLePfLdL9zGwp/oIl5cXRX06lUcIqoIJpAW4LWEC+iXF9oE153NxKPW04py9HOZ6dgqT1EbIMk24dtd10TAcx4EHEQQBBLSPIwJ2vp/ORUmhOeE7Ib//Q7z7Nf+6VKYLYjT++e1u9ITPH6bPd6MxAJjZYjWZPn/6/KUnx7//AoHOfq9En977AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;             md 0&apos; title=&apos;&apos; src=&apos;/static/5a51fcbc4aa4a4b538ccce81a702e55e/e5e51/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C_%EC%9C%88%EB%8F%84%EC%9A%B0%EC%9D%98_%EC%A0%95%EC%B2%B4.md_0.png&apos; srcset=&apos;/static/5a51fcbc4aa4a4b538ccce81a702e55e/08678/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C_%EC%9C%88%EB%8F%84%EC%9A%B0%EC%9D%98_%EC%A0%95%EC%B2%B4.md_0.png 190w,
/static/5a51fcbc4aa4a4b538ccce81a702e55e/2edd7/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C_%EC%9C%88%EB%8F%84%EC%9A%B0%EC%9D%98_%EC%A0%95%EC%B2%B4.md_0.png 380w,
/static/5a51fcbc4aa4a4b538ccce81a702e55e/e5e51/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C_%EC%9C%88%EB%8F%84%EC%9A%B0%EC%9D%98_%EC%A0%95%EC%B2%B4.md_0.png 458w&apos; sizes=&apos;(max-width: 458px) 100vw, 458px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;그렇다면 왜 그렇게 윈도우가 유니코드인지 아닌지가 중요할까? 첫째는 이를 모르는 경우에는 메시지 핸들러를 잘못 작성할 수 있기 때문이다. 다음 코드와 같이 윈도우 클래스 등록은 유니코드 윈도우로 해두고 해당 윈도우의 메시지 프로시저의 WM_GETTEXT같은 것은 멀티바이트로 처리해 버리는 것이다. 이러면 당연히 오류가 발생한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;WNDCLASSEXW wcex&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;
wcex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lpfnWndProc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; WndProc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;RegisterClassExW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;wcex&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

LRESULT CALLBACK &lt;span class=&quot;token function&quot;&gt;WndProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HWND wnd
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; UINT message
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WPARAM w
                        &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPARAM l&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;message &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; WM_GETTEXT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;StringCchCopyA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPSTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; l&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; w&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lstrlenA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPSTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; l&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DefWindowProcW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; message&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; w&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; l&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;둘째는 윈도우와 관련된 모든 행동을 할 때에 이것은 굉장히 중요하게 작용하기 때문이다. 이를 모르면 엉뚱하게 시스템을 헝클어 버리는 경우가 발생할 수 있다. 특정 윈도우를 서브클래싱을 한다고 해보자. 이 경우에도 유니코드 윈도우라면 SetWindowLongW를, 멀티바이트 윈도우라면 SetWindowLongA를 사용해야 한다. 만약 반대로 호출했다면 원본 윈도우는 유니코드로 메시지를 처리하고, 그걸 서브클래싱한 윈도우 프로시저는 멀티바이트로 처리하는 등의 혼선이 발생한다. 또한 원본 윈도우는 유니코드 윈도우였음에도 SetWindowLongA를 사용해서 서브클래싱하는 순간 해당 윈도우는 안시 윈도우로 변경된다. 이러한 내부 메커니즘을 모르고 서브클래싱을 하면 복잡한 변환 문제에 봉착할 수 있다.&lt;/p&gt;
&lt;p&gt;한가지 예를 더 들어보자면 이런 경우도 있다. 보통 메시지 프로시저는 필요한 부분만 작성하고 나머지 부분은 DefWindowProc 함수에 위임한다. 그런데 이 DefWindowProc함수도 DefWindowProcA가 있고, DefWindowProcW가 있다. 여기서 문제가 발생한다. 윈도우는 유니코드로 생성해놓고 DefWindowProcA를 호출한다거나, 윈도우는 멀티바이트로 생성해놓고 DefWindowProcW를 호출하는 것이다. 물론 이렇게 호출하면 대부분의 함수에 대해서 정상 동작하지만 일부 메시지에 대해서는 우리가 기대한대로 동작하지 않는 문제가 발생한다. 아래 윈도우는 그런 경우를 보여주고 있다. RegisterClassA 함수를 사용해서 ANSI 윈도우를 만들고 DefWindowProcW를 호출할 경우다. 정상적으로 처리됐다면 타이틀바에 Hello가 출력돼야 하지만 이상한 글자가 출력되고 있는 것을 볼 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 337px; margin-bottom: 16px;&apos; data-url=&apos;유니코드_윈도우의_정체.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/501c1c5256bcfaa44ff76af6cbe0ca80/f57f1/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C_%EC%9C%88%EB%8F%84%EC%9A%B0%EC%9D%98_%EC%A0%95%EC%B2%B4.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 50.526315789473685%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAAsTAAALEwEAmpwYAAABVElEQVR42mPonLZw2oKVHd29nb0TSqvq2rv7qxuaU7MLHLyDtczsdMwdrJx9XP3CcooqOnsntfZOntLaujorfntFbnd6EsPMhStXrd+xat2WhUtWzV+6euGyNbMWLOvsn5Zf3piaX5FWUJldXFtc3dLYMbFn8uyJMxZMn7UAiFfOX9je1sWwcevuS5fv33nw5tDhcw+efnjx9ufz19+B5Ov3v998+ANGv4Hsl29/vnjzA0S+/fnk9Y8P3/5v2LaP4dSZc//////9+/e/f//+IoE/qABZ4tevn0Athw4fZdi1dz+QBZT8TzQAmgUkN2/bwbB91144nyTNm7ZsZ9i0bQd5mtdu2Mywet1GIOvXr19/iQZAxUAty1etZVixZj2pNv8GK166YjVDRV3z1h27Vq3bAHTG+k1bN2zehoaAgus2bVmzYdPq9ZvWgNHKtRuAWkqrGwDot/b+W6nK/wAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;             md 1&apos; title=&apos;&apos; src=&apos;/static/501c1c5256bcfaa44ff76af6cbe0ca80/f57f1/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C_%EC%9C%88%EB%8F%84%EC%9A%B0%EC%9D%98_%EC%A0%95%EC%B2%B4.md_1.png&apos; srcset=&apos;/static/501c1c5256bcfaa44ff76af6cbe0ca80/08678/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C_%EC%9C%88%EB%8F%84%EC%9A%B0%EC%9D%98_%EC%A0%95%EC%B2%B4.md_1.png 190w,
/static/501c1c5256bcfaa44ff76af6cbe0ca80/f57f1/%EC%9C%A0%EB%8B%88%EC%BD%94%EB%93%9C_%EC%9C%88%EB%8F%84%EC%9A%B0%EC%9D%98_%EC%A0%95%EC%B2%B4.md_1.png 337w&apos; sizes=&apos;(max-width: 337px) 100vw, 337px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;앞서 언급한 실수를 방지하기 위해서는 그저 유니코드 윈도우의 존재와 그것이 처리되는 방식에 대해서만 이해하고 있으면 된다. 여기서 그것이 처리되는 방식이란 유니코드 윈도우는 윈도우 관련 함수에 W계통의 함수를 사용하고, 멀티바이트 윈도우는 A계통의 함수를 사용해야 한다는 것. 그리고 해당 윈도우들은 메시지를 유니코드나 멀티바이트로 처리한다는 점이다. 이것만 기억한다면 바보 같은 실수를 하지 않을 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#4&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;유니코드 윈도우라는 것이 있고, 그것을 잘못 다룰 때 어떤 재앙이 발생하는지에 대해서 살펴봤으니 이제는 당연히 우리가 작업을 하려고 하는 대상 윈도우가 유니코드 윈도우인지 아닌지가 궁금해질 것이다. 어떻게 대상 윈도우가 유니코드인지 아닌지 알 수 있는지 말이다. 이런 용도로 사용하기 위한 아주 간단한 함수가 하나 존재한다. 바로 IsWindowUnicode다. IsWindowUnicode(hwnd)를 호출해서 FALSE가 리턴되면 해당 윈도우는 안시 윈도우고, FALSE가 아닌 값이 반환되면 유니코드 윈도우라는 것을 나타낸다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#5&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;끝으로 몇 가지 추가적인 사항에 대해서 좀 더 알아보도록 하자. 앞선 코드를 실제로 테스트해본 개발자라면 윈도우가 유니코드인지 안시인지에 상관 없이 DefWindowProcA나 DefWindowProcW나 아무거나 호출해도 WM_GETTEXT의 메시지의 결과는 정상적으로 나온다는 것을 볼 수 있었을 것이다. 어떻게 이런 것일까? 답은 간단하다. 다음처럼 방어적인 코딩을 했다면 해당 메시지 프로시저는 윈도우의 종류에 관계없이 문자열을 적절하게 처리할 수 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WM_GETTEXT&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;IsWindowUnicode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hWnd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;StringCchCopyW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPWSTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; lParam&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; wParam&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; L&lt;span class=&quot;token string&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lstrlenW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPWSTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; lParam&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;StringCchCopyA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPSTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; lParam&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; wParam&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lstrlenA&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPSTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; lParam&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;끝으로 이 글을 읽고는 아마도 특정 윈도우에 메시지를 보낼 때에도 해당 윈도우가 유니코드 윈도우라면 SendMessageW를, 안시 윈도우라면 SendMessageA를 써야겠다는 생각을 한 개발자도 있을 것이다. 똑똑한 생각이다. 하지만 현실은 그렇게 불편하지는 않다. 테스트를 해보면 SendMessageA든 SendMessageW든 적절한 버퍼를 전달했다면 제대로 된 값을 반환해 주는 것을 볼 수 있을 것이다. 놀랄 필요는 없다. IsWindowUnicode를 호출해서 해당 윈도우로 적절한 버퍼를 전송하고 그 결과를 다시 우리 입맛에 맞게 WideCharToMultiByte, MultiByteToWideChar를 호출해서 변환하는 그 귀찮은 작업들을 SendMessage가 대신해 주고 있을 뿐이다. 물론 WM_GETTEXT외에도 이렇게 변환이 필요한 모든 메시지에 대해서 SendMessage는 내부적으로 적절하게 변환해주도록 되어 있다. 단지 우리는 SendMessageA를 사용했다면 안시 버퍼를, SendMessageW를 사용했다면 유니코드 버퍼를 전달해야 한다는 사실만 기억하면 된다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[04. 구구단을 만들어 보자, 2001]]></title><description><![CDATA[안녕하세요~ 오늘은 지난번에 배웠던 if…]]></description><link>https://jiniya.net/wp/archives/5231</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5231</guid><pubDate>Wed, 26 Oct 2011 23:57:48 GMT</pubDate><content:encoded>&lt;p&gt;안녕하세요~ 오늘은 지난번에 배웠던 if문과 함께 반복문에 대해서 익혀보도록 하겠습니다~ 지난번 숙제는 다 하셨나요..?! 이번 강좌부터는 숙제는 계속 나가지만 해답은 올리지 않도록 하겠습니다. 왜냐하면 해답을 그냥 자꾸 올리니까 어려분의 상상력을 억제하는 듯한 느낌이 드네요. 풀어보고 모르시겠으면 Q&amp;#x26;A란에 질문하시면 제가 아는 한도 내에서 답글을 올리도록 하겠습니다~ 그럼 오늘도 시작하도록 하죠~~!!…&lt;/p&gt;
&lt;p&gt;오늘 배울것은 for라는 놈입니다~ 이놈은 아마도 C++언어에서 가장 많이 접하는 놈이 아닐까 생각합니다. 그럼 한번 for문의 문법부터 살펴보고 가도록 합시다~&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;초기문&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 종료조건&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 반복할것&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
   실행문&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;조금 난해해 보일수도 있겠지만 저게 for문의 모든 요소입니다. 그럼 지금부터 설명하도록 하죠~ 우선 한가지 저 for문에 걸리는 실행문이 두개 이상이면 어떻게 해야한다구요?!… 예… 바로 {}로 묶어줘야 겠죠~~ 항상 C++에서는 한 구문에 걸리는 문장이 두개이상이면 {}로 묶어야 합니다. 그것을 블록을 만든다라구 표현하죠~ for문의 요소를 보면 세가지가 있습니다. 초기문, 종료조건, 반복할것인데. 하나씩 뜯어보도록 하죠. 제일 처음 저 구문이 실행되면 제일 처음 초기문이 실행되고 실행문이 실행되고, 다음으로 반복할 것이 실행됩니다. 그 다음 종료조건을 검사하고 종료조건이 참이면 다시 실행문을 실행하고 반복할 것을 실행한다음 종료조건을 검사합니다. 그렇게 종료조건이 거짓일때까지, 계속 반복하는 것이죠. 말로 적으니까 조금 난해해 보이는데. 하나씩 적으면서 따져보면 금방 이해가 가실 겁니다. 그럼 아래 예를 보도록 하죠!!!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
   cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위 소스를 실행하면 결과가 어떻게 나올까요? 아마도 0부터 9까지 출력이 될 겁니다. 아시겠죠. 그럼 아래 문장은 어떻게 될까요?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;똑같은 결과가 출력될 겁니다. 조금만 생각해 보면 금방 알수가 있겠죠~ 다음에를 보도록 합시다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위에 것도 똑같은 예 입니다. 이제 저것과 똑같은 예를 남아있는데로 한번에 열거해 보도록 하죠~&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
   &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; 

&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
   &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; 

&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;대충 이정도 보셨으면 마치 말장난 처럼, 똑같은 문법을 여러방법으로 돌려가면서 사용하는 것을 보셨을 겁니다. 처음 보시는 분들은 저런걸 왜 저렇게 머리아프게 다양한 방법으로 사용하는가 궁금해 하실텐데, 나중에 되면 저걸 알고 모르고가 얼마나 큰 차이인지 아실 겁니다. 가까운 예로 문자열을 입력받는 함수를 C로 한번 작성한다고 생각을 해 봅시다. 보통사람은 아래와 같이 작성합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get_str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;str&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; temp&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; ch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   ch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getchar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ch &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
   &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      temp&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

      ch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getchar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; 

   &lt;span class=&quot;token function&quot;&gt;strcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;str&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; temp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;보통 사람의 소스였습니다.. 조금 C언어를 공부한 사람들은 다음과 같이 작성하죠~~~!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get_str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;str&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; temp&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getchar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      temp&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   &lt;span class=&quot;token function&quot;&gt;strcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;str&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; temp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;어때요… 훨씬 깔끔해 졌죠… 하지만… 완벽하게 for문을 이해한 사람은 아래와 같이 작성합니다~~~~&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;get_str&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;str&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; temp&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getchar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
      temp&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ch&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   &lt;span class=&quot;token function&quot;&gt;strcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;str&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; temp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이런 연유로 for문을 여러방향으로 사용할 수 있어야 합니다. 아시겠죠?! 이 정도 겅부하셨으면 아마 이제는 어떠한 for 문장이 나와도 두렵지 않을 겁니다. 그럼 오늘의 본론 구구단 프로그램을 작성 해 볼까요?!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
   cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2 * &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; = &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;구구단 이단을 출력하는 프로그램입니다. 이제 몸에 금방 아!. 하고 느낌이 오죠~ 그럼 오늘 강좌는 여기서 마치도록 하겠습니다. 다음시간에는 while구문에 대해서 설명하도록 하죠!!!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;숙제!!!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;구구단을 2단부터 9단까지 출력하는 프로그램을 작성해보세요!! 단,. 각 단 사이에는 구분줄이 하나씩 들어가야 합니다. 아래 출력처럼 출력이 되도록작성해 보세요!!&lt;/p&gt;
&lt;p&gt;[Hint: C++에서의 산술연산자에는 다음이 있다… 곱하기(*), 나누기(/), 더하기(+), 빼기(-), 나머지(%) 이걸 이용하면, 금방 답을 찾으실 수 있얼거예엽~~~]&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&gt; 2\*1 = 2  
&gt; 
&gt; 2\*2 = 4  
&gt; 
&gt; …  
&gt; 
&gt; …  
&gt; 
&gt; 2\*9 = 18  
&gt; 
&gt; ============== &amp;lt;== 이넘이 출력되도록…  
&gt; 
&gt; 3\*1 = 3  
&gt; 
&gt; ….
&gt; 
&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;조금만 고민해 보면 금방 답이 보이실 겁니다~~~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[치프가 된다는 건…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/4629</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4629</guid><pubDate>Tue, 25 Oct 2011 23:57:47 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;치프 생활을 즐기는 것 같더군&lt;/p&gt;
&lt;p&gt;힘 있는 자리야&lt;/p&gt;
&lt;p&gt;이보다 더 사람들에 둘러싸여 본 적도&lt;/p&gt;
&lt;p&gt;이보다 더 외로웠던 적도 없을거야&lt;/p&gt;
&lt;p&gt;모든 이의 아버지이자 상사지만 친구는 없을거네&lt;/p&gt;
&lt;p&gt;깔끔한 절개, 정돈된 봉합 다 자네의 결정이지&lt;/p&gt;
&lt;p&gt;감정도 타협도 사생활도 없는 자릴세&lt;/p&gt;
&lt;p&gt;리처드&lt;/p&gt;
&lt;p&gt;난 뇌 수술을 받았네&lt;/p&gt;
&lt;p&gt;과일 바구니에 둘러싸여 있어&lt;/p&gt;
&lt;p&gt;찾아오는 사람마다 내 비위를 맞추려 안달이더군&lt;/p&gt;
&lt;p&gt;나는 이유가 있어서 자네를 선택했네&lt;/p&gt;
&lt;p&gt;우린 똑같아&lt;/p&gt;
&lt;p&gt;일이 우선이지&lt;/p&gt;
&lt;p&gt;I know you’re enjoying yourself, Preston&lt;/p&gt;
&lt;p&gt;It’s a power kick to be the chief.&lt;/p&gt;
&lt;p&gt;You’re never more surrounded.&lt;/p&gt;
&lt;p&gt;Never more alone.&lt;/p&gt;
&lt;p&gt;You’re everyone’s father, everyone’s boss, and no one’s friend.&lt;/p&gt;
&lt;p&gt;Choices you make.&lt;/p&gt;
&lt;p&gt;Clean slices and neat stitches.&lt;/p&gt;
&lt;p&gt;No emotions, no compromise, no personal life.&lt;/p&gt;
&lt;p&gt;But, Richard…&lt;/p&gt;
&lt;p&gt;I just had brain surgery.&lt;/p&gt;
&lt;p&gt;I’m surrounded by fruit baskets.&lt;/p&gt;
&lt;p&gt;The only people who’ve been in this room come and kiss my ass.&lt;/p&gt;
&lt;p&gt;I gave you a shot for a reason, Preston.&lt;/p&gt;
&lt;p&gt;You and I, we’re the same.&lt;/p&gt;
&lt;p&gt;We put the job first.&lt;/p&gt;
&lt;p&gt;from &lt;strong&gt;Grey’s Anatomy S02E01&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;모두를 이해해야 하지만, 정작 본인은 제일 이해받기 힘든 자리.&lt;/p&gt;
&lt;p&gt;모든 걸 자기 뜻대로 결정할 수 있지만, 동시에 하나도 자기 멋대로 할 수 없는 자리.&lt;/p&gt;
&lt;p&gt;모든 걸 책임져야 하지만 자기 힘으론 아무 것도 책임질 수 없는 자리.&lt;/p&gt;
&lt;p&gt;모두가 자기편인 척 하지만 진짜 자기편은 아무도 없는 자리.&lt;/p&gt;
&lt;p&gt;많은 사람들에 둘러싸여 있지만 가장 외로운 자리.&lt;/p&gt;
&lt;p&gt;치프가 된다는 건 그래서 힘든 것.&lt;/p&gt;
&lt;p&gt;그런 세상의 모든 치프들이 한없이 존경스럽게 느껴지는 밤.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[03. 급여 관리를 만들어 보자, 2001]]></title><description><![CDATA[이제 완연한 여름이 오는것 같네요~ 햇살도 아주 따스하고, 날씨도 맑고. 쿠쿠. 이런때일수록 나른하고 피곤해지기 쉬우니 모두들 건강관리에 신경을 써야할 것 같습니다. 오늘은 간단한 if…]]></description><link>https://jiniya.net/wp/archives/5194</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5194</guid><pubDate>Tue, 25 Oct 2011 23:57:46 GMT</pubDate><content:encoded>&lt;p&gt;이제 완연한 여름이 오는것 같네요~ 햇살도 아주 따스하고, 날씨도 맑고. 쿠쿠. 이런때일수록 나른하고 피곤해지기 쉬우니 모두들 건강관리에 신경을 써야할 것 같습니다. 오늘은 간단한 if문을 배워서 급여를 관리하는 시스템을 만들어 볼 생각입니다. 모두들 재미있게 읽고, 오늘 배우는 if문 만은 마스터한다는 생각으로 강좌를 읽어 주시면 되겠네요~ 자, 그럼 시작하겠습니다.&lt;/p&gt;
&lt;p&gt;if, 영어에서 가정문을 사용할때 쓰이는 단어입니다. 마찬가지로 플밍에서도 조건을 검사할때 사용합니다. “만약 이것이 참이면 이런행동을 하고, 이것이 거짓이면 저런 행동을 해라.” 따위의 조건을 판단하는 문장을 말하는 거죠~ 그럼 간단하게 사용되는 if문을 살펴보도록 할까요.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; 검사할 조건 &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
      실행문&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위의 예가 간단한 if문을 사용한 예입니다. 검사할 조건이 참이면 실행문이 실행이 되겠죠. 거짓이면 실행이 되지 않을 겁니다. 그리고 만약 실행문 두개 이상이 한 if문에 걸릴때는 항상 브레이스( { } )로 묶어 주어야 합니다. 그럼 다음으로 완전한 if문을 한번 살펴 보도록 합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;   &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;조건 &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
      실행&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;조건 &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
      실행&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;조건 &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
      실행&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; 
      실행&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;예~, 길죠. 위의 예가 모든 if문의 구성요소를 보여주는 예입니다. 구성요소별로 살펴보면 처음의 키워드 if는 본체입니다. 그리고 생략이 안되고 반복도 안되죠. 그리고 나머지 else if와 else는 옵션입니다. 옵션은 생략을 해도 되고, 붙여도 되는 겁니다. 끝으로 옵션중에 else if는 반복사용이 가능합니다. 휴~ 그럼 위 구문을 해독해 보도록 합시다. 조건1이 참이면 실행1이 실행이 되고, 조건2가 참이면 실행2. 이런식으로 실행이 될 겁니다. 그런데 위에서 중요한 것은 위의 나열된 조건들은 서로 배타적이라는 겁니다. 배타적이라는 의미가 뭐냐면 만약 조건1과 조건3이 동시에 만족할 경우에는 실행1만 실행되고, 나머지 조건은 무시되는 겁니다. 그럼 그걸 잘 생각해 본 다음에 아래있는 if문 예제를 보세요~&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;   &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;조건&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
      실행&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; 
      실행&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;조건&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
      실행&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위의 if문에서 조건 1과 2는 서로 배타적인 관계이며, 조건 3과는 서로 독립적인 관계입니다. 그러니까 만약 조건 1과 2가 참이면. 실행 1만 실행이 될 겁니다. 반면에 조건 1과 3이 참이면 실행1과 실행3이 순차적으로 실행이 되는 겁니다. 아시겠죠 자알~ 생각해 보시면 금방 원리를 알 수 있을 겁니다.&lt;/p&gt;
&lt;p&gt;아! 그리고 조건에 사용할 수 있는 관계연산자에는 ==(같다), &gt;=(크거나같다), &amp;#x3C;=(작거나같다), &gt;, &amp;#x3C;, !=(같지않다)가 있습니다. 그리고 주의할것은 =은 항상 모든 기호 오른쪽에 사용한다는 것입니다. 왼쪽에쓰면 구문오류가 발생합니다. 주의하세요!!!&lt;/p&gt;
&lt;p&gt;그럼 오늘의 본론으로 들어가서, 회사의 급여관리 시스템을 만들텐데. 우선 구체적인 스펙을 정하도록 하죠. 쉬운 예제니까 아주 제한을 많이 가하도록 하겠습니다. 우리가 관리하려는 회사의 직원은 5명이며, 회사의 순수익은 수익의 45%입니다. 그 중에 10%를 회사에 재투자하고, 나머지 남은 금액을 5명이 아주 공평하게 분배하는 것을 원칙으로 하겠습니다. 그런 회사가 어딨냐구요?! 여기있습니다. 쿠쿠. 그럼 만들어 볼까요? 변수 정리부터 하도록 하죠.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
   &lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; sun_suik&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; jae_tu_ja&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pay_per_man&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; suik&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; max_man &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위에 있는 변수들이 우리가 사용할 변수의 전부입니다. sun_suik은 순수익을, suik은 수익을, jae_tu_ja는 재투자비용을, 그리고 pay_per_man은 일인당 급여를 그리고 max_man은 전체 사원수를 저장하는 변수입니다. 그런데 사원수 앞에 붙어있는 const가 궁금하죠. 그건 상수라는 건데, 그 값은 한번 초기화 되면, 프로그램이 실행되는 동안 변하지 않는 값을 의미합니다. 다음에 한번 자세하게 설명하도록 하죠~&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;수익을 입력해 주세요!!!&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   cin &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; suik&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   sun_suik &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; suik &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.45&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   jae_tu_ja &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; sun_suik &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   pay_per_man &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sun_suik &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; jae_tu_ja&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; max_man&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;순수익은 &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; sun_suik &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; 입니다...&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;재투자 비용은  \&quot; &amp;lt;&amp;lt; jae_tu_ja &amp;lt;&amp;lt; \&quot; 입니다...&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;사원은 총 &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; max_man &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; 이며 , 일인당 급여는 &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; pay_per_man &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot; 입니다...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;소스를 다 짰는데 정작 중요한 오늘의 if문은 없는 것 같네요~ 그래서 그부분을 숙제로 내도록 하겠습니다~ ㅋㅋ&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;숙제!!!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;5명의 직원이 사장, 부장, 대리, 사원 2명으로 구성되어 있으며,. 각각의 급여는 35%, 20%, 15%, 20% * 2라고 합시당… 그래서 사용자가 각각의 직원 코드와 총수익을 입력하면… 그 사원의 급여를 상황에 맞게 출력하는 겁니다… 별로 어렵진 않죠…! [Hint : 아래 코드를 참조하세요!!!]&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

cin &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;code &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
   xxx&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;code &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
   yyy&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[02. 변수, 2001]]></title><description><![CDATA[오늘은 초보C++강좌…]]></description><link>https://jiniya.net/wp/archives/5181</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5181</guid><pubDate>Mon, 24 Oct 2011 23:57:45 GMT</pubDate><content:encoded>&lt;p&gt;오늘은 초보C++강좌 2탄으로 변수에 대해서 준비했습니다. 앞으로 강좌를 계속 올릴 예정이니 차근차근 읽고 숙제를 풀다보면 어느새 발전된 자신을 발견할 수 있을 겁니다. 그럼 그날을 위해서 오늘도 힘차게 한번 출발 해보도록 하죠~&lt;/p&gt;
&lt;p&gt;지난번 숙제부터 한번 푸러 볼까요?! 자신의 이름과 생을 화면에 출력하는 예제였죠~ 전 이렇게 했습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt;  &lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;namespace&lt;/span&gt; std&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
 cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;이름 : 신영진&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
 cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;생일 : 6월 10일&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

 &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;간단하죠~ 다들 잘 하셨으리라 생각합니다. 그럼 오늘 강좌의 본론인 변수에 대해서 알아보도록 합시다. 변수는 무엇일까요?! 변수는 말그대로, 변(변하는) 수(숫자) 이런 뜻이 아닐까요?! 제 생각이었습니다. 프로그래밍에서 말하는 변수는 프로그램의 실행도중에 변하는 값을 말합니다. 그렇게 변하는 값들을 메모리에 저장시키기 위해서 변수라는 것을 사용하는 것이죠~ 그럼 간단한 예를 한번 보도록 합시다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt;  &lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;namespace&lt;/span&gt; std&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
 &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; num&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

 cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;숫자를 한번 입력해 보세요&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
 cin &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; num&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

 cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;당신이 입력한 숫자는 &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; num &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;입니다...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

 &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위의 예제는 간단하게 사용자로 부터 숫자를 하나 입력받고 출력하는 예제입니다. 그럼 사용자에게 숫자를 하나를 입력 받아야 하는데, 사용자가 무엇을 입력할 지 알 수 있을까요? 물론 알 수 없겠죠. 사용자가 1을 입력할 수도 있고, 12를 입력할 수도 있고. 이런 식으로 다른 값이 프로그램 실행 도중에 입력되기 때문에 그런것들을 저장시키기 위해서 변수가 필요한 겁니다. 그럼 분석을 한번 해 보도록 할까요?!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; num&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;int형 변수로 num이라는 놈을 만든다는 것 입니다. int는 뭐죠?! 바로 정수형 변수 입니다. 위의 문장이 딱 실행이 되면, 메모리에 정수한넘을 저장할 공간을 만들어서 이름표를 다는데, 뭐라고 다냐면 바로 num이라고 다는 겁니다. 아시겠죠. 그렇게 여러개를 만들고 싶으면, int num1, num2, num3; 이렇게 선언해 줄 수 있습니다. 일종의 우리가 건물을 짓고 각각의 방을 만드러서 방번호를 붙이는 것과 같다고 생각하시면 되겠네요~ 그리고 꼭 변수는 선언과 동시에 초기화 시키는 게 중요합니다. 예를 들면 이렇게 하는 거죠~ int num = 0; 이렇게 하면 0으로 초기화가 되겠죠~ 그런데 여기서 여러분이 유의하셔야 할 개념이 하나 있습니다. 바로 초기화와 대입연산입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; num &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// int num(5); 이렇게 써도 됨. &lt;/span&gt;
num &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위의 예에서 보면 첫번째 문장, int num = 0; 은 num을 0으로 초기화 시킨다는 의미이고, 밑에 있는 문장은 num에다가 5라는 값을 넣는다는 걸 의미하는 겁니다. 그리고 첫번째 문장의 //이후의 글들은 주석이라고 도움말이라고 생각하면 되겠네요. 그러면 초기화와 대입을 왜 구분하냐고 의문을 가지시는 분들이 계실겁니다. 이 부분은 조금 더 배운 후에 설명을 해 주도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;그럼 다음줄을 분석해 보도록 합시다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;cin &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; num&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위의 문장은 num이라는 변수에 키보드로부터 숫자하나를 입력받으라는 문장입니다. 모양새를 잘 보면 &quot;&gt;&gt;&quot; 사용되서 cin을 num으로 보내느 것처럼 보이죠. 맞습니다. 그리고 여기서, cin은 표준입력(키보드)가 되는 거죠~&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;당신이 입력한 숫자는 &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; num &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;입니다...&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위의 문장은 당신이 입력한 숫자는 xx입니다를 출력하겠죠. 사용자가 입력한게 num에 저장되어 있으니 그걸 모니터로 보내 버리면 출력이 되는 겁니다.&lt;/p&gt;
&lt;p&gt;그럼 오늘 끝으로 변수의 종류에 대해서 알아보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;int 정수형 변수입니다.&lt;/p&gt;
&lt;p&gt;long 좀 더 큰 정수를 저장할 수 있는 변수입니다..&lt;/p&gt;
&lt;p&gt;float 실수를 저장하는 변수입니다.&lt;/p&gt;
&lt;p&gt;double 소수점이하 자리가 좀 더 정확한 변수입니다.&lt;/p&gt;
&lt;p&gt;char 문자형 변수입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;숙제!!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이름과 전화번호를 입력받아서 출력시키는 프로그램을 작성해 보세요~~~!! 그럼 다들 좋은 하루되세요~~~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[임의의 수를 뽑는 랜덤 함수 사용법, 2001]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/4969</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4969</guid><pubDate>Sat, 22 Oct 2011 23:57:44 GMT</pubDate><content:encoded>&lt;p&gt;일반적으로 랜덤함수는 임의의 수를 뽑기 위해서 많이 사용합니다. 이러한 원리가 가장 많이 적용되는 부분이 아마도 게임일 겁니다. 게임에서 매번 같은 경로를 통해서 나타나지 않는 것이 바로 랜덤함수를 이용했기 때문입니다. 이러한 랜덤함수는 다음과 같은 형태로 사용할 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;rand()함수는 임의의 정수를 리턴하게 됩니다. 하지만 이러한 식으로 뽑는 임의의 정수는 별로 큰 효용이 없습니다. 대부분의 경우는 정해진 범위 사이의 숫자를 뽑기 위해서 사용하는 일이 많습니다. 1에서 10 사이의 랜덤 숫자를 뽑기 위해서는 다음과 같이 하면 됩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;보면 알겠지만 간단한 공식을 적용한 것입니다. n으로 나눈 나머지는 0에서 n-1까지 범위라는 점을 이용한 것이죠.. 따라서 다음과 같은 일반적인 식이 성립됩니다.&lt;/p&gt;
&lt;p&gt;난수 = rand() % 범위 + 최소값;&lt;/p&gt;
&lt;p&gt;그럼 실제로 이러한 랜덤함수를 어떤식으로 써먹는지 알아보도록 하겠습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;msg&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Jack&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Sam&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Linda&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

&lt;span class=&quot;token function&quot;&gt;srand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
n &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%s&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; msg&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;실행시킬때마다 다른 사람의 이름이 적히게 되는 소스입니다.&lt;/p&gt;
&lt;p&gt;srand란 난수를 초기화 하는 함수입니다. 항상 rand를 하기 전에 한번쯤 해줘야하는 걸로 기억해 두시면 됩니다 [1]. 위의 식은 말그대로 현재 시간을 기준으로 난수를 뽑겠다는 말입니다. srand를 제비통을 섞는 함수 정도로 이해해 두시면 됩니다.&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;[1] srand는 위에 언급한대로 제비통을 섞는 일을 합니다. 따라서 전체 난수 세트를 리프레시할 필요가 있는 시점에만 사용해 주시면 됩니다. 참고로 시간을 기준으로 srand를 사용했고, 그 시점이 알려진다면 취약점이 될수도 있습니다. 왜냐하면 rand는 의사 난수를 발 생시키는 함수라 시드가 똑같으면 동일한 난수열을 생성하기 때문입니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[프레임워크를 넘어서…]]></title><description><![CDATA[개발을 처음 시작할 때에 누구나 한번쯤 특정 라이브러리를 사용해서 MP…]]></description><link>https://jiniya.net/wp/archives/5152</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5152</guid><pubDate>Fri, 21 Oct 2011 23:57:43 GMT</pubDate><content:encoded>&lt;p&gt;개발을 처음 시작할 때에 누구나 한번쯤 특정 라이브러리를 사용해서 MP3 플레이어나 게임 같은 것을 만들곤 우쭐해 하던 기억이 있을 것이다. 그러면서 우리는 잘 만든 라이브러리에 대한 환상에 빠진다.&lt;/p&gt;
&lt;p&gt;라이브러리를 넘어서 프레임워크라는 말이 대세가 된 요즘이다. 신기술이라 하면 프레임워크란 말 정도는 달아줘야 그나마 개발자들이 한 번이라도 쳐다보게 마련이다. 그렇다면 라이브러리나 프레임워크 같은 것들이 개발자에게 가지는 의미는 무엇일까?&lt;/p&gt;
&lt;p&gt;나는 개발자 게시판에서 벌어지는 도구에 관한 종교적인 논쟁에서 그러한 것들을 느껴보곤 한다. 그 중에 대표적인 논쟁이 언어에 관한 것이다. 자바 vs C++, C++ vs C#이런 류의 것들이다. 그런 논쟁의 중간을 잘라서 살펴보면 신입 개발자들이 프레임워크나 라이브러리에 대해서 가지는 환상을 쉽게 볼 수 있다. C#으로는 10줄이면 되는 것을 C++로는 1000줄을 작성해야 한다는 사실로부터 사용처나 목적을 떠나서 C#이 더 좋다고 하는 주장이 그 대표적인 예다. C#에서 10줄이 되기 위해서 뒤에서 다른 개발자들이 작성한 10만 줄의 코드를 보지 못하는 것이다.&lt;/p&gt;
&lt;p&gt;프레임워크의 대중화는 생산성을 극적으로 끌어올리는데 일조했다. 너도나도 레고 블록 같은 프레임워크의 구조만 익히면 이것저것 조합해서 근사한 것을 만들 수 있는 세상이 온 것이다. 하지만 다른 한편으로 프레임워크는 약골 개발자들을 대량으로 양산하는 첨병 역할 또한 같이 했다. 많은 신입 개발자들이 프레임워크에서 지원하지 않으면 만들 수 없는 기능이고 다음 버전의 프레임워크에 해당 기능이 포함되기를 기다려야 한다고 생각한다. 그들은 프레임워크는 완벽하다고 생각한다. 말 그대로 프레임워크라는 우물 안에 갇힌 개구리인 셈이다.&lt;/p&gt;
&lt;p&gt;하지만 좋은 개발자가 되기 위해서는 프레임워크에 한정되지 않은 강한 개발자가 되어야 한다. 더 넓게는 도구에 종속되지 않는 자유로는 개발자가 될 필요가 있다. 그렇다면 어떻게 강한 개발자가 될 수 있을까? 방법은 간단하다. 프로그래밍의 기초 체력이라 할 수 있는 논리력을 향상 시키는 것이다.&lt;/p&gt;
&lt;p&gt;그렇다면 논리력은 어디서 나오는 것일까? 그것은 여러분의 논리력을 향상 시켜주는 문제를 지속적으로 해결하는 것에서부터 길러진다. 처음부터 거창한 문제를 해결할 필요는 없다. 프레임워크나 운영체제에서 지원해 주는 기능을 사용해서 해결하고 있는 문제를 해당 기능 없이 구현해 보거나 프레임워크나 운영체제의 접근 방법과는 다른 좀 더 좋은 방법을 생각해 보는 것만으로도 충분하다.&lt;/p&gt;
&lt;p&gt;42.195 킬로미터를 달리는 마라톤을 하는데 가장 중요한 한 가지 요소는 기본적인 심폐 능력이다. 마찬가지로 프로그램을 작성하는데 있어서 가장 중요한 기본 요소는 논리력이다. 얼만큼 새로운 API를 아는지, 라이브러리 구조를 아는지, 프레임워크의 세부 기능을 암기하고 있는지가 아니라는 이야기다. 그러한 것들은 모두 시간이 지남에 따라 쉽게 습득할 수 있는 기술들이다. 특히나 요즘같이 인터넷이 대중화된 시대에는 더더욱 그런 것들은 가치가 없다. 하지만 논리력은 쉽게 습득하기도 힘들뿐더러 그 능력의 차이는 극복하기가 쉽지 않다. 바퀴를 새로 만들 필요는 없다. 하지만 그 바퀴를 만들 수 있는 사람과 그렇지 않는 사람과의 차이는 분명히 존재한다는 사실을 명심해야 한다.&lt;/p&gt;
&lt;p&gt; 12
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[스티브 잡스 타계]]></title><description><![CDATA[Steve Jobs, 1955 – 2011 IT 업계의 살아있는 신화에서, 이제는 전설이 되어버린 스티브 잡스 아저씨. “Stay Hungry. Stay Foolish…]]></description><link>https://jiniya.net/wp/archives/5143</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5143</guid><pubDate>Fri, 21 Oct 2011 23:57:42 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://www.apple.com/&quot;&gt;Steve Jobs&lt;/a&gt;, 1955 – 2011&lt;/p&gt;
&lt;p&gt;IT 업계의 살아있는 신화에서, 이제는 전설이 되어버린 스티브 잡스 아저씨.&lt;/p&gt;
&lt;p&gt;“Stay Hungry. Stay Foolish.”란 그의 말이 오늘 따라 더 가슴에 와 닿습니다.&lt;/p&gt;
&lt;p&gt;이제는 동영상에서 밖에 추억할 수 없는 분이 되었네요.&lt;/p&gt;
&lt;p&gt;삼가 고인의 명복을 빕니다.&lt;/p&gt;
&lt;p&gt;2011.10.06&lt;/p&gt;</content:encoded></item><item><title><![CDATA[01. Hello World를 만들어 보자, 2001]]></title><description><![CDATA[모든 플밍언어를 접하면 처음 해보는 게 있다. 바로 만국 공용, 첫단계 샘플 프로그램 Hello World…]]></description><link>https://jiniya.net/wp/archives/5132</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5132</guid><pubDate>Fri, 21 Oct 2011 23:57:41 GMT</pubDate><content:encoded>&lt;p&gt;모든 플밍언어를 접하면 처음 해보는 게 있다. 바로 만국 공용, 첫단계 샘플 프로그램 Hello World를 만드는 것이죠. 그럼 우선 간단한 소스를 보면서 시작해 봅시다. 두눈 크게 뜨고 자알 살펴보세용~&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;iostream&gt;&lt;/span&gt; &lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;namespace&lt;/span&gt; std&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello, World!&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;간단하죠~ 위의 프로그램을 컴파일해서 실행시키면 화면에 헬로, 월드!라고 찍힙니다. 그럼 지금부터 차근 차근 소스를 분석해 볼까요?!.. 너무 쉽다구요. 그래도 기초부터 튼튼히 해야 나중에 두려울게 없겠죠~&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;iostream&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;C++ 헤더 파일중에 iostream이라는 헤더 파일을 포함시키는 겁니다. 헤더 파일이 뭐냐구요?! 움… 그건.. 일종의 플밍을 쉽게 하도록 도와주는 유틸리티 같은 겁니다. 위에 있는 iostream을 포함시키면 화면에 출력과 입력을 할 수 있는 클래스인 cin, cout을 사용하게 해 줍니다. 그러니 저건 필수적으로 포함시켜야 겠죠~ 처음에는 그냥 꼭 포함시켜야 하는 것 정도로 이해하고 계세요~ 그리고 가끔 C++책들을 보면, #include &amp;#x3C;iostream.h&gt;라고 된것도 있는데 두개는 똑같은 겁니다. 반면에 .h를 쓰는 건 C언어식 표현 방법이죠. 그러니 간단하게 생략하고 표현하도록 합시다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이건 프로그램의 핵심이라고 할수 있는 본체 입니다. 프로그램에는 꼭 이 함수가 하나씩 드러가야 하죠. 쿄쿄. 안드러가면 아마도 링크가 되지 않을 겁니다. main이라는 함수가 프로그램의 시작위치를 지정하고 있는 함수라고 생각하면 되죠~ 그리고 main 앞에 붙어있는 int는 뭐냐구요. 그건 우리 프로그램이 종료되고 운영체제에게 int형으로 된 뭔가를 반환한다는 겁니다. 그러면 int가 뭐냐구요..?! 하하… int는 정수형을 말하는 겁니다. 따라서 우리의 메인은 정수를 반환하는 함수가 되겠죠~ 그리고 함수는 항상 {로 시작해서 }로 끝나야 합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;cout &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Hello, World!&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; endl&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위의 문장은 화면에 헬로 월드를 출력하는 실행문입니다. 그런데 잘 보면, &amp;#x3C;&amp;#x3C;게 있는 걸 알수 있는데 모양새를 잘 보세요. cout이라는 데로 헬로월드와 endl이라는 걸 집어넣는 것 처럼 보이죠. cout은 뭐냐구요. 바로 표준 출력(모니터)입니다. 그러니 모니터에다 헬로 월드와 endl를 집어넣는게 되죠. 그런데 헬로월드는 알겠는데 endl은 뭐냐구요. 그건 end of line의 약자로 다음줄로 가는 캐릭터 코드 입니다. 아래아한글에서 엔터를 치면 다음줄로 넘어가는 것 처럼 endl을 cout으로 넣으면 한줄 넘어가게 되죠~~~~!!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;운영체제에게 우리가 프로그램을 잘 실행했다고, 정수로 0을 반환하는 부분입니다. 리턴 다음에 반환할 값을 적으면 되죠. return 255이렇게 하면 255가 반환되는 겁니다. 반면에 return 12.5이렇게 하면 안되겠죠. 왜냐면 우리는 위에서 리턴값으로 정수형을 보낸다고 약속했기때문에 정수만 보내야 합니다. 일반적으로 관례상 정상종료시에는 0을 반환합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;숙제!!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;오늘 강좌를 다 읽으신 분들은 자신의 실력도 점검해 볼겸 화면에 자신의 이름과 생일을 출력하는 프로그램을 작성해 보세요. 다음 강좌 때 답을 갈켜 드리도록 하죠!!! 그럼 다들 수거하세요!!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[링버퍼, 2002]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/5127</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5127</guid><pubDate>Fri, 21 Oct 2011 23:57:40 GMT</pubDate><content:encoded>&lt;p&gt;링버퍼란 원형큐의 또다른 이름이라 생각할 수 있다. 뒤로 삽입이 이루어지고, 앞으로 삭제가 이루어지며 최대 갯수를 넘어설 경우 앞에 있는 것이 자동적으로 삭제되고 뒤에 추가가 이루어 진다. 요즘 흔히 사용하는 휴대전화기의 문자 메시지의 원리를 생각하면 된다. 최대 저장갯수가 초과하게 되면 가장 오래된 메시지가 삭제되고 새로운 메시지가 보관되는 원리아다. 물론 그렇게 처리가 되지 않은 구식 전화기도 종종있다.&lt;/p&gt;
&lt;p&gt;이러한 큐를 구현하는데 가장 많이 사용되는 방법중에 하나가 읽기, 쓰기 포인터를 이용한 방법이다. 각각은 MAXDATA가 되게 되면 다시 0으로 초기화 되어야 하므로 주로 나머지 연산자를 이용해서 많이들 구현하게 된다. 일반적으로 사용되는 수식은 대부분 아래와 같다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;MAXDATA&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; nPos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nPos &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; MAXDATA&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;흔히들 사용하는 진부한 식이다. 물론 이러한 수식을 처음 보는 분들께서는 위의 식에서 nPos가 움직이는 값을 관찰하면 금방 0~MAXDATA-1을 반복하면서 변화하게 되리란 것을 알수 있을것이다.&lt;/p&gt;
&lt;p&gt;몇일전 필자는 위와 같은 형태의 자료구조를 가진 것을 한번 만들 일이 있어서 프로그램을 작성한 일이 있었다. 하지만 작성도중 정말 어처구니 없는 일을 당하고 말았다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;MAXDATA&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;3600&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; nPos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nPos &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; MAXDATA&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;아무래도 이상한 결과가 출력되어 추적해 본 결과 nPos값이 0에서 200으로 변하는 것이 아닌가… ㅋㅋ… 이쯤 되었으면 아! 하는 분들이 많이 계시리라는 생각이 든다. 괄호가 빠져서 그런 결과가 나왔던 것이다. 하지만 실제로 선언과 참조가 한참이 분리된 코드에서는 그렇게 쉽게 생각나는 내용이 아니어서 한번 적어 보았다. 참고로 위 코드의 제대로 된 버전은 아래와 같이 되어야 한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;MAXDATA&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3600&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; nPos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nPos &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; MAXDATA&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[사소한 차이가 정답과 오답을 가른다, 2004]]></title><description><![CDATA[요즘 acm icpc 문제 풀이에 재미를 붙여 하루에 한두개씩 풀곤하는데 오늘 어이없는 것으로 한 20여 차례의 wrong answer를 만나야 했다. 문제는 너무나 간단해서 정답이 아닐리가 없고… 다 확인을 해 보았는데두 계속 wrong answer…]]></description><link>https://jiniya.net/wp/archives/5019</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5019</guid><pubDate>Fri, 21 Oct 2011 23:57:39 GMT</pubDate><content:encoded>&lt;p&gt;요즘 acm icpc 문제 풀이에 재미를 붙여 하루에 한두개씩 풀곤하는데 오늘 어이없는 것으로 한 20여 차례의 wrong answer를 만나야 했다. 문제는 너무나 간단해서 정답이 아닐리가 없고… 다 확인을 해 보았는데두 계속 wrong answer만 나오는 것이었다. 그 정답과 오답의 차이는 아래 루프에 있었다. 참고로 아래와 같은 루프는 주로 출력할것의 갯수를 잘라서 출력하는데 많이 사용되는 구조이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 루프1&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%3d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;putchar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;\n&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// 루프2&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;putchar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token char&quot;&gt;&apos;\n&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

    &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%3d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;원 문제의 요구는 15개씩 끊어서 출력하는 것이었다. 내가 작성한 루프는 1번구조였고 2번 구조가 정답의 루프 구조이다. 둘간의 차이를 금방 알수 있는 분은 충분히 코드를 머릿속으로 그릴수 있는 사람들이다. 나 또한 둘간의 차이를 구분하지 못해서 수십번의 오류를 가진 답을 제출해야 했다. 눈에 들어오지않는 사람들은 한번 쯤 곰곰히 생각해 보길 바란다. 둘간의 차이가 무엇일까??&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;15개씩 끊어주는 건 둘 다 같은데…&lt;/p&gt;
&lt;p&gt;한 가지 다르다면 15n-1의 경우 첫번째는 리턴값이 포함된다는 것 정도?&lt;/p&gt;
&lt;p&gt;by &lt;strong&gt;인터넷 논객&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[setjmp/longjmp, 2002]]></title><description><![CDATA[C언어를 가끔 사용하다 보면 이런 것들을 하고 싶을때가 있습니다. 이 함수를 넘어 저 함수로 이동하거나 함수의 경계를 넘나드는 어떤 처리를 하고 싶을때가 있죠. 처음 딱 생각하기에는 goto로 될 것 같지만, C언어의 goto…]]></description><link>https://jiniya.net/wp/archives/5030</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5030</guid><pubDate>Fri, 21 Oct 2011 23:57:38 GMT</pubDate><content:encoded>&lt;p&gt;C언어를 가끔 사용하다 보면 이런 것들을 하고 싶을때가 있습니다. 이 함수를 넘어 저 함수로 이동하거나 함수의 경계를 넘나드는 어떤 처리를 하고 싶을때가 있죠. 처음 딱 생각하기에는 goto로 될 것 같지만, C언어의 goto에는 함수의 범위를 넘지 못하는 제약이 있습니다. 대신 목적을 위해 만들어진 함수 두개가 있습니다. 바로 setjmp, longjmp입니다. 이름 그대로 아주 먼 거리를 점프하는 함수죠. 그럼 실제 소스 코드를 볼까요??&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;/span&gt;

jmp_buf pos&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;proc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
   &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
       &lt;span class=&quot;token function&quot;&gt;longjmp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; 

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; 
   &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setjmp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pos&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   &lt;span class=&quot;token function&quot;&gt;proc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;결과는 각자 감상하시면서 한번씩 생각해 보시길 바랍니다. 참고로 jmp_buf는 상태를 저장하는 버퍼 구조체 입니다. 기본 원리는 setjmp는 현재 상태를 저장하고 longjmp이전 상태로 이동하는 역할을 하게 됩니다. 각자 한번 실행해 보시면 금방 아! 하시게 될겁니다.&lt;/p&gt;
&lt;p&gt;그럼 다들 좋은 하루 되세요.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[iostream에서 지원하는 텍스트 포맷팅 함수들, 2001]]></title><description><![CDATA[C언어를 배우고 난 뒤 처음 C++ 책을 접하게 되면 iostream…]]></description><link>https://jiniya.net/wp/archives/4952</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4952</guid><pubDate>Thu, 20 Oct 2011 23:57:37 GMT</pubDate><content:encoded>&lt;p&gt;C언어를 배우고 난 뒤 처음 C++ 책을 접하게 되면 iostream이라는 것을 배우게 됩니다. 모두 단순히 출력또는 입력을 연산자 오버로딩을 통해 간단하게 해주는 정도의 기능을 알고 넘어가게 되는데 사실 그정도만 알면 되죠. 하지만 가끔 그 이상의 iostream기능이 궁금할때가 있습니다. 그것을 잘 몰라서 고생하는 경우가 계신것 같아서 옵션으로 쓸수 있는 것들을 한번 추려서 올려봅니다.&lt;/p&gt;
&lt;p&gt;이 자료는 모두 Practical C++ Programming에서 발췌된 것입니다. 참고로 책에서도 C++의 입,출력 포맷 방식이 아주 불편한 방식이라구 [1]. sprintf등을 통한 포맷된 문자열을 화면으로 출력하기를 권하고 있습니다. 하지만 때로는 이런것들을 알고 있는 것이 도움이 될때도 있기에 올려봅니다. 그럼 다들 즐프하세염.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;입출력 변환 플래그&lt;/p&gt;
&lt;p&gt;ios::skipws 입력에서 공백 문자를 건너뛴다.&lt;/p&gt;
&lt;p&gt;ios::left 출력 왼쪽 정렬&lt;/p&gt;
&lt;p&gt;ios::right 출력 오른쪽 정렬&lt;/p&gt;
&lt;p&gt;ios::internal 숫자 출력은 부호나 기조 문자와 숫자 사이에 채우기 문자 삽입&lt;/p&gt;
&lt;p&gt;ios::dec 10진수&lt;/p&gt;
&lt;p&gt;ios::oct 8진수&lt;/p&gt;
&lt;p&gt;ios::hex 16진수&lt;/p&gt;
&lt;p&gt;ios::showbase 각 숫자의 서두에 기저를 표시한다. 예를들어 16진수이면 0x가 앞에출력된다.&lt;/p&gt;
&lt;p&gt;ios::showpoint 모든 부동 소수에 대해 10진수로 표시한다.&lt;/p&gt;
&lt;p&gt;ios::uppercas 16진수 변환시 대문자로 출력&lt;/p&gt;
&lt;p&gt;ios::showpos 모든 양수 앞에 + 기호 붙임&lt;/p&gt;
&lt;p&gt;ios::scientific 출력 시에 모든 부동 소수를 지수 형식으로 변환&lt;/p&gt;
&lt;p&gt;ios::fixed 출력시에 모든 부동 소수를 고정 소수로 변환&lt;/p&gt;
&lt;p&gt;ios::unitbuf 버퍼 출력&lt;/p&gt;
&lt;p&gt;ios::studio 출력 후에 스트립 플러시&lt;/p&gt;
&lt;p&gt;입출력 조정자&lt;/p&gt;
&lt;p&gt;setiosflags(long flags) 지정 변환 플래그 설정&lt;/p&gt;
&lt;p&gt;resetiosflags(long flags) 지정 플래그로 복원&lt;/p&gt;
&lt;p&gt;dec 10진수&lt;/p&gt;
&lt;p&gt;hex 16진수&lt;/p&gt;
&lt;p&gt;oct 8진수&lt;/p&gt;
&lt;p&gt;setbase(int base) 기저를 8,10,16으로 변환&lt;/p&gt;
&lt;p&gt;setw(int width) 출력 너비 설정&lt;/p&gt;
&lt;p&gt;setprecision(int precision) 부동 소수 출력의 정확도 설정&lt;/p&gt;
&lt;p&gt;setfill(char ch) 채우기 문자 설정&lt;/p&gt;
&lt;p&gt;ws 입력시에 공백 문자 건너뜀&lt;/p&gt;
&lt;p&gt;endl 라인끝 출력&lt;/p&gt;
&lt;p&gt;ends 문자열 끝 출력&lt;/p&gt;
&lt;p&gt;flush 버퍼에 있는 내용을 출력&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;[1] boost::format을 사용하면 C++에서도 printf같이 편리하게 자료를 출력하실 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.boost.org/doc/libs/1_47_0/libs/format/&quot;&gt;http://www.boost.org/doc/libs/1_47_0/libs/format/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; 1
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[printf 가변 공백 삽입하기, 2001]]></title><description><![CDATA[오늘 방금 책을보다 깨닫게 된 것이 있어 올려봅니다. printf를 사용하다보면 공백을 적당하게 넣어야 하는 경우가 생기는데 그럴때 유용하게 사용할 수 있는 방법입니다. 위와같이 하면 6칸을 띄우고 Hello…]]></description><link>https://jiniya.net/wp/archives/4961</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4961</guid><pubDate>Thu, 20 Oct 2011 23:57:36 GMT</pubDate><content:encoded>&lt;p&gt;오늘 방금 책을보다 깨닫게 된 것이 있어 올려봅니다. printf를 사용하다보면 공백을 적당하게 넣어야 하는 경우가 생기는데 그럴때 유용하게 사용할 수 있는 방법입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%*sHello&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위와같이 하면 6칸을 띄우고 Hello가 출력이 됩니다. &lt;strong&gt;아직 확인해보지는 못했지만 책에서 봤으니까 맞는것 같네염 [1].&lt;/strong&gt; 다들 한번해보세염. 괜찮은 것 같은데. 그럼 좋은하루되세요!!!&lt;/p&gt;
&lt;p&gt;[1] 세상에서 제일 멍청한 생각이죠. 여러분은 절대로 이런 생각을 하지 말기를 바랍니다. ㅋㅋ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[비트 연산 몇 가지, 2002]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/5025</link><guid isPermaLink="false">https://jiniya.net/wp/archives/5025</guid><pubDate>Thu, 20 Oct 2011 23:57:35 GMT</pubDate><content:encoded>&lt;p&gt;요즘은 실제로 윈도우나 리눅스쪽에서 프로그래밍을 한일이 별로 없어서 그쪽으로 적을만한 것이 없네염. 드뎌 몇달간 당당히 오늘의 코드를 지키고 있던 진수 변환기를 재치고 새로운 코드를 올려 놓으려 합니다.&lt;/p&gt;
&lt;p&gt;요즘 원칩 플밍을 하면서 비트 연산이 자주 필요해서 만들어 본 함수입니다. 함수라고 하기보다는 매크로 입니당. 그럼 코드 내려 갑니당.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name function&quot;&gt;CHKBIT&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;var&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;var&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0x01&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name function&quot;&gt;CLRBIT&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;var&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;var&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0x01&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name function&quot;&gt;SETBIT&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;var&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;var&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0x01&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위에서 부터 설명 드리겠습니다.&lt;/p&gt;
&lt;p&gt;CHKBIT(숫자, 비트번호) 하면 해당 숫자에 비트번호가 세팅되어 있는지 되어 있지 않은지를 판단합니다. CLRBIT는 해당 숫자의 비트를 제거하는 것이며 SETBIT은 해당 숫자의 비트를 설정하는 것 입니다. 모든 기준은 8비트 자료형에 맞추어져 있습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[소수 판별하기, 2002]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/4982</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4982</guid><pubDate>Thu, 20 Oct 2011 23:57:34 GMT</pubDate><content:encoded>&lt;p&gt;일반적으로 소수를 판별하는 다항식은 존재하지 않는다고 많이 알려져 있습니다. 그래서 소수를 판별하는 것 또한 컴퓨터로 하기 힘든 일 중에 하나죠. 최근 그 문제에 대한 해답이 나왔나 봅니다. 소수를 판별하는 다항식에 대한 자세한 설명과 알고리즘이 나와 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.cse.iitk.ac.in/news/primality.pdf&quot;&gt;http://www.cse.iitk.ac.in/news/primality.pdf&lt;/a&gt; [1]&lt;/p&gt;
&lt;p&gt;기럼, 전 구시대적 방법으로 판별하는 함수를 하나 올리도록 할께염… ㅎㅎ&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;IsPrime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
       &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 소스는 위의 함수를 이용하여서 1000이하의 소스를 출력하는 소스 입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;IsPrime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%d &quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;[1] 링크가 깨졌네요. 글에서 언급한 소수 판별 다항 알고리즘은 “AKS 소수 판별법”입니다. 다음 위키 페이지에 설명이 나와 있습니다. &lt;a href=&quot;http://en.wikipedia.org/wiki/AKS_primality_test&quot;&gt;http://en.wikipedia.org/wiki/AKS_primality_test&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;소수라고 함은..정수로 하는 것인데..쓸대 없이 루프가 더 도네요….정수는 자신의 1/2 이상의 수로는 절대 나눌수 가 없죠….. for(i = 2; i &amp;#x3C; n/2 ; ++1) 라고 해야…효율적일듯&lt;/p&gt;
&lt;p&gt;by &lt;strong&gt;까칠한 인터넷 논객&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;n/2라뇨. 수학을 배웠으면 루트죠. 이게 더 효율적일듯…&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;MyRoot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
   x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; 

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;IsPrime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;MyRoot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
       &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; 

   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;by &lt;strong&gt;까칠한 인터넷 논객 제압자&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;안녕하세요,&lt;/p&gt;
&lt;p&gt;ICPC 자료들 구하다가 찾아들어왔습니다.&lt;/p&gt;
&lt;p&gt;좋은 자료 잘 받아갑니다.^^;&lt;/p&gt;
&lt;p&gt;마지막으로 올라온 코드에서 한가지 더 추가드리자면..&lt;/p&gt;
&lt;p&gt;n이 짝수일때는 소수일리가 없으므로..&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;IsPrime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

   &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;MyRoot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// increment i by 2&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
       &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; 

   &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그리고 위의 함수는 아래의 매크로로 사용될수 있습니다. (단 n이 홀수일때만).&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name function&quot;&gt;isprime&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//works when n is odd&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;글구…&lt;/p&gt;
&lt;p&gt;위에 예제처럼 primality testing을 여러번 해야 할 시에는 sieve라는 알고리즘을 많이 사용합니다. 테이블을 0부터 n까지 잡고, 각 숫자마다 2부터 sqrt(n) 까지만 테스팅을 해주는 방식인데요, 그걸 해주자면 배열에서 루프를 돌려서 각 인덱스마다 인덱스의 배수에 해당하는 엘리먼트들을 죄다 날려주는 겁니다. 이런식으로 날려(?)주다보면 나중엔 안날라(?) 간 아이들만 소수가 되는것이지요.. 간단한 코드 올려 봅니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;MAX&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;20000000&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; sieve&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;MAX&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;gen_sieve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token comment&quot;&gt;/*sieve: 0 means prime, 1 means composite*/&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ulimit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token function&quot;&gt;memset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sieve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20000001&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  sieve&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  sieve&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MAX&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    sieve&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  sieve&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MAX&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    sieve&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  ulimit&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MAX&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ulimit&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sieve&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;j&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;j&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MAX&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;j&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;j&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        sieve&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위 알고리즘의 시간복잡도는 O(n log log n )입니다.&lt;/p&gt;
&lt;p&gt;시간 복잡도 계산을 위해선 다음과 같이 생긴 harmonic series를 구해야 합니다.&lt;/p&gt;
&lt;p&gt;Sigma n/i, i=3..sqrt(n), where i=prime number&lt;/p&gt;
&lt;p&gt;ie) n/3 + n/5 + n/7 + n/11 + n/13 + …&lt;/p&gt;
&lt;p&gt;그리구 저 시리즈의 값은 다음 주소에 나와있네요.^^;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://mathworld.wolfram.com/MertensSecondTheorem.html&quot;&gt;http://mathworld.wolfram.com/MertensSecondTheorem.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;by &lt;strong&gt;인터넷 지존&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[How to wake up a PC using waitable timer.]]></title><description><![CDATA[I used to love listening to the pop-song radio program that aired early in the morning when I was a teenager. However, waking up in the…]]></description><link>https://jiniya.net/wp/archives/4910</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4910</guid><pubDate>Thu, 13 Oct 2011 23:57:33 GMT</pubDate><content:encoded>&lt;p&gt;I used to love listening to the pop-song radio program that aired early in the morning when I was a teenager. However, waking up in the early morning was almost impossible for me, then I couldn’t help wondering how convenient and wonderful it would be if the radio could automatically be turned on and wakes me up. (There was no such thing back then). However, I am guessing that some students nowadays might want the similar function from their PCs, so we are going to cover the method to do so today.&lt;/p&gt;
&lt;p&gt;The power status of the Windows are divided into five main categories. Please refer to the link below for further information.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/desktop/aa373229(v=vs.85).aspx&quot;&gt;http://msdn.microsoft.com/en-us/library/windows/desktop/aa373229(v=vs.85).aspx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If we were to categorize the five different power status, we have Operating mode (S0), Sleep mode (S1, S2, S3) and Hibernation (S4), soft off (s5) and Off(G3). The only categories we can wake up the computer via the software is when it’s on Sleep mode S1,S2,S3 and S4 mode while hibernation (S4) mode is the most frequently used to turn on the computer automatically as it consumes the lowest amount of power.&lt;/p&gt;
&lt;p&gt;Now we will look at the specific way we can turn the computer back on at a certain time. The most common technique for this would be to turn it off to the hibernation and wake it up at a certain time. Turning off the computer via hibernation mode is extremely simple. All it requires is the code as you see below.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;SetSystemPowerState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;FALSE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;However, it will not work as well as you expect, as we do not have the authority to turn off the power. Thus, we will need to gain the authority through the code SeShutdownPrivilege. This code allows the authority to turn your computer off via the code “SetSystemPowerState” successfully.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; BOOL WINAPI
&lt;span class=&quot;token function&quot;&gt;_EnableShutDownPriv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	BOOL ret &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	HANDLE process &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetCurrentProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	HANDLE token&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;OpenProcessToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TOKEN_ADJUST_PRIVILEGES &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; TOKEN_QUERY
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;token&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	LUID luid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;LookupPrivilegeValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;SeShutdownPrivilege&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;luid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	TOKEN_PRIVILEGES priv&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	priv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PrivilegeCount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	priv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Privileges&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Attributes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; SE_PRIVILEGE_ENABLED&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	priv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Privileges&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Luid &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; luid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ret &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AdjustTokenPrivileges&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;token&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;priv&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;token&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now I am going to cover the method to wake the computer up. In order to get the computer back on from the hibernation mode, we need what we call ‘waitable timer’, which operates when your PC is in the hibernation mode. Its primary function is as same is the timer, which triggers the event we appointed at the designated time. In other words, the event set in prior is triggered automatically as the code prepared starts its progress. The next code shows us how to use the pre-arranged timer. The only fact you need to be aware in this process is that the unit of time is based on 100 nano seconds. If you appoint the positive number, it becomes an absolute time, while using appointing negative becomes a relative time. The absolute time is recognized same as FILETIME on Windows. Therefore, as we appoint the negative number as per below, the timer will initiate itself after certain seconds from the moment we set the timer.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HANDLE timer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateWaitableTimer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;MyWaitableTimer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;timer &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

__int64 nanoSecs&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
LARGE_INTEGER due&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

nanoSecs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;secs &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
due&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;LowPart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DWORD&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nanoSecs &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0xFFFFFFFF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
due&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;HighPart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LONG&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nanoSecs &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SetWaitableTimer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;timer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;due&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The last thing you need to remember is that you need to notify the Windows that certain power is required if you need to turn on the monitor separately once the computer is turned on from the Hibernation mode. All you need is the code as per below, which will trigger the notification and automatically turn on the monitor.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;SetThreadExecutionState(ES_DISPLAY_REQUIRED);&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;SetThreadExecutionState(ES_DISPLAY_REQUIRED);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Overall, first you gain the authority, then set the waitable timer and initiate hibernation. When the waitable timer starts its procedure, it notifies the system that we want the power on. This is all done as per the code below.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;DWORD CALLBACK
&lt;span class=&quot;token function&quot;&gt;ShutDownProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPVOID p&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	PHANDLE timer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PHANDLE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; p&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;WaitForSingleObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;timer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; INFINITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;timer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;SetThreadExecutionState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ES_DISPLAY_REQUIRED&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

PWRMGMT_API BOOL WINAPI
&lt;span class=&quot;token function&quot;&gt;HibernateAndReboot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; secs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_EnableShutDownPriv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	HANDLE timer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateWaitableTimer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;MyWaitableTimer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;timer &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	__int64 nanoSecs&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	LARGE_INTEGER due&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	nanoSecs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;secs &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	due&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;LowPart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DWORD&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nanoSecs &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0xFFFFFFFF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	due&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;HighPart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LONG&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nanoSecs &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SetWaitableTimer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;timer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;due&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; ERROR_NOT_SUPPORTED&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	HANDLE thread &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ShutDownProc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;timer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;timer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;SetSystemPowerState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;FALSE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once your PC is turned on, it will be ready for you to do whatever you would like to do.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[학부 수업 명장면, 베스트 3]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/4806</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4806</guid><pubDate>Thu, 06 Oct 2011 23:57:32 GMT</pubDate><content:encoded>&lt;p&gt;자주 오시는 분들께서는 아시겠지만 개천절을 기해서 블로그를 리뉴얼 했습니다. 원래 제가 호스팅 받던 곳이 워드프레스 최신 버전을 지원하지 않아서 새로운 호스팅 업체로 옮기고 홈페이지에 있던 자료들도 정리했습니다. 블로깅 하기 이전의 사이트에 있던 자료들을 옮기려고 살펴보다 보니 예전 생각이 새록새록 나더군요. 풋풋한 시절에 제가 작성한 글들에서 묻어나는 풋내랄까요? ㅋㅋ~ 어쨌든 대학 시절에 쓴 글들을 읽고 있으니 자연스럽게 그 시절을 회상하게 되었습니다. 그러다 떠오른 세 가지 장면. 캡쳐해 보았습니다. 학부 4년의 수업 시간 중에서 가장 감동적이었던 장면, 베스트 3입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;처음으로 놀랐던 수업은 다름아닌 유명한 권혁철 교수님의 C언어 수업 시간이었습니다. 1학년 과목 중에 유일한 A+이있습니다. — 그거 말고는 전부 D, F였다죠 ㅠㅜ — 수업을 듣기 전부터 C언어를 알고 있었던 지라 수업은 그다지 새로울 것이 없을 거라고 생각하고 들었습니다. 그런데 아이러니한 사실은 대학 4년 동안 프로그래밍이란 관점에서 내지는 제가 프로그래머로 생활하는데 있어서 가장 큰 교훈을 준 수업은 바로 그 시간에 있었습니다. 그 후에도, 그 전에도 대학교 프로그래밍 수업에서 그런 감동을 느꼈던 적은 없었던 것 같네요.&lt;/p&gt;
&lt;p&gt;사설이 길었습니다. 어떤 내용이었는지 궁금하실 것 같네요. 바로 다름아닌 배열에 관한 내용이었습니다. 간단하게 학생 번호와 학점을 입력 받아 평균을 계산하는 프로그램이 예제였습니다. 너무 쉽죠. 그런데 그전까지 저는 매번 그런 프로그램을 작성할 때마다 항상 배열 오프셋에 -1을 하는 코드를 추가해서 계산을 했었습니다. 왜냐하면 C언어는 특성상 배열 인덱스가 0에서 시작하고 학생 번호는 1에서 시작하기 때문이었죠. 그 때 교수님께서 그러시더군요. 이렇게 멍청하게 하지 않는 방법은 없을까? 조용했습니다.&lt;/p&gt;
&lt;p&gt;교수님 설명이 이어졌습니다. “그럴 필요 뭐 있어. 그냥 배열을 1크게 잡으면 되는 거지.” 학생이 20명이면 21개를 배열로 잡으면 되는 거고, 30명이면 31개를 배열로 잡으면 되는 거라는 말씀이었습니다. 그게 컴퓨터 공학에 있어서의 숙명, 공간과 속도 사이의 트레이드오프라는 설명을 같이 해주셨습니다. 저에게는 샥(shock)이었습니다. 뭔가 번갯불이 머리를 스쳐 지나가는 느낌이었죠.&lt;/p&gt;
&lt;p&gt;여기서 끝이 아니었습니다. 교수님께서 말씀하십니다. “컴퓨터 공학에서 속도와 공간이라는 문제는 흔히 두 마리 토끼에 비유된다. 하나를 잡으면 다른 하나는 놓칠 수 밖에 없는 것이란 말이다. 하지만 이 조차도 때로는 고정관념에 불과하다. 이런 관점에서 앞선 문제를 좀 더 똑똑하게 해결할 수 있는 방법을 아는 사람?” 다시 조용해 졌습니다. 그리곤 포인터를 오프셋만큼 옮기는 테크닉을 설명해 주셨습니다. 배열을 정해진 크기만큼 할당하고 배열의 시작 위치에서 -1한 지점을 가리키는 방법이었죠. 아래와 같이 코딩한 다음 pscore를 배열로 사용한다는 의미입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; score&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;pscore &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; score &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;설명을 다 듣고 울었습니다. 물론 가슴속으로 말입니다. 그리곤 아주 잠깐 동안 이래서 엄마가 대학을 가라고 했던 거구나, 라는 생각을 뼈저리게 했었답니다. 지금도 무엇인가를 설계할 때, 프로그래밍을 할 때 가끔 그 수업 시간을 떠올리곤 합니다. ‘더 좋은 방법은 없을까? 내가 진리라고 믿고 있는 것 조차도 고정 관념이 아닐까? 내 틀에 갇혀 있는 것은 아닐까?’ 라는 생각을 하면서 말입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;두 번째 수업은 3번씩 재수강을 하고도 한번도 패스하지 못했던 일반물리학 수업 시간이었습니다. 변명을 좀 하자면 사실 전 물리를 제법 잘합니다. 고교 이과 선택과목도 물리 II였고, 수학능력시험에서 하나도 틀리지 않는 기염을 토했으며, 물리경시대회에 참가하기도 했었죠. 특별한 사유(?!)가 있었습니다. 너무 치명적인 사유였죠. ㅠㅜ&lt;/p&gt;
&lt;p&gt;계절학기 첫 수업 시간이었던 것 같습니다. 교수님께서 들어오시더니 본인의 인생사 이야기를 잠시 하셨습니다. 이어서 일반 물리학 책을 펼치면서 말씀하십니다.&lt;/p&gt;
&lt;p&gt;“여기 뉴턴이 이해한 물리학이 있다. 난 그걸 내가 해석한대로 가르칠 생각이다. 여러분은 여러분의 버전으로 그 내용을 이해하면 된다. 여기에 정답이란 없다. 뉴턴이 잘못된 생각을 했을 수도 있고, 우리 모두가 엉뚱한 착각에 빠졌을 수도 있다. 의문이 있다면 가지는 것이 당연한 일이다. 권위 앞에 주눅들 필요 없다. 그래야 우리 후배들은 더 정확한 물리학을 배울 수 있게 된다.”&lt;/p&gt;
&lt;p&gt;교수님의 짧았던 이 이야기는 저에게 자신감을 주는 동시에, 겸손함을 가르쳐 주었습니다. 정답은 없다는 사실. 누구나 의문을 제기할 수 있다는 사실. 저에게는 세상을 살아 나가는데 무엇과도 바꿀 수 없는 정말 값진 교훈이었습니다. 이 평범한 사실이 말입니다. 그 전에도 그 후에도 누구도 저에게 이런 이야기를 해주진 않았거든요.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;학부 마지막 감동 수업은 복학하고 들었던 컴퓨터 구조 수업 시간이었습니다. 지루하던 찰나, 교수님께서 굴곡진 인생을 살았다는 학부인지 대학원인지 동기에 관한 이야기를 하셨습니다. 처음에는 무슨 이야긴가 싶었습니다. 누구지라는 의문이 잠시 들다가 이야기가 중반을 넘어서면서 바로 알겠더군요. 그 친구가 누구인지 말이죠. 한국 프로그래머의 살아있는 전설로 불리는 바로 그 분, 송재경씨였습니다. 신선한 충격이었습니다. 우리 학교에 그 분과 친구였던 교수님이 있다는 사실이 말이죠. 교수님이 그 이야기를 하시는 10분 사이에 완전 새로워 보이는 기적을 경험했다고나 할까요. ㅋㅋ~ 아마 교수님께서 어렵겠지만 송재경씨를 한 번 수업시간에 초빙해 주셨다면 저는 그 교수님을 ‘신’이라 여겼을지도 모르겠습니다. 어쨌든 그런 기회는 저에겐 없었지만 단지 송재경씨와 친구 사이인 교수님께서 계시다는 사실만으로도 전 제법 감동을 받았습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[특정 시간에 컴퓨터를 깨우는 방법]]></title><description><![CDATA[중학교 때 가끔 굿모닝 팝스를 들었습니다. 그런데 잘 아시겠지만 그 때나 지금이나(?!) 굿모닝 팝스는 굉장히 아침 일찍 합니다. 아침잠 많은 제가 듣기에는 제법 벅찬 방송이었죠. 그 시절 뭐 지금처럼 mp…]]></description><link>https://jiniya.net/wp/archives/4511</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4511</guid><pubDate>Tue, 04 Oct 2011 23:57:31 GMT</pubDate><content:encoded>&lt;p&gt;중학교 때 가끔 굿모닝 팝스를 들었습니다. 그런데 잘 아시겠지만 그 때나 지금이나(?!) 굿모닝 팝스는 굉장히 아침 일찍 합니다. 아침잠 많은 제가 듣기에는 제법 벅찬 방송이었죠. 그 시절 뭐 지금처럼 mp3나 인터넷 스트리밍이 흔한 시절도 아니었으니 방송을 놓치면 그냥 그날은 공치는 셈이었습니다. 그래서 전 가끔 내 라디오가 그 시간에 나를 깨워주면 참 좋겠다는 생각을 많이 했었습니다. 제가 그 때 사용하던 구형 라디오는 정말 6.25 때나 쓰던 것처럼 생겼던 것이었지요. 당연히 알람 기능 따위는 없었습니다. 그래서 저는 알람 시계에 연결을 해서 그 녀석이 알람 시계가 울릴 때 켜지도록 하는 기능을 만들었었죠. 한동안 그렇게 잘 썼는데 알람시계를 라디오 내부에 연결을 해두니 미관상 별로 좋지가 않았습니다. 그래서 선을 깔끔하게 한다는 명분아래 시계를 밖으로 빼서 220볼트에 물렸죠. 그리곤 전원을 꽂았습니다. ㅋㅋ~ 미친 짓이었죠. 콘덴서가 펑하고 터지더니 안에서 휴지 같은 것들이 튀어 나오더군요. 그 때 이후로 그런 장난은 다시는 치지 않습니다.&lt;/p&gt;
&lt;p&gt;요즘은 머 라디오는 잘 쓰지도 않으니 종종 컴퓨터로 이런 짓들을 하고 있을 학생들이 있을지도 모르겠다는 생각을 해봅니다. 알람 시계를 컴퓨터에다 연결하는 학생들 말이죠. 컴퓨터가 아침에 자동으로 일어나서는 나에게 정보를 알려주는 일은 상상만으로도 즐겁잖아요. 뭐 일어나서 오늘의 날씨를 알려준다던지, 뉴스를 읽어준다든지 말이죠. 어쨌든 그런 니즈가 많이 있습니다. 물론 똑똑한 학생이라면 알람 시계를 연결하기 전에 웹서핑을 해볼 것이고, 그러면 자신이 사용할 수 있는 프로그램이 제법 많이 있다는 사실에 놀랄지도 모르겠군요. ㅋㅋ~ 오늘은 그런 프로그램들이 어떻게 해당 기능을 구현하는지에 대해서 알아보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;윈도우의 전원 상태는 크게 5가지 상태가 있습니다. 전원 상태에 대한 세부 설명은 아래 페이지에 자세하게 나와 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/windows/desktop/aa373229(v=vs.85).aspx&quot;&gt;http://msdn.microsoft.com/en-us/library/windows/desktop/aa373229(v=vs.85).aspx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;크게 구분을 지어 보자면 동작 상태(S0), 수면 상태(S1, S2, S3), 하이버네이션 상태(S4), 소프트 오프 상태(S5), 그리고 완전 오프 상태로(G3) 나뉩니다. 여기서 소프트웨어 적으로 깨어날 수 있는 상태는 동작, 수면, 하이버네이션 상태가 전부입니다. 소프트 오프와 완전 오프 상태에서는 소프트웨어 적으로 깨어날 수가 없습니다. 그 중에서도 컴퓨터를 특정 시간에 깨워주는 소프트웨어들이 자주 애용하는 상태는 다름아닌 하이버네이션입니다. 소프트웨어적으로 깨어날 수 있는 상태 중에서 가장 적은 에너지를 소모하기 때문입니다. 사실 뭐 거의 오프 상태나 다름 없습니다.&lt;/p&gt;
&lt;p&gt;자 그럼 이제 구체적으로 컴퓨터를 특정 시간에 어떻게 깨우는지에 대해서 방법을 알아보도록 하겠습니다. 여기에 사용되는 가장 기본적인 테크닉은 컴퓨터를 하이버네이션으로 끄고, 특정 시간 이후에 다시 깨우는 것입니다. 그렇담 당연히 하이버네이션으로 끄는 것을 먼저 알아야겠죠. 하이버네이션을 시키는 방법은 정말 간단합니다. 아래와 같은 단 한줄의 코드면 충분합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;SetSystemPowerState(FALSE, FALSE);&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;SetSystemPowerState(FALSE, FALSE);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;하지만 세상 일이란게 그리 쉽진 않죠. 생각처럼 잘 동작하지 않을 겁니다. 왜냐하면 우리에겐 권한이 없거든요. 전원을 꺼버릴 권한이요. 그렇다면 당연히 해당 권한을 획득해야겠죠. SeShutdownPrivilege가 그런 역할을 하는 권한입니다. 아래 코드는 그런 권한을 획득하는 역할을 합니다. 아래 코드를 통해서 권한을 획득하고 SetSystemPowerState를 하면 정상적으로 꺼지는 것을 확인하실 수 있을 겁니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; BOOL WINAPI
&lt;span class=&quot;token function&quot;&gt;_EnableShutDownPriv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	BOOL ret &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	HANDLE process &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetCurrentProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	HANDLE token&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;OpenProcessToken&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TOKEN_ADJUST_PRIVILEGES &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; TOKEN_QUERY
						&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;token&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	LUID luid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;LookupPrivilegeValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;SeShutdownPrivilege&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;luid&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	TOKEN_PRIVILEGES priv&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	priv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PrivilegeCount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	priv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Privileges&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Attributes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; SE_PRIVILEGE_ENABLED&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	priv&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Privileges&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Luid &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; luid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	ret &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;AdjustTokenPrivileges&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;token&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;priv&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;token&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이제는 다시 깨우기 위한 준비를 배워봅시다. 하이버네이션 상태에서 깨어나기 위해서는 윈도우에서 제공해주는 대기 타이머라는 것을 사용합니다. 웨이터블 타이머(waitable timer)가 정식 명친인데요, 이 녀석은 하이버네이션 상태가 되더라도 동작한다는 끈질긴 특징이 있습니다. 기본적인 기능은 타이머와 동일하다고 생각하면 되겠습니다. 즉, 우리가 지정한 시점이되면 이벤트가 트리거되고 타이머를 대기하던 코드가 깨어나서 수행되는 겁니다. 다음 코드는 대기 타이머를 사용하는 방법을 보여주고 있습니다. 여려운 건 없죠. 단지 시간이 100나노초 단위라는 것에 주의하면 되겠습니다. 양수를 지정하면 절대 시간을, 음수를 지정하면 상대 시간이 됩니다. 절대 시간은 윈도우에서 사용하는 FILETIME과 동일한 값을 가집니다. 아래 코드에서는 음수를 지정했으니 타이머를 대기하는 순간부터 secs초 이후에 해당 타이머가 발동하는 구조가 됩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HANDLE timer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateWaitableTimer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;MyWaitableTimer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;timer &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

__int64 nanoSecs&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
LARGE_INTEGER due&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

nanoSecs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;secs &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
due&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;LowPart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DWORD&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nanoSecs &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0xFFFFFFFF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
due&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;HighPart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LONG&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nanoSecs &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SetWaitableTimer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;timer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;due&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;끝으로 한 가지 더 기억해야 할 것이 있습니다. 하이버네이션 상태에서 깨어난 다음에 모니터 전원이 필요하다면 윈도우에 해당 전원이 필요하다는 사실을 알려주어야 합니다. 어떻게 요청하냐구요? SetThreadExecutionState(ES_DISPLAY_REQUIRED); 이 한 줄이면 충분합니다. 해당 함수를 호출하면 윈도우는 모니터 전원이 필요하다는 것을 눈치채고 모니터에도 전원을 공급해 줍니다. 즉, 모두 다 종합해보면 이렇습니다. 권한을 얻고, 웨이터블 타이머를 설정하고, 하이버네이션을 시킵니다. 웨이터블 타이머가 동작하면 시스템에 우리가 모니터 전원이 필요로 하다는 의사를 알려주고는 하고 싶은 나머지 작업을 진행하면 됩니다. 아래 코드에 모두 다 들어 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;DWORD CALLBACK
&lt;span class=&quot;token function&quot;&gt;ShutDownProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPVOID p&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	PHANDLE timer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PHANDLE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; p&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;WaitForSingleObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;timer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; INFINITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;timer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;SetThreadExecutionState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ES_DISPLAY_REQUIRED&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

PWRMGMT_API BOOL WINAPI
&lt;span class=&quot;token function&quot;&gt;HibernateAndReboot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; secs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_EnableShutDownPriv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	HANDLE timer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateWaitableTimer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;MyWaitableTimer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;timer &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	__int64 nanoSecs&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	LARGE_INTEGER due&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	nanoSecs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;secs &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	due&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;LowPart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DWORD&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nanoSecs &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0xFFFFFFFF&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	due&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;HighPart &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LONG&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nanoSecs &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SetWaitableTimer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;timer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;due&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetLastError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; ERROR_NOT_SUPPORTED&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

	HANDLE thread &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CreateThread&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ShutDownProc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;timer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;timer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;token function&quot;&gt;CloseHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;thread&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token function&quot;&gt;SetSystemPowerState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;FALSE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;깨우고 난 다음 무엇을 할지는 전적으로 여러분의 몫입니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[지식 근로자 관리의 어려움…]]></title><description><![CDATA[#…]]></description><link>https://jiniya.net/wp/archives/3803</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3803</guid><pubDate>Mon, 26 Sep 2011 23:57:30 GMT</pubDate><content:encoded>&lt;p&gt;#0.&lt;/p&gt;
&lt;p&gt;예전에 회사 생활을 하다가 울었던 적이 딱 한 번 있었다. 그 시절 나는 제법 열심히 일하는 프로그래머였는데, 한 날은 같은 팀원들끼리 게임을 하고 있었다. 그런데 같이 게임을 하다가 유독 나만 혼이 난 것이었다. 웃긴 것은 내가 혼날 만한 하등의 상황이 아니었다는 점이었다. 사실 혼난게 뭣같아서 울었다기 보다는 억울해서 울었다. 누가봐도 그건 아닌 상황이었기 때문이었다.&lt;/p&gt;
&lt;p&gt;그 때 느꼈다. 아 이거 x빠지게 열심히 일해봤자 하나도 소용없구나. 그 날로 그냥 쉬엄쉬엄 회사를 다녔다. 할 줄 아는 것도 남들이 못하면 못한다고 했고, 금방 할 수 있는 것도 개발팀에서 제일 못하는 사람 바로 위 정도로 일정을 맞췄다. 당연히 남들이 못잡는 버그는 나도 잡지 않았다. 그리고는 이해 관계가 끝나기가 무섭게 회사를 그만뒀다. 그런 회사에서 일하고 싶지는 않았기 때문이다. 마음이 그랬다.&lt;/p&gt;
&lt;p&gt;#1.&lt;/p&gt;
&lt;p&gt;뛰어난 개발자의 딜레마라는 이야기가 있다. 뛰어난 개발자 A와 그저 그런 B가 있을 때 아주 어려운 과제 P가 주어진 상황이다. A는 2달을 놀다가 2주만에 P를 깔끔하게 해결했고, B는 3달 동안 x빠지게 밤새고 야근하고 다녔지만 결국 해결하지 못했다. 이 때 보통 관리자는 A는 농땡이를 쳤다고 생각하고, B는 최선을 다했음에도 과제가 너무 어려웠다고 판단한다는 것이다. 결국 승진은 B가 한다는 서글픈 스토리다. 사실 내가 봐도 세상은 좀 그렇다. 특히 대기업 다니는 형들이 그런 이야기를 많이 한다.&lt;/p&gt;
&lt;p&gt;#2.&lt;/p&gt;
&lt;p&gt;우리 회사에도 뛰어난 개발자들이 많이(?!) 있다. 난 그런 개발자들이 나와 같은 감정을 회사에 느끼지 않기를 바란다. 사실 그런 감정을 느끼면 우리는 최고의 개발자가 아니라 그냥 타이핑 하는 기계 하나를 더 가진 것이나 다름 없기 때문이다. 그만큼 지식 근로자에게 감정은 중요하고, 어렵지만 공정한 보상은 중요하다. 그런데 6살 어린 아이도 똑바로 할 것 같은 이 단순한 “공정한 보상”이라는 것이 실상은 굉장히 어렵다.&lt;/p&gt;
&lt;p&gt;가장 큰 어려움은 바로 성과를 공정하게 판단한다는 그 자체가 불가능에 가까울 정도로 어려운 문제라는 점이다. 성과를 공정하게 판단하기 위해서는 과제의 난이도 x와 개인의 역량 y를 정확하게 측정하는 것이 가능해야 하는데, 이걸 측정한다는 것이 사실상 거의 불가능하기 때문이다. 과제의 난이도가 일정 수준 이상이 되면 누구도 그 문제가 얼마나 해결하기 어려운지 판단할 수 없다. 마찬가지로 개인의 역랑 y도 일정 수준을 넘어서면 그 사람이 얼마나 가능성이 있는지를 가늠하는 일 자체가 쉽지 않다. 즉, 지식 근로자의 성과를 측정한다는 자체가 애초에 넌센스라는 이야기다.&lt;/p&gt;
&lt;p&gt;물론 이러한 개념적인 어려움 외에도 이 문제를 힘들게 만드는 점이 있다. 바로 감정이다. 평가라는 것이 주관을 넘어서는 이루어질 수 없기 때문이다. 열손가락 깨물어서 안아픈 손가락이 없다고 하지만 무던 더 아픈 손가락이 있기 마련이다. 기계가 아닌 사람이 평가하면서 이러한 감정을 배제하기란 불가능에 가깝다. 이런 연유로 그렇게도 많은 직장인들이 처세에 몰두하는지도 모르겠다.&lt;/p&gt;
&lt;p&gt;끝으로 이 문제를 NP 컴플리트로 만드는 일등 공신은 다름아닌 간신들이다. 능력 없는 사람들은 보통 처세에 능하다. 그도 그럴 것이 먹고 살 방법이 그 길 밖에는 없기에 그 쪽 분야에 퍽이나 신경을 쓴다. 그러면서 열심히 일하는 사람들의 사생활부터 시작해서 아주 사소한 것들까지 들먹이면서 흠집을 낸다. 안타깝게도 아래 직원이 하고 있는 일을 정확하게 평가할 수 있는 능력의 관리자가 아니라면 이 흠집은 아주 그럴싸해 보인다. 그리고는 다음날 거위의 배는 갈라진다. 그렇게 어처구니 없는 말 한마디에 황금알을 낳는 거위가 사라지는 것이다. 애처로운 현실이다.&lt;/p&gt;
&lt;p&gt;#3.&lt;/p&gt;
&lt;p&gt;그렇다면 거위의 배를 가르지 않기 위해서는 어떻게 해야 할까? 핵심 가치에 집중해야 한다. 세상에 영구 기관은 없고 만병통치약도 없다. 사람은 누구나 장점도 있고, 몇 가지 정도는 단점도 가지고 있게 마련이다. 그 단점이라는 것이 회사에서 그 사람에게 요구해야 하는 핵심 가치가 아니라면 어느 정도는 신경쓰지 않을 필요가 있다는 것이다. 싱거워 보이는 이 사소한 일이 얼마나 어려운지는 두말하면 잔소리다.&lt;/p&gt;
&lt;p&gt;뛰어난 인력으로 넘쳐나는 대기업은 이런 고민이 필요 없을지도 모르겠다. 거기에는 아주 중요한 나사 하나쯤 빠져도 그 자리를 메워줄려고 대기하는 수많은 부품들이 있을테니깐 말이다. 하지만 작은 기업들에게는 사람이 전부다. 특히나 근속 횟수가 많고 히스토리를 아는 직원들의 가치란 상상을 초월한다. 그래서 더욱 그들을 보호해야 하고, 그들이 공정한 보상을 받을 수 있도록 해줘야 한다. 그들이 공정한 보상을 받지 못해 단순 타이핑 기계로 전락하거나 조금이라도 더 나은 보상을 받기 위해 능력 개발보다 처세에 집중할 때 회사 발전은 그날로 끝난 거나 다름 없는 셈이기 때문이다.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[광식이 동생 광태]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/4543</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4543</guid><pubDate>Thu, 25 Aug 2011 23:57:29 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;그 장면… 기억나지?? 윤경이랑 광태랑 삼겹살 집 같은데서 대화하는 장면…&lt;/p&gt;
&lt;p&gt;광태가 윤경이한테 묻잖아- “우리 형이 윤경씨 어떻게 생각하는지 알았죠?”&lt;/p&gt;
&lt;p&gt;그러면 윤경이가 그러잖아- “바보가 아닌 이상 나도 짐작은 하죠. 근데, 여자들은 짐작만으로는 움직이지 않아요.”&lt;/p&gt;
&lt;p&gt;여자들은 정말 그래- 짐작만으론 움직이지 않고, 남자의 마음을 알면서도 확인하고 싶어하거든.&lt;/p&gt;
&lt;p&gt;– 그 여자&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;영화에 공감가는 대사, 장면들이 무지 많았는데, 특히나 인상 깊었던 장면은 광태가 여자 친구한테 차이는 장면. 여자 친구가 그러자나 “너랑 나랑 추억이 있냐?” 그리곤 광태의 독백이 이어지잖아, “그녀와 난 추억이 정말 없다. 모텔, 차, 집 … 모텔, 차, 집… ” 이상하게 그 장면이 인상 깊더라공.&lt;/p&gt;
&lt;p&gt;…&lt;/p&gt;
&lt;p&gt;언젠가 49-1번을 타려고 버스 정류장으로 가던 날이었어. 하나로 카드가 바닥나서 그 앞 편의점엘 들어갔는데 갑자기 당신 얼굴이 떠올랐어. 저쪽 라면대 위에 네가 올라가 있는거 같았거든. 그래서 나도 모르게 아이스크림을 사가지고는 그 쪽으로 가서 먹었지. 그 장소, 그 시간, 그 물건엔 네 생각이 베어 있었나 봐. 추억이란 그런 거 아닐까? 한참 후에, 시간이 엄청 많이 지난 후에도, 당신에게 가끔은 내 생각이 나는 어떤 장소, 어떤 시간, 어떤 물건들이 있었으면 좋겠다.&lt;/p&gt;
&lt;p&gt;– 그 남자&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[조엘 온 소프트웨어]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/4497</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4497</guid><pubDate>Mon, 01 Aug 2011 23:57:28 GMT</pubDate><content:encoded>&lt;p&gt;음… 많은 사람들이 너무나도 마니 극찬을 했기에 나까지 칭찬할 필요가 있을까 하는 생각이 들지만… ㅎㅎㅎ~ 눈물없이 볼 수 없었던 책이었기에 칭찬을 좀 붙여볼까?? 한다.. 몇일전 강컴에서 구매한 책의 하나로 조엘 아저씨가 블로그에 기고한 글들을 묶어서 책으로 출간한 것이다. 나온지는 꽤(?!) 되었다. 나름대로 이전에 조엘씨 블로그를 조금 봤었으나 그다지 큰 감흥은 없었다. 오늘 느낀 점은 아무래도 어려운 영어 때문이 아니었나 하는 점이었다. 한글로 다시 만나보니 감동 백배였다.&lt;/p&gt;
&lt;p&gt;책을 어제 읽기 시작해서 조금 보다가 오늘 레폿하다 심심해서 마저 읽어버렸다. 음음… 그런데 단숨에 읽게하는 소설같은 마력이 있다. ㅎㅎㅎ~ 글이 워낙 재밌기도 하고 기지가 넘치다 보니 그런것 같다. 그게 아마도 이 책의 가장 큰 장점이 아닐까 하는 생각이 든다. 그의 다양한 경험에서 나오는 뛰어난 통찰력들을 종종 볼 수 있다.&lt;/p&gt;
&lt;p&gt;cvs를 써야 한다는 점. 일일빌드를 해야 한다는 점. 사용자에게 자동화된 버그 보고를 받아야 한다는 점. 모든것을 새로 개발하는 것은 좋지 않지만, 적어도 가져다 쓰되 지나친 의존성은 가지지 말아야 한다는 점등은 기존의 내가 가지고 있는 생각과 일치했다.&lt;/p&gt;
&lt;p&gt;버그 패치를 비용 관점에서 볼 수 있다는 점. 대형 벤더의 오픈 소스 지지를 미시 경제학적인 관점에서 분석해본 점. 닭이 먼저냐 달걀이 먼저냐의 문제를 호환성 측면에서 바라본 점등은 다소 신선한 아이디어로 보였다.&lt;/p&gt;
&lt;p&gt;다소 차이가 났었던 부분으로는 블로트웨어가 있었다. 그는 대부분의 사용자가 사용하는 기능이 전체 기능의 20% 밖에 되지 않는 건 맞지만 대부분의 사용자가 서로 다른 20%를 주로 사용한다는 점에서 블로트웨어를 당연하다고 피력했다. 음… 난 기존에 simply the best란 오래된 유닉스 격언 추종자로 당연히 사라져야할 악으로 생각했으나… 그의 관점이 맞을 수 있을것도 같다는 느낌이 들었다. 얼마전 워드를 쓰는 나에게 수식 편집이 불편하지 않냐고 물어본 한글 애용자 처럼 사람들이 쓰는 20%는 제각각이란 생각이든다~&lt;/p&gt;
&lt;p&gt;내가 XP를 가지고 설계를 안하는데 정당한 방패로 삼은 것에 대해서 그의 지적을 들을 수 있었던 점은 좋았다. 앞으론 설계를 열심히 해야 겠다는 생각을 가졌다. ㅋㅋㅋ 역쉬 귀가 얇은… 소심남… ^^ 그리고 msdn에 대한 의견은 정말 나와같았다. 정말 몇해전 msdn을 봐도 볼 수 있는 챕터라곤 한두개 밖에 없다. win32 q&amp;#x26;a 정도… ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;에릭 레이먼드의 TAOUP(The art of unix programming)에 대한 다소 비난적인 부분도 그리 썩 맘에 들지 만은 않았다. 그런데 사실 레이먼드 아저씨가 완전 유닉스맨인건 사실이다. 하지만 그의 책을 읽으면서 느낀건 조엘씨도 완전 윈도우맨이란 사실이다. 서로 피장파장 정도였다. 그러나 그가 TAOUP의 전부를 무시 하지 않은 점은 정말 다행이었다. ㅋㅋㅋ~ TAOUP도 눈물 흘리며 읽었기에… ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;음~ 읽다가 생각난건 나도 미시 경제학을 한번 들어봐야 겠다는 점이었다… 그리고 또 하나는 우리학교가 일학년들에게 C에서 VB를 가르치기로 바꾼건 좀 실수가 아니었나 하는 생각… 조엘씨가 마이크로소프트에 굉장히 우호적인 감정을 가지고 있으며, 그가 MS에서 한일에 대해서 프라이드를 마니 가지고 있다는 점… @.@&lt;/p&gt;
&lt;p&gt;그리고 챕터가 끝으로 갈수록 묘해지는 그의 리치 클라이언트에 대한 생각들은 지금 현재 그러한 것들을 개발하는 나로써는 다소 받아들이기 힘들었다. 웹이 대세란 말인가? ㅎㅎ~&lt;/p&gt;
&lt;p&gt;꽤나 다양한 생각을 할 수 있게 해준 좋은 책이었던거 같다. 올만에 진국을 만난듯한 느낌??? ㅎㅎㅎ~ 오랜만에 독서를 한거겠지. ㅋㅋ 개발과 관련된 분야에 있다면 꼭 일독하기를 권하고 싶다. 특히나 관리자라면… 더더욱~ ^^&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[비스타 테마 리스트 컨트롤 만들기]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/4479</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4479</guid><pubDate>Sun, 31 Jul 2011 23:57:27 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./비스타_테마_리스트_컨트롤_만들기.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/756500c45a45efb88c866ee78ed69aeb/dface/%EB%B9%84%EC%8A%A4%ED%83%80_%ED%85%8C%EB%A7%88_%EB%A6%AC%EC%8A%A4%ED%8A%B8_%EC%BB%A8%ED%8A%B8%EB%A1%A4_%EB%A7%8C%EB%93%A4%EA%B8%B0.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 67.89473684210526%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAAsTAAALEwEAmpwYAAADKklEQVR42lWT6VPbVhTF9Xf3Uz/3S0rbEAJt2qRDm5BQhmBinMYmGDBgYzYveNNmW4steZVjW1749UmknemdOSPp3XfPPefdJ2kr2SCW0YhdGkQyNhsxjbVYnWdRjSc7JZ7t13hz1mM73efNqcvzA531mM7mcZu9yy6f831S+RbXZ3l2tv9G+ubXGGvv4zx5G+eX6BmrOwk29o5Z2U3y/c4hP0WOeZG44mXyVuCG1dgF321/YiWS5MdoiqexFGufzvk5ecXKQRpp6/CCzXiG10dZIhc5dlPXrEcSPBWb18X6RiLL2seUaPiBjYMjNpNpnu/H+f3onD9PM/yWOOHVUYq3ZxlW9+JIY3/BYzx8fS7wejUG/R7/hj8Z45hNXNtkMhph6Br9bvex6uEhRBCp6wKS3PLwZ3OBWficzaeYjVtct8NisWA+nzMYDJBlhZpAq+1QKpVoGhaL5QNTfxZiuVwST98g9b0xs5kfFs7nC6bTiSC8w7SscFPQ3fM8VFVFEeh2OlQqFSzLDlUFdTMhJoh3H5NI5aZJ07RE4rHLZDKibeVwHCckW/6PUKErrFYrZexW6z/CAEG8/pAQlg2NarUa2gqi7bgcHl+jKqpQYQnrLq4g174qDL5luUZF1ATHFDQNmoyGA/aPM0iqXAjtBV2W4syG3ojLq2J4To1Gk16vL9BD0zRUgY6wXK/r3Iu8bdvhMAM3vW6Hg1QWyTQN0a0slDkh6dT3Me0WSi2YdD9U/UVY1jUVXUw3KNR1lftiAVWWBd9SOGiLqXeInl4iTb/Y1Kp5jKYl5C8Zj8fkikXKsk5/7DMWt8rpe5RqgkTWMJyOeFfI5goooibIN+w2bXEroifC8mLmUinf0WjaobrA8l2pwm2xSqvnMfSX2N0B+YpCrqqgGC2KgjhXkTE7wzCv2Q5m22X38znSX3/8gGqKTYpOXXS3+kNKdYNyw0B3u9ijMb3FA63xnKY3Qxv4yD2fcsen6PjcWhPSdY+sMWEtKn69Fy9XyTcdCgL3Vpdco01WbnKpGiFuxPqt4XKhWqR1h5OaTeSqyvtsje2LCltn5RDv0grfvoryD0B47Yl6qWKPAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                   md 0&apos; title=&apos;&apos; src=&apos;/static/756500c45a45efb88c866ee78ed69aeb/dface/%EB%B9%84%EC%8A%A4%ED%83%80_%ED%85%8C%EB%A7%88_%EB%A6%AC%EC%8A%A4%ED%8A%B8_%EC%BB%A8%ED%8A%B8%EB%A1%A4_%EB%A7%8C%EB%93%A4%EA%B8%B0.md_0.png&apos; srcset=&apos;/static/756500c45a45efb88c866ee78ed69aeb/08678/%EB%B9%84%EC%8A%A4%ED%83%80_%ED%85%8C%EB%A7%88_%EB%A6%AC%EC%8A%A4%ED%8A%B8_%EC%BB%A8%ED%8A%B8%EB%A1%A4_%EB%A7%8C%EB%93%A4%EA%B8%B0.md_0.png 190w,
/static/756500c45a45efb88c866ee78ed69aeb/2edd7/%EB%B9%84%EC%8A%A4%ED%83%80_%ED%85%8C%EB%A7%88_%EB%A6%AC%EC%8A%A4%ED%8A%B8_%EC%BB%A8%ED%8A%B8%EB%A1%A4_%EB%A7%8C%EB%93%A4%EA%B8%B0.md_0.png 380w,
/static/756500c45a45efb88c866ee78ed69aeb/dface/%EB%B9%84%EC%8A%A4%ED%83%80_%ED%85%8C%EB%A7%88_%EB%A6%AC%EC%8A%A4%ED%8A%B8_%EC%BB%A8%ED%8A%B8%EB%A1%A4_%EB%A7%8C%EB%93%A4%EA%B8%B0.md_0.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;비스타에서 리스트 뷰는 상당히 고급 스런 디자인을 하고 있습니다. 특히나 선택 영역은 과거의 그것과는 비교가 불가할만큼 고급스럽죠. ㅎ 저런데서 그냥 푸른색 칠해진 리스트 뷰를 보면 정말 싼티나 보입니다. 대부분의 개발자가 저도 그랬고, 리스트 뷰가 비스타에 가면 그냥 자연스럽게 저렇게 그려질거라 생각합니다. 커먼 컨트롤이 업그레이드 되면서 그렇게 됐겠지 하는 생각을 하죠. 그런데 천만에 말씀, 만만에 콩떡입니다. 매니페스트를 적용한 프로그램의 리스트도 저렇게 고급스럽게 그려지지 않죠. 그렇다면 도대체 이 마법 같이 아름다운 리스트 컨트롤은 어떻게 해야 만들 수 있는 걸까요?&lt;/p&gt;
&lt;p&gt;물론 그렇게 어렵지는 않습니다. ㅋㅋ~ 바로 마법 같은 함수가 있기 때문이죠. &lt;strong&gt;SetWindowTheme&lt;/strong&gt;라는 함순데요. 여러분이 사용하는 리스트 컨트롤에 대고, &lt;strong&gt;SetWindowTheme(리스트 컨트롤 핸들, _T(“explorer”), NULL);&lt;/strong&gt; 하는 순간 싼티나던 리스트 컨트롤이 탐색기의 그것과 똑같아지는 기적을 경험하게 될겁니다. 안된다구요? 네. 아마 커스텀 드로나 오너 드로를 사용하고 계신가 보군요. 그렇다면 좀 더 복잡하지만 &lt;strong&gt;DrawThemeBackground&lt;/strong&gt;라는 함수를 사용하셔서 배경을 그리면 되겠습니다. 참고로 이 두 함수를 사용하기 위해서는 uxtheme.h 파일과 uxtheme.lib 파일이 필요합니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[DLL_PROCESS_DETACH의 비밀]]></title><description><![CDATA[예전 글에서 DllMain이 얼마나 위험한 곳인지, 로더락이란 것이 얼마나 무서운 놈인지에 대해서 소개했었습니다. 그 때 주로 로더락 관점에서 DllMain에서 하지 말아야 할 것들을 소개 했는데요. 이 로더락을 배제하고도 DLL_PROCESS…]]></description><link>https://jiniya.net/wp/archives/4457</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4457</guid><pubDate>Sun, 31 Jul 2011 23:57:26 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/tt/788&quot;&gt;예전 글에서 DllMain이 얼마나 위험한 곳인지, 로더락이란 것이 얼마나 무서운 놈인지에 대해서 소개했었습니다.&lt;/a&gt; 그 때 주로 로더락 관점에서 DllMain에서 하지 말아야 할 것들을 소개 했는데요. 이 로더락을 배제하고도 DLL_PROCESS_DETACH가 호출되는 시점에는 주의해야 할 것이 있습니다. 바로 이 놈이 호출되는 시점입니다. 보통 여러분이 알고 있는 것처럼 DLL_PROCESS_DETACH로 DllMain이 호출되는 시점은 DLL이 프로세스로부터 떨어져 나가는 시점. 즉, FreeLibrary가 호출되서 해당 DLL의 레퍼런스 카운트가 0이 되는 시점에 호출됩니다. 하지만 이 경우 외에도 다른 한 가지 경우가 더 있습니다. 바로 프로세스가 종료되는 시점에도 호출되죠.&lt;/p&gt;
&lt;p&gt;이런 특성 때문에 DLL_PROCESS_DETACH에 대해서 가지는 흔한 오해가 있는데요. 바로 TerminateProcess에 의해서 종료될 때에도 DLL_PROCESS_DETACH가 실행된다는 것과, DLL_PROCESS_DETACH에서 종료 작업을 하는 것이 좋다라는 생각입니다. 물론 이 두 가지 생각 모두 제대로 잘못된 생각들입니다.&lt;/p&gt;
&lt;p&gt;우선 프로세스의 종료를 만들어내는 두 가지 API, ExitProcess와 TerminateProcess의 구현을 살펴보면 아래와 같이 되어 있습니다. 보이는 것처럼 둘 다 NtTerminateProcess를 사용합니다. 둘의 차이라면 ExitProcess는 이 NtTerminateProcess 이후에 shutdown process라는 작업을 진행하는 것이라고 보면 되겠습니다. 이 shutdown process의 진행 과정의 일환으로 호출되는 것이 DLL_PROCESS_DETACH입니다. 따라서 TerminateProcess로 프로세스가 종료될 때에는 이 shutdown process라는 것이 존재하지 않기 때문에 당연히 DLL_PROCESS_DETACH의 호출 또한 받을 수 없습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;ExitProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;NtTerminateProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ExitCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// shutdown process&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;NtTerminateProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetCurrentProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ExitCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;TerminateProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;NtTerminateProcess&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Process&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ExitCode&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;우리가 ExitProcess의 구현에서 눈치채야할 다른 중요한 시사점은 바로 NtTerminateProcess를 호출한 다음 shutdown process를 진행한다는 점입니다. 여기에는 굉장히 중요한 점이 내포되어 있는데요. 바로 여러분의 DLL_PROCESS_DETACH가 호출되는 시점에는 그 어떠한 스레드도 살아 있지 않다는 점입니다. NtTerminateProcess(NULL, ExitCode)를 거치는 순간 해당 프로세스의 모든 스레드는 강제로 터미네이트(Terminate)되기 때문입니다.&lt;/p&gt;
&lt;p&gt;요약하면 이렇습니다. &lt;strong&gt;DLL_PROCESS_DETACH가 호출되는 시점에는 스레드가 다 죽고 없는 시점이다. 따라서 DLL_PROCESS_DETACH에서 복잡한 클린업 작업을 하는 것은 **짓이나 다름 없다.&lt;/strong&gt; 여기서 복잡하다는 것은 적어도 스레드를 하나 이상 생성해서 종료 작업에 해당 스레드가 필요한 녀석으로 이해하면 되겠습니다. 물론 이런 작업 외에 간단한 작업도 하지 않는 것이 정신 건강에는 무척 유익합니다.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[리소스 풀어 헤치기]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/4366</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4366</guid><pubDate>Sun, 31 Jul 2011 23:57:25 GMT</pubDate><content:encoded>&lt;p&gt;디버그뷰나 프로세스 익스플로러같은 프로그램을 보면 실행 파일 하나로 구성되어 있는데 프로그램을 실행하면 드라이버를 로딩하는 것을 볼 수 있습니다. 어떻게 하는 걸까요? 답은 간단한데요. 해당 드라이버 파일을 리소스에 포함시켜 놓고 런타임에 풀어서 사용하는 방식입니다. 리소스에 추가하는 방법은 간단합니다. Visual Studio 리소스 뷰에서 오른쪽 클릭하시고 임포트 하시면 됩니다. sys 파일 같은건 안보이시죠. *.*로 필터링한다음 추가하시면 됩니다. 그러면 어떤 타입을 추가할지 물어볼텐데요. 아무렇게나 이름을 지어 주시면 됩니다. Binary 이런 식으로요. 자 그렇다면 이제 이렇게 추가된 리소스 파일을 런타임에 어떻게 조작하는지를 알아보도록 합시다.&lt;/p&gt;
&lt;p&gt;조작하는 API는 소 심플합니다. FindResource, LoadResource, SizeOfResource, LockResource라는 API가 사용됩니다. 각각의 함수 사용 방법을 알아보도록 합시다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HRSRC &lt;span class=&quot;token function&quot;&gt;FindResource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HMODULE hModule&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCTSTR lpName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCTSTR lpType&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;FindResource 함수입니다. 이 함수는 우리가 분리해 내려고 하는 리소스를 찾는데 사용됩니다. hModule에는 리소스를 찾을 DLL의 모듈 핸들을 넣어주면 됩니다. NULL을 전달하면 현재 프로세스의 실행 파일 모듈에서 찾습니다. lpName에는 리소스 이름을 전달합니다. MAKEINTRESOURCE를 사용해서 리소스 ID를 문자열로 변환한 것을 대입해 주면 됩니다. 리소스 ID가 IDR_BINARY1이라면 MAKEINTRESOURCE(IDR_BINARY1)을 전달하면 되겠죠. lpType에는 리소스 타입을 넣어줍니다. 리소스 타입이 Binary라면 “Binary”를 전달하면 됩니다. 이렇게 넣어주면 리소스를 찾아서 해당 리소스의 핸들을 넘겨줍니다. 실패하면 NULL이 리턴되겠죠.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;DWORD &lt;span class=&quot;token function&quot;&gt;SizeofResource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HMODULE hModule&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HRSRC hResInfo&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;러소스의 크기를 구할 때 사용하는 함수입니다. hModule에는 모듈 핸들을 hResInfo에는 FindResource를 통해서 찾은 리소스 핸들을 넣어줍니다. 성공한 경우에는 리소스 크기를, 실패한 경우에는 0을 리턴합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;HGLOBAL &lt;span class=&quot;token function&quot;&gt;LoadResource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HMODULE hModule&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; HRSRC hResInfo&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;리소스를 로드하는 함수입니다. hModule에는 모듈 핸들을 hResInfo에는 FindResource로 찾은 리소스 핸들을 전달하면 되겠습니다. 해당 리소스의 포인터가 리턴됩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;LPVOID &lt;span class=&quot;token function&quot;&gt;LockResource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HGLOBAL hResData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;마지막 함수입니다. LoadResource 한 메모리의 실제 포인터를 반환합니다. hResData에는 LoadResource에서 반환한 포인터를 넣어줍니다. 그럼 실제 포인터가 리턴됩니다.&lt;/p&gt;
&lt;p&gt;종합해서 함수 하나로 만들어 봅시다. GetResourceInfo라는 함수입니다. module에서 type, name의 리소스를 찾아서 해당 리소스의 포인터를 data에 크기를 rsize에 있는지 없는지를 리턴 값으로 리턴해 주는 함수입니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;BOOL WINAPI &lt;span class=&quot;token function&quot;&gt;GetResourceInfo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HMODULE &lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt;
                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCTSTR type
                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPCTSTR name
                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PVOID &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;data
                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SIZE_T &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rsize&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    DWORD size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    HGLOBAL mem&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    PVOID ptr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    HRSRC src&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;FindResourceW&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;src&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    size &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;SizeofResource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; src&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;size&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    mem &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;LoadResource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; src&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;mem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    ptr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;LockResource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mem&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;ptr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    __try
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ptr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rsize&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;rsize &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;__except&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;EXCEPTION_EXECUTE_HANDLER&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; TRUE&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;여기까지만 설명하고 마칠까 하는데 아마 똑똑한 분들이라면 먼가 찜찜한 기분이 드실 거예요. 화장실가서 볼 일 보고 뭔가 정리하지 않고 나온 느낌이겠죠. 실컷 로딩하고 락하고 했는데 그것들을 해제하는 작업에 대해서는 하나도 설명하지 않았으니 말입니다. UnlockResource, FreeResource와 같은 함수들이 있긴 한데, 그것들은 사용하지 않아도 됩니다. 왜냐하면 여기서 사용하는 리소스 핸들을 구하고 하는 함수들은 로드된 모듈에서 포인터를 참조해 오는 일이거든요. 여러분이 획득한 모든 포인터 내지는 리소스는 hModule이 FreeLibrary 되는 시점에 같이 사라집니다. 따라서 별도로 해제할 필요가 없는 셈이죠. 참고로 그래도 나는 해제하겠다고 UnlockResource, FreeResource를 호출한들 실제 해당 함수에서 하는 일은 return 밖에는 없답니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Visual Studio로 드라이버 개발하기]]></title><description><![CDATA[빌 조이는 vi로 vi를 개발하고, 리차드 스톨만 아저씨는 emacs를 emacs…]]></description><link>https://jiniya.net/wp/archives/4195</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4195</guid><pubDate>Sun, 31 Jul 2011 23:57:24 GMT</pubDate><content:encoded>&lt;p&gt;빌 조이는 vi로 vi를 개발하고, 리차드 스톨만 아저씨는 emacs를 emacs로 개발한다는 전설같은 무용담들이 있지만, 우리같은 쪼렙 개발자들에게는 에디터보다는 편리한 툴들이 필요합니다. 전 그간 드라이버를 개발할 때에는 소스 인사이트라는 프로그램을 사용했는데, 혼자 개발할 때에는 그럭 저럭 편했는데 여러 명이 개발하게 되니깐 좀 불편하더군요. 그래서 여차저차해서 Visual Studio로 개발 환경을 모두 통합하게 되었습니다. 물론 이제는 &lt;a href=&quot;http://zpacket.blogspot.com/2011/06/visual-studio.html&quot;&gt;Visual Studio에 드라이버 개발 프로젝트&lt;/a&gt;가 빌트인된 시대지만 아직까지 구시대적인 개발 방법도 필요한지라 정리해놓습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;제일 먼저 필요한 도구는 ddkbuild입니다. ddkbuild.bat 파일만 있으면 끝입니다. 해당 파일을 Visual Studio 프로젝트 파일이 있는 폴더에 같이 복사해 둡니다. 깔았냐, 머 설치해라 이런말 안해도 되서 여러모로 편합니다. 근데 ddkbuild를 어디서 다운 받냐구요? &lt;a href=&quot;http://www.hollistech.com/Resources/ddkbuild/ddkbuild.htm&quot;&gt;여기서&lt;/a&gt; 받으시면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ddkbuild 설명서를 보면서 sources 파일을 수정하면 한 군데서 막힐 텐데요. 브라우저 정보를 생성하는 부분이죠. 아래와 같이 브라우저 정보를 생성하도록 source 파일을 수정하면 오류가 발생할 겁니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;sources&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;BROWSER_INFO=1&lt;/p&gt;
&lt;p&gt;BSCMAKE_FLAGS=$(BSCMAKE_FLAGS) -n&lt;/p&gt;
&lt;p&gt;BROWSERFILE=$(TARGETNAME).bsc&lt;/p&gt;
&lt;p&gt;오류가 생기는 원인은 ddk 때문에 그런 건데요. ddk 설치 폴더를 간 다음 verify.src 파일의 아래 줄들을 주석 처리해 주시면 해당 오류가 발생하지 않도록 만들 수 있습니다. 브라우저 정보는 왜 생성하냐구요? 여러분이 F12를 눌렀을 때 정의된 곳으로 이동시켜 주기 위해서 생성한답니다. 그 기능을 사용하고 싶으시다면 이 작업을 하시고, 필요 없다면 안하셔도 됩니다. 하지만 하시는게 좋을 거예요.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C:\WinDDK\7600.16385.1\bin\verify.src&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;#!if defined(BROWSER_INFO) &amp;#x26;&amp;#x26; !defined(USER_ENV_BROWSER_INFO)&lt;/p&gt;
&lt;p&gt;#!error BLD1007 : BROWSER_INFO defined in sources file – this is a user environment setting ($(MAKEDIR))&lt;/p&gt;
&lt;p&gt;#!endif&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;요즘은 64비트를 지원하는게 필수기 때문에 대부분 한 드라이버 프로젝트에서 32, 64 빌드가 모두 나옵니다. 그런데 이 때 32, 64 구성 파일이 모두 동일하다면 상관 없는데 아마도, 종종, 제법 심하게 자주 구성 파일 한 두개가 서로 다른 시츄에이션이 발생할 겁니다. 현란한 전처리기를 사용해서 그것들을 처리하는 것도 한 방법이긴 하지만 별로 추천해 드리고 싶지는 않군요. 제가 추천해 드리고 싶은 방법은 속편하게 sources 파일을 두 개 만들라는 겁니다. sources_x86, source_x64 이렇게 두 개를 만들어 두세요.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이제 빌드 배치 파일을 만들어 봅시다. 이 배치 파일들이 하는 일은 32, 64 빌드에 따른 sources 파일 교체 및 인증서 서명, 그리고 최종적으로 빌드된 파일을 Dist 폴더로 복사해주는 역할을 합니다. 이 마법같은 배치 파일은 다음과 같이 작성하면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;build_x64_release.bat&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;set name=%1&lt;/p&gt;
&lt;p&gt;copy sources_x64 sources&lt;/p&gt;
&lt;p&gt;call ddkbuild.bat -WIN7A64 -oacr free .  -cZg&lt;/p&gt;
&lt;p&gt;call sign.bat objfre_win7_amd64\amd64%name%64.sys&lt;/p&gt;
&lt;p&gt;mkdir Dist&lt;/p&gt;
&lt;p&gt;copy objfre_win7_amd64\amd64%name%64.sys Dist&lt;/p&gt;
&lt;p&gt;copy objfre_win7_amd64\amd64%name%64.pdb Dist&lt;/p&gt;
&lt;p&gt;del sources&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;build_x86_release.bat&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;set name=%1&lt;/p&gt;
&lt;p&gt;copy sources_x86 sources&lt;/p&gt;
&lt;p&gt;call ddkbuild.bat -WIN7 -oacr free .  -cZg&lt;/p&gt;
&lt;p&gt;call sign.bat objfre_win7_\i386%name%32.sys&lt;/p&gt;
&lt;p&gt;mkdir Dist&lt;/p&gt;
&lt;p&gt;copy objfre_win7_x86\i386%name%32.sys Dist&lt;/p&gt;
&lt;p&gt;copy objfre_win7_x86\i386%name%32.pdb Dist&lt;/p&gt;
&lt;p&gt;del sources&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;sign.bat&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;signtool sign /a /v /ac MSCV-VSClass3.cer /s my /n “인증서이름” /t “&lt;a href=&quot;http://timestamp.verisign.com/scripts/timestamp.dll%E2%80%9D&quot;&gt;http://timestamp.verisign.com/scripts/timestamp.dll”&lt;/a&gt; %1&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#4.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;다시 정리하면 이렇습니다. 드라이버 프로젝트 폴더에는 ddkbuild.bat, sources_x86, sources_x64, build_x64_release.bat, build_x86_release.bat, sign.bat 파일이 있는 겁니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#5.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;이제 Visual Studio에서는 make 프로젝트로 프로젝트를 생성하시고 프로젝트 빌드 커맨드로는 build_x86_release.bat 드라이버명, build_x64_release.bat 드라이버명 이렇게 만드시면 됩니다.&lt;/p&gt;
&lt;p&gt; 4
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[[소고] 끝나지 않은 전쟁: 논클라이언트 봇]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/4372</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4372</guid><pubDate>Sun, 31 Jul 2011 23:57:23 GMT</pubDate><content:encoded>&lt;h3&gt;요약&lt;/h3&gt;
&lt;p&gt;영겁의 세월을 두고 진화하는 우주처럼 보안에서의 창과 방패의 싸움도 영원히 이어질 수 밖에 없는 구조로 되어 있다. 여기서는 그런 이슈 중에 하나인 논클라이언트 봇과의 전쟁에 대해서 살펴본다. 논클라이언트 봇의 정의 및 구조적 특징과 함께 그간 논클라이언트 봇에 대응하기 위해서 논의되었던 전략들에 대해서 알아보도록 하자.&lt;/p&gt;
&lt;h3&gt;필자 메모&lt;/h3&gt;
&lt;p&gt;“보안 프로그래밍”이라는 주제로 글을 부탁 받고는 어떤 내용을 담을지를 한참 고민했다. 정수 연산의 위험성 이라든지, 포맷 스트링 버그 라든지, 버퍼 오버플로우와 같은 보안 프로그래밍을 생각했을 때 누구나 떠올리는 다소 식상한 내용은 담고 싶지 않았다. 달리 생각하면 PC 클라이언트 보안을 하는 업체에서 10년 가까운 세월을 일했지만 감히 “보안”이라는 주제로 글을 쓰기가 두려웠는지도 모르겠다. “보안”이라는 것은 너무도 넓고 너무도 방대한 내용들을 포함하고 있기 때문이다.&lt;/p&gt;
&lt;p&gt;식상한 주제는 피하고 싶고, 모르는 것에 대해서 글을 쓰는 것만큼 멍청한 일도 없으니 결국은 내가 그간 했던 고민 중에서 한 꼭지를 끄집어 내 보기로 결정했다. 여기서 설명할 논클라이언트 봇은 과거에도 심각한 문제였고, 현재에도 계속 문제가 되고 있다. 그럼에도 글을 쓰고 있는 지금 이 시점에도 완벽한 대응 전략은 부재중인 상태다. 이 글을 읽고 여러분이 다소 자극을 받아서 혁신적인 새로운 대응 방법을 생각해 낸다면 그 또한 엄청나게 의미 있는 일이 아닐까라는 생각을 하면서 글을 시작해 보려고 한다.&lt;/p&gt;
&lt;p&gt;혹시 앞서 언급했던 일반적인 “보안 프로그래밍”이라는 주제에 대해서 공부하고 싶은 독자라면 이 세 권의 책을 꼭 일독하기를 권한다. Writing Secure Code 2/e, 윈도우 비스타 보안 프로그래밍, Secure Coding in C and C++이 그 세 권의 책이다. 그 어떤 책보다도 여러분에게 일반적인 보안 프로그래밍의 관점에 대해서는 가장 많은 영감을 줄 수 있는 책이라고 감히 자부한다.&lt;/p&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;p&gt;이 문제는 여러분이 잘 알고 있는 튜링 테스트와 유사하다. 여러분의 여자친구 내지는 남자친구를 생각해 보자. 없다면 부모님을 생각해도 되겠다. 벽이 하나 있고, 반대편에 여러분의 사랑스런 그 사람이 앉아 있는 것이다. 여러분은 상대에게 질문을 할 수 있고, 상대는 여러분에게 대답을 할 수 있다. 이 질문과 답변 과정은 대리인을 통해서 이루어지며 그 사람은 벽 반대편 사람이 여러분이 알고 있는 사람인 것처럼 보이게 하기 위해서 질문과 답변 내용을 조작할 수 있다. 과연 이런 상황에서 여러분은 벽 반대편에 있는 상대가 여러분이 알고 있는 그 사람인지 아닌지를 구분할 수 있을까라는 것이 문제다. 물론 질문은 여러분이 확신이 들 때까지 계속 할 수 있다.&lt;/p&gt;
&lt;p&gt;이러한 이야기를 하면 대다수 사람들은 제일 먼저 하고 싶은 질문으로 상대와 나만 알고 있는 은밀한 내용을 꼽는다. 처음 데이트 했던 장소 라던지, 상대의 신체적 특징, 기호 등을 묻는 것이다. 하지만 이는 벽 반대편에 어떤 엉뚱한 존재가 우리의 사랑스런 사람을 인질로 잡고 있다면 전혀 의미가 없다. 협박을 해서 답을 얻어낼 수도 있기 때문이다. 이런 극단적인 상황까지 고려한다면 우리는 이 문제를 풀기 위해서 상대에게 어떤 질문을 던져야 할까? 또 과연 그러한 질문을 통해서 벽 반대편에 있는 보이지 않는 대상의 정체를 판별할 수 있을까?&lt;/p&gt;
&lt;p&gt;가볍게 설명한 이 문제가 오랫동안 보안 업계에서 이슈가 되고 있는 원격 클라이언트의 인증 문제다. 인증이라는 말만 듣고 반사적으로 아이디와 비밀번호를 생각했다면 번지수를 잘못 짚었다. 여기서는 원격 사용자에 대한 인증이 아니라 원격에서 실행되고 있는 클라이언트 프로그램 그 자체에 대한 인증이기 때문이다. 그렇다면 원격 사용자도 아닌 원격지 클라이언트의 인증이 왜 그토록 중요할까?&lt;/p&gt;
&lt;p&gt;이 문제가 주요 이슈로 부각된 분야는 다름아닌 게임이다. 게임의 경우에는 게임 플레이를 사람이 할 수도 있지만 기계가 할 수도 있기 때문이다. 생각해 보자. 여러분이 온라인으로 철수와 바둑을 두고 있는데 사실은 알고 봤더니 철수가 둔 것이 아니라 철수 컴퓨터가 뒀다면 어떨까? 물론 여러분은 졌다고 가정했을 때 말이다. 별 느낌이 들지 않는다면 다른 사례를 생각해보자. 요즘 유행하는 MMORPG 게임은 해당 가상 세계 속에서의 행위를 통해서 캐릭터를 육성하는 방식으로 진행되는 게임이다. 이러한 캐릭터 육성 과정에는 필연적으로 시간과 노력이 들어간다. 그런데 여러분은 그런 것들을 실제 여러분의 시간과 노력을 투입해서 얻은 반면에 철수는 철수 컴퓨터가 대신 게임을 해서 그런 것들을 자동으로 얻었다고 한다면 어떤 느낌이 들까?&lt;/p&gt;
&lt;p&gt;물론 두 가지 사례 모두 여러분이 게임을 하지 않는다면 단지 기분 나쁜 사건 정도로 생각할 수 있는 문제다. 자본주의 세상답게 진짜 문제는 머니(money)가 개입했을 때 발생한다. MMORPG같은 온라인 게임의 경우에는 해당 가상 세계에서 통용되는 화폐가 실제 화폐와 교환 가지를 가진다. 즉, 가상 세계의 1골드가 실제 세계에서 100원에 팔릴 수 있다는 말이다. 실제로 소위 유명한 게임들의 경우에는 이를 환율과 같은 시세로 표기하는 사례도 있다. 이러한 가상 세계에서 골드를 획득하는 방법은 보통의 경우 사냥을 통해서인데, 이는 상당히 단순한 반복 작업을 필요로 한다. 이러한 반복 작업을 기계가 대신하고 그것을 운영한 사람이 부가적인 수익을 얻는다면 그것은 과연 공정한 일일까? 더욱이 이런 기계 때문에 가상 세계 속에서 사람이 획득할 수 있는 리소스가 줄어든다면 말이다.&lt;/p&gt;
&lt;p&gt;여기에는 두 가지 중요한 이슈가 내포되어 있는데 하나는 이러한 부정 게임 방식이 게임 운영에 나쁜 영향을 미친다는 점이다. 생각해 보자. 누구나 부정 행위를 통해서 게임을 한다면 과연 그 게임을 누가 멍청하게 자신의 힘으로 하려고 하겠는가? 아마 아무도 하지 않고 전부 기계들만 게임을 하다가 결국 그 게임은 아무도 하지 않는 게임이 되고 말 것이다. 다른 한 가지는 이런 프로그램들이 아이템 거래 시장을 왜곡 시킨다는 점이다. 아이템 거래 시장이란 앞서 말했던 게임 머니를 실제 머니와 교환하는 시장을 말한다. 일반적인 경우라면 그 시장을 통해서 통용될 수 있는 게임 리소스는 제한적일 수 밖에 없다. 하지만 봇 프로그램의 등장으로 그 속에서 획득할 수 있는 게임 리소스가 폭발적으로 증가했고, 그것들은 별 노력 없이 획득한 것이기 때문에 아이템 거래 시장에서 낮은 가격에 팔릴 수 있다. 이는 결과적으로 정직하게 노력해서 해당 리소스를 획득한 사용자들에게는 자신이 획득한 리소스에 대한 가치를 불법적으로 하락 시키는 행위가 되는 셈이고 결국 시장은 공정하지 않은 상태가 되고 만다.&lt;/p&gt;
&lt;p&gt;앞서 언급한 여러 가지 이유로 부정 클라이언트 프로그램이 자동으로 게임을 하는 행위는 좁게는 게임 업체에게 그리고 넓게는 게임 사용자들에게 다시 피해가 가기도 하는 것이다. 따라서 이런 부정 클라이언트 프로그램을 막는 것은 게임 업체에게는 굉장히 중요한 당면 과제라고 할 수 있다.&lt;/p&gt;
&lt;h3&gt;논클라이언트 봇&lt;/h3&gt;
&lt;p&gt;게임 업계에서는 앞서 설명한 것과 같이 벽 반대 편에 앉아서 마치 우리가 알고 있는 사람인척 하는 나쁜 프로그램을 두고 논클라이언트 봇(Non-client Bot)이라고 부른다. 좀더 엄밀히 말하자면 논클라이언트 봇이란 게임 프로토콜을 모방해 게임 클라이언트가 아닌 별도의 클라이언트가 게임 서버에 접속해서 플레이어와 같은 행위를 하는 것을 말한다. 즉, 논클라이언트라는 말은 클라이언트가 없다는 것을 봇이라는 말은 자동으로 게임 플레이를 한다는 것을 의미한다.&lt;/p&gt;
&lt;p&gt;이렇게 복잡하게 프로토콜을 모방해서 논클라이언트 봇을 제작하는 이유는 게임 클라이언트에서 로딩하는 복잡한 그래픽 리소스 등이 필요하지 않아서 한 PC에서도 여러 개의 논클라이언트 봇 프로그램을 띄워서 동시 작업을 원활하게 할 수 있기 때문이다. 동시 실행이 원활하다는 말은 달리 표현하면 단위 시간당 더 많은 게임 리소스를 획득할 수 있음을 의미한다. 이러한 이유로 논클라이언트 봇은 주로 작업장이라고 불리는 곳에서 은밀하게 제작되기 때문에 실제로 구동이 되는 프로그램을 구하기는 쉽지 않다.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;그림 1&gt;에는 정상적인 게임 클라이언트와 서버의 통신 구조가 나와 있다. C는 게임 클라이언트를 S는 게임 서버를 의미한다. 이 그림이 나타내는 의미는 서버가 Q라는 패킷을 전달하면 클라이언트가 R이라는 응답을 하는 구조로 통신이 이루어진다는 것이다. &amp;#x3C;그림 2&gt;에는 이 구조를 도용한 논클라이언트 프로그램의 구조가 나와있다. 클라이언트는 변조되거나 새롭게 만든 NC이지만 통신 구조를 그대로 모방했기 때문에 게임 서버 입장에서는 이 클라이언트가 정상적인 게임 클라이언트 프로그램인지 아닌지를 판별할 방법이 없다. 논클라이언트 봇을 구현하는 핵심 기술은 이러한 게임 서버와 클라이언트의 통신 구조를 도용하는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./끝나지_않은_전쟁_논클라이언트_봇.md_0.png&apos; data-alt=&apos;그림 1 정상 클라이언트 통신 구조&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 217px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/2ca9046713f0ac1495769e0079a748bf/58178/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 101.05263157894737%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABwklEQVR42mP4//9/3YsXL47u3r17B5B99M+fP+EMQABkMzMQAYDqEo4dO9Z05cqVZiA7AiSw9tevX/8vXrz4E8j+DzSwHKqQhYBBjFD6yPnz5/9fu3YNpH0bSEDr3bt3PjNnzswDsp2BWA5ZAxEu1FmzZk3yxo0bE4BsDZg4NxA7MJAOYJZqAbE6XNTFxYUfCJyANjCBMLqu+vp6plWrVsHClAmKGWEGiouLa4Mwsh5cLmRE0owPWAOxBrIAF5KBTOhe2rNnjzQwFehCxUSBWAqIVYDYEIhVgdgD3UB0F4K8xyQpKSkCpAW6uromA8F9qLeU2dnZFYG0IFQdCGijhCEQsAJxAhAbQW3XBGI9Pj4+kCuElixZ4g90YStS+DKi0broLgRJNEENNQdiJWgwsGIJLyaYD5AM1MHmZXuoIl4glgQpYmVl1QfScsHBweUtLS37pkyZwgPks2BJNjrYIsUZ3SmwpAKMlLKlS5euADJloJYYQH0hDsQc0KBSxxcp+JILyIXsQCwBjWGQ4b3QWGcgJacwoiUpZC8bEHIhsdmOBVeyoTQv6xBK2BQbCIplO6qVNrRwISgZ6FFgoDwojYJYAOzHnoVNYriDAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그림 1 정상 클라이언트 통신 구조&apos; title=&apos;&apos; src=&apos;/static/2ca9046713f0ac1495769e0079a748bf/58178/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_0.png&apos; srcset=&apos;/static/2ca9046713f0ac1495769e0079a748bf/08678/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_0.png 190w,
/static/2ca9046713f0ac1495769e0079a748bf/58178/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_0.png 217w&apos; sizes=&apos;(max-width: 217px) 100vw, 217px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그림 1 정상 클라이언트 통신 구조&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./끝나지_않은_전쟁_논클라이언트_봇.md_1.png&apos; data-alt=&apos;그림 2 논클라이언트 통신 구조&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 217px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/245ac8a828127f2fd8c4d881af063ad2/58178/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 101.05263157894737%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABvUlEQVR42mP4//9/3Zo1a47Onj17x/Pnz48C+eEMQACkmRmIAEB1CceOHWu6cuVKM5AdARJYe/bs2f8bNmz4+R8CyqEKWQgYxAilj5w/f/7/tWvXQHq3gQS0gNhnyZIleUDaGYjlkDUQ4UIdoA+TN27cmABka8DEuYHYgYF0ALNUC4jV4aIuLi78QOAEtIEJhNF11dfXM61atQoWpkxQzAgzUFxcXBuEkfXgciEjkmZ8wBqINZAFuJAMZEL30p49e6R3796tCxUTBWIpIFYBYkMgVgViD3QD0V0I8h6TpKSkCJAW6OrqmgwE96HeUmZnZ1cE0oJQdSCgjRKGQMAKxAlAbAS1XROI9fj4+ECuEAKmAH+gC1uRwpcRjdZFdyFIoglqqDkQK0GDgRVLeDHBfIBkoA42L9tDFfECsSRIESsrqz6QlgsODi5vaWnZN2XKFB4gnwVLstHBFinO6E6BJRVgpJQtXbp0BZApA7XEAOoLcSDmgAaVOr5IwZdcQC5kB2IJaAyDDO+FxjoDKTmFES1JIXvZgJALic12LLiSDaV5WYdQwqbYQFAs21GttKGFC0HJQI8CA+VBaRTEAgAv25ylyv9QKgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그림 2 논클라이언트 통신 구조&apos; title=&apos;&apos; src=&apos;/static/245ac8a828127f2fd8c4d881af063ad2/58178/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_1.png&apos; srcset=&apos;/static/245ac8a828127f2fd8c4d881af063ad2/08678/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_1.png 190w,
/static/245ac8a828127f2fd8c4d881af063ad2/58178/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_1.png 217w&apos; sizes=&apos;(max-width: 217px) 100vw, 217px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그림 2 논클라이언트 통신 구조&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;h3&gt;프로토콜 변형&lt;/h3&gt;
&lt;p&gt;이러한 논클라이언트 봇의 등장을 맞이한 게임 개발자들이 취한 그 첫 번째 대응은 프로토콜 변형이었다. &amp;#x3C;그림 3&gt;에는 이렇게 통신 방법이 변경된 그림이 나와 있다. 기존의 Q와 R이 Qa, Ra라는 새로운 값들로 변경되었다. 따라서 기존 논클라이언트 봇은 이 서버와는 통신을 할 수가 없다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./끝나지_않은_전쟁_논클라이언트_봇.md_2.png&apos; data-alt=&apos;그림 3 프로토콜 변조 통신 구조&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 217px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/e3acc49f706cb8faa168f5e352397427/58178/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 101.05263157894737%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB4klEQVR42rVUv0tCURR+Pi3zhUYgWBkFmVRqYTU0BBnl0FDkVm1Co9TalmDgIDQ4NPgXSGKDiwQ6mjglioh/gINLzibC6ztyjNfD0n4d+LiH8879znfuufcJsixfNxqNp0wm8wj/qdPpnAgw+FphCEOeP5/PhyqVyg38Uwo8tNttuVQqvcKXQXjFiboBRBpec8ViUa5Wq7Q9TQFHs9k8jMVil/D3gTnlhiEUupLJ5HkqlfLDX+7Fx4Fd4fvWK+oAlt6jXq93AraHCiJBvSuRSGjpCFg1QeS1S2ixWJwE5Z7PFPY2D7JtYFkZkBSEouqMtOVyeaFerx/VajUzQpMGg8GKdRFYB+zAgZpQrVDr8Xhoykafz7cZjUYb6XRajkQiF4hNmUwmGxFTHuc7P5whbATwAxvADLACrAELdrvdigneZbPZaKvV6qoIBoOiaiiraoX0IcSkW0TExzDCbUuKXJGViQpCV7+WPZxkBKY5qVs5EAg8Q+VLoVA45gJqha5+Q9nv9xLQnjmXy93H4/FmOBw+Q8gmSdIGd2EBxviolr4aikbVEhUYZWU0LD0NhyfsBm556sKwL0XT70op4u5BCod9drrPrs1v37Jr0MX+NSFNeefP/jb/oVDPT+2nhPPALHlvye7DNQGSoy0AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그림 3 프로토콜 변조 통신 구조&apos; title=&apos;&apos; src=&apos;/static/e3acc49f706cb8faa168f5e352397427/58178/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_2.png&apos; srcset=&apos;/static/e3acc49f706cb8faa168f5e352397427/08678/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_2.png 190w,
/static/e3acc49f706cb8faa168f5e352397427/58178/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_2.png 217w&apos; sizes=&apos;(max-width: 217px) 100vw, 217px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그림 3 프로토콜 변조 통신 구조&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;이 방식은 일견 기존의 논클라이언트 봇을 일망타진하면서 동시에 논클라이언트 봇 제작자들에게 새롭게 프로토콜을 분석해야 한다는 짐까지 던져주는 셈이기 때문에 굉장히 효과적인 대응으로 생각되기 쉽다. 하지만 이는 큰 착각이다. 그 사실이 잘못된 가장 큰 이유는 기존의 서비스되고 있는 서버, 클라이언트의 프로토콜 구조 전체를 새롭게 설계하는 작업은 전혀 소프트하지 않기 때문이다. 사실상 이러한 작업을 한다는 것은 거의 미친 짓이나 다름 없다. 보통의 경우에 서비스되고 있는 프로그램에서 선택할 수 있는 방법의 최대치는 새로운 패킷 추가나 기존 패킷의 상수 값을 변경하는 정도가 전부다. 하지만 이러한 것들은 이미 프로토콜 전체가 분석된 논클라이언트 봇 제작자 입장에서는 전혀 어렵지 않은 과제다. 단순히 변경된 부분만 추적하면 되기 때문이다. 결과론적으로 이 방법은 막는 입장에서는 굉장한 노력이 필요하지만 공격하는 입장에서는 그렇게 많은 노력이 필요하지 않다고 할 수 있다.&lt;/p&gt;
&lt;p&gt;여기까지 이야기를 듣고 보통 나오는 첫 번째 반응은 그러면 패킷을 암호화하면 되지 않냐는 질문이다. 그런데 이 말은 지금까지의 논의를 전혀 이해하지 못해서 나오는 반응이다. 논클라이언트 봇 제작자가 날패킷(raw packet)을 살펴보지 않는 것은 아니지만 어차피 그들은 게임의 거의 모든 코드를 꿰고 있으므로 암호화는 그들에게 큰 장애물이 되지 못한다. 필연적으로 해독하는 코드가 클라이언트에 같이 존재할 수 밖에 없기 때문이다. 즉, 아주 뛰어난 해커를 가정했을 때 패킷 암호화라는 것은 그 효과가 0이라고 할 수 있다. 물론 현실세계에 존재하는 수많은 어중이떠중이 해커를 고려한다면 하지 않는 것 보다는 하는 것이 효과가 있지만 실제로 논클라이언트 봇을 제작할 수 있는 수준의 실력자들에게는 큰 효과를 보기는 힘들다.&lt;/p&gt;
&lt;h3&gt;키인증&lt;/h3&gt;
&lt;p&gt;본격적으로 보안 업체가 관여하면서 나온 첫 번째 생각은 키인증이다. 키인증이란 클라이언트와 서버만이 알고 있는 비밀스런 질문과 답변을 주고 받자는 것이었다. 이 방법은 서버에서 클라이언트로 특정 키를 전송하고 클라이언트에서는 그 키에 대해서 아주 특수한 연산을 한 다음 그 값을 서버로 전송한다. &amp;#x3C;그림 4&gt;에 이러한 방식의 통신 구조가 나와 있다. 서버와 클라이언트는 사전에 약속된 아주 비밀스러운 연산 E를 각자 가지고 있다. 이 상태에서 서버는 클라이언트에게 Q를 보내고 클라이언트는 그것을 자신이 가진 연산 E의 인자로 전달해서 나온 결과, R을 서버로 전송한다. 서버에서는 다시 동일한 연산을 수행해서 클라이언트가 응답한 R이 자신이 계산한 답과 맞는지를 비교해서 정상 클라이언트인지 아닌지를 판단한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./끝나지_않은_전쟁_논클라이언트_봇.md_3.png&apos; data-alt=&apos;그림 4 키인증 통신 구조&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 298px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/c34433053f6b79bc81032a754ac496c4/c9fe3/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_3.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 73.68421052631578%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB+UlEQVR42o1TvWsaYRh/vY+otSeYq41xSWns0nx2k0LrlK1dEiQhdHTL1A/p4GDHrlIcnEUEBddgbBDFv8DaXh1E0cEMKmbMZH/P5T24vvWkP/j5PD7ve797vo4xGxaLhcztea/X+z0ajX7A/8JjEhNgxWCPm81mYTabfWUOgif9fr/d7XY78D+vELTuXzQajZvJZHLJlsBFP36/fx3muT1GiMfjcjqdlmwx0/p8vn0YjTlB0zRdVdU9/ldmK0AvURTlla7rmmOGkUgkGAgEdnlM4lmxYrH4JpPJvKR3ut3uJ7DPwBD4GnzISqWSXK/XFSIeUnK5nGor+YV5ibHHHo9nC3YjlUp9g+AH+N5oNOq1ZX+wtGQ02MywUCi8TSQSJbib4CPwAT9XhAFZvTw0Ba+AdrvdGw6HvyqVilGtVo1arfZzOp3ezefzMS6p4mC47xLi9xkahpEfDAbN8Xj8vdVqXWOfroErCN5C8EYQJEqCuPRfJUP8fT6fp73SwTWbsAj5r5JpCJ1OZ42IoZikHoXDYZ3voR/cxkSfUi+TyeRHTPqUFGKxmPJPyU5rEwqFgljWHStGG0BOuVz+lM1m39EVbMI2LL0oCB7RfjsKAvYvRRb6ZoFa4eWCZ9x3FKSSd4TGmz3mfXYJZ4crPz1+uLVkZZwSiFCGfwA4DcryBTLw0wAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그림 4 키인증 통신 구조&apos; title=&apos;&apos; src=&apos;/static/c34433053f6b79bc81032a754ac496c4/c9fe3/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_3.png&apos; srcset=&apos;/static/c34433053f6b79bc81032a754ac496c4/08678/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_3.png 190w,
/static/c34433053f6b79bc81032a754ac496c4/c9fe3/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_3.png 298w&apos; sizes=&apos;(max-width: 298px) 100vw, 298px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그림 4 키인증 통신 구조&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;은행에서 사용하는 보안카드를 게임 클라이언트에 적용했다고 생각하면 쉽게 이해할 수 있다. 서버가 보내는 Q는 보안 카드의 인덱스를 의미하고 E는 보안 카드에서 인덱스에 대응하는 값을 찾는 과정을 R은 해당 보안 카드에 기록된 보안 코드 4자리 숫자를 의미하는 것이다. 상당히 유사한 만큼 이 방식은 은행 보안카드와 동일한 맹점을 가지고 있다. 보안카드 자체를 분실하면 무용지물이라는 점이다. 즉, 우리가 아주 은밀하다고 앞서 언급했던 연산 E가 도용되면 해킹툴도 얼마든지 정상 클라이언트로 둔갑할 수 있는 것이다. &amp;#x3C;그림 5&gt;에는 이러한 연산 함수 E 코드를 도용한 논클라이언트 봇의 통신 구조가 나와있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./끝나지_않은_전쟁_논클라이언트_봇.md_4.png&apos; data-alt=&apos;그림 5 키인증 함수를 도용한 논클라이언트 통신 구조&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 298px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/e7c702dc3f24491129e291d552e577ca/c9fe3/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_4.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 73.68421052631578%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACEUlEQVR42o1TO4wSURSdGWYWEIaEnUWRZo2Ljetnt0PjSmWnjQnRwpLOyg+xoGBLW2IoqAkhgYTWsLgSPsViqACdyoSQAFsAwdIKzx3fS/DtzMabnNybd++c+x1JgqzXaxfTj8rl8qDZbH6bTqfddrttDgaDY/JlMhlFEgTxCtPPW61WcblcfrQcIOGED0By1uv1voKw3e12zclk8uESQv7daxRxPp/PP0s2QTIzt/1+/21m8zcpkUi4GLm86fP5fPeg9AuEvBJd1w1N0+6yZ5d0iVASVVWPDMPQ7fxWxmg0GgoGg3fYm8ITlUqlp9ls9iHldLvdN6BvAWHgMeC35tdoNFQCPlLz+bxGHwYCgW2oQytIkq56PJ5d6GvpdPoTCN/C9sZiMe9G9fdtW+YzLBaLz5LJZBnmdWAHuML8Kt+uMN8Di/AE0u/3f47H4x/VatWs1WpmvV7/vlgsfq9WqxmCNHExzJaF978VmqZZGI1Grdls9qXT6Zzink4hJyD8BcJzgZCgCOTKf7UM8jeFQoHuygC2NohFcf3TMi1hOBxuEbAUCzSjSCRCRHSHAWAPG71Js0ylUu+w6RfEEI/H1QstO51NOBwO4Vj3+RtdABmVSuV9Lpd7RSG4hD1oShQCntB9OxLSn8Iq5G3JNrE0Ci8jfMlsR0JqeV8YvDVjNmdZ8B04tcyFnLs2J+NUQJQq/AMUoNX51Z6DUgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그림 5 키인증 함수를 도용한 논클라이언트 통신 구조&apos; title=&apos;&apos; src=&apos;/static/e7c702dc3f24491129e291d552e577ca/c9fe3/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_4.png&apos; srcset=&apos;/static/e7c702dc3f24491129e291d552e577ca/08678/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_4.png 190w,
/static/e7c702dc3f24491129e291d552e577ca/c9fe3/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_4.png 298w&apos; sizes=&apos;(max-width: 298px) 100vw, 298px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그림 5 키인증 함수를 도용한 논클라이언트 통신 구조&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;연산을 도용한다는 것은 무엇을 의미할까? 컴퓨터에서 말하는 연산은 결과론적으로는 수행되는 코드의 집합. 즉, 함수가 된다. 앞서 &amp;#x3C;그림 4&gt;에서 살펴본 연산 E가 아주 단순하게는 XOR이라고 생각할 수 있다. Q, R이 4바이트 정수이고 E는 XOR인 것이다. 그 규칙을 모르면 통신 구조가 어려워 보이지만 규칙을 알면 쉽게 도용할 수 있다. 물론 논클라이언트 봇 제작자들이 이렇게 날패킷(raw packet)을 보고 규칙을 추론해 내는 것은 아니다. 그들은 클라이언트 게임 코드를 보고 그 코드를 직접 가져다 사용한다.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;리스트 1&gt;에는 원본 클라이언트에서 사용했다고 생각할 수 있는 SomeFantasticFunction이라는 연산이 나와 있다. 여기서는 간단하게 산술 연산을 수행한 후에 결과 값을 돌려준다. 이 코드를 컴파일해서 실행 코드를 생성하면 해당 코드에 대한 어셈블리어 코드가 어딘가에는 존재한다. 논클라이언트 봇 제작자들은 그 코드를 찾는 것이다.&lt;/p&gt;
&lt;p&gt;리스트 1 원본 연산 함수&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;ULONG &lt;span class=&quot;token function&quot;&gt;SomeFantasticFunction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG Q&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    ULONG R&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    R &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Q &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;34&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1573&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; R&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&amp;#x3C;그림 6&gt;에는 IDA와 같은 정적 분석 툴을 사용해서 해당 코드를 찾아본 화면이 나와 있다. 코드를 보면 오른쪽에는 어셈블리어 코드가 나와 있고 왼쪽에는 바이트 코드가 나와있다. 뛰어난 논클라이언트 봇 제작자라면 함수 자체의 기능도 이해하겠지만, 사실은 그럴 필요도 없다. 이 함수가 특정 시점에 수행된다는 사실만 확인하고 나면 그냥 바이트 코드를 그대로 긁어다 사용하면 되기 때문이다. &amp;#x3C;리스트 2&gt;에는 이렇게 도용한 함수 코드가 나와 있다. 보면 알겠지만 함수는 바이트 코드를 저장해놓고 실행 시점에 가상 메모리에 복사한 다음 해당 함수를 다시 호출하는 구조로 되어 있다. 여기서는 간단하게 컨셉만 보여주기 위해서 이렇게 코드로 만들었지만 실제로는 이렇게 복잡하게 코드로 구성하지 않고도 손쉽게 도용할 수 있는 다양한 방법이 존재한다. 어쨌든 이 이야기의 결론은 특정 코드가 무엇을 하는지, 내지는 어느 시점에 수행되는 지만 판단하고 나면 그 코드를 훔치는 것은 식은 죽 먹기라는 사실이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./끝나지_않은_전쟁_논클라이언트_봇.md_5.jpg&apos; data-alt=&apos;그림 6 IDA로 살펴본 SomeFantasticFunction&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 601px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ffbbad40b222830985fb1878de2ee8c8/9a33a/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_5.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 66.31578947368422%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAECAwX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAB70ua0GR//8QAGBAAAwEBAAAAAAAAAAAAAAAAARAxAAL/2gAIAQEAAQUCuCg5X//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEABj8CX//EABkQAAIDAQAAAAAAAAAAAAAAAAABEBEhUf/aAAgBAQABPyFZK8KQsDcf/9oADAMBAAIAAwAAABAwD//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABURAQEAAAAAAAAAAAAAAAAAABBx/9oACAECAQE/EIf/xAAaEAEAAwEBAQAAAAAAAAAAAAABABExIRBx/9oACAEBAAE/EGCpzcgaiLe5AMJSsRCWu/fP/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그림 6 IDA로 살펴본 SomeFantasticFunction&apos; title=&apos;&apos; src=&apos;/static/ffbbad40b222830985fb1878de2ee8c8/9a33a/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_5.jpg&apos; srcset=&apos;/static/ffbbad40b222830985fb1878de2ee8c8/8ccab/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_5.jpg 190w,
/static/ffbbad40b222830985fb1878de2ee8c8/ea4c8/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_5.jpg 380w,
/static/ffbbad40b222830985fb1878de2ee8c8/9a33a/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_5.jpg 601w&apos; sizes=&apos;(max-width: 601px) 100vw, 601px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그림 6 IDA로 살펴본 SomeFantasticFunction&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;리스트 2 도용한 함수 코드&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ULONG&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;SFFT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG Q&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
ULONG &lt;span class=&quot;token function&quot;&gt;SomeFantasticFunction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ULONG Q&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    UCHAR code&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;token string&quot;&gt;&quot;\x55\x8b\xec\x81\xec\xcc\x00\x00\x00&quot;&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;\x53\x56\x57\x8d\x8d\x34\xff\xff\xff&quot;&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;\xb9\x33\x00\x00\x00\xb8\xcc\xcc\xcc\xcc&quot;&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;\xf3\xab\x8b\x45\x08\xc1\xe8\x0d\x6b\xc0\x22&quot;&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;\x05\x25\x06\x00\x00\x89\x45\xf8\x8b\x45\xf8&quot;&lt;/span&gt;
                    &lt;span class=&quot;token string&quot;&gt;&quot;\x5f\x5e\x5b\x8b\xe5\x5d\xc3&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    PVOID cptr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;VirtualAlloc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;
                                &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;code&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                                &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MEM_COMMIT &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; MEM_RESERVE
                                &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PAGE_EXECUTE_READWRITE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cptr&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cptr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;code&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        SFFT sfft &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SFFT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; cptr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        ULONG R &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sfft&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Q&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;VirtualFree&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cptr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; MEM_FREE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; R&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;무결성 검사&lt;/h3&gt;
&lt;p&gt;E를 도용 당한 보안 업계의 반격은 무결성 검사로 이어졌다. 이는 말 그대로 클라이언트의 내용물을 검사해서 진짜인지 아닌지, 변조가 있었는지 없었는지를 판별하겠다는 말이다. 앞선 키 인증이 사랑하는 사람과 둘만 알고 있는 기억에 대한 질문이었다면, 이는 사랑하는 사람이 가진 고유한 신체적인 특징을 묻는 것이라고 할 수 있겠다.&lt;/p&gt;
&lt;p&gt;&amp;#x3C;그림 7&gt;에는 이러한 경우의 통신 구조가 나와 있다. 서버는 Q라는 랜덤한 값을 보내고 클라이언트는 그 값과 클라이언트 프로그램 자체를 해시 함수 H에 입력으로 넣는다. 그러면 H 함수는 클라이언트에서 Q로 표기된 부분의 해시 값을 구해서 R에 저장한다. 서버에서는 구해진 해시 함수를 가지고 변조된 클라이언트인지 아닌지를 판단하는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./끝나지_않은_전쟁_논클라이언트_봇.md_6.png&apos; data-alt=&apos;그림 7 클라이언트 무결성 검사 통신 구조&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 319px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/1349ad5b7d3f8aecc19c1c6ea1bc4f02/759af/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_6.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 68.42105263157895%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABzElEQVR42o2TS0sCURTHZ3TK6WllYU1Wo4kvkgp3QQWFidDGhdE+RFr7AfwMQiIEtmzdQhEiXwsDRQhx4RMyRBDRb1BM58gI023MDvw4Zy6X/z2voSjCBEFgRH9Tr9c/+v1+A+Jr8UxJ3FWI3pnP55+63e4dJSOoFP1lpVJJtlqtZ4jPpQIygu5cLvfWbrcfqTFGi54DeOJsFNPEuRlY/lOQ5/kdjuNMMoIjw/bM2Gy2ebBTk8m0SqXTaQb7hmCMFIvFKbxtNBp1Wq12mKHX68VWMH6/fz8cDt/jY/C9BaBfAg6AlUkl6wAnlq5SqQzgtR6PZy8ajd4GAoE5onTLUDAWi530ej13o9FwZbNZF0zL1el0XPF4/KxaraYSicQL3g4Gg8yYh5U/BGE67yAglMvlLyhXyGQyQrPZFED4E0wYDAZJyfRxqkoQn5aIKn4IwkUDYAHMSKlUGvparWaAPXwtFAopuZWRydA6sYdqtVrPsuwxhOvALrBmt9t1oVDoQvLArwxpEihJQe6hw+HAyat8Pt9RJBJ5gHhbnPIGMAscTtxDUVBP7qEkOxbQ4PSBK2BxkuAmIUgTqyIt2fqfPdSI/Rv3p9ASQWzBwjc01N1Cx+0a1gAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그림 7 클라이언트 무결성 검사 통신 구조&apos; title=&apos;&apos; src=&apos;/static/1349ad5b7d3f8aecc19c1c6ea1bc4f02/759af/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_6.png&apos; srcset=&apos;/static/1349ad5b7d3f8aecc19c1c6ea1bc4f02/08678/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_6.png 190w,
/static/1349ad5b7d3f8aecc19c1c6ea1bc4f02/759af/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_6.png 319w&apos; sizes=&apos;(max-width: 319px) 100vw, 319px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그림 7 클라이언트 무결성 검사 통신 구조&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;이 방식의 가장 큰 특징은 연산 H의 입력으로 클라이언트 프로그램 그 자체를 넣도록 만들었다는 점이다. 따라서 클라이언트에 가해진 사소한 수정 사항도 모두 검사할 수 있다. 하지만 과연 이 방법으로 논클라이언트 봇을 막을 수 있었을까? 안타깝게도 아니다. 앞선 키 인증과 마찬가지로 논클라이언트 봇이 클라이언트 프로그램 자체를 도용한다면 여전히 무용지물이 되기 때문이다. &amp;#x3C;그림 8&gt;에는 이러한 방식으로 게임 클라이언트 프로그램 C와 해시 함수 H를 도용한 논클라이언트 봇의 통신 구조가 나와 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./끝나지_않은_전쟁_논클라이언트_봇.md_7.png&apos; data-alt=&apos;그림 8 클라이언트 및 해시 함수를 도용한 논클라이언트 통신 구조&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 319px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/c27e0affc4ae05e36c859144a606be10/759af/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_7.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 68.42105263157895%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACDElEQVR42o2TzYsScRjHZ9Rt7NVqC82sdU3cXUkqvAUVBJvs0YNdO4l09tLNv6CDkIiBnWQPXooY8VKjHgwUIW1QfIMUEXy9ePBUTN/fMAO//eW2PfDheUYevr/nTY6DKYrCa15otVqfM5lMfzgcyu12W242m/JgMPhRLBZHq9XqDcnLZrNGLd+g+cNKpfJpMpm84xjBrel0+laSpI/z+fyYiNfrdXGxWGQgLq7X61eMkO6PyuXy99FodMxtMv0BmB04tZinUnjqW/d74NomMWMqldoisc1m27Hb7R4Sk9+oh3QzgfNer/cS7JnH47nBFQoFExJVSEyo1WqqoNvtdlitVrXCUChE5maKRCIPEonEe6fTuYPvO4D4q+AhuM6dYnolDnBIWhcEwQVvDQaD99Pp9OtoNHqRaX1fFRRF8elsNjvq9XqBUqkUwLYC4/E4kMvlnmMRUj6f/0KyY7GY6ZSHjScEsZ2fEFBkWf6NdhWch9Lv9xUI/4Ipy+Xyqz5bOLJVI8TPUaKGE4JIdIF9sEdoNBqq73Q6rm63+61arUr0ifyjwoMzZ2ixWHbNZvMTsnBwD9z0+XyOeDz+gnrgrwp5FrRkYO/Q7/eTzQvhcPhxMpn8gPiutuVb4AJ4tPEOmS0TwV32sKnqzGCbbB+8BFfOErzNCPLMqdAtH/zPHW5r82P/enSeLkhGcPkPtO0Hw4g+pKEAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그림 8 클라이언트 및 해시 함수를 도용한 논클라이언트 통신 구조&apos; title=&apos;&apos; src=&apos;/static/c27e0affc4ae05e36c859144a606be10/759af/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_7.png&apos; srcset=&apos;/static/c27e0affc4ae05e36c859144a606be10/08678/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_7.png 190w,
/static/c27e0affc4ae05e36c859144a606be10/759af/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_7.png 319w&apos; sizes=&apos;(max-width: 319px) 100vw, 319px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그림 8 클라이언트 및 해시 함수를 도용한 논클라이언트 통신 구조&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;앞서 함수를 도용하는 것에 대해서는 설명했다. 그렇다면 게임 클라이언트를 도용한다는 것은 무슨 의미일까? 그 말에 대한 해답이 &amp;#x3C;리스트 3&gt;과 &amp;#x3C;리스트 4&gt;에 나와 있다. &amp;#x3C;리스트 3&gt;은 정상 게임 클라이언트의 응답 함수가, &amp;#x3C;리스트 4&gt;에는 논클라이언트 봇의 응답 함수가 나와 있다. 이 둘의 차이를 보면 알겠지만 정상 클라이언트는 H 함수에 현재 실행되고 있는 프로그램을 입력으로, 논클라이언트 봇은 자신이 도용한 클라이언트 프로그램을 입력으로 넣는 차이를 가지고 있다. 즉, 이 경우에는 앞선 함수 도용처럼 Reply 함수를 통째로 도용하는 경우에는 동작을 하지 않겠지만 &amp;#x3C;리스트 4&gt;에 나와 있는 것처럼 약간의 수정을 가한 후에 사용한다면 서버와 통신이 가능하다.&lt;/p&gt;
&lt;p&gt;리스트 3 원본 응답 함수 코드&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;ULONG &lt;span class=&quot;token function&quot;&gt;Reply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pvoid received_data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    R &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetModuleHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;R&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;리스트 4 논클라이언트 봇 응답 함수 코드&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;GameClient &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;LoadGameToMemory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

ULONG &lt;span class=&quot;token function&quot;&gt;Reply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;pvoid received_data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    R &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;GameClient&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;R&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 방법을 우회하는 논클라이언트 봇의 핵심은 &amp;#x3C;리스트 4&gt;에 나와 있는 LoadGameToMemory 함수다. 이 함수는 게임 클라이언트를 로딩하는 역할을 한다. Windows 실행 포맷인 PE 파일의 구조는 이미 분석이 많이 되었기 때문에 이러한 별도의 실행 파일을 메모리에 올리는 작업은 무척이나 간단하다. 물론 실행 파일 자체에 자가 수정 코드나 폴리모픽, 메타모픽 등의 기법을 적용해서 단순히 로딩 만으로는 실제 구동되는 단계의 클라이언트와 다르도록 만들 수 있다. 하지만 이 또한 VM 환경을 사용하면 간단하게 해결할 수 있다. VM 환경이란 실제 CPU를 사용해서 구동하는 것이 아닌 가상의 메모리 공간과 가상의 CPU를 사용해서 게임 클라이언트 코드를 에뮬레이팅해서 푸는 작업을 말한다.&lt;/p&gt;
&lt;h3&gt;타이밍 체크&lt;/h3&gt;
&lt;p&gt;이 방법은 실상 필드에서는 큰 효과가 없는 방법이나 논문에서는 흔히 등장하는 해법 중에 하나다. &amp;#x3C;그림 9&gt;에 나온 것처럼 해당 연산을 수행하는데 소요된 시간을 같이 보낸다는 것이 핵심 개념이다. 그림에서는 t가 E라는 연산을 수행하는데 소요된 시간을 나타낸다. 물론 t 값은 R안에 은밀하게 포장될 수도 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./끝나지_않은_전쟁_논클라이언트_봇.md_8.png&apos; data-alt=&apos;그림 9 타이밍 체크를 사용하는 통신 구조&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 319px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/15d4a9fec44869a5daeccc62e9c1db58/759af/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_8.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 68.42105263157895%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB3klEQVR42o1Sv0tCURRWn6X2y3oJL9RKRdQkqP6ACgoRoUXIaG+QhiZXwa2/IAcDB5cGpwZdxKc4GOhg6iLaoKKDg+CPKSR5nfN4ht6e2YGP797L4TvnfPdIJERwHCcX+K5WqzW73e4HnG+FN4rIlQnsyOVyr51O50kiIkgJfFWpVNhGo5GA8+W0gIigK5vNvrdarRfJnJAKrAUYiLfJWUq8WwFbfwoaDIZ9rVZrERGcBNqjstvtaxDnFotFw3uWTqflE0aEQqElzDabzXqGYfgOPR4PWiH3er1HwWDwGYvBfReAvAk4BtCLRtYDHDi6QqEwATNut/swHA7f+3y+VWJ0Gy84Go3Oksmkq9/vO4vFojORSDgzmYyz1+tdVKvVVDweT2J2IBCQzylMzQiOx+N6qVTi6vX6GJllWS4Wi3HD4fALbOBgbdip35fC6MvRaFQFBSY/LpsRhEQTwAawIgaDgbXdblubzaYJ9vAtn8+nxFZGpMODhR6q1WqjUqk8heMOeGhG8/1+/3W5XH4AMIIVvzqUkphK+tlDHBW7iUQij4VC4RM/BveOpmkd8ArgZOEeCoJGcg+hqAqABRQADf4+4AawsUhQJyJIEUsu+7eHENvon0iHvDWE4B5g/RtSXvJBL3TfKQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그림 9 타이밍 체크를 사용하는 통신 구조&apos; title=&apos;&apos; src=&apos;/static/15d4a9fec44869a5daeccc62e9c1db58/759af/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_8.png&apos; srcset=&apos;/static/15d4a9fec44869a5daeccc62e9c1db58/08678/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_8.png 190w,
/static/15d4a9fec44869a5daeccc62e9c1db58/759af/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_8.png 319w&apos; sizes=&apos;(max-width: 319px) 100vw, 319px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그림 9 타이밍 체크를 사용하는 통신 구조&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;우선 이 방법의 가장 큰 문제점은 범용 OS가 보통은 RTOS가 아니라는 점이다. 이는 시간 측정이 정확할 수 없다는 이야기다. 모든 스레드나 프로세스는 다른 스레드나 프로세스에 의해서 선점될 수 있고, 이는 곧 정상 환경에서도 실제 동작 시간이 지연될 수 있음을 의미한다. 또한 클라이언트가 구동되는 실행 환경은 천차만별이라는 점도 문제점이다. 같은 게임을 셀러론 CPU에서 실행하는 사용자도 있고, i7 쿼드 코어 컴퓨터에서 실행하는 사용자도 있다. 이 둘의 실행 시간은 아주 당연하게 전혀 같지 않다.&lt;/p&gt;
&lt;p&gt;그리고 결정적으로 앞선 무결성 검사에서 살펴보았던 것처럼 연산 E는 도용뿐만 아니라 변조도 당할 수가 있다. 따라서 이 경우에는 정상의 경우 t가 일정한 값으로 나올 것이기 때문에 조작을 해서 실행 시간에 상관 없이 같은 시간을 보내도록 하면 손쉽게 우회할 수 있다.&lt;/p&gt;
&lt;p&gt;물론 이렇게 여러모로 실전에서 사용하기에는 다소 부족한 점이 많은 방법이지만 이 방법을 소개한 이유는 이 방법의 경우 기존 방법과 달리 직접적인 값 보다는 간접적인 값을 통해서 논클라이언트 봇을 진단하려고 했다는 점이다. 즉, 기존 방식들이 예, 아니오의 답을 원하는 닫힌 질문이라면 이 방법은 주관식으로 답할 수 밖에 없는 열린 질문이라는 점이다. 즉, 시간이라는 변수 외에도 이러한 열린 질문을 통해서 정상 클라이언트를 판단을 할 수 있는 방법이 존재한다면 이 테크닉은 논클라이언트 봇에 대한 좋은 대응 방법이 될 수도 있다.&lt;/p&gt;
&lt;h3&gt;CAPTCHA&lt;/h3&gt;
&lt;p&gt;지금까지 우리는 이 문제를 논클라이언트와 정상 클라이언트를 판단하는 것으로 파악했다. 하지만 이것들 전혀 새로운 관점에서 기계와 인간을 구분하는 관점에서 바라본 해법이 CAPTCHA다. CAPTCHA(Completely Automated Public Turing test to tell Computers and Humans Apart)는 흔히 인터넷에서 자동 가입 방지용으로 사용되는 사람인지 기계인지를 테스트하는 방법을 말한다. &amp;#x3C;그림 10&gt;와 같이 아주 이상하게 생긴 문자열을 보여주고는 그대로 다시 입력하라고 하는 방법이 대표적이다. 사실 사람도 이해하기가 쉽지 않다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./끝나지_않은_전쟁_논클라이언트_봇.md_9.jpg&apos; data-alt=&apos;그림 10 사람도 이해하기 힘든 인증&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 387px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/09dffa7113f8a2c1fc8f2359ee5a7e7a/e1e87/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_9.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 27.89473684210526%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAGABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAIDBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHWmJcF/8QAGBAAAwEBAAAAAAAAAAAAAAAAAAERAgP/2gAIAQEAAQUCnQS3T//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABgQAAIDAAAAAAAAAAAAAAAAAAABEDEy/9oACAEBAAY/AtItR//EABoQAAEFAQAAAAAAAAAAAAAAABEAARAhUfH/2gAIAQEAAT8h5CuXBgj/2gAMAwEAAgADAAAAEI/P/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPxA//8QAHRAAAgEEAwAAAAAAAAAAAAAAAREhABAxQVGhsf/aAAgBAQABPxAZ3ngw8oES8WCald2//9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그림 10 사람도 이해하기 힘든 인증&apos; title=&apos;&apos; src=&apos;/static/09dffa7113f8a2c1fc8f2359ee5a7e7a/e1e87/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_9.jpg&apos; srcset=&apos;/static/09dffa7113f8a2c1fc8f2359ee5a7e7a/8ccab/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_9.jpg 190w,
/static/09dffa7113f8a2c1fc8f2359ee5a7e7a/ea4c8/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_9.jpg 380w,
/static/09dffa7113f8a2c1fc8f2359ee5a7e7a/e1e87/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_9.jpg 387w&apos; sizes=&apos;(max-width: 387px) 100vw, 387px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그림 10 사람도 이해하기 힘든 인증&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;이 방식을 논클라이언트 봇 문제에 적용하는 것은 간단하다. 위와 같은 이미지 코드가 Q가 되고 사용자가 입력한 문자열이 R이 되는 것이다. 물론 입력 받는 함수가 연산 E가 되겠다. 이 경우에는 CAPTCHA라는 방식 자체가 기계가 자동으로 답을 판단할 수 없도록 고안되었기 때문에 이론적으로는 사람이 개입할 수 밖에 없다. 즉, 자동으로 입력하는 것이 불가능해진다는 의미이고, 그렇다면 논클라이언트 봇은 자연스럽게 의미가 없어진다.&lt;/p&gt;
&lt;p&gt;물론 이 방법도 논클라이언트 봇이 작정하고 자동화를 하겠다고 다짐을 한다면 할 수 있는 방법이 전혀 없는 것은 아니다. 서버가 가지고 있는 모든 이미지 코드에 대한 결과 값을 수집한 다음 해당 값들에 대한 매핑 함수를 제작하는 것이다. &amp;#x3C;그림 11&gt;에 이러한 방법이 나와 있다. 모든 가능한 Q들에 대한 R을 구한 다음 그것 사이를 매핑하는 M 함수를 제작해서 자동으로 대답하는 방법이다. 하지만 이 경우에는 앞선 프로토콜 변경과 마찬가지로 논클라이언트 봇 제작자 입장에서는 무척 힘든 작업이지만 서버 쪽에서 요청의 내용을 교체하는 것은 쉽다는 특징이 있다. 즉, 서버 쪽에서는 데이터만 교체하면 순식간에 모든 논클라이언트 봇이 무력화되고, 논클라이언트 봇 제작자는 모든 요청과 결과에 대한 내용을 다시 수집해야 한다는 말이다. 더욱이 이런 교체 작업은 자동화 시킬 수 있기 때문에 논클라이언트 봇 제작자 입장에서는 이러한 M을 만들어서 대응하는 것은 사실상 의미가 없다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./끝나지_않은_전쟁_논클라이언트_봇.md_10.png&apos; data-alt=&apos;그림 11 매핑 함수를 사용한 논클라이언트 봇&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 319px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5a66c27dd1efb28f642df27a8a05f473/759af/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_10.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 76.84210526315789%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACOUlEQVR42o2Tz4tSURTH/TGNpvks5zU2FRPMGE4GEy2FZhdRf4BBbgLpHwiiyI2I0FpCIXCVCxPBnagLFU0XLtwokjxwoSiUItY8eYE/8Pa9znvweo02Bz7cc8+793vPOfc+FSFEq4ItFotX8H+Ab4CjpFIprtlscuPxmJNi4vfvwE/3YdSo5CYJYnxL6A6Om3e7XdJut0mtViPVapXU63UCYTKZTMhsNpuTM/sk7lPzPM9WKhU7/Jtywdd0Az6c5nI5IZ/PCxAWyuXybwgKpVJJ6PV6lFMYFfwoS+pDo9EggiBkVyfQIBbtwL8P6En3gC2dTj+Kx+OP4R+IsSOR4+FwuCcTZEOh0PNWq2VXrTG1OFrBgSK2bu0x0K2aKrIFLlESicQ2XeF0Ou84HA6bvPnJZHI3Go0+hWsCNMtDvV6/D05sNpvuIhnSky/DblMBt9v9LBwOx6xW6y7mDNhSZmgEZsDIoHNdNpt9FwgEvmCh2WKx0M0al8ul3VjydDrNFwqFeafT+YUb5WOxGJ/JZHjc8M/lcklGo9FX5Xvz+XwamdA/PXwJMR8e73vcnBdPxFssFr39fv8N5h2MJYWgWoHmL8FNPfT7/Sco0UN7aTKZdmjP7Ha7KRKJWM8p+YGUoVYJSlo12mAw3JCejdFopCJmj8fzJBgMfoZ/HVwDVy+cIcuyewzDHIqxVWmDweAKDr0FVyseSG/7Lnix4a2e+7A1azZIsYf/zVAsa18eo7+q9LsqLuUIbP8B4OSIKD9cMQ0AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;그림 11 매핑 함수를 사용한 논클라이언트 봇&apos; title=&apos;&apos; src=&apos;/static/5a66c27dd1efb28f642df27a8a05f473/759af/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_10.png&apos; srcset=&apos;/static/5a66c27dd1efb28f642df27a8a05f473/08678/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_10.png 190w,
/static/5a66c27dd1efb28f642df27a8a05f473/759af/%EB%81%9D%EB%82%98%EC%A7%80_%EC%95%8A%EC%9D%80_%EC%A0%84%EC%9F%81_%EB%85%BC%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8_%EB%B4%87.md_10.png 319w&apos; sizes=&apos;(max-width: 319px) 100vw, 319px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;그림 11 매핑 함수를 사용한 논클라이언트 봇&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;CAPTCHA 방식이 가지는 문제점은 이러한 논클라이언트 봇에 대한 대응력이 아닌 다른 곳에 있다. 바로 저 문자열을 입력하라는 귀찮은 과정을 게임 플레이 중간 중간에 하게 한다면 과연 어떤 사용자가 그 게임을 하고 있겠냐는 점이다. 사실 인터넷 사이트도 CAPTCHA가 적용된 곳은 진짜 필요한 곳이 아니면 가입이 꺼려지는 것이 사실이다. 더 중요한 사실은 이런 입력의 경우 기계뿐만 아니라 사람도 이해하기 힘들며 종종 틀린다는 점이다. 따라서 실제로 이를 게임이나 특정 클라이언트 프로그램에 적용하는 것은 실용적인 관점에서의 한계가 존재한다.&lt;/p&gt;
&lt;p&gt;그렇다면 사람이 귀찮아 하지 않는 CAPTCHA 방식을 사용하면 괜찮을까? 그런 것들 중에 하나가 게임 상에서 GM(Game Master)들이 하는 말걸기가 있다. GM들이 필드에서 이상 행위를 반복하는 사람들을 보면 말을 걸어보고 제대로 된 대답을 하지 않는다면 자동 플레이로 간주하고 해당 사용자를 퇴장 시키는 방법이다. 그럴듯해 보이지만 요즘 나오는 논클라이언트 봇은 GM의 질문에 대한 몇 가지 대답들을 미리 준비해 놓거나 주변에 GM이 오면 자동으로 다른 곳으로 움직이는 기능을 추가하고 있는 경우도 있다. 따라서 이러한 비강제성 CAPTCHA 방식은 효과를 가지기가 쉽지 않다.&lt;/p&gt;
&lt;p&gt;그럼에도 이 방식이 의미가 있는 것은 새로운 CAPTCHA 방식이 강제성을 가지지만 사람은 전혀 귀찮음을 느끼지 않고, 오히려 흥미를 느끼며, 사람이라면 거의 99.9%의 확률로 틀리지 않는 방식이라면 논클라이언트 봇을 손쉽게 무력화 시킬 수 있는 가장 강력한 방법이라는 특징 때문이다.&lt;/p&gt;
&lt;h3&gt;데이터 마이닝&lt;/h3&gt;
&lt;p&gt;끝으로 소개할 방법은 데이터 마이닝이다. 이 방법은 논클라이언트 봇 문제를 정상 플레이어와 비정상 플레이어의 문제로 바라본 해결책이다. 간단하게 소개하자면 서버 쪽에서 개별 플레이어의 행위를 모두 파악한 다음 그것을 토대로 데이터 마이닝을 해서 해당 플레이어가 정상의 범주에 속하는지 비정상의 범주에 속하는지를 판별한다는 것이다.&lt;/p&gt;
&lt;p&gt;이론적으로는 굉장히 깔끔해 보이지만 실상 이 방법은 많은 단점을 가지고 있다. 우선 플레이어의 모든 행위를 기록내지는 실시간으로 판별해야 한다는 점이다. 이를 위해서는 추가적인 많은 리소스가 투입될 수 밖에는 없다. 그리고 그것을 자동적으로 판별하는 함수를 제작하는 것도 쉬운 일은 아니다. 논클라이언트 봇이 문제가 되는 MMORPG 류의 게임에서 정상의 플레이어 임에도 논클라이언트 봇처럼 플레이를 하는 사용자들도 많기 때문이다.&lt;/p&gt;
&lt;p&gt;하지만 그런 모든 단점을 극복했다고 하더라도 정말 이 방법이 효과가 없을 수 밖에 없는 마지막 약점이 있다. 논클라이언트 봇이 정상의 범주와 같이 플레이를 한다면 이 방법으로는 절대로 논클라이언트 봇을 잡을 수 없다는 점 때문이다. 물론 그것이 문제가 되지 않을 수 있다고 생각할 수 있겠지만 기계가 사람을 대신하여 게임을 자동으로 플레이한다는 관점에서는 여전히 공평하지 않다.&lt;/p&gt;
&lt;p&gt;결론적으로 다시 설명하자면 이렇다. 이 방법에서 생각하는 정상과 비정상을 구분하는 방법을 담고 있는 함수를 P라고 가정하자. 이 P라는 함수가 정상의 범주를 좁히면 좁힐수록 정상 플레이어도 차단되는 경우가 생기는 문제가 발생한다. 반면에 이 P라는 함수가 정상의 범주를 넓히면 넓힐수록 비정상 플레이어가 차단되지 않는 경우도 생긴다. 결정적으로 논클라이언트 봇 제작자는 이 P의 범주를 파악해서 딱 그 범주의 최대치만큼만 부정적인 방법으로 플레이를 한다면 이 방법은 무용지물이 된다. 즉, 이 P의 판단 범주를 어떤 범위에 두더라도 논클라이언트 봇은 항상 그것을 통과할 수 있다는 점에서 이 방법은 좋은 대안이 되기는 힘들다.&lt;/p&gt;
&lt;h3&gt;끝은 없다&lt;/h3&gt;
&lt;p&gt;여기까지가 그간 논클라이언트 봇에 대응하는 게임 업계, 보안 업계, 그리고 학계의 생각들이다. 하지만 개별 항목에서 설명한 것처럼 하나같이 단점 없는 방법이 없으며, 완전하게 논클라이언트 봇을 탐지할 수 있는 방법은 더더욱 없다. 그래서 이 문제가 더욱 매력적인지도 모르겠다.&lt;/p&gt;
&lt;p&gt;다시 제일 앞 소개 글에서 했던 질문을 해보자. 과연 여러분은 질문을 통해서 벽 반대편에 있는 사람의 정체를 판단할 수 있을까? 결론은 불가능하다. 왜냐하면 질문과 답변이라는 메커니즘 자체가 이미 결정돼 있는 것들이기 때문이다. 여러분이 질문을 던지는 순간 그 해답은 이미 나와 있는 것이라는 말이다. 이는 결국 그 질문들을 미리 다 알고 있는 상대라면 얼마든지 여러분의 판단을 흐리게 만들 수 있다는 것을 의미한다.&lt;/p&gt;
&lt;p&gt;하지만 이러한 이론적인 결론 때문에 기죽을 필요는 없다. 실제 현실 세계에 존재하는 논클라이언트 봇 제작자가 우리가 가정한 신적인 존재는 아니라는 점 때문이다. 그들도 결국 사람이기 때문에 모든 코드들을 한번에 다 파악할 수는 없다. 문제는 얼마나 적은 리소스를 사용해서 효과적으로 그들을 괴롭히는가에 달려있다.&lt;/p&gt;
&lt;p&gt;이런 이야기가 끝날 즈음엔 사람들은 항상 왜 보안 업체가 완벽하게 막을 수 없는지를 궁금해 한다. 그러면서 잘 생각해 내면 뭔가 마법 같은 방법으로 이 모든 것을 해결해 낼 은탄환(silver bullet)이 있지 않을까라는 생각도 덧붙인다. 이 싸움이 원숭이나 개나 고양이와의 싸움이었다면 그런 은탄환이 존재했을지도 모른다. 하지만 이 싸움은 적어도 우리와 동등한 내지는 우리보다 더 나은 지능을 가진 사람들과의 싸움이다. 우리가 완벽하게 막을 방법을 생각해 낸다는 건 그들이 완벽하게 우회할 방법을 생각해 낼 수 있다는 말과 같은 의미다. 결국 이 싸움은 뫼비우스의 띠처럼 끝없이 반복될 수 밖에 없는 구조로 되어 있는 것이다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 안티 덤프]]></title><description><![CDATA[덤프(dump…]]></description><link>https://jiniya.net/wp/archives/4369</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4369</guid><pubDate>Sat, 30 Jul 2011 15:00:01 GMT</pubDate><content:encoded>&lt;p&gt;덤프(dump)란 메모리 상의 내용을 그대로 파일에 기록하는 것을 말한다. 이 또한 공격자들이 실행 파일을 분석하기 위해서 사용하는 한 가지 방법이다. 알려지지 않은 실행 압축 프로그램을 사용한 실행 파일도 덤프 기법을 사용하면 쉽게 압축이 해제된 원본 코드를 저장할 수 있기 때문이다.&lt;/p&gt;
&lt;p&gt;공격 기법이 있으면 응당 그에 대한 방어 기법이 있기 마련이다. 어떤 형태로 덤프를 막을 수 있을지 한번 생각해보자. 여러 가지 방법이 있지만 그 중에 가장 간단한 방법은 덤프에 사용되는 정보를 삭제하는 방법이다. &amp;#x3C;리스트 2&gt;에 이 방법을 구현한 소스 코드가 나와 있다. 코드를 살펴보면 NT 헤더의 OptionalHeader 부분의 SizeOfImage와 AddressOfEntryPoint 부분을 제거하여 덤프 프로그램이 이미지 크기와 실행 파일의 시작 코드를 추척하기 힘들도록 만들고 있다.&lt;/p&gt;
&lt;p&gt;리스트 2 안티덤프 소스&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;windows.h&quot;&lt;/span&gt;  &lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tchar.h&quot;&lt;/span&gt;  &lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;stdio.h&quot;&lt;/span&gt;  &lt;/span&gt;
  
PVOID &lt;span class=&quot;token function&quot;&gt;GetPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LPCVOID addr&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SIZE_T offset&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PVOID&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DWORD_PTR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; addr &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; offset&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;  
  
&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  
    HANDLE &lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetModuleHandle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
  
    MEMORY_BASIC_INFORMATION mbi&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
    &lt;span class=&quot;token function&quot;&gt;VirtualQuery&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;mbi&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mbi&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
    DWORD old&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
    BOOL b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;VirtualProtect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt;  
                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mbi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;RegionSize  
                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; PAGE_READWRITE  
                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;old&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
  
    PIMAGE_DOS_HEADER dos&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
    PIMAGE_NT_HEADERS nt&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
    PIMAGE_SECTION_HEADER sec&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
  
    dos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PIMAGE_DOS_HEADER&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
    nt &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PIMAGE_NT_HEADERS&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; dos&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;e_lfanew&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
    sec &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;PIMAGE_SECTION_HEADER&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetPtr&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nt&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;nt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
  
    nt&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;OptionalHeader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SizeOfImage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
    nt&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;OptionalHeader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;AddressOfEntryPoint &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
  
    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;  
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;  
        &lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;hello\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
        &lt;span class=&quot;token function&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;  
  
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;💡 &lt;em&gt;2015-06-26&lt;/em&gt;&lt;br&gt;
&lt;br&gt;
사실 실질적으로 덤프를 방지하기 위해서는 위와 같은 코드가 크게 도움이 되지 않는다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;SizeOfImage 필드는 진짜 거의 의미가 없는데 왜냐하면 EXE이 DLL이 매핑된 섹션 영역을 구해서 덤프를 뜨는 경우가 많기 때문이다. 따라서 실질적으로 덤프 프로그램이 SizeOfImage를 참조하는 일은 잘 없다고 보는게 옳다.&lt;/li&gt;
&lt;li&gt;AddressOfEntryPoint는 효과는 있겠지만 그 효과가 제한적이다. 왜냐하면 대부분 CRT 코드에 연결해서 사용하기 때문에 패턴 검색을 통해서 진입점을 추론할 수 있는 경우가 많기 때문이다. 그리고 DLL 같은 경우에는 로딩/언로딩에 엔트리가 계속 호출되기 때문에 위와 같이 제거해 버리면 문제가 발생할 소지가 있기도 하다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;덤프 대응력을 높이는 실질적인 방법으로는 ASLR을 사용하고 재배치 정보를 숨기는 것이 있다. 이렇게 할 경우 덤프를 뜬 대상체도 원본이 있었던 주소에서만 정상적으로 실행할 수 있기 때문에 덤프를 뜬 것을 재사용하기 위해서는 제약이 따른다. 다른 방법으로는 이미지 밖의 다른 주소 영역을 참조하는 포인트를 만드는 방법이 있을 수 있다. 이 경우에는 덤프를 원본 이미지 영역만 추출하게 되면 같이 딸려 있는 메모리가 추출되지 않았기 때문에 참조 포인터를 추론하기가 쉽지 않아서 효과적이다. 물론 이 두가지 방법다 이미지 로딩 전처리기 단계에서 뭔가를 프로세싱 해야 하기 때문에 위에 있는 것보다는 훨씬 더 복잡한 내용이다.&lt;br&gt;
&lt;br&gt;
끝으로 사족을 하나 더 달자면 원론적인 관점에서 덤프를 방지할 수 있는 방법은 사실상 없다. 덤프 뜬 걸 분석, 재활용 하는 작업을 얼마나 더 어렵게 만들 것인가의 관점에서 접근하는 것이 옳다.&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[키보드 훅, IME 메시지, 그 복잡함 속에 숨겨진 진실들]]></title><description><![CDATA[URL 하이재커를 만드는 한 가지 방법으로 키보드 후킹을 사용하는 방법이 있습니다. 키보드 후킹을 해서 엔터 키를 누르는 메시지를 감시하고 있는 것이죠. 아래 코드는 IE…]]></description><link>https://jiniya.net/wp/archives/4310</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4310</guid><pubDate>Tue, 19 Jul 2011 23:57:22 GMT</pubDate><content:encoded>&lt;p&gt;URL 하이재커를 만드는 한 가지 방법으로 키보드 후킹을 사용하는 방법이 있습니다. 키보드 후킹을 해서 엔터 키를 누르는 메시지를 감시하고 있는 것이죠. 아래 코드는 IE 주소창의 내용을 변경시키는 전형적인 키보드 후킹 프로시저 입니다. 야후라고 입력하고 엔터를 누르면 그 내용을 &lt;a href=&quot;http://www.devpia.com%EC%9C%BC%EB%A1%9C&quot;&gt;http://www.devpia.com으로&lt;/a&gt; 변경 시키는 것이죠.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;LRESULT CALLBACK
&lt;span class=&quot;token function&quot;&gt;KeyHookMsg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WPARAM w&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPARAM l&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;code &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; HC_ACTION
        &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;l &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x80000000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; w &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; VK_RETURN&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        HWND g_HwndServer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;FindWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;IEFrame&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        HWND worker &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;FindWindowEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;g_HwndServer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;WorkerW&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        HWND rebar &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;FindWindowEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;worker&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ReBarWindow32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        HWND combo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;FindWindowEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rebar&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ComboBoxEx32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        HWND box &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;FindWindowEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;combo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ComboBox&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        HWND edit &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;FindWindowEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;box&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Edit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetFocus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; edit&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;   
            TCHAR str&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;GetWindowText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;edit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;str&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_tcscmp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;str&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;야후&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;SetWindowText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;edit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;http://www.devpia.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CallNextHookEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; w&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; l&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그런데 위 코드에는 사소하지 않은 한 가지 문제가 있습니다. 바로 IME 조합 과정에서 내용이 엉뚱하게 바뀌는 문제죠. 아래 그림을 봅시다. 첫번째 그림은 야후라는 글자에 후가 조합 중인 상태입니다. 이 상태에서 엔터키를 누르면 오른쪽에 있는 것처럼 “후ttp://&lt;a href=&quot;http://www.devpia.com%E2%80%9D%EC%9C%BC%EB%A1%9C&quot;&gt;www.devpia.com”으로&lt;/a&gt; 주소창이 변경됩니다. 반면 두번째 그림처럼 조합이 완료된 상태에서 엔터 키를 누르면 정상적으로 변환이 돼죠. 왜 이런 일이 벌어지는 것일까요?&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;사용자 삽입 이미지&lt;/td&gt;
&lt;td&gt;사용자 삽입 이미지&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;사용자 삽입 이미지&lt;/td&gt;
&lt;td&gt;사용자 삽입 이미지&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;답은 IE의 메시지 처리 순서를 살펴보면 금방 알 수 있습니다. 물론 이는 단순히 IE에만 국한되는 내용은 아닙니다. IME를 사용하는 모든 에디터가 보통 이런 방식을 사용하기 때문이죠. 아래 그림은 SPY++을 사용해서 IE의 메시지를 캡쳐한 화면입니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.jiniya.net/tt/attach/1/1688651044.png&quot; alt=&quot;사용자 삽입 이미지&quot;&gt;&lt;/p&gt;
&lt;p&gt;포커스가 있는 부분이 B를 누른 시점이죠. 참고로 세벌식에서 B가 후의 ㅜ글자가 됩니다. 그 다음으로 엔터를 눌렀습니다. WM_KEYDOWN 전에 생소해 보이는 메시지 하나가 있죠. WM_IME_COMPOSITION 메시지 입니다. 보통 한글을 지원하는 에디터는 이 메시지에서 조합 중인 글자를 변경합니다. 이 메시지의 플래그가 GCS_COMPSTR이면 조합중이라는 의미를 나타내고, GCS_RESULTSTR이면 완료되었다는 메시지를 나타냅니다.&lt;/p&gt;
&lt;p&gt;이 과정을 보면 딱 두 가지 의문이 듭니다. VK_PROCESSKEY는 무엇인가? WM_IME_COMPOSITION 따위의 메시지는 도대체 누가 언제 어떻게 발생 시키는가? 라는 것 입니다. VK_PROCESSKEY는 GetMessage나 PeekMessage를 통해서 키보드 메시지를 꺼낼 때 생성되는 놈 입니다. 하드웨어 입력 메시지를 꺼내는 깊숙한 곳에서 IME에게 이 키보드가 처리할 때 필요하냐고 묻는 부분이 있습니다. 그 때 IME가 이 키가 필요하다고 리턴하면 GetMessage는 크 키 값을 VK_PROCESSKEY로 변경한 다음 리턴합니다. 그리고 그 과정에서 IME 핸들러가 각종 IME 메시지들을 생성해서 메시지 큐에 집어넣습니다. 종종 TranslateMessage에서 IME 메시지가 생성된다는 이야기를 하시는 분들이 있는데 그렇지 않습니다. TranslateMessage는 WM_KEYDOWN, WM_SYSKEYDOWN등의 메시지에서 WH_CHAR, WM_SYSCHAR등의 메시지를 생성해내는 역할만 합니다.&lt;/p&gt;
&lt;p&gt;끝으로 한가지 더 이해해야 하는 부분은 WM_IME_COMPOSITION 메시지 입니다. 대부분의 한글 에디터들은 이 메시지를 별도로 특별하게 처리해 줍니다. 이 메시지의 역할은 현재 조합중인 글자가 변경되었음을 나타냅니다. 따라서 보통 에디터들은 이 메시지가 날라오면 현재 카렛이 있는 위치의 글자를 GetCompositionString의 결과 값으로 변경시킵니다. ‘아’라는 글자에서 ‘ㄴ’을 눌러서 ‘안’이 되는 과정을 생각해 봅시다. ‘ㄴ’을 누른 순간 WM_IME_COMPOSITION이 발생해고 에디터는 현재 위치의 ‘아’를 지우고 그 자리를 ‘안’으로 변경하는 겁니다. 워낙 순식간에 일어나기 때문에 우리는 그것이 지웠다가 다시 그려진다는 것을 모를 뿐이죠.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.jiniya.net/tt/attach/1/1281720214.png&quot; alt=&quot;사용자 삽입 이미지&quot;&gt;&lt;/p&gt;
&lt;p&gt;설명이 너무 길었습니다. 이제 훅 프로시저가 적용되면 어떻게 되는지 살펴보도록 합시다. 위 그림은 훅 프로시저가 적용된 경우의 메시지 순서를 캡쳐한 화면입니다. B키를 누르고 엔터를 친 상황이죠. WM_SETTEXT로 &lt;a href=&quot;http://www.devpia.com%EC%9C%BC%EB%A1%9C&quot;&gt;http://www.devpia.com으로&lt;/a&gt; 변경하는 부분이 우리의 훅 프로시저가 호출된 시점입니다. 값을 변경했기 때문에 카렛은 h앞에 위치하고 있을 겁니다. 그 다음으로 WM_IME_COMPOSITION이 호출되죠. 그럼 에디터 프로시저는 현재 위치에 있는 h란 글자를 지우고 그 자리에 GetCompositionString의 리턴 값을 넣습니다. ‘후’란 글자가 그 자리에 추가되겠죠. 그리고 WM_KEYDOWN 프로시저가 시작됩니다.&lt;/p&gt;
&lt;p&gt;여기서 가장 먼저 드는 의문은 왜 VK_RETURN을 꺼내는 시점이 아닌 VK_PROCESSKEY 앞에서 우리 루틴이 호출되냐 하는 것입니다. VK_RETURN 앞에서 훅 루틴이 호출된다면 이런 일이 없기 때문이죠. 그건 윈도우의 IME 처리와 관련이 있습니다. 이 과정을 간단하게 코드로 살펴보는 것이 좋을 것 같습니다. 코드를 보고 나면 왜 이런 일이 벌어졌는지 모두 이해할 수 있습니다. 아래 코드에 나타난 것처럼 GetMessage API에서 키 값을 VK_PROCESSKEY로 변경하기 전에 키보드 훅 프로시저를 호출하기 때문에 그렇습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;GetMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// 키보드 메시지인가?&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;IsKeyboardMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token comment&quot;&gt;// IME가 처리하는 키인가?&lt;/span&gt;
        ret &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;IsIMEWantThisKey&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// 등록된 키보드 훅 프로시저 호출&lt;/span&gt;
        &lt;span class=&quot;token function&quot;&gt;CallHookFunctions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token comment&quot;&gt;// IME가 처리하는 키인 경우 키 값을 VK_PROCESSKEY로 변경&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ret&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            msg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;wParam &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; VK_PROCESSKEY&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그럼 키보드 훅 프로시저에서는 방법이 없는 건가요?&lt;/p&gt;
&lt;p&gt;물론 모두 사람이 만든 것들인데 방법이 없을 순 없겠죠. 단지 호출되는 시점이 앞서 소개한 것과 같기 때문에 키보드 훅 프로시저에서 에디터 값을 변경하는 것은 좋은 생각은 아닙니다.&lt;/p&gt;
&lt;p&gt;그럼 답을 찾아 봅시다. 가장 큰 원인은 WM_IME_COMPOSITION 메시지에서 글자를 지우고 그 위치에 마지막에 조합 중이던 글자가 추가된다는 점 이었습니다. 마지막에 조합 중이던 글자는 ImmGetCompositionString으로 구한다고 앞서 소개했습니다. 그렇다면 방법은 이제 나왔죠. ImmGetCompositionString이 조합 중이던 값이 아닌 다른 값을 리턴 하도록 만들면 됩니다.&lt;/p&gt;
&lt;p&gt;ImmSetCompositionString이라는 함수를 사용하면 간단하게 ImmGetCompositionString의 값을 변경할 수 있습니다. &lt;a href=&quot;http://www.devpia.com%EC%9C%BC%EB%A1%9C&quot;&gt;http://www.devpia.com으로&lt;/a&gt; 바꾸어야 한다면 ImmSetCompositionString으로 조합 중인 문자를 h로 지정해 주면 됩니다. 그러면 WM_IME_COMPOSITION에서 h를 지우고 다시 h를 추가하는 겪이 되기 때문에 원래 의도했던 URL로 이동하겠죠. 한 가지 주의할 점은 IME 상태를 조사해서 한글 모드인 경우만 이런 일을 해야합니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;LRESULT CALLBACK
&lt;span class=&quot;token function&quot;&gt;KeyHookMsg&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; WPARAM w&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; LPARAM l&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;code &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; HC_ACTION
        &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;l &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x80000000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; w &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; VK_RETURN&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        HWND g_HwndServer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;FindWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;IEFrame&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        HWND worker &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;FindWindowEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;g_HwndServer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;WorkerW&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        HWND rebar &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;FindWindowEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;worker&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ReBarWindow32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        HWND combo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;FindWindowEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rebar&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ComboBoxEx32&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        HWND box &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;FindWindowEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;combo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ComboBox&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        HWND edit &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;FindWindowEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;box&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Edit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetFocus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; edit&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;   
            TCHAR str&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token function&quot;&gt;GetWindowText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;edit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;str&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            TCHAR &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;http://www.devpia.com&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_tcscmp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;str&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;야후&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                HIMC imc&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ImmGetContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;edit&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                DWORD conv&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; sent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;ImmGetConversionStatus&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;imc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;conv&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;sent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

                &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;conv &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; IME_CMODE_ALPHANUMERIC&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; 
                    &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ImmGetVirtualKey&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;edit&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; VK_RETURN&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

                    &lt;span class=&quot;token function&quot;&gt;ImmSetCompositionString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;imc
                                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; SCS_SETSTR
                                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; url
                                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;TCHAR&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
                                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;
                                            &lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

                    &lt;span class=&quot;token function&quot;&gt;SetWindowText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;edit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                    &lt;span class=&quot;token function&quot;&gt;SendMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;edit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; EM_SETSEL&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt;
                    &lt;span class=&quot;token function&quot;&gt;SetWindowText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;edit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

                &lt;span class=&quot;token function&quot;&gt;ImmReleaseContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;edit&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; imc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;CallNextHookEx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; code&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; w&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; l&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[헷갈리는 유니코드 출력: %s vs %S]]></title><description><![CDATA[유니코드는 참 사람을 헷갈리게 만듭니다. 유니 코드가 아니라 문자열이란 자체가 사람을 헷갈리게 만드는 것 같아요. 오늘은 그 중에서도 특히나 우리를 더 헷갈리게 만드는 포맷 문자열 변환 지시자 %s와 %S에 대해서 살펴보겠습니다. 우선 %s와 %S…]]></description><link>https://jiniya.net/wp/archives/4299</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4299</guid><pubDate>Tue, 19 Jul 2011 23:57:21 GMT</pubDate><content:encoded>&lt;p&gt;유니코드는 참 사람을 헷갈리게 만듭니다. 유니 코드가 아니라 문자열이란 자체가 사람을 헷갈리게 만드는 것 같아요. 오늘은 그 중에서도 특히나 우리를 더 헷갈리게 만드는 포맷 문자열 변환 지시자 %s와 %S에 대해서 살펴보겠습니다. 우선 %s와 %S가 먼지에 대해서 알아볼까요. 일단 아래 코드를 봅시다.&lt;/p&gt;
&lt;p&gt;printf(“%s”, str);&lt;/p&gt;
&lt;p&gt;C언어 처음 배우는 학생도 다 알법한 코드죠. str이라는 문자열을 출력하는 코드입니다. 그러면 다음은요?&lt;/p&gt;
&lt;p&gt;printf(“%S”, str);&lt;/p&gt;
&lt;p&gt;네. 이건 C언어만 배워서는 알긴 힘들지만 어쨌는 앞서 설명한 것과 비슷하게 문자열을 출력하는 역할을 합니다.&lt;/p&gt;
&lt;p&gt;그렇다면 대문자 %S와 소문자 %s는 무엇이 다른 걸까요? 바로 변환 방식입니다. 설명하려면 조금 어려운데요. %s는 사용되는 함수와 동일한 문자열 타입으로 출력을 하는 것이고, %S는 사용되는 함수의 반대되는 문자열 타입으로 출력을 하는 지시자입니다. 듣고도 모르겠죠. 당연합니다. ㅋㅋ~ 예를들어 보겠습니다. wprintf에 %s를 사용했다. 그러면 뒤에 str은 wchar_t *로 인식하겠다는 말입니다. %S를 사용했다. 그러면 뒤에 str은 char *로 인식하겠다는 거죠. printf는 어떨까요? %s를 사용하면 char *, %S를 사용하면 wchar_t *로 변환해서 출력합니다. 이해되시나용?&lt;/p&gt;
&lt;p&gt;헷갈리지만 자동으로 변환을해서 출력해주니 편리한 기능이긴 합니다. 하지만 사실 대문자 %S 옵션은 사용하지 않는 편이 좋습니다. 왜냐구요? 헷갈리잖아요.&lt;/p&gt;
&lt;p&gt;다음 코드를 봅시다.&lt;/p&gt;
&lt;p&gt;TCHAR *str;&lt;/p&gt;
&lt;p&gt;_tprintf(_T(“%s”), str);&lt;/p&gt;
&lt;p&gt;위의 구문은 전형적으로 MBCS빌드와 유니코드 빌드에서 다 안전한 코드입니다. 코드에서 향기가 느껴지지 않으신가요? ㅎㅎ~&lt;/p&gt;
&lt;p&gt;wchar_t *str;&lt;/p&gt;
&lt;p&gt;_tprintf(_T(“%S”), str);&lt;/p&gt;
&lt;p&gt;자 이 코드는 어떻습니까? 먼가 우스꽝 스럽죠. 맞습니다. 이 코드는 유니코드 빌드에서 실패하는 코드입니다.&lt;/p&gt;
&lt;p&gt;wchar_t *str;&lt;/p&gt;
&lt;p&gt;printf(“%S”, str);&lt;/p&gt;
&lt;p&gt;%S 옵션이 유일하게 힘들 얻는 순간입니다. 하지만 이 순간에서 조차도 편리하긴 하지만 헷갈리는건 어쩔 수 없습니다. 왜냐구요? %S만 보고는 이게 어떻게 변환되는 건지 추론을 할 수 없기 때문이죠. printf까지 봤을 때, 아 이게 wchar_t *로 변환되는 거구나라고 판단할 수 있기 때문입니다. 뇌에 부담을 준다고 생각할 수 있겠습니다.&lt;/p&gt;
&lt;p&gt;이런 헷갈리는 문제 때문에 다른 변환 지시자들이 존재합니다. 바로 %hs, %ws(=%ls)가 그것이죠. %hs는 대상을 함수에 상관없이 char *로 변환해서 출력해 주는 역할을 합니다. 반대로 %ls, %ws는 wchar_t *로 변환해서 출력하는 역할을 하죠. 따라서 마지막에 쓴 코드는 다음과 같이 사용하는게 덜 헷갈리는 코드라고 할 수 있겠습니다.&lt;/p&gt;
&lt;p&gt;wchar_t *str;&lt;/p&gt;
&lt;p&gt;printf(“%ws”, str);&lt;/p&gt;
&lt;p&gt; 15
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[디지털 서명은 반드시 마지막에…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/307</link><guid isPermaLink="false">https://jiniya.net/wp/archives/307</guid><pubDate>Tue, 19 Jul 2011 23:57:20 GMT</pubDate><content:encoded>&lt;p&gt;디지털 서명과 실행파일 프로텍트를 같이 하면서 흔히들 저지르는 실수가 하나 있습니다. 디지털 서명을 처음 적용하시는 분들이 많이들 하는 실수 같은데요. 실행 파일을 빌드한 다음 디지털 서명을 적용하고, 해당 파일을 실행 파일 프로텍터로 보호하는 겁니다. 그런데 웃기게도 이렇게 해버리는 경우는 실행 파일 프로텍터가 실행 파일 내용을 바꾸면서 자연스럽게 해시 값이 변경되서 디지털 서명으로 인한 인증효과가 전혀 없어진다는 겁니다. 그러니 이렇게 백날 디지털 서명을 해봤자 백신 프로그램이나 다른 여타 보안 프로그램에서는 허구헌날 그 프로그램을 잡게 됩니다. 왜냐하면 디지털 서명이 되어 있지만 변조된 파일이거든요.&lt;/p&gt;
&lt;p&gt;그렇다면 제대로 하려면 어떻게 하면 되느냐? 바로 순서를 반대로 하면 됩니다. 프로텍터로 보호하고, 디지털 서명을 하는 거죠. 그러면 디지털 서명이 최종적으로 적용되었기 때문에 실행 파일 해시는 디지털 서명의 그것과 일치하고 백신등이 검사했을 때 변경되지 않았기 때문에 안전하게 예외처리가 될 겁니다. 물론 디지털 서명을 제대로 해도 잡는 백신도 많습니다.&lt;/p&gt;
&lt;p&gt;결론은 “디지털 서명을 제대로 적용하기 위해서는 반드시 실행 파일에 최종 수정을 가하는 것이 인증서 프로그램이 되도록 만들어야 한다”로 요약할 수 있겠습니다.&lt;/p&gt;
&lt;p&gt;아래는 참고로 프로그램에서 디지털 서명을 체크하는 코드가 나와 있는 사이트입니다. 프로그램에 디지털 서명 체크 기능을 추가해야 한다면 유용하게 카피앤페이스트해서 사용하실 수 있습니다. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/aa382384(VS.85).aspx&quot;&gt;http://msdn.microsoft.com/en-us/library/aa382384(VS.85).aspx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://support.microsoft.com/kb/323809/ko&quot;&gt;http://support.microsoft.com/kb/323809/ko&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[PE 헤더 사이즈 필드 믿을 수 있을까?]]></title><description><![CDATA[PE 포맷의 NT 헤더에 보면 OptionalHeader에 SizeOfHeaders란 필드가 있습니다. 이 필드는 보통 파일 기반의 헤더 크기로 정의 됩니다. SizeOfImage…]]></description><link>https://jiniya.net/wp/archives/4250</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4250</guid><pubDate>Tue, 19 Jul 2011 23:57:19 GMT</pubDate><content:encoded>&lt;p&gt;PE 포맷의 NT 헤더에 보면 OptionalHeader에 SizeOfHeaders란 필드가 있습니다. 이 필드는 보통 파일 기반의 헤더 크기로 정의 됩니다. SizeOfImage는 반대로 파일을 로딩하기 위해서 메모리에 확보해야할 공간을 의미하죠. 그래서 SizeOfHeaders는 FileAlignment 단위로 정렬되고, SizeOfImage는 SectionAlignment 단위로 정렬됩니다.&lt;/p&gt;
&lt;p&gt;보통의 경우 이 SizeOfHeaders 필드가 정상적입니다. 파일일 때의 크기와 일치한다는 것이죠. 그런데 얼마전에 정말 어처구니 없는 상황을 알게 되었습니다. 이 SizeOfHeaders 필드가 upx 압축이 되면 잘못될 수 있다는 것이죠. upx의 경우 소스를 보지 않아서 정확하게 왜 그러는지는 알 수 없지만 실행 파일의 SizeOfHeaders 필드를 4K로 만들어 버립니다. 더 재미난 사실은 그러고도 파일에서의 헤더 크기는 전과 똑같다는 것이죠.&lt;/p&gt;
&lt;p&gt;즉, 문제는 upx 압축을 거치고 나면 원래 0x400이던 헤더 크기가 0x1000이 되어 버린다는 점 입니다. 그러고도 파일에서의 크기는 여전히 0x400인채 말이죠. 따라서 upx 압축을 해버린 파일의 SizeOfHeaders 필드는 믿을 수가 없습니다. 즉, SizeOfHeaders 필드로 뭔가를 해보려는 코드에게 upx 압축된 파일은 위험할 수 있습니다.&lt;/p&gt;
&lt;p&gt;그렇다면 upx 압축된 파일의 헤더 크기를 알 수 없는 것일까요? 물론 방법이 없는 것은 아닙니다. 보통 PE 파일의 경우 헤더는 섹션이 시작되기 전까지 위치합니다. 따라서 첫 번째 섹션 헤더의 PointerToRawData 필드를 헤더 크기로 사용하면 정상적으로 처리할 수 있습니다.&lt;/p&gt;
&lt;p&gt;시간나면 upx 소스를 한번 분석해봐야 겠네요. 버그인지 아니면 심오한 이유가 있는건지 알아봐야겠죠. *^^* PE 포맷의 SizeOfHeaders 필드로 뭔가를 해야 한다면 주의하시기 바랍니다. 여러분이 그 값을 순진하게 믿고 별 생각없이 코딩하는 순간 여러분의 프로그램이 삐걱 거릴 수 있습니다.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[인터센더블 훅…]]></title><description><![CDATA[64비트 환경에서 메시지 훅을 해보셨다면 한번 쯤은 프로그램이 행에 걸리는 문제를 겪어 보셨을 겁니다. 안겪어 보셨을 수도 있구요. ㅋㅋ~ 문제의 증상은 다음과 같습니다. 64비트 DLL을 인젝션한 경우에는 64비트 프로세스들은 잘 돌아가는데 3…]]></description><link>https://jiniya.net/wp/archives/3090</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3090</guid><pubDate>Tue, 19 Jul 2011 23:57:18 GMT</pubDate><content:encoded>&lt;p&gt;64비트 환경에서 메시지 훅을 해보셨다면 한번 쯤은 프로그램이 행에 걸리는 문제를 겪어 보셨을 겁니다. 안겪어 보셨을 수도 있구요. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;문제의 증상은 다음과 같습니다. 64비트 DLL을 인젝션한 경우에는 64비트 프로세스들은 잘 돌아가는데 32비트 프로세스만 가면 32비트 프로세스가 행이 걸리면서 크래시가 발생합니다. 마찬가지로 32비트 DLL을 인젝션한 경우에는 32비트 프로세스는 잘 돌아가는데 64비트 프로세스만 가면 행이 걸리죠. MSDN을 보아도 뭐 당연한 소리만 있습니다. 32비트 프로세스에는 32비트 DLL만 인젝션 할 수 있고, 64비트는 뭐 64비트만 인젝션 할 수 있다는 둥. 32비트 DLL을 64비트, 64비트 DLL을 32비트 프로세스에 인젝션 할 수 없다는 그런 이야기죠.&lt;/p&gt;
&lt;p&gt;그렇다면 왜 도대체 저렇게 따로 따로 잘 돌아가는 것처럼 적어 놓은 것들이 제대로 돌아가지 않고 행이 걸리는 걸까요? 이유는 간단합니다. 인터센더블 타입의 훅이 문제인 겁니다. HKF_INTERSENDABLE이라는 타입의 훅들이 있습니다. WH_KEYBOARD, WH_MOUSE, WH_JOURNAL*, WH_SHELL, WH_KEYBOARD_LL, WH_MOUSE_LL 같은 놈이죠. 이 인터센더블이 뭐냐면 훅 메시지가 발생한 곳과 훅 프로시저가 처리되는 부분이 다르다는 겁니다. 제가 몇 년 전에 했던 후킹 강좌를 보시면 아시겠지만 WH_KEYBOARD_LL 같은 경우에는 전역 훅을 하더라도 굳이 DLL에 훅 프로시저를 넣을 필요 없이 실행 파일에 훅 프로시저를 작성해도 잘 동작합니다. 그 이유가 윈도우 하부 시스템에서 이 인터센더블 훅이면 다른 프로세스로 SendMessage를 해서 훅을 처리해주기 때문입니다. 대신에 훅 프로시저가 호출되는 컨텍스트는 당연히 틀리죠.&lt;/p&gt;
&lt;p&gt;그렇다면 도대체 왜 이 인터센더블이 64비트로 가면서 문제를 일으키는 걸까요? 간단합니다. 인터센더블 처리를 제대로 해주지 않아서 그런 겁니다. 32비트 윈도우 환경에서는 WH_KEYBOARD 전역 훅을 했고, DLL에 훅 프로시저를 작성했다면 항상 같은 컨텍스트에서 해당 훅 프로시저가 호출됩니다. 이게 64비트로 가면 어떻게 되느냐? 64비트 DLL을 인젝션 했다면 32비트 프로세스들은 그 64비트 윈도우 훅 DLL을 로드할 수 없기 때문에 대신에 64비트 훅을 설치한 그 프로세스로 훅 처리를 넘겨주게 되는 겁니다. 즉, 32비트 환경과는 달리 DLL에 훅 프로시저를 두어도 필연적으로 64비트 환경에서는 인터센더블 상황이 발생하는 것이죠.&lt;/p&gt;
&lt;p&gt;그렇다면 이제 이건 다 이해했는데 왜 행이 걸린 걸까요? 그건 간단합니다. 훅을 설치한 프로세스가 메시지 프로시저를 가지고 있지 않기 때문입니다. 윈도우 하부 시스템에서는 이 인터센더블을 구현하기 위해서 SendMessage를 사용합니다. 그런데 훅을 설치한 프로세스가 메시지 핸들러가 없다면 이 SendMessage를 받아서 처리할 수가 없겠죠. 그러니 행이 걸리는 겁니다.&lt;/p&gt;
&lt;p&gt;자, 그러면 64비트 환경에서 제대로 인터센더블 훅을 처리하려면 어떻게 해야 할까요? 일단 행을 없애려면 훅을 설치한 스레드는 반드시 메시지 핸들러를 가지고 있어야 합니다. 더불어서 다른 프로세스에서 발생한 이벤트가 우리 쪽에서 처리되기 때문에 이에 대한 결정도 해야 합니다. 이걸 무시할지 안할지 말입니다. 무시하는 방법은 간단합니다. 호출되는 스레드 컨텍스트가 우리 메시지 핸들러 컨텍스트인지만 확인하면 되겠죠.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[붕어 없는 붕어빵? 알 수 없는 윈도우 98의 세계…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/4244</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4244</guid><pubDate>Tue, 19 Jul 2011 23:57:17 GMT</pubDate><content:encoded>&lt;p&gt;누군가 저에게 직업 개발자로써 가장 피곤한 일이 무어냐고 물어본다면 전 딱 두 가지를 말할 겁니다. 하나는 제가 만들기 싫은 것도 만들어야 한다는 것이고, 나머지 하나는 경계선을 제가 정할 수 없다는 것 입니다. 그 중에서도 제일 피곤한게 이 경계선입니다. 가장 악몽같은 경계가 운영체제죠. 그 경계에서도 끝판 대장은 바로 Windows 9x입니다. &lt;/p&gt;
&lt;p&gt;회사에서 만드는 프로그램은 지금 이 시점에서도(옛날 시점입니다) Windows 98을 여전히 지원해야 합니다. 심한 경우에는 Windows 95 OSR2까지 지원하기를 요청받는 경우도 있습니다. Windows 95 OSR2에 얼마나 많은 API가 없는지 알게된다면 분명 피토하고 쓰러질 겁니다. ㅎㅎ 각설하고 오늘 알게된 Windows 98의 놀라운 현상에 대해서 알려드리겠습니다.  아래 스크린 샷을 한 번 살펴보도록 합시다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 596px; margin-bottom: 16px;&apos; data-url=&apos;./붕어_없는_붕어빵_알_수_없는_윈도우_98의_세계.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/7e79fac4e761b3d25f8b55e92bd4503a/fe133/%EB%B6%95%EC%96%B4_%EC%97%86%EB%8A%94_%EB%B6%95%EC%96%B4%EB%B9%B5_%EC%95%8C_%EC%88%98_%EC%97%86%EB%8A%94_%EC%9C%88%EB%8F%84%EC%9A%B0_98%EC%9D%98_%EC%84%B8%EA%B3%84.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 64.21052631578948%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAAsTAAALEwEAmpwYAAACmklEQVR42o1R+0/aUBTun7m4+V5kZkYzfzDGoZsbExhzyVymMfIKuulailie2m4TU7Qd0FLelIo4UCqwRAzga8DOcPt9X05Ozr3nfOf7ci8yPbPW028ZGN4YHEX7x6yPJomhKaJvilC88Cpeecff7z9ZCjxcYIeWgkMrnMIkKFajw2hyZTu4YEYRFF3HcHwdw1AMN5vMlrVlHLXhax+XVwwoZh0ZG+3qedAz2Pc3Bnq7B3rv93bf6+56PDqC4FbcZt88YGiGoXd3SdpP+ve+7fsoivKyjP/dh/mp2Ylp1aRSNTmhHJ9VKzVvX84vaFWvnytnnyKCEKXpQDicicdzx8c/D6VKPP4jLcrZbDkWywrhw0Q8HwqKYV76ziZ4TuS5jJQpFvJVj5tEKhXZ6TyYeebRaimdzqfV7qtUXzUaWqejNRrqT2j35tR7UKjV1Jv5Xchzarj3bWx8Qer1erP5i3Q44/FoPp9rNOpXV1fNZvP29laSxHQ6Ua/Xms1WLncIIYopUUyWSmdnZzJFkUgymTw9Pf28+okkKZr2C0KE58NbW8T2NkkQhM226XA4XS6X3b4FBY5vut0enucZhl1cXEQcDofH4+F4DrZwHOfqwOfzHXQQCARIkvR6vTs7O36/PxgMwka32y0IAswgoVAonU6D+Xa7fXl5mUqlJEnKZDKJDsAfdEXwmkxGo9Hz8/NIJMKybK1WA78ILAAb5XIZyBcXFyDFdsAwDBBkWYbpWCwGUiBTqVRgACjVavXk5ATJZrPFYvH6+hrINzc3UOfzedgKNGiDVOnufWQZWo1GAy6Pjo7gOQuFAnJnuNVqtf8b8BeQQQMxmUx6vd5oNK52YDAY4Gg2my0Wi7EDKKz/gOM4ZAzD7Ha7Xq//DZvrTVkGw8HlAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                     98     md 0&apos; title=&apos;&apos; src=&apos;/static/7e79fac4e761b3d25f8b55e92bd4503a/fe133/%EB%B6%95%EC%96%B4_%EC%97%86%EB%8A%94_%EB%B6%95%EC%96%B4%EB%B9%B5_%EC%95%8C_%EC%88%98_%EC%97%86%EB%8A%94_%EC%9C%88%EB%8F%84%EC%9A%B0_98%EC%9D%98_%EC%84%B8%EA%B3%84.md_0.png&apos; srcset=&apos;/static/7e79fac4e761b3d25f8b55e92bd4503a/08678/%EB%B6%95%EC%96%B4_%EC%97%86%EB%8A%94_%EB%B6%95%EC%96%B4%EB%B9%B5_%EC%95%8C_%EC%88%98_%EC%97%86%EB%8A%94_%EC%9C%88%EB%8F%84%EC%9A%B0_98%EC%9D%98_%EC%84%B8%EA%B3%84.md_0.png 190w,
/static/7e79fac4e761b3d25f8b55e92bd4503a/2edd7/%EB%B6%95%EC%96%B4_%EC%97%86%EB%8A%94_%EB%B6%95%EC%96%B4%EB%B9%B5_%EC%95%8C_%EC%88%98_%EC%97%86%EB%8A%94_%EC%9C%88%EB%8F%84%EC%9A%B0_98%EC%9D%98_%EC%84%B8%EA%B3%84.md_0.png 380w,
/static/7e79fac4e761b3d25f8b55e92bd4503a/fe133/%EB%B6%95%EC%96%B4_%EC%97%86%EB%8A%94_%EB%B6%95%EC%96%B4%EB%B9%B5_%EC%95%8C_%EC%88%98_%EC%97%86%EB%8A%94_%EC%9C%88%EB%8F%84%EC%9A%B0_98%EC%9D%98_%EC%84%B8%EA%B3%84.md_0.png 596w&apos; sizes=&apos;(max-width: 596px) 100vw, 596px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이상한 걸 발견하셨나요? 그렇습니다. MSGSRV32.EXE란 프로세스의 모듈 목록에 MSGSRV32.EXE가 없습니다. 이 무슨 얼토당토 않는 상황일까요? 그런데 이런 프로세스가 한 두개도 아니고 부지기수로 발견됩니다. 희한한 일이 아닐 수 없습니다. 해당 프로세스의 모듈 목록에 그 프로세스가 없다니요? 물론 다 없으면 98의 프로세스 관리는 그렇게 되는거구나라고 이해하고 넘어갈텐데 그렇지도 않습니다. 있는 것이 좀 더 많고, 없는 것이 나머지 입니다. 당황스럽습니다. 그 위에 부모 프로세스가 KERNEL32.DLL인 것도 조금 당황스럽긴 하네요. ㅎㅎ&lt;/p&gt;
&lt;p&gt;비밀을 파헤치기 위해서는 Toolhelp32 라이브러리를 살펴보는 것이 도움이 됩니다. Toolhelp32로 프로세스와 모듈을 열거하면 나오는 구조체는 다음과 같은 모양을 하고 있습니다. 비밀은 구조체 속에 있는 th32ModuleID에 있습니다. 지금은 사용되지 않는 이 필드를 통해서 9x는 모듈 관리를 하고 있답니다. 물론 그 체계도 우리가 상상하는 그것과는 완전히 다르답니다. 보다 더 자세한 내용이 궁금하신 분들은 도서관에 가셔서 매트 피에트릭을 영접하시기 바랍니다. 어쨌든 9x에서는 프로세스 빠진 모듈 목록이 이상한 현상은 아니랍니다.&lt;/p&gt;
&lt;p&gt;typedef struct tagPROCESSENTRY32 { &lt;/p&gt;
&lt;p&gt;    DWORD dwSize; &lt;/p&gt;
&lt;p&gt;    DWORD cntUsage; &lt;/p&gt;
&lt;p&gt;    DWORD th32ProcessID; &lt;/p&gt;
&lt;p&gt;    ULONG_PTR th32DefaultHeapID; &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DWORD th32ModuleID;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;    DWORD cntThreads; &lt;/p&gt;
&lt;p&gt;    DWORD th32ParentProcessID; &lt;/p&gt;
&lt;p&gt;    LONG pcPriClassBase; &lt;/p&gt;
&lt;p&gt;    DWORD dwFlags; &lt;/p&gt;
&lt;p&gt;    TCHAR szExeFile[MAX_PATH];&lt;/p&gt;
&lt;p&gt;} PROCESSENTRY32, *PPROCESSENTRY32;&lt;/p&gt;
&lt;p&gt;typedef struct tagMODULEENTRY32 {&lt;/p&gt;
&lt;p&gt;  DWORD dwSize;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DWORD th32ModuleID;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;  DWORD th32ProcessID;&lt;/p&gt;
&lt;p&gt;  DWORD GlblcntUsage;&lt;/p&gt;
&lt;p&gt;  DWORD ProccntUsage;&lt;/p&gt;
&lt;p&gt;  BYTE *modBaseAddr;&lt;/p&gt;
&lt;p&gt;  DWORD modBaseSize;&lt;/p&gt;
&lt;p&gt;  HMODULE hModule;&lt;/p&gt;
&lt;p&gt;  TCHAR szModule[MAX_PATH];&lt;/p&gt;
&lt;p&gt;  TCHAR szExePath[MAX_PATH];&lt;/p&gt;
&lt;p&gt;  DWORD dwFlags;&lt;/p&gt;
&lt;p&gt;} MODULEENTRY32, *PMODULEENTRY32, *LPMODULEENTRY32;&lt;/p&gt;
&lt;p&gt;덧1) 네. 여기 저기서 웅성 거리는 소리가 들립니다. NT에도 그런 일들은 많다구요. 루트킷에 그런 것들이 많다구요. 맞습니다. NT에서도 모듈 엔트리를 끊으면 9x 캡처 화면에 나온 것처럼 프로세스에 로드된 모듈 목록에 실행 파일이 존재하지 않도록 만들 수 있습니다. 하지만 그건 어디까지나 트릭을 썼을 때 이야기입니다. 노멀한 일은 아니죠.&lt;/p&gt;
&lt;p&gt;덧2) 흠, 한 십만년만에 9x 이야기를 하니 제가 왠지 올드한 프로그래머라는 느낌이 드는군요. 예전 선배님들이 8비트를 추억하는 느낌이랄까요 ㅋㅋ~ 저 시절에는 저것 또한 대단한 일이었지만, 아쉽게도 지금 생각해보면 9x는 사실 운영체제가 아니었습니다. 응용 프로그램으로 분류를 하고 싶은 마음이 굴뚝같네요. 9x를 고민하지 않아도 되는 여러분은 정말 행복한 개발자입니다. 정말로요. ㅋ~&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[윈도우 API에 사용되는 인자의 특성]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/4236</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4236</guid><pubDate>Tue, 19 Jul 2011 23:57:16 GMT</pubDate><content:encoded>&lt;p&gt;호기심이 많은 사람은 똑 같은 걸 보고도 더 많은 것을 배울 수 있습니다. 이 경우는 개발자에게도 마찬가지 입니다. 함수 원형에 사용된 인자의 종류를 토대로 다음과 같은 의문을 품는 것은 함수를 사용하는데 큰 도움을 줍니다. 더불어 함수를 잘못된 방식으로 사용하는 것을 방지해 줍니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;입력 – 과연 무슨 값을 전달할 수 있는가?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;일반적으로 문자열, 정수, 포인터, 기호화된 값이라는 네 가지 종류의 입력 형태가 존재합니다. 파일 이름과 같은 것은 문자열이 될 것이고, 버퍼의 크기를 전달하는 인자는 정수에 해당합니다. 이 두 가지 값은 자신이 적합한 값을 지정해서 넘겨야 합니다. 포인터가 입력 인자인 경우는 주로 구조체로 다량의 정보를 함수에게 공급하는 경우입니다. 이 경우에는 구조체의 각 필드의 의미와 지정할 수 있는 값을 꼼꼼히 살펴보아야 합니다. 더불어 이 정보를 NULL을 사용해서 생략 가능한지도 체크해야합니다. MSDN에 NULL로 지정해도 된다는 문구가 없다면 *절대로* 해당 정보를 생략해서는 안됩니다. 끝으로 기호화된 값을 전달해야 하는 경우에는 반드시 레퍼런스에 명시된 기호들을 보고 어떤 값을 전달해야 할지를 신중하게 결정하도록 합니다. 무작정 0을 지정하는 습관은 좋지 않습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;출력 – 이 출력 버퍼의 크기는 얼마인가? NULL을 지정할 수 있는가?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;윈도우 API가 출력 버퍼에 접근하는 방식은 크게 두 가지 입니다. 고정 크기와 가변 크기가 그것입니다. 고정 크기의 출력 버퍼는 주로 구조체를 출력 버퍼로 사용하는 경우입니다. 이 방식의 특징은 크기가 고정이기 때문에 별도로 출력 버퍼의 크기를 지정하지 않는다는 점 입니다. 가변 크기의 대표적인 형태는 문자열 버퍼를 사용하는 경우입니다. 이런 경우에는 반드시 함수 인자에 출력 버퍼의 크기를 지정하는 항목이있습니다. 가변 크기 출력 버퍼를 사용하는 경우에는 크게 두 가지를 잘 살펴야 합니다. 하나는 버퍼 크기를 올바로 지정하는 것이고, 다른 하나는 버퍼가 부족한 경우에 처리 방식입니다. 대부분의 윈도우 API는 이 버퍼가 부족한 경우에 적절한 오류코드를 반환하도록 설계되어 있습니다. 따라서 해당 오류 코드가 반환된다면 버퍼를 늘려서 다시 함수를 호출하도록 작성해야 합니다. 여기에는 흔히 사용되는 두 종류의 패턴이 있습니다. 하나는 0 크기 버퍼를 넣어의 질의를 한 다음 버퍼 크기 만큼 할당해서 함수를 호출하는 방식입니다. 다른 하나는 고정 크기 버퍼를 넣어서 호출을 한 후 부족하다면 다시 할당해서 함수를 호출하는 방식입니다. 성능을 생각한다면 두 번째 방법이 더 좋다는 것을 알 수 있습니다.&lt;/p&gt;
&lt;p&gt;다량의 출력 버퍼를 사용하는 함수들은 대부분 NULL을 통해서 해당 정보를 받지 않도록 지정할 수 있습니다. 하지만 이 또한 MSDN에 NULL로 지정해도 된다는 말이 없다면 절대로 NULL을 넘기지 마세요. 지금의 운영체제에서는 문제가 발생하지 않더라도 구식 운영체제에서는 오류가 뜰 수 있습니다.&lt;/p&gt;
&lt;p&gt;일부 함수이긴 하지만 이중 포인터를 사용해서 함수가 직접 출력 버퍼를 할당하는 경우도 있습니다. 이 경우에 함수를 호출하는 쪽에서는 출력 버퍼의 크기에 전혀 신경을 쓰지 않아도 됩니다. 하지만 반대로 반환된 출력 버퍼를 해제하는 것에 신경을 써야 합니다. 해제에 관한 부분을 꼼꼼히 읽도록 합니다. 삭제를 해야 하는 것인지, 어떤 방식을 통해서 삭제를 해야 하는지를 기억하면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;입출력 – 이 출력 버퍼의 크기는 얼마인가? NULL을 지정할 수 있는가? 함수 호출 전에 어떤 부분을 설정해 주어야 하는가?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;기본적인 접근은 출력버퍼와 동일합니다. 한 가지 틀린 점이라면 함수 호출 전에 어떤 부분을 설정해야 하는지를 확실하게 이해하는 것 입니다. 윈도우 API가 입출력 방식을 사용하는 가장 흔한 형태는 운영체제에 따라서 다른 크기의 구조체를 사용하는 경우입니다. 따라서 대부분 구조체의 크기를 미리 지정하도록 설계되어 있습니다. 이 경우 가장 주의해야 할 점은 여러분이 어떤 구조체를 사용하고 있는지 정확하게 인지하는 것 입니다. 여러분이 사용하는 구조체가 하위 버전의 운영체제에서는 지원되지 않을 수 있습니다 (&lt;a href=&quot;http://www.jiniya.net/tt/635&quot;&gt;관련 삽질&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[갓 댐 매니페스트]]></title><description><![CDATA[유저 모드 후킹 모듈을 만들고 있는데 이상하게 csrss.exe에서 해당 모듈이 로딩이 되지 않는 겁니다. GetLastError로 에러를 출력해보니 998, 잘못된 메모리 접근이라고 하더군요. 별로 하는 짓도 없는 모듈인데 csrss.exe…]]></description><link>https://jiniya.net/wp/archives/4224</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4224</guid><pubDate>Tue, 19 Jul 2011 23:57:15 GMT</pubDate><content:encoded>&lt;p&gt;유저 모드 후킹 모듈을 만들고 있는데 이상하게 csrss.exe에서 해당 모듈이 로딩이 되지 않는 겁니다. GetLastError로 에러를 출력해보니 998, 잘못된 메모리 접근이라고 하더군요. 별로 하는 짓도 없는 모듈인데 csrss.exe에서만 로딩이 안되길래 별 쑈를 다하다가 결국 dummydll을 만들었습니다. 진짜 아무것도 없는 그야말로 더미였습니다. 얼마나 깨끗한지는 다음을 보면 잘 알 수 있죠.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.jiniya.net/tt/attach/1/1703224123.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.jiniya.net/tt/attach/1/1050545700.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;그런데 이 놈 더미 조차 csrss.exe에서 로딩이 되지 않는 겁니다. 정말 어처구니 없었습니다. 왜 그럴까. 한 세 시간 쌩쑈를 하다가 결국 windbg를 띄우고 LoadLibraryW에 브포를 걸었습니다. 그리곤 트레이스를 했더랬죠. windbg에 출력되는 이 어이없는 메시지. 정말… 어처구니… 그 자체였습니다. 갓 댐 매니페스트…&lt;/p&gt;
&lt;p&gt;SXS: BasepCreateActCtx() Calling csrss server failed&lt;/p&gt;
&lt;p&gt;LDR: LdrpWalkImportDescriptor() failed to probe c:\dummydll.dll for its manifest, ntstatus 0xc0000005&lt;/p&gt;
&lt;p&gt;매니페스트를 빼주니 잘 되더군요. Visual C++의 매니페스트 옵션이 디폴트로 포함된게 화근이었더군요. CRT빼고 온 쑈를 하면서도 매니페스트는 생각도 못했답니다. 정말… 퐝당했습니다. 그나마도 windbg에 저런 메시지가 나와서 정말 다행이었습니다. 안나왔으면 *영원히* 헬로 빠질 뻔 했습니다. 고마워요. windbg. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;어쨌든 유저 모드 후킹 모듈을 만들고 계신가요? csrss.exe에 여러분의 알흠다운 dll을 인젝션 시키고 싶으신가요? 일단 매니페스트 빼고 하세요. 그게 여러분의 정신 건강에 좋습니다.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[8초 랙에 숨겨진 진실]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/4205</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4205</guid><pubDate>Thu, 30 Jun 2011 23:57:14 GMT</pubDate><content:encoded>&lt;p&gt;최근에 회사 제품에 서비스를 추가하는 코드를 작성할 일이 있었습니다. 간단한 시스템 서비스 파일을 윈도우 폴더에 복사하고 등록하고 실행하는 간단한 코드인데 이 놈을 추가하고 나서는 초기 로딩이 무지하게 느려지는 현상이 있더군요. 그것도 매번 딱 정확하게 8초가 지연되는 묘한 현상이 있었습니다. 새로 만든 서비스가 무려 600kb가 넘는 바람에, 실제 크기는 23kb인데 Themida 프로텍트를하니 크기가 무지막지하게 커지더군요. 그래서 그걸 가상 파일 시스템에서 꺼내서 기록하는데 지연이 될까란 생각이 들었습니다. 가상 파일 시스템에 저렇게 큰 놈을 넣어본 적은 없었거든요. 그래서 코드에 로그를 추가하기 시작했습니다. 생각보다 어디서 지연이 되는지를 찾기가 쉽지 않더군요. 결국 이잡듯이 한줄한줄마다 로그를 죄다 추가했습니다. 그러자 아래 결과처럼 로그가 나오더군요. 헐킈. 44초의 wriatea와 52초의 closea 사이에 수행하는 함수는 단 하난, CloseHandle 헉.~ 이건 멀까?&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 459px; margin-bottom: 16px;&apos; data-url=&apos;./8초_랙에_숨겨진_진실.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5213231233854547caa21c206d28ea12/e38a7/8%EC%B4%88_%EB%9E%99%EC%97%90_%EC%88%A8%EA%B2%A8%EC%A7%84_%EC%A7%84%EC%8B%A4.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 55.78947368421052%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACUElEQVR42k2QW08TQRTH96P5IYxPPvjgi6/amAYVsD6YgEqCCcSggcQgxvAAtaW3pfQCbekNti20ZXtZ9j6z7W5r291xr0z1hZMzk/85mV/OnD/h/xxa2Tpc+fLrw9YBFktr3/2r24GN/cX1H8vru48Xvj14uvrIt/HQt/kksLfy9eDT9uHGx83Q0sLay1fEbvA0RJ4nzxrBWD6aqaVL3VSxky3jvMlV6WShFU5R0TSVOGuQ+Xa6RGfKdLZ0U2mwOz9DRKXWNgykaX9aTXo2Q7btWpZjmo5puQocjsZTz/McBzddy5z3EbIMw8TNZCpL1JsdTVV1Xb9lWEEQJAnIosSxrCxDURRZlpckqUN3pjPdth3Lsq1/geFYnCSoZk+BcKYb3R6Dn/KChE+/z8hAARDikuOFVqs9mRkYsB3PdXG6WB/FSOKaZqajofkXQZFXoTgaAA1KishqQ2WkKqqCSwEInHcv8Bb4TmULRKLYTjYGuZ5+VOZjFyJZA3FKjlS447pC1mH8EkQvhGCRK7J2ibPztzYztD1vDpOpU2Iv0/dHDF9YD8Qnb+PTN5HJYnSC9evIdDlhBEj9HTl7n0LPj9CLMHp2gPYp4z98jOEy1RxACRk6y/RFngWSKAncba8DgQxkQeR5pkvjpmObrot9wmMd7Nx8cvqMqLWZsaYhhHiOxyAAcwoLVR0NVRV7ht2WZaCNxvd2nsOZfJEgc5dXNwzNwctmj2r1rzoc/svvcCQcjcXI40K1cXJaiCcziZPseYWq1lvl2nWJuqo3uzt7wTtv+Cw6bz0UoQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;8            md 0&apos; title=&apos;&apos; src=&apos;/static/5213231233854547caa21c206d28ea12/e38a7/8%EC%B4%88_%EB%9E%99%EC%97%90_%EC%88%A8%EA%B2%A8%EC%A7%84_%EC%A7%84%EC%8B%A4.md_0.png&apos; srcset=&apos;/static/5213231233854547caa21c206d28ea12/08678/8%EC%B4%88_%EB%9E%99%EC%97%90_%EC%88%A8%EA%B2%A8%EC%A7%84_%EC%A7%84%EC%8B%A4.md_0.png 190w,
/static/5213231233854547caa21c206d28ea12/2edd7/8%EC%B4%88_%EB%9E%99%EC%97%90_%EC%88%A8%EA%B2%A8%EC%A7%84_%EC%A7%84%EC%8B%A4.md_0.png 380w,
/static/5213231233854547caa21c206d28ea12/e38a7/8%EC%B4%88_%EB%9E%99%EC%97%90_%EC%88%A8%EA%B2%A8%EC%A7%84_%EC%A7%84%EC%8B%A4.md_0.png 459w&apos; sizes=&apos;(max-width: 459px) 100vw, 459px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;윈도우는 왜 우리 파일만 CloseHandle을 하는데 8초나 지연을 시킬까요? 근데 또 왜 유독 그놈의 서비스 파일만 8초나 지연이 될까요? 온갖 생각을 다했습니다. “CloseHandle slow” 따위로 구글링을 했죠. 정말 다양한 이야기가 있었습니다. 심지어는 NTFS의 성능을 운운하는 이야기들까지 있더군요. 그런데 우리는 고작 600kb짜리 서비스잖아요. 구글링을 한 30분쯤 했는데도 뾰족한 답은 없더군요. 그러다 불현듯 스치는 생각. 백신. 후킹. 필터. 그렇습니다. 그 PC에 백신이 설치가 되어 있었드랬죠. MS Security Essential이란 놈이 말입니다. 실시간 감시기를 중지하고 프로그램을 켰습니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 459px; margin-bottom: 16px;&apos; data-url=&apos;./8초_랙에_숨겨진_진실.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/3546aad0c17e17ad10609ddc7ae100ab/e38a7/8%EC%B4%88_%EB%9E%99%EC%97%90_%EC%88%A8%EA%B2%A8%EC%A7%84_%EC%A7%84%EC%8B%A4.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 55.78947368421052%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACUUlEQVR42k2R208TQRTG90/zjzA++eCDL74qGoLh6oNJUUwwQgwYEhWNkQdutaVdpAVKoRdgt0W23e52uzuzlynbbi97obuzdYDE+OV7OOfL/M7JzFCj77cjS5uRjz/fLK9HljYm330ZnV2ZWVibmP82Nb/6cOzTvcezD0Y+3B9ZfDTzPbK8PreysfB2cXtybO7FS2p183A7ebJ7WNrYOYqlztN5IZWrHRSIq0en/O9jLppi4mkmmSnT2Uo6z+8X+IN8tViWP/+IUkW24tieaXa4y2q3ZwdB6Pt44GPfD5vItDr94XCIMQlDf4AHA+x5vuv6JKT39qkLTuhYluM4jYYMoapphq5qigJ0A0EAZQVomlbja33bCQIyMfBvFIQY7x+dUAxXb7fatu0IoiTLAEJNAVAQ6yqZQvjb9pKr9G2XbAvwMAyJQ1LnzsoUV2u4vc615yEVtJBqXRktpDU10DablonaTb2NoAGV4X+6g7MFltot8KlLKyPYsQLYOVOTrJE412NFQJdQkkUJxoifwq2cklOCvBJkG4FkBgQncCbPUl/T4ljcfR51phPd6UR/PNabiPemdnrj8f407c7Qzivafr3nPf11/SzqPVn31hj3Ds4Wy9RZqdK1TNe1ZamuKrKhQQ0qiiQaumZoqgpBQ6whXcXYD0OyExMywDdwKlukytVGt9PxPA8AqOs6QsjQdVI3b0US8ubkF1pm69+d8R2cyVN0luFEpaag8z9CjuEYTipVpNMyz3ISW7k1VycnLmpAhFciNAXQ5GUkaebW7vFfw80wlL9zE64AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;8            md 1&apos; title=&apos;&apos; src=&apos;/static/3546aad0c17e17ad10609ddc7ae100ab/e38a7/8%EC%B4%88_%EB%9E%99%EC%97%90_%EC%88%A8%EA%B2%A8%EC%A7%84_%EC%A7%84%EC%8B%A4.md_1.png&apos; srcset=&apos;/static/3546aad0c17e17ad10609ddc7ae100ab/08678/8%EC%B4%88_%EB%9E%99%EC%97%90_%EC%88%A8%EA%B2%A8%EC%A7%84_%EC%A7%84%EC%8B%A4.md_1.png 190w,
/static/3546aad0c17e17ad10609ddc7ae100ab/2edd7/8%EC%B4%88_%EB%9E%99%EC%97%90_%EC%88%A8%EA%B2%A8%EC%A7%84_%EC%A7%84%EC%8B%A4.md_1.png 380w,
/static/3546aad0c17e17ad10609ddc7ae100ab/e38a7/8%EC%B4%88_%EB%9E%99%EC%97%90_%EC%88%A8%EA%B2%A8%EC%A7%84_%EC%A7%84%EC%8B%A4.md_1.png 459w&apos; sizes=&apos;(max-width: 459px) 100vw, 459px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;원래 이랬어야 하는 거겠죠. 그놈이 범인이 맞았습니다. 그러면 이제 어떻게 해야 할까요? 백신이 문제니깐 그냥 그러고 끝내면 될까요? 안되겠죠. 저희 제품은 백신이 설치 되어 있으면 매번 8초씩 로딩이 느려지는 현상이 있습니다. 이럴수는 없잖아요. 얄팍하게 확장자를 exe가 아닌 걸로 변경해 봤습니다. 히지만 요즘 백신, 그렇게 호락호락하지 않더군요. 몇 가지 꼼수를 써보다가 안되서 그냥 파일을 기록하지 않기로 했습니다. 일단 먼저 읽어서 우리가 가지고 있는 버퍼랑 똑같으면 말이죠. 물론 최초 설치 시에는 느려지지만 그 담부터는 기록하지 않으니깐 8초같은 어마어마한 랙은 발생하지 않았습니다.&lt;/p&gt;
&lt;p&gt;근데 600kb짜리 파일 하나 검사하는데 8초는 좀 심한거 아닌가요? MS Security Essesntial 말이죠. Themida로 프로텍트해서 그럴까요? 어쨌든 좀 심했어요. 8초는 ㅠㅠ~ 파일 I/O가 비정상적으로 느리다면 일단 백신부터 의심해 보세요.&lt;/p&gt;
&lt;p&gt;덧) 서비스 설치 코드를 작성하다 알게 된 사실인데요. 여러분들이 서비스 조작 코드를 막 싸지르다보면 의도하지 않은 결과가 나올 수 있습니다. 무슨 말이냐하면 서비스를 설치하고 구동하는 데에는 관리자 권한이 필요한데, 정지시키고 삭제하는데는 일반 권한으로도 되거든요. 그래서 서비스 설치 코드를 삭제, 설치 이렇게 만들고(MSDN 샘플이 그렇게 되어 있습니다), 그 코드를 그냥 실행 한다면 일반 계정에서 실행했을때 서비스가 사용안함 되는 요상한 문제가 생길 수 있습니다.&lt;/p&gt;
&lt;p&gt;덧2) 비교해서 파일을 복사하는 것과 그냥 막 복사하는 것 사이에는 어떤 차이가 있을까요? 비교해서 복사하는게 더 우아해 보이시나요? 근데 해킹을 막는 입장에서 본다면 막 복사하는게 더 좋습니다. 왜냐하면 if문이 많다는건 손쉽게 우회될 수 있다는 걸 의미하기 때문입니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[소리통 2011.5.8.442]]></title><description><![CDATA[친절한 회사 동료가 mp3 파일을 공유해 줬는데, 안타깝게도 이소라의 바람이 분다 mp3 파일이 소리통에서 재생이 되지 않더군요. 안습한 시츄에이션을 고치기 위해서 주말에 작업을 좀 했습니다. 그래서 드디어 이소라의 바람이 분다 mp…]]></description><link>https://jiniya.net/wp/archives/4153</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4153</guid><pubDate>Mon, 09 May 2011 23:57:13 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 338px; margin-bottom: 16px;&apos; data-url=&apos;./소리통_2011_5_8_442.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/c04e2f3de86e88525a2ca2d3dfe6954f/74935/%EC%86%8C%EB%A6%AC%ED%86%B5_2011_5_8_442.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 31.578947368421055%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABeUlEQVR42gFuAZH+AMO/vNXTz8jY48DK1MXR3snX4MnX5sXe98Le+cLg+7vX8brU7cLb9MDQ4MTO2LzJ1cC3vM6RitOZkLiZmgCipriCiaGFl6+BkKuHmLOFla6Dla98lLh6lLd8lblyiap0iqd8kK14i6l6jKeAkq+DkqyHjqOEjKWWoLEAa3+iPElkUlVhNkBbOUBUTVJgS1JkKzxrMD9mMkJpWVpiRUtZWlldS1NlS09dM0RyTFVoWFxnQEphe4KJAHaIrj5QgE1be0dXfUtZfkRTeklZfUNYjkdajEBWjEpbhE5cflpjfElagUlYe0VZjE1bfE5Zd0FUgneDmAB9krdGXpxMZaRGYaZHYqVFYaRFYKRHYaNGYKNRZ6FMZaFEYKVEX6RGYKRFYKRHYaNEYKVKZKNLY6Bzh64Ak6fHeZLAeZLCXHWnVm6eWHCgV3CgV3ChV2+hX3ScXnKZVW2eWHCeWHCfWHCgWXGhWXGhX3WeYXSbfo+pVCe3PDAvwt4AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;    2011 5 8 442 md 0&apos; title=&apos;&apos; src=&apos;/static/c04e2f3de86e88525a2ca2d3dfe6954f/74935/%EC%86%8C%EB%A6%AC%ED%86%B5_2011_5_8_442.md_0.png&apos; srcset=&apos;/static/c04e2f3de86e88525a2ca2d3dfe6954f/08678/%EC%86%8C%EB%A6%AC%ED%86%B5_2011_5_8_442.md_0.png 190w,
/static/c04e2f3de86e88525a2ca2d3dfe6954f/74935/%EC%86%8C%EB%A6%AC%ED%86%B5_2011_5_8_442.md_0.png 338w&apos; sizes=&apos;(max-width: 338px) 100vw, 338px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;친절한 회사 동료가 mp3 파일을 공유해 줬는데, 안타깝게도 이소라의 바람이 분다 mp3 파일이 &lt;a href=&quot;http://jiniya.net/wp/archives/tag/%EC%86%8C%EB%A6%AC%ED%86%B5&quot;&gt;소리통&lt;/a&gt;에서 재생이 되지 않더군요. 안습한 시츄에이션을 고치기 위해서 주말에 작업을 좀 했습니다. 그래서 드디어 이소라의 바람이 분다 mp3 파일을 제대로 재생할 수 있는 소리통을 만들었습니다. 거짐 일년에 한 번 업데이트 하는 것 같군요. 어버이날 에디션에는 다음과 같은 상콤한 기능들이 업데이트 되었습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;거의 모든 종류의 mp3 파일을 플레이할 수 있도록 고쳤습니다.&lt;/li&gt;
&lt;li&gt;ShoutCast 소스 필터 성능이 좀 더 좋아졌습니다.&lt;/li&gt;
&lt;li&gt;선호도 순으로 정렬하는 메뉴가 생겼습니다. 자주 들은 곡 순서대로 정렬해 주는 기능입니다. 따라서 좋아하는 노래를 끝까지 자주 들어야 효과가 있습니다. 거대한 목록에서 자신이 좋아하는 곡을 찾는데 도움을 줄 수 있을 것 같아요. 멜론 Top 100 이런 목록을 많이 가지고 있으시다면 유용할 겁니당 ㅎㅎ&lt;/li&gt;
&lt;li&gt;전역 단축키 사용 메뉴가 생겼습니다. 해당 메뉴를 활성화 하면 CTRL+SHIFT+N을 사용해서 다음 곡을, CTRL+SHIFT+P를 사용해서 이전 곡으로 이동하실 수 있습니다. 소리통에 포커스가 없는 상태에서도 손쉽게 곡을 이동할 수 있겠죠. CTRL+SHIFT+S를 사용해서 재생 시작을, CTRL+SHIFT+T를 사용해서 재생 중지 시킬 수도 있습니다.&lt;/li&gt;
&lt;li&gt;폴더 열기 기능이 추가되었습니다. d를 누르면 선택된 파일이 위치한 폴더를 열어 줍니다.&lt;/li&gt;
&lt;li&gt;앨범 볼륨 조절 기능이 추가되었습니다. SHIFT+왼쪽, SHIFT+오른쪽 키를 눌러서 앨범 전체 볼륨을 일괄적으로 낮추거나 올릴 수 있습니당.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;업데이트 된 파일은 아래 경로에서 다운로드 받으시면 됩니당.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/bins/soritong/soritong.2011.5.8.442.zip&quot;&gt;soritong.2011.5.8.442.zip&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[xfav 0.9.7]]></title><description><![CDATA[xfav 프로그램이 업데이트 되었습니다. 다음 사항이 변경되었습니다. 탐색기에서 폴더나 파일 이름을 변경하는 에디터 상자에서 ESC를 눌렀을 때 메뉴가 팝업되지 않도록 변경되었습니다. 에디터 상자에서 ESC…]]></description><link>https://jiniya.net/wp/archives/4089</link><guid isPermaLink="false">https://jiniya.net/wp/archives/4089</guid><pubDate>Wed, 13 Apr 2011 23:57:12 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/archives/2821&quot;&gt;xfav 프로그램&lt;/a&gt;이 업데이트 되었습니다.&lt;/p&gt;
&lt;p&gt;다음 사항이 변경되었습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;탐색기에서 폴더나 파일 이름을 변경하는 에디터 상자에서 ESC를 눌렀을 때 메뉴가 팝업되지 않도록 변경되었습니다. 에디터 상자에서 ESC 키를 누르면 정상적으로 편집이 취소 됩니다.&lt;/li&gt;
&lt;li&gt;“탐색기 창 모두 닫기” 메뉴를 사용했을 때 IE 창까지 종료되는 문제가 수정되었습니다. 이제 탐색기 창만 종료됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;아래 경로에서 다운로드 받으실 수 있어욤.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/bins/xfav/xfav32.0.9.7.zip&quot;&gt;xfav 0.9.7 32비트 버전&lt;/a&gt;&lt;a href=&quot;http://www.jiniya.net/bins/xfav/xfav64.0.9.7.zip&quot;&gt;xfav 0.9.7 64비트 버전&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[자이언트]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/3554</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3554</guid><pubDate>Thu, 07 Apr 2011 23:57:11 GMT</pubDate><content:encoded>&lt;p&gt;챙겨보던 드라마, 자이언트가 끝났다. 정말 재밌었다. 난 최고의 드라마로 모래시계와 아일랜드를 항상 꼽는데, 이 녀석을 추가해도 될만큼 재미있게 봤다. 다소 통속적이지만 그 시대를 정말 잘 표현한 것 같다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;조필연: 재춘아, 너도 날 만난 걸 후회하냐?&lt;/p&gt;
&lt;p&gt;고재춘: 의원님 덕분에 한 생전 신명나게 놀았습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;작위적인 막장 스토리, 토건족 쉴드 드라마라는 말들도 많은데 난 참 재미있게 봤다. 살면서 저정도 스토리도 없을 만한 인생이 있을까 싶기도 하고, 누구의 인생을 드라마로 만들어도 이런 이야기는 60회 정도는 나오지 않을까 싶기도 했다. 나이가 들수록 정말 희한한 일들을 더 겪어서 그런지도 모르겠다. 살다보면 이런 일도 있고, 저런 일도 있는 거지. 고재춘이 말처럼 어떤 삶을 살았건 한 생전 신명나게 놀다가면 그 뿐 아닐까. 누구나 자신의 신념을 위해 사는 거니깐. 그렇다고 조필연처럼 살자는 이야기는 아니다. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;모든 것이 사실 시작보다 끝맺음이 더 어려운 법이다. 드라마도 그런데 자이언트 엔딩은 진짜 짱이었다. 그들이 가장 행복했던 순간을 회상하는 장면에서 박진희의 다음 대사가 오버랩 되는데 온몸에 전율이 그냥. 너무 구구절절하게 해피엔딩임을 안보여 준것도 잘 처리한 것 같은 부분. ^^;;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;황정연: 빨리와요. 당신 막내 동생, 준모씨가 찾아왔어요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[가면]]></title><description><![CDATA[10년 전이네.…]]></description><link>https://jiniya.net/wp/archives/2462</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2462</guid><pubDate>Wed, 16 Mar 2011 23:57:10 GMT</pubDate><content:encoded>&lt;p&gt;10년 전이네.&lt;/p&gt;
&lt;p&gt;7살이나 많았던 그 선배가 그 허름한 술집에서 그랬지.&lt;/p&gt;
&lt;p&gt;사는 건 다 전략이라고. 공부도 그렇고, 사업도 그렇고, 연애도 그렇다고 말이야.&lt;/p&gt;
&lt;p&gt;아직은 순수했던 때였을까? 사람을 만나는 것도 그렇다는 이야기에 발끈했었지.&lt;/p&gt;
&lt;p&gt;그냥 썩 유쾌하지만은 않았던 것 같아.&lt;/p&gt;
&lt;p&gt;시간 참 많이 흘렀다.&lt;/p&gt;
&lt;p&gt;나이 탓일까? 이제는 그 선배 말을 조금은 이해할 수 있을 것도 같다는 생각이 들었어.&lt;/p&gt;
&lt;p&gt;선배가 말했던 그 전략 이란거 말이야. 안그래도 그런 척, 그래도 안그런 척.&lt;/p&gt;
&lt;p&gt;어쩌면 그건 전략이라기 보다는 그냥 쉬운것 같아.&lt;/p&gt;
&lt;p&gt;골치 아프지도 않고 말이야.&lt;/p&gt;
&lt;p&gt;그래서 다들 그렇게 사는지도 모르지.&lt;/p&gt;
&lt;p&gt;그 날 가면 속 네 모습을 보았을 때, 그 날 그 사람의 가면 속 모습을 들었을 때.&lt;/p&gt;
&lt;p&gt;그냥 미안하단 생각이 들었어. 이해도 되고 말이야.&lt;/p&gt;
&lt;p&gt;…&lt;/p&gt;
&lt;p&gt;ATM 기계에 올려져 있었던, 누군가 흘리고 간 그 만원짜리 한장에&lt;/p&gt;
&lt;p&gt;해맑게 웃으며 원두막으로 뛰어갔던 그 날이 생각나.&lt;/p&gt;
&lt;p&gt;평생을 그렇게 살 것 같았는데, …&lt;/p&gt;
&lt;p&gt;쉽지 않은 것 같다. 정말.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[xfav 0.9.6]]></title><description><![CDATA[xfav 프로그램이 업데이트 되었습니다. 다음 사항이 변경되었다는군요. ㅋㅋ 사용 도중 특정 시점부터 메뉴가 팝업 되지 않는 문제가 해결되었습니다. 캡스락 키를 ESC…]]></description><link>https://jiniya.net/wp/archives/3989</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3989</guid><pubDate>Tue, 15 Mar 2011 23:57:09 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/archives/2821&quot;&gt;xfav 프로그램&lt;/a&gt;이 업데이트 되었습니다.&lt;/p&gt;
&lt;p&gt;다음 사항이 변경되었다는군요. ㅋㅋ&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;사용 도중 특정 시점부터 메뉴가 팝업 되지 않는 문제가 해결되었습니다.&lt;/li&gt;
&lt;li&gt;캡스락 키를 ESC 키로 매핑하는 기능이 추가되었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;잡메뉴에 들어 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;메뉴가 한글로 변경되었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;아래 경로에서 다운로드 받으실 수 있어욤.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/bins/xfav/xfav32.0.9.6.zip&quot;&gt;xfav 0.9.6 32비트 버전&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/bins/xfav/xfav64.0.9.6.zip&quot;&gt;xfav 0.9.6 64비트 버전&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[py2exe, ImportError 어떻게 해결하나요?]]></title><description><![CDATA[파이썬으로 개발한 모듈을 배포할 때 py2exe 모듈을 많이 사용하는데요, 이게 종종 배포를 하면 최종 실행된 파일에 특정 모듈이 포함이 되지 않아서 ImportError…]]></description><link>https://jiniya.net/wp/archives/3954</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3954</guid><pubDate>Wed, 09 Mar 2011 23:57:08 GMT</pubDate><content:encoded>&lt;p&gt;파이썬으로 개발한 모듈을 배포할 때 py2exe 모듈을 많이 사용하는데요, 이게 종종 배포를 하면 최종 실행된 파일에 특정 모듈이 포함이 되지 않아서 ImportError가 나는 경우가 있습니다. 전에는 잘됐는데, … 전에는 잘됐는데, … 이러기를 한 30분 한 것 같네요. 답은 py2exe 사이트에 친절하게 잘 나와 있었습니다. 등잔 밑이 어둡다더니. ㅋㅋ ~아래 페이지에 해결 방법이 나와 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.py2exe.org/index.cgi/ExeWithEggs&quot;&gt;http://www.py2exe.org/index.cgi/ExeWithEggs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;전 ply 모듈이 임포트가 안되는 문제였는데요. ply 모듈을 –always-unzip 옵션으로 새로 설치하니 해결이 됐습니다.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] C++ 가상 함수의 정렬 순서]]></title><description><![CDATA[고급 언어를 사용하는 대다수 개발자들이 하는 가장 큰 착각은 고급언어와 최종 기계어가 1:1로 매핑된다는 상상이다. 쉽게 말해서 그냥 눈에 보이는 대로 믿는 것을 말한다. 대표적인 예가 최적화 이슈다. 많은 C언어 개발자들이 i=i+1보다는 ++i…]]></description><link>https://jiniya.net/wp/archives/3946</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3946</guid><pubDate>Wed, 09 Mar 2011 23:57:07 GMT</pubDate><content:encoded>&lt;p&gt;고급 언어를 사용하는 대다수 개발자들이 하는 가장 큰 착각은 고급언어와 최종 기계어가 1:1로 매핑된다는 상상이다. 쉽게 말해서 그냥 눈에 보이는 대로 믿는 것을 말한다. 대표적인 예가 최적화 이슈다. 많은 C언어 개발자들이 i=i+1보다는 ++i가 더 최적화된 코드라고 생각한다. 여기서 중요한 것은 그것이 진실인지 아닌지가 아니다. 단지 글자 수가 작기 때문에 더 최적화된 코드라고 생각한다는 그 과정이다. 삼항 연산자를 배운 C언어 개발자들은 다음과 같은 맛깔스런 코드를 쓰면서 자부심을 느끼곤 한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;meaning &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; flag &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;on&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;off&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그러면서 다음과 같이 if문을 쓰는 개발자들을 오스트랄로피테쿠스 취급하는 것 또한 잊지 않는다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;flag&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; meaning &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;on&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; meaning &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;off&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;하지만 그런 그들도 경험이 쌓이고, 연륜도 생기고, 시야가 넓어지고, 마음도 유해지고 하다 보면 이런 것들이 얼마나 부질없는 생각이었는지를 배운다. 그 즈음이 되면 더 이상 고급 언어와 최종 단계의 결과물 사이에는 그렇게 큰 연관성이 없다는 것을 알게 되고, 더 이상 보이는 것에 현혹되지 않아야겠다는 생각을 한다. 하지만 그렇게 굳게 마음을 먹어 보지만 보이는 것에 혹하지 않기란 생각보다 쉽지 않다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_V1&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    size_t size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; first&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; V1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;_V2&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    size_t size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; first&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; second&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; V2&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위와 같은 구조체의 확장 방식은 C언어에서 널리 사용되는 기법이다. V1 구조체를 V2 구조체로 자연스럽게 확장해 나가는 이 방식은 군더더기가 없고 확장된 함수를 만들기도 쉽고 관리하기도 편하다는 장점을 가지고 있다. 윈도우의 수많은 API들도 이러한 방식으로 95에서 98로, 2k에서 XP로 구조체를 확장해가며 기능을 늘려왔다. 이런 방식을 사용할 수 있는 가장 큰 근간은 바로 구조체의 멤버가 우리가 바라보는 그것과 완전히 일치한다는 점에 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IV1&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;M1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;M1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IV2&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;M1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;M1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;virtual&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;M1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그렇다면 위와 같은 가상 함수의 정렬 순서는 어떨까? 과연 저 함수들도 구조체와 동일한 방식으로 매핑될까? 결론만 말하자면 가상 함수의 정렬 순서는 눈에 보이는 그것과는 다르다. Visual Studio는 위 예제에 해당하는 가상 함수들을 다음과 같이 배치한다. IV1의 경우는 M1(int a)은 0번째에, M1()은 1번째에 위치시킨다. IV2의 경우에는 M1(int a, int b)가 0번째에, M1(int a)가 1번째에, M1()이 2번째에 배치가 된다. 이 말이 의미하는 바는 이 녀석들이 바이너리 단계에서는 전혀 호환되지 않는다는 것이다. 즉, IV1으로 컴파일된 모듈에다 IV2의 포인터를 집어넣으면 크래시가 난다는 소리다. 이 경우에 원래 의도했던 형태로 작성을 하기 위해서는 C++의 상속을 이용하는 것이 바람직하다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[녹차라떼]]></title><description><![CDATA[2007년 이었던가, 2008년 이었던가, 언젠가 K가 마트에서 정말 맛있는 거라면서 녹차라떼를 사온 적이 있었다. 그 때는 나는 이 놈의 존재감조차 몰랐던지라 난생 처음 맛보게 되었다. K…]]></description><link>https://jiniya.net/wp/archives/3890</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3890</guid><pubDate>Tue, 08 Mar 2011 23:57:06 GMT</pubDate><content:encoded>&lt;p&gt;2007년 이었던가, 2008년 이었던가, 언젠가 K가 마트에서 정말 맛있는 거라면서 녹차라떼를 사온 적이 있었다. 그 때는 나는 이 놈의 존재감조차 몰랐던지라 난생 처음 맛보게 되었다. K가 집에서 만든 녹차라떼를 먹고는 대뜸 그랬다. 이런 건 강아지나 주라고… ㅋㅋㅋ~ 녹차도 아닌 것이 라떼도 아닌 것이 별로였다.  녹차라떼와의 첫 만남은 그랬다.&lt;/p&gt;
&lt;p&gt;커피숍에서 내가 골르는 메뉴는 딱 하나다. 여름이나 겨울이나, 눈이오나 비가오나 아이스 카페 모카, 크림 뺀 아이스 카페 모카만 먹었다. 스타벅스가 우리 나라에 들어오기 전에 캐나다를 갔을 때 이 놈과 처음 만나게 됐는데 그 맛이 너무 강렬했던 것이다. 당연한 수순이겠지만 그 해 여름부터 나는 이놈에게 중독됐고, 커피숍만 가면 메뉴판도 안보고 이 놈만 주문하기에 바빴다. 뜨거운 걸 싫어하면서 적당히 단 걸 좋아하는 나에게는 꿀같은 메뉴였다.&lt;/p&gt;
&lt;p&gt;유난히도 추운 겨울이었다. 서울 올라온지 제법 해가 지났지만 이렇게 뼛속까지 에이는 추위를 안겨주는 겨울은 정말 처음이었다. 그래서였을까? 나의 고정 메뉴에도 작은 변화가 생겼다. 너무 추워서 차마 아이스를 먹기는 그랬던 것이다. 그러다 생각난 이 놈. “커피숍 녹차라떼는 어떨까?”라는 생각으로 먹었는데, 내가 난생 처음 맛보았던 하우스 메이드 녹차라떼랑은 격이 달랐다…. 말 그대로 신세경… 우왕 굳… 그 날 K도 이 맛을 떠올리며 사온 거였겠지라는 생각이 절로 났다. 그리곤 너무 당연하다는 듯이 나는 녹차라떼에 중독돼 버렸다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 592px; margin-bottom: 16px;&apos; data-url=&apos;./녹차라떼.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/ec41769a6232065e6a766ee4cde43340/d9142/%EB%85%B9%EC%B0%A8%EB%9D%BC%EB%96%BC.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 24.736842105263158%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAIAAADKYVtkAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAA6klEQVR42o2PQU7DMBBFczDuwopjsETqpkdAXcKmErBtF+wQEiABYtOSpKoJjR07iYPdeCx7jJNwAP7i62tGX/MmQfQerUcXQgDjAYaAiNGNMZSytpVfRSHqRkrJOY8Ta20Ylehjt/14OOw3VSVYwzefubVu2imlsixnrErTrCi+y5ISQrJ810rZ970BSCDg4/ksXSzz8vV2fnZ3PfcBp7KBnjEm6rppGiEEHXM36CdCQSxb595X693z24FvF6cnN5cXseb9cNyjUarT+qi1jhSTO/fHNWDH9wjZ05IC6Kvl7Onlfiz78A/9Ajb6Fc7zA0DzAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;     md 0&apos; title=&apos;&apos; src=&apos;/static/ec41769a6232065e6a766ee4cde43340/d9142/%EB%85%B9%EC%B0%A8%EB%9D%BC%EB%96%BC.md_0.png&apos; srcset=&apos;/static/ec41769a6232065e6a766ee4cde43340/08678/%EB%85%B9%EC%B0%A8%EB%9D%BC%EB%96%BC.md_0.png 190w,
/static/ec41769a6232065e6a766ee4cde43340/2edd7/%EB%85%B9%EC%B0%A8%EB%9D%BC%EB%96%BC.md_0.png 380w,
/static/ec41769a6232065e6a766ee4cde43340/d9142/%EB%85%B9%EC%B0%A8%EB%9D%BC%EB%96%BC.md_0.png 592w&apos; sizes=&apos;(max-width: 592px) 100vw, 592px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;회사 근처에 정말 미친듯이 커피 전문점이 많은데, 그 중에서도 HOLLYS 녹차라떼가 제일 맛있다. HOLLYS에서 줄서서 녹차라떼를 시킨 다음 햇살이 잘드는 푹신한 쇼파에 — 점심 시간에는 쫌 빡쎄다. — 앉아서 푸는 노가리는 일품이다. 이 밥보다 비싼 커피를 마시려고 줄 서 있는 사람을 보면 토가 절로나오는데 일단 맛을보고 나면 그 기나긴 줄이 조금 이해가 가기도 한다. 물론 맛도 일품이지만 이 된장짓을 하고 나면 “디버깅 200% 가속 버프”라는 아름다운 보너스 효과를 받을 수 있다. 이 버프 받고 디버깅하면 부왘… 쩐다… ㅋㅋ~ 라떼를 마시다 2% 확률로 버그가 자동으로 해결되는 신세경을 경험하는 경우도 있다고 하니 뉴요커 개발자에게 녹차라떼는 센스가 아닌 필수라고 할 수 있겠다.&lt;/p&gt;
&lt;p&gt;이런 아름다운 녹차라떼에게도 치명적인 한 가지 단점이 있는데, 다름아닌 가난한 프로그래머가 마시기에는 좀 비싸다는 점이다. 사실 좀 비싸다. 그래서 겁도 없이 몇 년만에 다시 하우스 메이드 녹차라떼에 도전해 보려고 하는데 그 맛이 나올지는… 후훗… 그 맛이 나오면 HOLLYS가 그리 비싼 가격에 팔지는 않았겠지? ㅎㅎ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[IIS7 + FastCGI PHP는 진리…]]></title><description><![CDATA[이번에 회사 로그 서버를 한 대 더 확충했다. 리눅스는 당췌 관리하기가 빡쎄서 윈도우를 설치했다. 서버 2008을 설치하고는 리눅스에서 쓰던 파이썬 스크립트를 그대로 가져왔다. IIS7에 파이썬을 돌리기 위해서는 CGI…]]></description><link>https://jiniya.net/wp/archives/3860</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3860</guid><pubDate>Sun, 06 Mar 2011 23:57:05 GMT</pubDate><content:encoded>&lt;p&gt;이번에 회사 로그 서버를 한 대 더 확충했다. 리눅스는 당췌 관리하기가 빡쎄서 윈도우를 설치했다. 서버 2008을 설치하고는 리눅스에서 쓰던 파이썬 스크립트를 그대로 가져왔다. IIS7에 파이썬을 돌리기 위해서는 CGI 핸들러 매핑만 해주면 끝이었는데 리눅스에서 그 삽질을 한 걸 생각하면서 다시한번 GUI의 위대함을 느꼈다. ㅋㅋ~ 어쨌든 파이썬 스크립트는 몇 년간 써왔던 것인만큼 문제없이 잘 동작했다.&lt;/p&gt;
&lt;p&gt;문제는 그 다음이었다. 주말에 심심해서 서버에 로그인을 했는데 CPU가 100%에서 떨어지질 않는 것이었다. python.exe가 뻥 좀 쳐서 한 200개는 떠 있었다. 이건 뭥밍. 이랬다. 테스트 삼아 피크 시간에 쿼리를 날려보니 한 5-6초가 걸려서 처리가 되는 것이었다. 난 파이썬빠지만 이건 좀 아니라는 생각이 들었다. 그래서 스크립트를 asp.net으로 바꾸면 좀 나아질까 싶어서 asp.net 문법을 좀 살펴보는데 스크립트를 asp.net으로 바꾸기가 좀 껄끄러웠다. raw data를 처리하는 부분이 있는데 그런 부분 지원이 좀 그랬다. 그래서 다음으로는 그러면 그냥 C++로 컴포넌트를 만들어서 넣을까라는 생각이 들었다. 네이티브로 도니깐 빠르지 않을까라는 생각이었는데, 난 그 부분에 대해서는 아는게 하나도 없었다. 검색을 좀 해보니 죄다 C#에 Managed C++ 관련 내용 뿐이었다. 머가 먼지도 모르겠어서 포기할 즈음에 발견한 글은 다름 아닌 MS와 php가 같이 작업해서 사고를 쳤다는 내용의 글이었다. performance 관련 검색을 하다가 발견한 글이었는데 IIS7이라면 자기라면 php를 선택하겠다는 논지의 글이었다. 그리고는 다음 동영상이 링크되어 있었다. 동영상을 보고도 뭐 크게 차이가 있을까 싶었지만 그래도 속는 셈치고 한 번 바꿔봤다. CPU가 탈까 걱정스러웠기 때문이다.&lt;/p&gt;
&lt;p&gt;150줄 안팎의 아주 간소한 스크립트를 php로 바꾸면서 내가 다시금 느낀 것은 python은 위대하다는 것. 정말 python은 스크립트를 짤 때 내 멋대로 짜도 잘 돌아간다. 문제를 푸는데 집중할 수 있다. 문법적인 문제로 크게 고민할 부분이 없다는 점이다. 아주 간단한 몇 가지 규칙으로 거의 대부분의 문제를 깔끔하게 처리할 수 있다는 점이 핵심 포인트라 할 수 있겠다. 그런데 php는? 거추장스러운 함수를 일일히 검색해서 인터페이스를 확인해야 했다. 아주 간단한 조작조차도 함수가 없으면 안되는 ㅠㅠ~ 물론 php.net 사이트가 굉장히 잘 만들어져 있기 때문에 그닥 문제될 건 없지만 그래도 귀찮은 건 어쩔 수 없었다. 거기다 pack/unpack 함수 인터페이스는 뭔가 맘에 안들었다. 그래도 Microsoft님들과 고생해서 뭔가 만들었다니 기대를 하고는 힘겹게 스크립트 한 줄 한 줄을 번역했다.&lt;/p&gt;
&lt;p&gt;두둥. 끝나고 IIS7에 php를 설치했다. 여기서 다시 한 번 놀랐는데 예전처럼 뭐 php 사이트에서 파일 받아서 설치하고 이런 과정이 없었다. 그냥 웹플랫폼 관리자라는 곳에서 php 설치 클릭하니깐 알아서 다 끝났다. 이게 MS 방식 아니겠는가? ㅋㅋㅋ~ 그리고는 php 파일을 돌렸는데 너무 우아하게 잘 돌아가는 것이 아닌가. 풉. 새벽 시간이라 접속자가 별로 없어서 기존 python에 비해서 얼마나 좋아졌는지는 알 수는 없었다.&lt;/p&gt;
&lt;p&gt;날은 밝았고 다시 사람들이 게임할 시간. 서버에 들어갔다. 어제 100%던 CPU는 과연 어떻게 됐을까? 10% 밑에서 놀고 있었다. 그 많던 python.exe는 몇 안되는 php-cgi.exe로 바꼈다. 우왕 FastCGI이거 장난 아니다. ㅋㅋ~ 쿼리를 날려봤다. 바로 응답이 온다. 그렇지 이거다. 유튜브 동영상은 진리였다. IIS7을 쓴다면 php로 가자. python은 우아하고 아름답고 순결하지만 그게 전부다. 현실 세계에서 버티려면 그런 것쯤은 버리고 타협할 필요도 있는 법이다.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[push 할 때 조심할 것]]></title><description><![CDATA[너무 어처구니 없는 실수를 해서 끄적여 봅니다. 어제부터 xfavorites 코드를 좀 수정하고 있었는데요. 이 놈이 64비트에서는 WH_KEYBOARD…]]></description><link>https://jiniya.net/wp/archives/3799</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3799</guid><pubDate>Mon, 28 Feb 2011 23:57:04 GMT</pubDate><content:encoded>&lt;p&gt;너무 어처구니 없는 실수를 해서 끄적여 봅니다. 어제부터 xfavorites 코드를 좀 수정하고 있었는데요. 이 놈이 64비트에서는 WH_KEYBOARD가 인터센더블 훅이라 제대로 동작하지 않는 경우가 좀 있더라고요. 여튼 그런 이유 때문에 방식을 조금 변경하고 있었는데, 문제는 이상하게 해당 코드가 실행만 되면 탐색기가 크래시가 난다는 것이었습니다. 어제 한참 신나게 디버깅 하다가 잠와서 잤는데 오늘 방금 들어와서 밥먹고는 다시 코드를 좀 살펴보니 정말 어처구니 없는 오류였습니다.&lt;/p&gt;
&lt;p&gt;push dword ptr [esp+16]&lt;/p&gt;
&lt;p&gt;push dword ptr [esp+12]&lt;/p&gt;
&lt;p&gt;push dword ptr [esp+8]&lt;/p&gt;
&lt;p&gt;push dword ptr [esp+4]&lt;/p&gt;
&lt;p&gt;call eax&lt;/p&gt;
&lt;p&gt;특별한건 없고 단순히 인자로 넘어온 파라미터를 넣어서 다시 함수를 호출하는 과정입니다. 그런데 자꾸 이 함수의 실행 결과가 이상해서 크래시가 발생하는 거였습니다. 그래서 도대체 왜 그렇지 하면서 익스플로러를 디버깅을 해보니 스택에는 제가 생각한 값들이 없더라고요. 네. 당연한거 맞습니다. 스택에 푸시를 하면 esp 값이 변하는데 그걸 생각을 안한 것이죠. 위와 동일한 코드를 만드려면 실제로는 다음과 같이 해야 정상적인 동작을 합니다.&lt;/p&gt;
&lt;p&gt;push dword ptr [esp+16]&lt;/p&gt;
&lt;p&gt;push dword ptr [esp+16]&lt;/p&gt;
&lt;p&gt;push dword ptr [esp+16]&lt;/p&gt;
&lt;p&gt;push dword ptr [esp+16]&lt;/p&gt;
&lt;p&gt;call eax&lt;/p&gt;
&lt;p&gt;가독성은 좀 떨어지죠. 인덱스, 포인터 개념이 괜히 있는건 아니겠지요. 아래처럼 바꾸면 가독성이 좀 나아집니다. ㅎㅎ~&lt;/p&gt;
&lt;p&gt;mov ecx, esp&lt;/p&gt;
&lt;p&gt;push dword ptr [ecx+16]&lt;/p&gt;
&lt;p&gt;push dword ptr [ecx+12]&lt;/p&gt;
&lt;p&gt;push dword ptr [ecx+8]&lt;/p&gt;
&lt;p&gt;push dword ptr [ecx+4]&lt;/p&gt;
&lt;p&gt;call eax&lt;/p&gt;
&lt;p&gt;이걸 세 시간 넘게 디버깅을 하다뉘… 헐킈…&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[원고 대량 업데이트. 부왘…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/3830</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3830</guid><pubDate>Mon, 28 Feb 2011 23:57:03 GMT</pubDate><content:encoded>&lt;p&gt;언젠가 리누스 토발즈가 그랬다죠. 진짜 남자는 백업을 하지 않는다고요. 인터넷에 올려서 남들이 백업하게 만든다라고 이야기 했었죠. ㅎㅎ~ 진짜 그러는지 아닌지는 뭐 알길이 없지만, 솔직히 요즘은 하드에 있는 것보다 웹에 있는 걸 검색하는게 편하긴 편한 것 같습니다. 그런 연유로 하드디스크에서 썩고 있는 원고를 힘겹게 찾아서 올렸습니다. 가젯 원고 4편, PE 포맷 3편, 윈도우 프로그래밍 6편이 업데이트 되었습니다.&lt;/p&gt;
&lt;p&gt;별볼일 없는 자료지만 공부하시는 분들에게 작은 도움이라도 됐으면 좋겠네용. 자료는 아래 페이지에서 다운로드 받으실 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/microsoftware&quot;&gt;http://jiniya.net/wp/microsoftware&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[바티칸…]]></title><description><![CDATA[젤로 형의 역작, 유일하게 젤로 형의 서명을 가진 피에타. 원래 마리아 가슴팍에 서명이 있다는데 복원한거라 그런지 안보인다. 20대에 만든 작품이라는데 참 천재는 천재다. 6.2…]]></description><link>https://jiniya.net/wp/archives/3022</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3022</guid><pubDate>Fri, 25 Feb 2011 23:57:02 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./바티칸.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/e08f48a6c558297ae440fb90fcebc56e/e224a/%EB%B0%94%ED%8B%B0%EC%B9%B8.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAEDBf/EABYBAQEBAAAAAAAAAAAAAAAAAAEAAv/aAAwDAQACEAMQAAABy6ReVkRv/8QAGRAAAgMBAAAAAAAAAAAAAAAAAQIQESES/9oACAEBAAEFAkGutQGzuP/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABQQAQAAAAAAAAAAAAAAAAAAACD/2gAIAQEABj8CX//EABoQAAIDAQEAAAAAAAAAAAAAAAABESExQVH/2gAIAQEAAT8hpxpvfUJJaRoNH6TNn//aAAwDAQACAAMAAAAQuM//xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPxBX/8QAFhEBAQEAAAAAAAAAAAAAAAAAABEh/9oACAECAQE/ENR//8QAGhABAAMAAwAAAAAAAAAAAAAAAQARITFBUf/aAAgBAQABPxBGqawZeHMLr2GaJrBscWO7bEB6Zfmn/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;    md 0&apos; title=&apos;&apos; src=&apos;/static/e08f48a6c558297ae440fb90fcebc56e/e224a/%EB%B0%94%ED%8B%B0%EC%B9%B8.md_0.jpg&apos; srcset=&apos;/static/e08f48a6c558297ae440fb90fcebc56e/8ccab/%EB%B0%94%ED%8B%B0%EC%B9%B8.md_0.jpg 190w,
/static/e08f48a6c558297ae440fb90fcebc56e/ea4c8/%EB%B0%94%ED%8B%B0%EC%B9%B8.md_0.jpg 380w,
/static/e08f48a6c558297ae440fb90fcebc56e/e224a/%EB%B0%94%ED%8B%B0%EC%B9%B8.md_0.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;젤로 형의 역작, 유일하게 젤로 형의 서명을 가진 피에타.&lt;/p&gt;
&lt;p&gt;원래 마리아 가슴팍에 서명이 있다는데 복원한거라 그런지 안보인다.&lt;/p&gt;
&lt;p&gt;20대에 만든 작품이라는데 참 천재는 천재다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;6.26&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;마지막 날 아침이 밝았다. 오늘은 로마의 양대 코어중 하나인 바티칸 투어를 가는 날이다. 7시 30분에 P가 깨운다. 7시 50까지 떼르미니 역에 가야 투어를 할 수 있다는데… … 씻지도 않고 머리에 물만 묻히고 세수를 하고 나왔다. 빵을 들고 역으로 가려다, 공속으로 먹고 가기로 했다. 실수였다. 떼르미니 역에 도착하니 8시쯤 되었다. 24번, 1번 플랫폼 어디에도 한국 사람들 무리가 보이지 않았다. 일단 바티칸으로 가기로 했다. 지하철로 바티칸으로 이동해서 출구로 나가니 자전거 여행 투어가 보인다. 잽싸게 합류했다. 26세 위로 25유로, 26세 이하 20 유로 였다. 학생은 더 쌌다. 돈을 내고 투어에 참가했다. 가이드 투어는 이번이 첨이다. 무선으로 가이드 말을 들을 수 있는 장치를 받고 바티칸으로 향했다. 지하철 역을 나와 바티칸 성벽으로 나오니 8시도 이르지 않다는 생각이 든다. 사람들이 개미처럼 행렬을 지어있었기 때문이다. 그 뒤에 20여명이 추가로 선다. 기다리는 동안 가이드가 이런 저런 전체적인 설명을 해준다. 주로 미친젤로와 라파엘로 이야기다. 가이드가 설명을 재밌게 해서 참 좋았다. 입국하고 박물관 표를 사고 그늘로 이동해서 2시간 가량 미켈란젤로란 사람과 천지창조, 최후의 심판에 대한 설명을 들었다. 투어에서 가장 흥미로웠던 부분이다. 동시에 미켈란젤로란 한 인간에 대해서 좀 더 알아보고 싶다는 생각이 들기도 했다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;미켈란젤로는 89세 까지 살았으나 결혼을 하지 않았다. 여러가지 학설이 있으나 그가 심각한 외모 컴플렉스를 가지고 있었다고 한다. 코는 선배에게 맞아서 비뚫어 졌으며, 5년간 천지창조 벽화 작업을 하느라 등이 굽고, 얼굴 안면이 손상되었다고 한다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;그리고 나서 회화관으로 입장했다. 가이드가 중세, 르네상스, 바로크로 구분지어 설명을 해주었다. 중세는 원근감, 표정, 동작, 명암이 없는 것이 르네상스는 표정, 동작, 명암, 원근이 살아 있으나 이상적인 아름다움을 표현한 것이, 바로크는 르네상스의 이상적임을 타파(종교개혁)하고 사실적인 그림을 그린 것이 특징이라 했다. 그리고 인물 도상학을 조금 배웠는데 흥미로웠다. 열쇄 가진건 베드로, 털옷 세례자 요한, 이런식이었다. 하지만 성경의 전체적인 내용을 모르는지라 그림 내용은 지루했다. 점심시간, 햄버거(완전 구리다)를 먹고 인증샷 좀 찍고 2시 50분 부터 오후 일정을 시작했다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;조형관에 가서 동상을 보고 관련 신화 설명을 들었다. 재밌었다. 그리고는 라파엘로의 역작 아테네 학당을 보았다. 아테네 학당은 워낙 유명한 작품인만큼 나도 알고 있었다. 실제로보니 무지 크다는 것이 인상적이었다. 가이드가 그림 속에 있는 라파엘로가 어딘지와 아리스토텔레스의 얼굴이 그가 존경하던 다빈치로 중간에 최후의 심판을 보고 미켈란젤로를 그려 넣어 좌우 대칭이 깨졌다는 이야기를 해주었다. 이후에는 드디어 소성당에 있는 미친젤로의 걸작 천지창조와 최후의 심판을 보러갔다. 성당 내부에 너무 많은 사람들이 몰리지 않도록 하기 위해 구불구불한 긴 통로를 통해서 가야 했다. 제법 멀었다. 가이드가 드디어 마지막 입구 앞에서 인원 점검을 하고 주의 사항을 설명한 다음 입장했다. 두둥. 들어가니 내부에도 정말 사람이 많았다. 가이드가 미친 젤로의 자서전에서 찬장화를 제일 잘 볼 수 있는 곳을 언급해 놓았다면 쭉쭉 들어오라고 했다. 중간쯤 계단에 앉아서 올려다보니 그야말로 장관이었다. 제일 유명한 아담의 탄생, 신과 손가락을 닿고 있는 그 부분이 딱 한눈에 들어왔다. 정말 웅장했다. 가이드의 말처럼 한 인간이 만들었다고 믿기에는 실로 대단한 작품이었다. 최후의 심판과 천지창조는 벽을 기준으로 닿아 있었다. 경외심이 절로 생기는 작품이었다. 한 인간의 한계를 뛰어넘는 열정, 노력, 피와 땀을 느낄 수 있었다. 미친 젤로가 나에게 묻는다, 너 한번이라도 나처럼 미쳐본 적이 있냐고. 그는 거의 5년이란 시간을 그가 좋아하는 조각도 아닌 그림을 그리는데 바친 사람이다. 투입된 노력과 고생을 말로 표현할 수 없을 것이다. 그 거대함, 웅장함, 또 그런 작품을 만드는 그의 노력 앞에 절로 고개가 숙여졌다. 동시에 오만한 나에게 속죄의 시간이 되기도 했다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;좀 더 작품을 감상하고 싶었지만 가이드 투어의 특성상 다음 장소로 이동해야 했다. 성 베드로 대성당이었다. 나탈리가 그렇게 꼭 가보라고 노래를 불렀던 싼 삐에뜨로. 입구에서 설명을 들은 다음 입장했다. 근데 바로 옆으로 들어가면 되는데 실수로 출구로 나가 버렸다. 다시 들어오려니 가드가 안된다고 한다. 다시 입구로 가서 들어오란다. 한참을 실갱이하다 다시 입구로 갔다. 엎친데 덮친 격으로 비까지 온다. 뛰어뛰어 다시 성당으로 들어갔다. 성당안은 일단 컸다. 세계에서 제일 크다는데 오죽하겠는가? 근엄한 음악이 울려 퍼지고, 입구에 미친 젤로의 역작 피에타가 있었다. 피에타는 마리아가 예수의 죽은 시체를 들고 있는 작품으로 우리말로 하면 비탄, 영어로 하면 pity가 된다고 했다. 원래 가까이서 볼 수 있는데 미친 x가 망치로 다 때려 부수는 바람에 유리벽을 통해 멀리서나 겨우 볼 수 있었다. 젤로의 서명과 상세한 근육을 표현한 모습을 볼 수 없어서 아쉬웠다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;다음으로는 베드로 성인의 무덤을 구경했다. 정말 화려하게 장식되어 있었다. 인증샷을 몇 개 찍고는 나왔다. 나와서 만나기로 한 분수대로 가니 사람들이 모여 있었다. 가이드가 끝으로 베드로 광장에 대해서 설명했다. 딱봐도 베드로 성당과 광장을 공중에서보면 열쇠 모양이었다. 그런데 이건 원래 그렇게 설계된 것이 아니라 증축하다보니 그렇게 된거란다. 과연 그럴까? 광장에서 인증샷 몇 장 찍고 해산했다. 가이드가 괜찮은 아이스크림 집, 올드브릿지를 갈켜줘서 1.5유로 짜리를 하나 사먹었다. 그냥 아이스크림이었다. 알바 애들이 한국말을 너무 잘해서 조금 놀랐다. 뭐 줄까라길래 농담삼아 아무거나 이랬는데 알아들었다. 헐킈. 메트로 타고 떼르미니로와서 숙소로 갔다. 씻고 밥먹자는게 피곤했는지 씻고 자버렸다. 인나니 11시. 걍 계속 쭉 잤다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[“C++ 개발자를 위한 수퍼 개발자로 가는길” 세미나 발표 자료]]></title><description><![CDATA[어제 있었던  “C++ 개발자를 위한 수퍼 개발자로 가는 길” 세미나 발표 자료 입니당. 평일이라 한 2-30명 오겠지 하는 생각으로 부담없이 갔었는데 정말 많이 오셨더군요. 후훗. 데쎄랄 카메라의 힘이란 ㅋㅋ~ 발표 내용은 C/C…]]></description><link>https://jiniya.net/wp/archives/3736</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3736</guid><pubDate>Thu, 24 Feb 2011 23:57:01 GMT</pubDate><content:encoded>&lt;p&gt;어제 있었던  “C++ 개발자를 위한 수퍼 개발자로 가는 길” 세미나 발표 자료 입니당. 평일이라 한 2-30명 오겠지 하는 생각으로 부담없이 갔었는데 정말 많이 오셨더군요. 후훗. 데쎄랄 카메라의 힘이란 ㅋㅋ~ 발표 내용은 C/C++의 기본적인 정수 연산에 관한 규칙과 Visual Studio 2010에 번들된 SafeInt를 사용하는 방법입니다. 슬라이드만 바서는 “먼 내용이지?” 하실거 같네요. 그래도 SafeInt의 기본적인 사용 방법을 아예 모르셨던 분들이라면 일말에 도움이라도 되지 않을까 하는 생각으로 올려봅니당. 뒤풀이가 더 쩔었던 세미나가 아니었나 하는 생각이 슝슝 드는군요. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;아래는 Channel9에 올라온 SafeInt 동영상 입니다. 같이 참고하시면 SafeInt를 사용할 때에 어떤 점에 주의를 해야 하는지 도움을 얻으실 수 있을 겁니당.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://channel9.msdn.com/Shows/Going+Deep/David-LeBlanc-Inside-SafeInt&quot;&gt;http://channel9.msdn.com/Shows/Going+Deep/David-LeBlanc-Inside-SafeInt&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;VS 2010을 사용하지 않으시는 분들은 아래 경로에서 SafeInt 클래스를 다운로드 받아서 사용하시면 됩니다. 히스토리가 좀 쩔죠. 머든지 제대로 만드려면 이 정도 시간은 걸리나 봅니다. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://safeint.codeplex.com/&quot;&gt;http://safeint.codeplex.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[호가든 잔에 부쳐.]]></title><description><![CDATA[마트를 갔어. 고기나 구워먹으려고 말이야. 고기와 야채를 사고는 돌아 나오는데 뭔가 조금 허전하드라공. 갑자기 막 호가든이 뗑기는거야. 맥주는 하이네켄 다크라는 철학으로 살아왔는데 미친듯이 호가든의 거품 맛을 느끼고 싶더라공. 그래서 호가든…]]></description><link>https://jiniya.net/wp/archives/2466</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2466</guid><pubDate>Tue, 15 Feb 2011 23:57:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./호가든_잔에_부쳐_.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/946c3711bfcffec63f605298c2163d4e/e224a/%ED%98%B8%EA%B0%80%EB%93%A0_%EC%9E%94%EC%97%90_%EB%B6%80%EC%B3%90_.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQFAgP/xAAVAQEBAAAAAAAAAAAAAAAAAAABA//aAAwDAQACEAMQAAABZWpy407mAf/EABoQAQADAAMAAAAAAAAAAAAAAAEAAgMREyP/2gAIAQEAAQUCMa1myFmhOJqenYz/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAbEAABBAMAAAAAAAAAAAAAAAABAAIQMRIhUf/aAAgBAQAGPwLQTGdKqAcKj//EABsQAAMBAAMBAAAAAAAAAAAAAAABESExQVGR/9oACAEBAAE/IVEQacvQ59GHodcMtvNsdPdH/9oADAMBAAIAAwAAABBrD//EABYRAQEBAAAAAAAAAAAAAAAAABEQIf/aAAgBAwEBPxBcn//EABcRAQEBAQAAAAAAAAAAAAAAAAEAESH/2gAIAQIBAT8QDHW7f//EAB0QAQACAgIDAAAAAAAAAAAAAAEAEUFRIWExccH/2gAIAQEAAT8QLFV1OI0zjF1Ww/IsSX1K9ocYjGm+Wth4svfUcEOp/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;           md 0&apos; title=&apos;&apos; src=&apos;/static/946c3711bfcffec63f605298c2163d4e/e224a/%ED%98%B8%EA%B0%80%EB%93%A0_%EC%9E%94%EC%97%90_%EB%B6%80%EC%B3%90_.md_0.jpg&apos; srcset=&apos;/static/946c3711bfcffec63f605298c2163d4e/8ccab/%ED%98%B8%EA%B0%80%EB%93%A0_%EC%9E%94%EC%97%90_%EB%B6%80%EC%B3%90_.md_0.jpg 190w,
/static/946c3711bfcffec63f605298c2163d4e/ea4c8/%ED%98%B8%EA%B0%80%EB%93%A0_%EC%9E%94%EC%97%90_%EB%B6%80%EC%B3%90_.md_0.jpg 380w,
/static/946c3711bfcffec63f605298c2163d4e/e224a/%ED%98%B8%EA%B0%80%EB%93%A0_%EC%9E%94%EC%97%90_%EB%B6%80%EC%B3%90_.md_0.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;마트를 갔어. 고기나 구워먹으려고 말이야. 고기와 야채를 사고는 돌아 나오는데 뭔가 조금 허전하드라공. 갑자기 막 호가든이 뗑기는거야. 맥주는 하이네켄 다크라는 철학으로 살아왔는데 미친듯이 호가든의 거품 맛을 느끼고 싶더라공. 그래서 호가든 4병짜리를 하나 샀어. 그런데 사고 보니깐 자연스레 호가든 잔 생각이 나는게 아니겠어. 호가든은 또 호가든 잔에 따라 마시는게 간지지. 바로 2층으로 갔어. 유리잔을 살펴보는데 마땅한 놈이 없었어. 그리고 무슨 유리잔이 글케 비싼지. 그래서 그냥 위스키 잔에 따라 마실 생각에 집으로 왔어. 그런데 이게 영 위스키 잔에 따라 마시는 건 맛이 아닌거야. 호가든은 남은 걸 돌려서 거품을 내서 마무리로 따라 주는게 간진데 위스키 잔이라 그게 안되서 너무 아쉬웠어. 다음에 바에 가면 호가든 잔을 꼭 하나 업어와야 겠다는 생각을 했지.&lt;/p&gt;
&lt;p&gt;그러다 근래에 바에 갈 일이 몇 번 있어서 호가든 잔을 하나 얻어와야 겠다는 생각이 들었어. 목요일에는 정말 맥주를 오지게 많이 마셨는데 호가든 잔이 생각이 나질 않았어. 그러다 금요일 날 전에 자주 가던 바에 가서 하나를 업어 왔지. 두개를 얻으려고 했는데 실패했어. 토요일에도 집 앞 바에 갈 일이 있었는데 그 날도 맥주를 좀 많이 마셨지 뭐야. 그러다 생각나서 호가든잔 드립을 쳤는데, 글쎄 잔이 다 떨어졌다고 담주에 오면 주겠다고 하드라공.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./호가든_잔에_부쳐_.md_1.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/00b449ccb8a916daac13ca2d9cc4c3c1/e224a/%ED%98%B8%EA%B0%80%EB%93%A0_%EC%9E%94%EC%97%90_%EB%B6%80%EC%B3%90_.md_1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAUBA//EABYBAQEBAAAAAAAAAAAAAAAAAAABA//aAAwDAQACEAMQAAAB7ZKZ2yjj/8QAGxAAAgIDAQAAAAAAAAAAAAAAAQIAEwMREiL/2gAIAQEAAQUCLTv3BnYG3bXtP//EABURAQEAAAAAAAAAAAAAAAAAAAAR/9oACAEDAQE/AVf/xAAVEQEBAAAAAAAAAAAAAAAAAAAAEv/aAAgBAgEBPwGUv//EABsQAAEEAwAAAAAAAAAAAAAAAAEAAhAhEVFx/9oACAEBAAY/AqWIB0i4uvkf/8QAHBABAAMBAAMBAAAAAAAAAAAAAQARITFBUWGR/9oACAEBAAE/IWDCvoho15yuTGWdu17MID8R9z8n/9oADAMBAAIAAwAAABAQH//EABYRAQEBAAAAAAAAAAAAAAAAAAABEf/aAAgBAwEBPxCVh//EABYRAQEBAAAAAAAAAAAAAAAAAAABEf/aAAgBAgEBPxC00//EABkQAQEBAQEBAAAAAAAAAAAAAAERACGx8P/aAAgBAQABPxAn0QAVW45Ax3FfeZUrlAZADi5odrCa6ef/2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;           md 1&apos; title=&apos;&apos; src=&apos;/static/00b449ccb8a916daac13ca2d9cc4c3c1/e224a/%ED%98%B8%EA%B0%80%EB%93%A0_%EC%9E%94%EC%97%90_%EB%B6%80%EC%B3%90_.md_1.jpg&apos; srcset=&apos;/static/00b449ccb8a916daac13ca2d9cc4c3c1/8ccab/%ED%98%B8%EA%B0%80%EB%93%A0_%EC%9E%94%EC%97%90_%EB%B6%80%EC%B3%90_.md_1.jpg 190w,
/static/00b449ccb8a916daac13ca2d9cc4c3c1/ea4c8/%ED%98%B8%EA%B0%80%EB%93%A0_%EC%9E%94%EC%97%90_%EB%B6%80%EC%B3%90_.md_1.jpg 380w,
/static/00b449ccb8a916daac13ca2d9cc4c3c1/e224a/%ED%98%B8%EA%B0%80%EB%93%A0_%EC%9E%94%EC%97%90_%EB%B6%80%EC%B3%90_.md_1.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;어제는 회사 앞에 바엘 갔는데 뽑기 놀이를 해서 미니어처를 두 개 받았어. 사실 내가 뽑은 건 죄다 꽝이었는데,… 같이 가신 분의 뽑기 신공 + 포스로 몇 개 얻었지. 맞아. 요즘 좋지도 않은 술을 너무 많이 마셨어. 근데 자꾸 마실 일만 생기네. ㅠㅠ~&lt;/p&gt;
&lt;p&gt;더 웃긴건 이렇게 쭉 두고 보니까 와인을 마시고 싶은게 아니겠어. 그래서 마트에서 싸구려 8천원짜리 국적 불명의 화이트 와인을 하나 사왔어. 와인을 살 때 마다 놀라는건데 8천원 짜리나 3만원 짜리나 그 맛이 그 맛이란거. 취하게 마시면 3만원 짜리가 뒤끝이 덜하려나? ㅎㅎ~ 어쨌든 사람이란게 참. 간사해. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;—&lt;/p&gt;
&lt;p&gt;제법 오래 전에 쓴 글인데 어제, 오늘 맥주집에서 호가든 마시는 분이 많아서 생각나서 올려봅니다. 호가든 참 매력적인 맥주예요. 전 어제, 오늘 모두 하이네켄 다크를 마셨습니다. 하이네켄 다크하면 떠오르는 분이 계신데 잘 계신지 무척 궁금하네요. 올 해 꼭 연락을 드려야지 하고는 생각했는데 벌써 연말이 코 앞이네요. 저 때나 지금이나 술은… ㅠㅠ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[내 파일, 하지만 접근은 불가능…]]></title><description><![CDATA[예전 하드디스크에 있는 자료를 새 하드디스크로 복사하는데 계속 파일 접근 권한이 없다면서 오류가 나더군요. 아래 화면처럼 말입니다. 제 하드디스크이고 전 관리자 권한이고, UAC…]]></description><link>https://jiniya.net/wp/archives/3377</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3377</guid><pubDate>Mon, 14 Feb 2011 23:56:59 GMT</pubDate><content:encoded>&lt;p&gt;예전 하드디스크에 있는 자료를 새 하드디스크로 복사하는데 계속 파일 접근 권한이 없다면서 오류가 나더군요. 아래 화면처럼 말입니다. 제 하드디스크이고 전 관리자 권한이고, UAC도 꺼져있고, 도대체 왜 그런지를 알 수가 없었습니다. &lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 496px; margin-bottom: 16px;&apos; data-url=&apos;./내_파일,_하지만_접근은_불가능.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f09df7e3f481eaed6caa5e1bf80ba89d/60009/%EB%82%B4_%ED%8C%8C%EC%9D%BC%2C_%ED%95%98%EC%A7%80%EB%A7%8C_%EC%A0%91%EA%B7%BC%EC%9D%80_%EB%B6%88%EA%B0%80%EB%8A%A5.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 62.10526315789474%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACKklEQVR42nVRS4/TMBDOz+M3cOJPIHHgsCfgwhVYJBYkOOxygiIOfWyrttuqzbbNq0k2tuMkTvNo2qRxkr454GZBy4VP4/HMaL6x/Zl78fLV+4svHcGo94XGCFeG9jferaq0qmZXPeuyDS7bsDIKq9NVS6c9mPHOeiA7k69X3z9+5prNlm0rnh9gm0DThshi3rTK2HRKby8TGqd5nGbMEmY0Lw6/BoLG8cOO1j9zWQ/Cd5pu6DowAALAuDOwaSIINXWKELKwZSJkYmxZWNe0KAgESeXG43GeUUIcURBlSVFkRRQlRZZZbBggDOeEENu2HYfY1mlnKZu1XC4FWeUa183D4ZgkqyyjlKar1SpmSbqiJfI832zW2xK73W6z2eQlDvs9L6hcvVbf73dRFBl4pkKbeEE4XxDHHd/e3nS7nXZXUaYWPsEwDNedpZTGccwmDhm5UasdjwdnFjy9qDx59wEFnuEGvKKaAEiiBCGaR/PAD8Iw9H0vihaMnCTJdrs5kZt1Rj5iMnt8/ubR2+cKAdgnEtDXecGunf2D/ORomqbsWX/I1yXZIu5Z5dOzyusJlJIodoib/h8PZP6mxaRYLJa+H9yb54fzKKJ/W7NStoKt8tyTqmm6226HwpSTR73tbs9KRVGsiweUomZsAW/Oq6AvqmNE2FCb/bOuLRdRf6xwnfqPmTezWM3CAEAA0b2xCKITeHFabfd+NrtdQbuDpiDJw9EEQLPaHvwGsBxvzdxrLv8AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                  md 0&apos; title=&apos;&apos; src=&apos;/static/f09df7e3f481eaed6caa5e1bf80ba89d/60009/%EB%82%B4_%ED%8C%8C%EC%9D%BC%2C_%ED%95%98%EC%A7%80%EB%A7%8C_%EC%A0%91%EA%B7%BC%EC%9D%80_%EB%B6%88%EA%B0%80%EB%8A%A5.md_0.png&apos; srcset=&apos;/static/f09df7e3f481eaed6caa5e1bf80ba89d/08678/%EB%82%B4_%ED%8C%8C%EC%9D%BC%2C_%ED%95%98%EC%A7%80%EB%A7%8C_%EC%A0%91%EA%B7%BC%EC%9D%80_%EB%B6%88%EA%B0%80%EB%8A%A5.md_0.png 190w,
/static/f09df7e3f481eaed6caa5e1bf80ba89d/2edd7/%EB%82%B4_%ED%8C%8C%EC%9D%BC%2C_%ED%95%98%EC%A7%80%EB%A7%8C_%EC%A0%91%EA%B7%BC%EC%9D%80_%EB%B6%88%EA%B0%80%EB%8A%A5.md_0.png 380w,
/static/f09df7e3f481eaed6caa5e1bf80ba89d/60009/%EB%82%B4_%ED%8C%8C%EC%9D%BC%2C_%ED%95%98%EC%A7%80%EB%A7%8C_%EC%A0%91%EA%B7%BC%EC%9D%80_%EB%B6%88%EA%B0%80%EB%8A%A5.md_0.png 496w&apos; sizes=&apos;(max-width: 496px) 100vw, 496px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 377px; margin-bottom: 16px;&apos; data-url=&apos;./내_파일,_하지만_접근은_불가능.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/674a3e94bcc930976186821336b8f43e/fdd90/%EB%82%B4_%ED%8C%8C%EC%9D%BC%2C_%ED%95%98%EC%A7%80%EB%A7%8C_%EC%A0%91%EA%B7%BC%EC%9D%80_%EB%B6%88%EA%B0%80%EB%8A%A5.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 136.8421052631579%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAbCAIAAADzvTiPAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAEsElEQVR42mVUS2wbZRDeOydOIHFCwAEJiRsHTtw4cAEOFaKCAxVCKhIUVVSoRRVEDeUhFUqSVoqqEK83zrNOkzixmzQPhzRSU8eJ8/D6vWuvd73r2Pu29+XdZXadpATGv3+Nx/N5Zr75vMj1X+/+1j/8482+np8Hrt34/bsfbl289P2nFy5+cO7jl19747nnX3zhpVdeff3Nt95+59333v/w3PmPPrnQ/9n5ia8/v/nFl8gQFo5vbD1a3YwtxRcW45Ho8sTkfSw0ioXG+u8M3vqj/3bf3dt/3hm8NxQIhsbGp6bCM7Nz8yvLy30Dg0gkuoLjh1tbiUwml0zurMXjyd0U3xRqTK3R5NOHYHihUNzb28cz2eQ2pOxC3HXducg8Eltal2UFvq5UKIZhFUXN5/MMzVDVKkmWcRzP5wsQIX2DHEVRNN0AcHh6BllafWzbdpPnFVlW1Van0xEEodlo8LwgCgLfbIpggiCJIg85igIJkA9gaB5Zjf8tCGI+l68xLEmQ+VyBomjbcSEF0jq203UsHwSXYZrttgbg+WgMebKVUBUh+XS9TJA0Rcgi7zodwLrPjn32hsIWgNfW1pF4fEPTW5uJpxvJwuPdAlFXWaXDSGZNsmqyxSkWK5usbLGS6QVFiJtkQ2uZ7uLiEoIGRzqOjT7avzzd+CZ8dGWGv7ogXZkVLj8QvppqfDvTuBYRrs7x12PSTyta77LWu6JdmpGfVN1QEAVwCPrBMwdlslwmSmWSrDFMmSAYhga/VCxUvHCR5Tho1XEcuCzLa/ve0DAyjAbB0w0T4t6BmRzHtv0sB+YDwpzj2zkOGqYHDo2MIoEgBl6VAqsyUJOs0DTD1jjYaokg25phmfCyJFnmOA7WThAkNAXUh6enATwCPwergkMQRNlrkmg0Grqua1rbL+ZZq9WiaTq1m4KcSqUCERQLIdjIqMgLicR2NpMtFUvZbC6dxvF0GiozNaaLhI5AReBIolTn6l2RhO9PAWEYzFEsFksl75IkRW21RMnTEwis3W4bhsGyLFOrmaYpnugMwNhICEFRb+YMngENa5p+0uYZg2zQ7Anb7jO2u4ThaRxmrla99Wiap3uPcN/OgP1gF/zXcMBv23WzeKZKVRVVlWXZsjr/rwwN/6fycCCIBD223Ww2W68fnX59aqeVeZ8w2+8Hhgc/EBw7BudzOY/tEgn/XdiWeba448nGPv143DZUDviEqaqqaVqr1YZ9dn1D141/meab6Zvqsx0IYAiGjUB0ZyeV2tuHZ83+QRpoh8XmCwX/GVI8OMSrNA07I4hSIpFIpXbxTMYDoxgSxEIwClOlaDhUWRK7K7Hd7vHcDry72wYlgMJAyZ7CUCAMDcJ8eU4jm1aF75SOzHLDKNbh6AVOz3N6pqbxrTMUwPPEbxtF4K1bbonhKU6i6lKFk+gjGQ7TVKkjmarLFU4WVR1IAkaAji4pAA6iKDI+PgmeqWsdy+iYhmubrKptH+kbOSrJqVleq7NM+vDg4CAN/yoQAiycYWqeticnkZ6entXVtfnIQjQaW1iIPYzFpuYWBiYifdjUwMTscDgyPj4BYoIzHQ4/jEbn5yJzD2Y2NzZ+6b3xDy3MeN7hg3pCAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                  md 1&apos; title=&apos;&apos; src=&apos;/static/674a3e94bcc930976186821336b8f43e/fdd90/%EB%82%B4_%ED%8C%8C%EC%9D%BC%2C_%ED%95%98%EC%A7%80%EB%A7%8C_%EC%A0%91%EA%B7%BC%EC%9D%80_%EB%B6%88%EA%B0%80%EB%8A%A5.md_1.png&apos; srcset=&apos;/static/674a3e94bcc930976186821336b8f43e/08678/%EB%82%B4_%ED%8C%8C%EC%9D%BC%2C_%ED%95%98%EC%A7%80%EB%A7%8C_%EC%A0%91%EA%B7%BC%EC%9D%80_%EB%B6%88%EA%B0%80%EB%8A%A5.md_1.png 190w,
/static/674a3e94bcc930976186821336b8f43e/fdd90/%EB%82%B4_%ED%8C%8C%EC%9D%BC%2C_%ED%95%98%EC%A7%80%EB%A7%8C_%EC%A0%91%EA%B7%BC%EC%9D%80_%EB%B6%88%EA%B0%80%EB%8A%A5.md_1.png 377w&apos; sizes=&apos;(max-width: 377px) 100vw, 377px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;해당 파일의 속성을 살펴보니 다른 사용자들은 모두 접근 불가이고 이상한 계정만 풀 권한을 가지고 있더군요. 아마도 전에 쓰던 운영체제에서의 관리자 아이디가 아닌가 추측만 해봅니다. 어쨌든 전 이미 해당 운영제체를 깔끔하게 날려버린 후였기 때문에 전 해당 파일을 복사하지 못했습니다. ㅠㅠ~ cygwin 관련 파일에 이상하게 이런 속성이 많은 것 같더군요. 덴장~&lt;/p&gt;
&lt;p&gt;당연히 속성에서 권한 조정 조차도 권한이 없다고 되지 않습니다. 이 무슨 뷇스런 상황인지… ㅠㅠ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[냉정과 열정사이]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/3151</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3151</guid><pubDate>Tue, 08 Feb 2011 23:56:58 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./냉정과_열정사이.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/096ccb0e3b5fc64330a20e5e4fd3911d/e224a/%EB%83%89%EC%A0%95%EA%B3%BC_%EC%97%B4%EC%A0%95%EC%82%AC%EC%9D%B4.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAUCAwT/xAAXAQADAQAAAAAAAAAAAAAAAAAAAQID/9oADAMBAAIQAxAAAAFlC1fm1RvLP//EABsQAQACAgMAAAAAAAAAAAAAAAIBAwAREiEi/9oACAEBAAEFApPTnw6krJPLLFqZsJz/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAWEQEBAQAAAAAAAAAAAAAAAAAAEQH/2gAIAQIBAT8B2q//xAAbEAACAQUAAAAAAAAAAAAAAAAAARECECExYf/aAAgBAQAGPwKDpU4N2yj/xAAaEAEAAwEBAQAAAAAAAAAAAAABABEhMVFB/9oACAEBAAE/IRyzMr5Lmc9woNF6HY9HKMFvDseCxq8J/9oADAMBAAIAAwAAABCs7//EABcRAAMBAAAAAAAAAAAAAAAAAAABEWH/2gAIAQMBAT8QUJh//8QAFhEBAQEAAAAAAAAAAAAAAAAAAREQ/9oACAECAQE/EKNM/wD/xAAcEAEAAwADAQEAAAAAAAAAAAABABEhMVFxQZH/2gAIAQEAAT8QDQ+Sw+GFbnAE3sjxM1iHcPtIAhXFzfm1U/kYImmG+z//2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;         md 0&apos; title=&apos;&apos; src=&apos;/static/096ccb0e3b5fc64330a20e5e4fd3911d/e224a/%EB%83%89%EC%A0%95%EA%B3%BC_%EC%97%B4%EC%A0%95%EC%82%AC%EC%9D%B4.md_0.jpg&apos; srcset=&apos;/static/096ccb0e3b5fc64330a20e5e4fd3911d/8ccab/%EB%83%89%EC%A0%95%EA%B3%BC_%EC%97%B4%EC%A0%95%EC%82%AC%EC%9D%B4.md_0.jpg 190w,
/static/096ccb0e3b5fc64330a20e5e4fd3911d/ea4c8/%EB%83%89%EC%A0%95%EA%B3%BC_%EC%97%B4%EC%A0%95%EC%82%AC%EC%9D%B4.md_0.jpg 380w,
/static/096ccb0e3b5fc64330a20e5e4fd3911d/e224a/%EB%83%89%EC%A0%95%EA%B3%BC_%EC%97%B4%EC%A0%95%EC%82%AC%EC%9D%B4.md_0.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;아가타 쥰세이는 나의 모든 것이었다. 그 눈동자도, 그 목소리도, 불현듯 고독의 그림자가 어리는 그 웃음진 얼굴도, 만약 어딘가에서 쥰세이가 죽는다면, 나는 아마 알 수 있으리라. 아무리 먼 곳이라도, 두 번 다시 만나는 일이 없어도…&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;사람이 있을 곳이란, 누군가의 가슴 속밖에 없는 것이란다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;우리는 세월의 어둠 속을 손으로 더듬어 서로의 윤곽을 확인하려 했다. 만남이라는 기세를 타고 우리의 열정에는 불이 붙고, 냉정에는 물이 뿌려졌다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;고작 사흘로, 당연한 일이지만 통속 멜로 드라마처럼 우리는 8년의 공백을 복원시킬 수 없었다. 두 사람은 같은 그림을 바라보면서도 제각기 자신의 생각을 이야기했을 따름이다. 어느 쪽에도 그림을 복원시킬 만한 열정은 남아 있지 않았다. 그리움만 간직한 냉정한 동창회와도 같았다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;결국 냉정이 이겼다. 구내를 헤매고 다니던 비둘기가 이제 겨우 밖으로 빠져 나갔다. 낮게 한숨을 토해 냈다. 눈 깜짝할 사이였다. 반추할 만한 추억도 남기지 않고 막은 내렸다. 이런 결말을 위해 8년이란 세월을 기다렸던가. 온몸에서 힘이 빠져 꼼짝도 할 수 없었다. 죽음과도 같았다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;– 냉정과 열정 사이 중에서&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;언젠가 누구와 멜랑꼴리한 이야기를 하던 중에 이 소설이 생각나서 다시 읽게 되었다. 에쿠니 가오리를 좋아해서 rosso편만 읽었었는데 내친김에 blu편도 사서 보았다. 그런데 생각보다 blu편이 더 좋았다. 읽는 내내 두 작가의 글빨에 감탄을 하지 않을 수가 없었다. 어찌나 문장이 산뜻한지, ‘아~ 글 읽는 재미가 이런 거구나’라는 생각을 하면서 한 장 한 장을 넘겼다. 그 말랑말랑하고 달짝지근한 문장이란~ 훗~&lt;/p&gt;
&lt;p&gt;책 내용은 그렇다. 헤어진 두 연인이 각자의 시간 동안을 서로의 관점에서 기술해 나가는 식이다. 쉽게 말하면 연인들끼리 하는 교환 일기장 정도 되겠다.&lt;/p&gt;
&lt;p&gt;책을 다 읽고 덮으면서 떠오르는 생각들이란 우리가 했던 오래된 약속들, 잊혀진 기억들, 빛 바랜 추억들… 그리곤 그 후미지고 낡은 기억의 틈 사이를 들추어 본다. 그 속엔 아직도 열정으로 가득했던 그 시절의 내 모습이 그대로 있는데 말이지… ㅋㅋ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[겨울 야생, 부왘…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/3596</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3596</guid><pubDate>Mon, 31 Jan 2011 23:56:57 GMT</pubDate><content:encoded>&lt;p&gt;주말에 영종도 선녀바위에 캠핑을 갔습니당.&lt;/p&gt;
&lt;p&gt;난생 처음 가는 겨울 야생이라 후훗, 기대되더군요.&lt;/p&gt;
&lt;p&gt;예상대로 날씨는 오지게 추웠습니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; margin-bottom: 16px;&apos; data-url=&apos;./겨울_야생,_부왘.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/db5ea76b870611d9ba95d2a704f00d85/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAECAwT/xAAVAQEBAAAAAAAAAAAAAAAAAAABAP/aAAwDAQACEAMQAAABjThmEMH/xAAaEAEAAgMBAAAAAAAAAAAAAAABAAIDEiEi/9oACAEBAAEFAsZsGTWl/S2WDOz/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAWEQEBAQAAAAAAAAAAAAAAAAAAARH/2gAIAQIBAT8BjH//xAAZEAACAwEAAAAAAAAAAAAAAAAAEQEQITH/2gAIAQEABj8CgWDO5f8A/8QAHBAAAgICAwAAAAAAAAAAAAAAAREAMSFBUXGh/9oACAEBAAE/IclwLuK+csyiBrQj0NshUZhPuMa8n//aAAwDAQACAAMAAAAQhO//xAAWEQEBAQAAAAAAAAAAAAAAAAAAARH/2gAIAQMBAT8QrY//xAAVEQEBAAAAAAAAAAAAAAAAAAAAAf/aAAgBAgEBPxAtP//EAB0QAQEAAwACAwAAAAAAAAAAAAERACExQVFhcYH/2gAIAQEAAT8QBxI6dhfM5zITxAXm98nxcACGg0S/aXLSSXiH5kDIPjDoRPSkz//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;          md 0&apos; title=&apos;&apos; src=&apos;/static/db5ea76b870611d9ba95d2a704f00d85/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_0.jpg&apos; srcset=&apos;/static/db5ea76b870611d9ba95d2a704f00d85/8ccab/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_0.jpg 190w,
/static/db5ea76b870611d9ba95d2a704f00d85/ea4c8/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_0.jpg 380w,
/static/db5ea76b870611d9ba95d2a704f00d85/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_0.jpg 640w&apos; sizes=&apos;(max-width: 640px) 100vw, 640px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; margin-bottom: 16px;&apos; data-url=&apos;./겨울_야생,_부왘.md_1.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/f0293bca61bc91d56d02d9a15683b170/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQFAgP/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHU64mdhQP/xAAbEAEBAAIDAQAAAAAAAAAAAAABAgARAwQSIf/aAAgBAQABBQL7htY7HmWSh4Ayp0//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPwGH/8QAGxAAAgIDAQAAAAAAAAAAAAAAAAECERAxQXH/2gAIAQEABj8CnJcZaKx6bZ//xAAaEAEBAQEAAwAAAAAAAAAAAAABEQAhMUFR/9oACAEBAAE/IWBBEEufwDk5LlAPrpPOSverhga//9oADAMBAAIAAwAAABAzD//EABYRAQEBAAAAAAAAAAAAAAAAAAEQEf/aAAgBAwEBPxBdn//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAECAQE/EBE//8QAGxABAAMAAwEAAAAAAAAAAAAAAQARITFBUbH/2gAIAQEAAT8QBG7GIX8jOhd6e4UrI4vkeo8gwvdmq6KDVMX0Fdz/2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;          md 1&apos; title=&apos;&apos; src=&apos;/static/f0293bca61bc91d56d02d9a15683b170/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_1.jpg&apos; srcset=&apos;/static/f0293bca61bc91d56d02d9a15683b170/8ccab/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_1.jpg 190w,
/static/f0293bca61bc91d56d02d9a15683b170/ea4c8/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_1.jpg 380w,
/static/f0293bca61bc91d56d02d9a15683b170/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_1.jpg 640w&apos; sizes=&apos;(max-width: 640px) 100vw, 640px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;도착해서 텐트를 치기 시작합니다. 일단 먹어주는 텐트 크기의 위엄. 핡~. 성인 남자가 안에서 허리를 안구부리고 설 수 있을 정도로 크더군요. 물론 180cm 이하의 성인 남자에 한해서 입니다 ㅋㅋㅋ~ 겨울 야생에서 살아남으려면 이 정도 크기는 해줘야겠죠. 고프로님은 열심히 바람에 안쓰러 지도록 텐트 못을 치고 계십니다. 전 옆에서 구경했어요. 셀카질이나 하면서 유후~&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; margin-bottom: 16px;&apos; data-url=&apos;./겨울_야생,_부왘.md_2.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/2e0b155f37d1b09aa445d740777dc176/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_2.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAQDBf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/aAAwDAQACEAMQAAABS7wZdFOR/8QAGhABAAMAAwAAAAAAAAAAAAAAAgEDEQATIf/aAAgBAQABBQIjOO4o11QjvWc8OxH/xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPwFX/8QAFhEBAQEAAAAAAAAAAAAAAAAAABES/9oACAECAQE/Aay//8QAGhAAAwADAQAAAAAAAAAAAAAAAAEREiExQf/aAAgBAQAGPwLJ9RJCuGPWzw0f/8QAGhAAAgMBAQAAAAAAAAAAAAAAAREAITFBcf/aAAgBAQABPyFIiosQAQZO7Hhsa6xMJ8vBA7khaSlEVez/2gAMAwEAAgADAAAAEHsf/8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQMBAT8QSP/EABYRAQEBAAAAAAAAAAAAAAAAAAABEf/aAAgBAgEBPxCUw//EAB0QAQACAgIDAAAAAAAAAAAAAAERIQAxQVFxgdH/2gAIAQEAAT8QMlSMhqkvvEFc8KE349Y1PVUx0HeLKQyzGyL3hW8oJYOZ+ZBgFZbP/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;          md 2&apos; title=&apos;&apos; src=&apos;/static/2e0b155f37d1b09aa445d740777dc176/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_2.jpg&apos; srcset=&apos;/static/2e0b155f37d1b09aa445d740777dc176/8ccab/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_2.jpg 190w,
/static/2e0b155f37d1b09aa445d740777dc176/ea4c8/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_2.jpg 380w,
/static/2e0b155f37d1b09aa445d740777dc176/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_2.jpg 640w&apos; sizes=&apos;(max-width: 640px) 100vw, 640px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; margin-bottom: 16px;&apos; data-url=&apos;./겨울_야생,_부왘.md_3.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5aeaba69dcaa3e217501d0834e89c7da/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_3.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABAADBf/EABYBAQEBAAAAAAAAAAAAAAAAAAABAv/aAAwDAQACEAMQAAABXy3hzdY8f//EABwQAAICAgMAAAAAAAAAAAAAAAECAAMEEhARIf/aAAgBAQABBQKsl4cpg23c28etTx//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAgEBPwGn/8QAHBAAAQMFAAAAAAAAAAAAAAAAEQABEAIiMTJx/9oACAEBAAY/AjUeIXMy2jEf/8QAGhABAAMBAQEAAAAAAAAAAAAAAQARIUExgf/aAAgBAQABPyEC7RgYvtZ67F6v9hxyWD6lpP/aAAwDAQACAAMAAAAQ5+//xAAWEQEBAQAAAAAAAAAAAAAAAAAAASH/2gAIAQMBAT8QsY//xAAXEQADAQAAAAAAAAAAAAAAAAAAARFR/9oACAECAQE/EForP//EABsQAQEAAwADAAAAAAAAAAAAAAERACExQXGh/9oACAEBAAE/EOnUeEBowEhOmh8xHbvkVcoSoNRkxkhD13feOkxnM//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;          md 3&apos; title=&apos;&apos; src=&apos;/static/5aeaba69dcaa3e217501d0834e89c7da/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_3.jpg&apos; srcset=&apos;/static/5aeaba69dcaa3e217501d0834e89c7da/8ccab/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_3.jpg 190w,
/static/5aeaba69dcaa3e217501d0834e89c7da/ea4c8/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_3.jpg 380w,
/static/5aeaba69dcaa3e217501d0834e89c7da/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_3.jpg 640w&apos; sizes=&apos;(max-width: 640px) 100vw, 640px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;완성된 텐트의 모습. 숲속의 아늑한 우리만의 공간입니다. 풉. 안에서 다시 곤로를 점검하고 계신 고프로님. 역시 전 구경만. 겨울 야생은 난로 없이는 버틸수가 없더군요. 난로를 계속 켜놔도 텐트가 온통 얼어버릴 정도로 날씨가 추웠습니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; margin-bottom: 16px;&apos; data-url=&apos;./겨울_야생,_부왘.md_4.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/9ee152c8a575511044828ca8d832077b/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_4.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMEAv/EABYBAQEBAAAAAAAAAAAAAAAAAAIBA//aAAwDAQACEAMQAAAB2qtVLyEGv//EABsQAAICAwEAAAAAAAAAAAAAAAECAxEAEhMi/9oACAEBAAEFApZwWWRcUedRXIW9I3//xAAWEQEBAQAAAAAAAAAAAAAAAAAAARH/2gAIAQMBAT8BlY//xAAVEQEBAAAAAAAAAAAAAAAAAAAAEv/aAAgBAgEBPwFT/8QAGxAAAgMAAwAAAAAAAAAAAAAAAAERITECEkH/2gAIAQEABj8CfVSeo0pUUtI5af/EABkQAQEBAQEBAAAAAAAAAAAAAAERACExcf/aAAgBAQABPyEcQyXMgv0NKAp1xzhih6PgxSUz/9oADAMBAAIAAwAAABD0D//EABYRAQEBAAAAAAAAAAAAAAAAABEBEP/aAAgBAwEBPxBaY//EABcRAAMBAAAAAAAAAAAAAAAAAAABEVH/2gAIAQIBAT8QaiKw/8QAHhABAAICAQUAAAAAAAAAAAAAAQARIWExQXGRocH/2gAIAQEAAT8QyhEho3TLY82HkhEqII1dq/YAAdAENTVSdogMOQcep//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;          md 4&apos; title=&apos;&apos; src=&apos;/static/9ee152c8a575511044828ca8d832077b/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_4.jpg&apos; srcset=&apos;/static/9ee152c8a575511044828ca8d832077b/8ccab/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_4.jpg 190w,
/static/9ee152c8a575511044828ca8d832077b/ea4c8/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_4.jpg 380w,
/static/9ee152c8a575511044828ca8d832077b/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_4.jpg 640w&apos; sizes=&apos;(max-width: 640px) 100vw, 640px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; margin-bottom: 16px;&apos; data-url=&apos;./겨울_야생,_부왘.md_5.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/d60652cd7f972e1d28ec4efa5bacb3bc/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_5.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAIEAQP/xAAUAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHk2qNREB//xAAYEAADAQEAAAAAAAAAAAAAAAABAgMABP/aAAgBAQABBQJ+gsSazUdS6k0nizUBA3//xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPwFH/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oACAECAQE/Aa1//8QAHhAAAgEDBQAAAAAAAAAAAAAAAAEiAhEhEDEyQVH/2gAIAQEABj8CjsKq7sSTMd5JcfNP/8QAGxABAAICAwAAAAAAAAAAAAAAAQARITFhcYH/2gAIAQEAAT8hXmF6Ce7RmLNriHDlqKlDfRqCZ//aAAwDAQACAAMAAAAQGP8A/8QAFhEAAwAAAAAAAAAAAAAAAAAAAAER/9oACAEDAQE/EEqSf//EABYRAAMAAAAAAAAAAAAAAAAAAAEQEf/aAAgBAgEBPxAov//EAB0QAAIDAAIDAAAAAAAAAAAAAAERACFBMVFhcfD/2gAIAQEAAT8QWCY2AwPcacBIKDOP7iAZA89Rz5EaQ2BssGxUFdbERKsn/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;          md 5&apos; title=&apos;&apos; src=&apos;/static/d60652cd7f972e1d28ec4efa5bacb3bc/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_5.jpg&apos; srcset=&apos;/static/d60652cd7f972e1d28ec4efa5bacb3bc/8ccab/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_5.jpg 190w,
/static/d60652cd7f972e1d28ec4efa5bacb3bc/ea4c8/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_5.jpg 380w,
/static/d60652cd7f972e1d28ec4efa5bacb3bc/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_5.jpg 640w&apos; sizes=&apos;(max-width: 640px) 100vw, 640px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;하나하나 텐트 내부를 세팅했어욤. 야전 침대도 놓고. 식탁도 놓고. 먹을것도 챙겨오고. 먹을걸 어찌나 맞춰서 샀는지 남긴게 거의 없었습니당.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; margin-bottom: 16px;&apos; data-url=&apos;./겨울_야생,_부왘.md_6.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/2cd86935fcf8bc15154fdfe3cb1a7364/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_6.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAIEAQP/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAABpm7IjGB//8QAGxAAAQQDAAAAAAAAAAAAAAAAAwABAhEQEhP/2gAIAQEAAQUCIQbLrFPWJ1q5F//EABURAQEAAAAAAAAAAAAAAAAAAAAS/9oACAEDAQE/AYS//8QAFhEAAwAAAAAAAAAAAAAAAAAAAAES/9oACAECAQE/AbZbP//EAB0QAAICAQUAAAAAAAAAAAAAAAABAjEQESFBcZH/2gAIAQEABj8C5fSFrGW5T8xVMo//xAAZEAEBAQEBAQAAAAAAAAAAAAABEQAxIaH/2gAIAQEAAT8hqBkQECpzIuVvV1Bag737+b//2gAMAwEAAgADAAAAELDv/8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQMBAT8QhL//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ECv/xAAdEAEAAgMAAwEAAAAAAAAAAAABABEhMUFxgbHw/9oACAEBAAE/EHUscZH3qapinPzj5MsynHBCldl+xBrdjFbt7+dn/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;          md 6&apos; title=&apos;&apos; src=&apos;/static/2cd86935fcf8bc15154fdfe3cb1a7364/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_6.jpg&apos; srcset=&apos;/static/2cd86935fcf8bc15154fdfe3cb1a7364/8ccab/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_6.jpg 190w,
/static/2cd86935fcf8bc15154fdfe3cb1a7364/ea4c8/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_6.jpg 380w,
/static/2cd86935fcf8bc15154fdfe3cb1a7364/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_6.jpg 640w&apos; sizes=&apos;(max-width: 640px) 100vw, 640px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; margin-bottom: 16px;&apos; data-url=&apos;./겨울_야생,_부왘.md_7.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/88f36e57208dbdd437a0ebc3eeb4a076/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_7.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIFBv/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAGm+VZNiQw//8QAGRAAAwEBAQAAAAAAAAAAAAAAAQIDABES/9oACAEBAAEFAp0WgpQSXKD3pfe23//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABoQAQACAwEAAAAAAAAAAAAAAAEQEQACMVH/2gAIAQEABj8CHVwX2pC+R//EABoQAQADAAMAAAAAAAAAAAAAAAEAEUEQITH/2gAIAQEAAT8hKh3mzcAcBLGoWpNtYUeT/9oADAMBAAIAAwAAABDE7//EABYRAQEBAAAAAAAAAAAAAAAAAAARgf/aAAgBAwEBPxCMf//EABYRAQEBAAAAAAAAAAAAAAAAAAARgf/aAAgBAgEBPxC1r//EABwQAQEAAwADAQAAAAAAAAAAAAERACExUYGR4f/aAAgBAQABPxBaqbaR5phR0MLHb313IYEbRPd8wQrbVgx9Pw/uf//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;          md 7&apos; title=&apos;&apos; src=&apos;/static/88f36e57208dbdd437a0ebc3eeb4a076/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_7.jpg&apos; srcset=&apos;/static/88f36e57208dbdd437a0ebc3eeb4a076/8ccab/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_7.jpg 190w,
/static/88f36e57208dbdd437a0ebc3eeb4a076/ea4c8/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_7.jpg 380w,
/static/88f36e57208dbdd437a0ebc3eeb4a076/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_7.jpg 640w&apos; sizes=&apos;(max-width: 640px) 100vw, 640px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;텐트 다 쳐놓고는 난로 기름을 구하러 다시 밖으로 나갔습니다. 오는 길에 선녀 바위를 구경했다지요. 오른쪽에 있는게 선녀 바위라는데, 그닥 선녀삘은 ㅋㅋ~ 겨울 바다, 해안이랑 닿은 부분이 얼어서 그런지 바닷물이 참 오묘하게 왔다리 갔다리 하더군요. 사진은 눈감고 찍어야 제맛 ㅋ~&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; margin-bottom: 16px;&apos; data-url=&apos;./겨울_야생,_부왘.md_8.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/d25e0ac02b7ecae2148340739e29c464/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_8.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAUBAwT/xAAVAQEBAAAAAAAAAAAAAAAAAAABAv/aAAwDAQACEAMQAAABt1IJuGInB//EABoQAQACAwEAAAAAAAAAAAAAAAEAAgMRIgT/2gAIAQEAAQUCMpHJQq+im+mdRTf/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAgEBPwFX/8QAGhAAAgIDAAAAAAAAAAAAAAAAABABAiExMv/aAAgBAQAGPwJalZsdH//EABsQAQACAgMAAAAAAAAAAAAAAAEAMUGBESGh/9oACAEBAAE/IR49gxW8TMeoFSR4FEN2bqf/2gAMAwEAAgADAAAAEL/v/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAR/9oACAEDAQE/EALL/8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQIBAT8QVY//xAAcEAACAgIDAAAAAAAAAAAAAAAAAREhMWFBccH/2gAIAQEAAT8QcKrF41MLaFWXYN1R0cd9KfCMMoyf/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;          md 8&apos; title=&apos;&apos; src=&apos;/static/d25e0ac02b7ecae2148340739e29c464/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_8.jpg&apos; srcset=&apos;/static/d25e0ac02b7ecae2148340739e29c464/8ccab/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_8.jpg 190w,
/static/d25e0ac02b7ecae2148340739e29c464/ea4c8/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_8.jpg 380w,
/static/d25e0ac02b7ecae2148340739e29c464/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_8.jpg 640w&apos; sizes=&apos;(max-width: 640px) 100vw, 640px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; margin-bottom: 16px;&apos; data-url=&apos;./겨울_야생,_부왘.md_9.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/3175cd8281f2321f07d4481fbfd9953c/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_9.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAUGAwT/xAAWAQEBAQAAAAAAAAAAAAAAAAAAAQL/2gAMAwEAAhADEAAAAWGsv2M0YqF//8QAGhAAAwADAQAAAAAAAAAAAAAAAQIDAAQSEf/aAAgBAQABBQKt1QSoHT0YaHvUZ+i7qf/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EAB0QAAECBwAAAAAAAAAAAAAAAAABERAhIjFRYYH/2gAIAQEABj8ClUuBFtqDjdGP/8QAGhABAAMBAQEAAAAAAAAAAAAAAQAhMREQUf/aAAgBAQABPyGh+uCcc9O/HgwXrCMZaTUrAZ//2gAMAwEAAgADAAAAEE/P/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAERIf/aAAgBAwEBPxCJGH//xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQIBAT8Q1bG//8QAHhABAAICAgMBAAAAAAAAAAAAAQARITFBcVFhkcH/2gAIAQEAAT8QyIdT6vt4lrQsjavEGLETuKdolu0cH2ZhsWwe40St2Ffs/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;          md 9&apos; title=&apos;&apos; src=&apos;/static/3175cd8281f2321f07d4481fbfd9953c/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_9.jpg&apos; srcset=&apos;/static/3175cd8281f2321f07d4481fbfd9953c/8ccab/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_9.jpg 190w,
/static/3175cd8281f2321f07d4481fbfd9953c/ea4c8/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_9.jpg 380w,
/static/3175cd8281f2321f07d4481fbfd9953c/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_9.jpg 640w&apos; sizes=&apos;(max-width: 640px) 100vw, 640px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;노을이 지면서 날이 저물기 시작합니다. 밖에서 에스키모 놀이 했어요. 무지하게 추웠습니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; margin-bottom: 16px;&apos; data-url=&apos;./겨울_야생,_부왘.md_10.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/4bad3024181d800b78f21e2b08780753/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_10.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQBAgMF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAePeMIcEg//EABkQAQADAQEAAAAAAAAAAAAAAAEAAhESA//aAAgBAQABBQK2kLcnRD0ds6z/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAgEBPwFH/8QAFxAAAwEAAAAAAAAAAAAAAAAAABARAf/aAAgBAQAGPwKa6Vf/xAAaEAEAAwADAAAAAAAAAAAAAAABABEhEEFR/9oACAEBAAE/IQlG+TETiOexEVNrLn//2gAMAwEAAgADAAAAEBff/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxA//8QAFhEBAQEAAAAAAAAAAAAAAAAAERAx/9oACAECAQE/EB2P/8QAGhABAQEBAAMAAAAAAAAAAAAAAREAITFBcf/aAAgBAQABPxCnAPrAHQck8YYOaraKC5USqr26/a7/2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;          md 10&apos; title=&apos;&apos; src=&apos;/static/4bad3024181d800b78f21e2b08780753/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_10.jpg&apos; srcset=&apos;/static/4bad3024181d800b78f21e2b08780753/8ccab/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_10.jpg 190w,
/static/4bad3024181d800b78f21e2b08780753/ea4c8/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_10.jpg 380w,
/static/4bad3024181d800b78f21e2b08780753/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_10.jpg 640w&apos; sizes=&apos;(max-width: 640px) 100vw, 640px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; margin-bottom: 16px;&apos; data-url=&apos;./겨울_야생,_부왘.md_11.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/c8cdd241153ef5dc3ca85ace8e6d61b2/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_11.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAMBBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAHi7WcRB//EABgQAQEBAQEAAAAAAAAAAAAAAAIBEAAD/9oACAEBAAEFAoryzzRhZkz/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAZEAACAwEAAAAAAAAAAAAAAAABEQACECH/2gAIAQEABj8C1GrM4Xn/xAAbEAEAAgIDAAAAAAAAAAAAAAABABEQITFBUf/aAAgBAQABPyERQ1Eey4ltHcaBtOax/9oADAMBAAIAAwAAABCEL//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABURAQEAAAAAAAAAAAAAAAAAABBB/9oACAECAQE/EKf/xAAaEAEBAQEAAwAAAAAAAAAAAAABEQAhMUFx/9oACAEBAAE/EAM5fMzmg+Zp7mCIhxMxQheEfZmjF6b/2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;          md 11&apos; title=&apos;&apos; src=&apos;/static/c8cdd241153ef5dc3ca85ace8e6d61b2/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_11.jpg&apos; srcset=&apos;/static/c8cdd241153ef5dc3ca85ace8e6d61b2/8ccab/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_11.jpg 190w,
/static/c8cdd241153ef5dc3ca85ace8e6d61b2/ea4c8/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_11.jpg 380w,
/static/c8cdd241153ef5dc3ca85ace8e6d61b2/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_11.jpg 640w&apos; sizes=&apos;(max-width: 640px) 100vw, 640px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;꽁치김치찌개로 배를 좀 채우고 맥주도 한 잔 하고 있을 무렵. 세 번째 손님이 합류했습니다. 깜깜한 동굴에 있는 우리에게 한줄기 빛과 같은 랜턴을 제공해주신 바로 그 분. 후훗~ 50년도 넘은 랜턴이라는데 동작은 잘 하더군요. 술먹다 말고 오른쪽에 랜턴을 급세팅하고 있습니다. 저녁에 이것 때문에 골로 갈뻔 한 일이 있었습니다. 자는 도중에 랜턴에서 연기가 나서 텐트 안이 온통 연기로 가득 찬 거였죠. 그나마도 술먹고 자는 바람에 저는 알지도 못했는데 고프로님께서 총알같이 랜턴을 밖으로 빼고 환기를 시켜서 살았답니다. 그냥 황천길 갈 뻔 했어요. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; margin-bottom: 16px;&apos; data-url=&apos;./겨울_야생,_부왘.md_12.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a00a00df1fe318f8988e6580d59fb48c/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_12.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAIBAwX/xAAVAQEBAAAAAAAAAAAAAAAAAAABAP/aAAwDAQACEAMQAAABxGrEUkn/xAAYEAADAQEAAAAAAAAAAAAAAAABAhEAIP/aAAgBAQABBQKXFCF4/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAFxAAAwEAAAAAAAAAAAAAAAAAABEgIf/aAAgBAQAGPwIeT//EABoQAQACAwEAAAAAAAAAAAAAAAERIQAQMUH/2gAIAQEAAT8hGgEl8y9UTFOiuZLydf/aAAwDAQACAAMAAAAQHy//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAVEQEBAAAAAAAAAAAAAAAAAAAQIf/aAAgBAgEBPxCn/8QAHBABAAEEAwAAAAAAAAAAAAAAAREAECFBMVGB/9oACAEBAAE/EECGIlzNHJ3sk8slCkTImqUMkdW//9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;          md 12&apos; title=&apos;&apos; src=&apos;/static/a00a00df1fe318f8988e6580d59fb48c/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_12.jpg&apos; srcset=&apos;/static/a00a00df1fe318f8988e6580d59fb48c/8ccab/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_12.jpg 190w,
/static/a00a00df1fe318f8988e6580d59fb48c/ea4c8/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_12.jpg 380w,
/static/a00a00df1fe318f8988e6580d59fb48c/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_12.jpg 640w&apos; sizes=&apos;(max-width: 640px) 100vw, 640px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; margin-bottom: 16px;&apos; data-url=&apos;./겨울_야생,_부왘.md_13.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/a1ec83cea02c1d97aedd6ab63c31c05f/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_13.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQFAgb/xAAUAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAFtWToeqJQH/8QAGhABAQACAwAAAAAAAAAAAAAAAQIAAxESIv/aAAgBAQABBQLv5KhY4ZFnFm8077nX/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGhAAAwEAAwAAAAAAAAAAAAAAAAERAhIigf/aAAgBAQAGPwK52xrexM6srtJyXqP/xAAbEAADAQADAQAAAAAAAAAAAAAAAREhMUFR0f/aAAgBAQABPyFUmmsujaKezeyOcMeUVC+gKFs9D//aAAwDAQACAAMAAAAQ0z//xAAXEQADAQAAAAAAAAAAAAAAAAAAARFB/9oACAEDAQE/EElLpD//xAAXEQEBAQEAAAAAAAAAAAAAAAABABEh/9oACAECAQE/EFRy5f/EABoQAQADAQEBAAAAAAAAAAAAAAEAESFRMUH/2gAIAQEAAT8QNWgIYt89IbsOFAtjyFBALN7BDjKSCB8Fu2QEJ0WGq6JP/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;          md 13&apos; title=&apos;&apos; src=&apos;/static/a1ec83cea02c1d97aedd6ab63c31c05f/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_13.jpg&apos; srcset=&apos;/static/a1ec83cea02c1d97aedd6ab63c31c05f/8ccab/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_13.jpg 190w,
/static/a1ec83cea02c1d97aedd6ab63c31c05f/ea4c8/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_13.jpg 380w,
/static/a1ec83cea02c1d97aedd6ab63c31c05f/56d4e/%EA%B2%A8%EC%9A%B8_%EC%95%BC%EC%83%9D%2C_%EB%B6%80%EC%99%98.md_13.jpg 640w&apos; sizes=&apos;(max-width: 640px) 100vw, 640px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이렇게 우리의 밤은 깊어만 갔습니다. 6-7년 전에는 술만 마시면 윈도우와 C, 그리고 각종 프로그래밍 이야기로 날밤을 지새웠던 우리지만 더 이상 그 이야기들은 우리의 안주 거리가 되지는 못했습니다. 날씨가 너무 추운 관계로 예정됐었던 천체 관측은 깔끔하게 삭제됐습니다. 그날도 자체 제작하셨다는 돕소니아 망원경은 구경을 못했네욤.&lt;/p&gt;
&lt;p&gt;날이 밝았습니다. 일어나서는 라면에 햄에 온갖거를 먹고 또다시 취침 모드로 돌입하신 두 분. ㅋㅋ~ 전 옆에서 고즈넉한 분위기에 책이나 읽고 있었습니다. 저녁 사이에 개인지 고양이인지 알 수 없는 야생 동물이 들어와서 한 덩이 남은 피같은 소고기를 훔쳐갔더군요. 야생은 정말 위험한 곳이예요. 뺐고 뺐기는, 또 죽고 죽이는. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;안나푸르나를 기약하면서 집으로 컴백했습니다. 단촐한 야생에서의 1박 2일이었지만 정말 재밌었어요. 뭐든지 잉여롭게 따라가면 재미있다는 사실을 다시 한번 확인한 캠핑이었습니다. 아스트랄했던 저의 정신 세계에 얼마간 안정을 찾게 해주는 시간이기도 했습니다. 흐흐~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Visual C++ 파워풀 개발 테크닉 오류 수정]]></title><description><![CDATA[p19, p20  p19, p20에 있는 그림1과 그림2가 위와 같은 형태로 변경되어야 합니다. 위쪽이 그림1, 아래쪽이 그림2를 나타냅니다. 잘못된 내용은 우선 FREE와 RESERVE 메모리가 구분 없이 그려졌고, 1…]]></description><link>https://jiniya.net/wp/archives/3577</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3577</guid><pubDate>Mon, 13 Dec 2010 23:56:56 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;p19, p20&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 620px; margin-bottom: 16px;&apos; data-url=&apos;./Visual_C++_파워풀_개발_테크닉_오류_수정.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/8168e82a9a7f358c5813e179c46f4f7e/abf7b/Visual_C%2B%2B_%ED%8C%8C%EC%9B%8C%ED%92%80_%EA%B0%9C%EB%B0%9C_%ED%85%8C%ED%81%AC%EB%8B%89_%EC%98%A4%EB%A5%98_%EC%88%98%EC%A0%95.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 26.842105263157894%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAIAAADKYVtkAAAACXBIWXMAAA7CAAAOwgEVKEqAAAABFUlEQVR42mN4/tzm7VuPv39//v///9+/f/+hAMT48+fthw/unz7F////GyYIVfD5c/L79/4MT558O3v2wbNnzz9+/HD06FEXFxdra+vAwEA7Oztzc0tb2yA7u0ArK2tLS0tvb28vLy8LCwtraxtzc6/w8GyGd+96b9+u+fLlE9DWBw8ezJo1a8qUKTNnzpw2bcaUKT2dnRodHcaTJk2YNGny1KlTp0+fDiSnTZvW0WE6c6Ytw8uXGe/fF//7B3cYwtm/f7//9q3y589+oA/QnP3pU+ubNyUMjx59OHTo/KNHj96/f79r1y41NTVpaWlDQ0NZWVkFBeWNG/cCld6/fx8oe+/ePWVlZRkZGWNjY3FxZWtrDwAM88sDOww/+gAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Visual C                    md 0&apos; title=&apos;&apos; src=&apos;/static/8168e82a9a7f358c5813e179c46f4f7e/abf7b/Visual_C%2B%2B_%ED%8C%8C%EC%9B%8C%ED%92%80_%EA%B0%9C%EB%B0%9C_%ED%85%8C%ED%81%AC%EB%8B%89_%EC%98%A4%EB%A5%98_%EC%88%98%EC%A0%95.md_0.png&apos; srcset=&apos;/static/8168e82a9a7f358c5813e179c46f4f7e/08678/Visual_C%2B%2B_%ED%8C%8C%EC%9B%8C%ED%92%80_%EA%B0%9C%EB%B0%9C_%ED%85%8C%ED%81%AC%EB%8B%89_%EC%98%A4%EB%A5%98_%EC%88%98%EC%A0%95.md_0.png 190w,
/static/8168e82a9a7f358c5813e179c46f4f7e/2edd7/Visual_C%2B%2B_%ED%8C%8C%EC%9B%8C%ED%92%80_%EA%B0%9C%EB%B0%9C_%ED%85%8C%ED%81%AC%EB%8B%89_%EC%98%A4%EB%A5%98_%EC%88%98%EC%A0%95.md_0.png 380w,
/static/8168e82a9a7f358c5813e179c46f4f7e/abf7b/Visual_C%2B%2B_%ED%8C%8C%EC%9B%8C%ED%92%80_%EA%B0%9C%EB%B0%9C_%ED%85%8C%ED%81%AC%EB%8B%89_%EC%98%A4%EB%A5%98_%EC%88%98%EC%A0%95.md_0.png 620w&apos; sizes=&apos;(max-width: 620px) 100vw, 620px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;p19, p20에 있는 그림1과 그림2가 위와 같은 형태로 변경되어야 합니다. 위쪽이 그림1, 아래쪽이 그림2를 나타냅니다. 잘못된 내용은 우선 FREE와 RESERVE 메모리가 구분 없이 그려졌고, 16진수를 사용하면서 더하기는 10진수로 해버린 문제가 있었습니다. 흰색은 RESERVE 영역, 회색은 COMMIT영역, 검은색은 FREE 영역입니다. 그림1에서 FREE 영역의 크기가 0x2000으로 표기된 것이 0x8000이 되어야 하고, 그림2에서는 0x1000의 COMMIT 뒤쪽 부분이 모두 잘못 그려진 내용이 수정되었습니다. 노란 박스는 화살표 지점이 메모리의 어떤 번지를 나타내는지를 의미합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;p21&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;VirtualFree(0x12000, 0x5000, MEM_DECOMMIT)을 하면 책의 설명처럼 2, 4번 영역을 모두 예약 상태로 변경하지 않습니다. 0x12000부터 0x16fff까지의 영역을 해제하기 때문에 결과적으로 2번 영역만 해제가 됩니다. 책에 나온대로 2, 4번 영역을 모두 한번에 해제하기 위해서는 VirtualFree(0x12000, 0x5001, MEM_DECOMMIT)과 같은 형태로 사용해야 합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;p90, p91&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;그림2, 그림3에 표기된 EPS는 ESP가 되어야 합니다. ESP 레지스터가 가리키는 지점을 나타냅니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[휴식]]></title><description><![CDATA[육체 노동을 하는 사람들에게 휴식은 너무도 당연한 일이다. 일정 시간을 일을 하면 그 다음에 휴식을 가져야 다시 일을 할 수 있다는 사실이 너무 자연스럽기 때문이다. 무작정 30시간, 4…]]></description><link>https://jiniya.net/wp/archives/3567</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3567</guid><pubDate>Thu, 09 Dec 2010 23:56:55 GMT</pubDate><content:encoded>&lt;p&gt;육체 노동을 하는 사람들에게 휴식은 너무도 당연한 일이다. 일정 시간을 일을 하면 그 다음에 휴식을 가져야 다시 일을 할 수 있다는 사실이 너무 자연스럽기 때문이다. 무작정 30시간, 40시간 달아서 일한다고 생산량이 선형적으로 증가하지 않는다는 사실을 우리 몸은 본능적으로 알고 경고 시그널을 보낸다. 그런데 지식 근로자들은 이 단순한 사실을 너무 쉽게 간과해 버린다. 뇌도 그 속성은 근육과 마찬가지로 휴식을 필요로 함에도 그것이 표면적으로 드러나지 않기 때문이다. 그들은 자신의 뇌를 ‘난 아직 피곤하지 않아, 더 할 수 있어’라는 스팀팩으로 자극을 하면서 장시간의 노동을 이어간다. 안타까운 사실은 결국 그건 황금알을 낳는 거위의 배를 가른 농부처럼 자신의 배를 갈라버리는 짓이라는 점이다. 그러다 한방에 ‘훅’ 간다.&lt;/p&gt;
&lt;p&gt;이제 솔직해지자. 우리의 뇌는 괜찮다는 세뇌도, 할 수 있다는 스팀팩도 필요하지 않다. 단지 우리 뇌는 휴식을 필요로 하는 거다. 거위를 잃기 싫으면 휴식을 취하자. 거위 잃고 나면 다 소용 없다는 사실을 그냥 느낀다. 잃기 전에 지키자.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[IRP 처리 방법…]]></title><description><![CDATA[윈도우 드라이버를 개발하다보면 IRQL, IRP 같은 말들을 매번 듣게 됩니다. 그만큼 윈도우 드라이버 개발에 있어서 중요한 개념이란 의미겠죠. 필터 드라이버를 만들다보면 특히 이중에서도 IRP…]]></description><link>https://jiniya.net/wp/archives/3527</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3527</guid><pubDate>Wed, 17 Nov 2010 23:56:54 GMT</pubDate><content:encoded>&lt;p&gt;윈도우 드라이버를 개발하다보면 IRQL, IRP 같은 말들을 매번 듣게 됩니다. 그만큼 윈도우 드라이버 개발에 있어서 중요한 개념이란 의미겠죠. 필터 드라이버를 만들다보면 특히 이중에서도 IRP 처리와 관련해서 문제가 생기는 경우가 많습니다. 기본 개념을 모르고 남의 샘플 코드를 참고해서 만드는 경우라면 샘플 소스들의 IRP 처리 방식이 달라서 의문이 생기는 경우도 있습니다. 도대체 어떤 방식이 맞는지 말이죠. 어쨌든 이런 말도많고 탈도많은 IRP 처리에 대해서 명쾌하게 정리해서 핵심만 콕 찝어서 설명한 문서가 있어서 소개합니다. MSDN 아티클인데, 딱 10분만 읽으신다면 무엇이 어떻게 돌아가는지 이해하실 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://support.microsoft.com/default.aspx?scid=kb;EN-US;320275&quot;&gt;http://support.microsoft.com/default.aspx?scid=kb;EN-US;320275&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q326315&quot;&gt;http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q326315&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[조카]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/3342</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3342</guid><pubDate>Sat, 13 Nov 2010 23:56:53 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./조카.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/978de07f709da11b2b27d5dd5f5e401f/e224a/%EC%A1%B0%EC%B9%B4.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIDBf/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAFs3ZWSZQP/xAAbEAACAwADAAAAAAAAAAAAAAAAAwECERATIv/aAAgBAQABBQJ3shTJ4dlTLHdQ/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAERIf/aAAgBAwEBPwGpGH//xAAVEQEBAAAAAAAAAAAAAAAAAAAQIf/aAAgBAgEBPwGn/8QAHBAAAgICAwAAAAAAAAAAAAAAAREAAhAhAxIx/9oACAEBAAY/AhWqcfix14wmdnG5/8QAGRAAAwEBAQAAAAAAAAAAAAAAAREhADFB/9oACAEBAAE/IRNB0X5hyJs1IB4VcagzhDmRen291S1HWN//2gAMAwEAAgADAAAAEPgv/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQARcf/aAAgBAwEBPxAxDd3/xAAXEQEBAQEAAAAAAAAAAAAAAAABABFB/9oACAECAQE/EE4sb//EAB0QAQEAAQQDAAAAAAAAAAAAAAERACFBUWExgfD/2gAIAQEAAT8QWXWXCA57co3crKmXbAg53wEGiGITz24tvUADGgn1xQEGgSj6z//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;   md 0&apos; title=&apos;&apos; src=&apos;/static/978de07f709da11b2b27d5dd5f5e401f/e224a/%EC%A1%B0%EC%B9%B4.md_0.jpg&apos; srcset=&apos;/static/978de07f709da11b2b27d5dd5f5e401f/8ccab/%EC%A1%B0%EC%B9%B4.md_0.jpg 190w,
/static/978de07f709da11b2b27d5dd5f5e401f/ea4c8/%EC%A1%B0%EC%B9%B4.md_0.jpg 380w,
/static/978de07f709da11b2b27d5dd5f5e401f/e224a/%EC%A1%B0%EC%B9%B4.md_0.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;주말에 부모님 생신이라 부산엘 다녀왔다. 올해는 부모님 건강이 좋지 않으셔서 집에서 조촐하게 밥을 먹었는데, 매형들에 조카들에 나름 북적댔다. 이제는 작은 매형까지 와서 왠지 혼자만 소외된 느낌 ㅋㅋ~ 전날 무리하게 과음한 관계로 속은 쓰려 죽겠는데 엄마가 회를 또 오지게 많이 사와서 서로 먹으라고 난리도 아닌 장면이 연출되기도 했었다.&lt;/p&gt;
&lt;p&gt;밥을 먹고는 다시 방에 들어와서 병원놀이, 환자놀이 모드로 들어가려는데 이 녀석들이 삼촌, 삼촌 하면서 오는게 아닌가. 특히 둘째 녀석 정말 쩔게 귀엽다. 크면 여자 꽤나 울리겠다고 우리가 농담삼아 말하는데 어찌나 귀여운지. 쓰린 속을 달래며 스마트폰에 하나도 없던 게임을 무려 두 개나 친히 다운로드 받아서 실행시켜 주었다. 첫째는 할 줄을 알고, 둘째는 방법도 모르면서 자기가 하겠다고 난리를 부리는 통에 매형이 다시 차에 내려가서 스마트폰을 가져오는 진풍경이 벌어지기도 했다. 아이들은 정말 핸드폰을 좋아한다.&lt;/p&gt;
&lt;p&gt;술래잡기를 하자고 해서 숨으라고 하고는 방에 들어가서 한 10분쯤 잤나. 작은 누가가 들어오더니 이런다. 아이가 애타게 찾기를 기다리고 있으니 안 울리려면 언능가서 찾아주라고. 쓰린 속에 다른 방으로 갔더니 혼자 이불을 뒤집어 쓰고 10분 넘게 가만히 있었던게 아닌가. 그 때묻지 않은 순수함에 티를 묻힌것 같아서 못내 미안했다. 계속 하자는걸 좀 쉬었다 하자고 했더니. 언제까지 쉴거냐고? 작은 바늘이 11에 오면 다시 하는 거냐고. 그래서 그러자고 했다. 참고로 그 때 시간은 4시가 다 되어 가는 시간이었다. 그길로 나는 깊은 수면에 빠져들 수 있었다.&lt;/p&gt;
&lt;p&gt;난 아이들을 참 싫어했다. 모든게 의존적인 그놈들이 귀찮기만 하다고 느꼈었다. 물론 나도 어느 누군가의 아이였지만 말이다. 그런데 이번에 녀석들을 보면서 묘한 생각이 들었다. 어쩌면 자신의 존재감을 극한으로 느낄 수 있는 것이 아이를 가지는 일이 아닐까란 생각. &lt;/p&gt;
&lt;p&gt;이 녀석들도 언젠가는 대학도 가고, 군대도 가고, 연애도 하고, 결혼도 하겠지? 그들이 사는 세상은 지금보다는 좀 더 나은 세상이었으면 좋겠다는 상상을 해봤다. 우리는 모두 누군가의 자식이었고, 또 언젠가는 누군가의 부모가 된다. 그렇게 세월의 수레바퀴는 쉬임없이 돌아가는게 아닐까?&lt;/p&gt;
&lt;p&gt;때묻지 않은 동심을 키워줄 근사한 크리스마스 선물이 뭐가 있을지 찾고 있는 요즘이다.&lt;/p&gt;
&lt;p&gt;덧) 글을 쓰고 전수연씨의 곡을 듣고 있자니 초등학교 1학년 그 때가 생각난다. 따스한 초여름이 다가오는 날이었던 것 같은데, 난 학교에서 채점된 받아쓰기 시험지를 들고는 하교하는 중이었다. 학교 운동장을 나와 교문으로 가는 동안 무지하게 갈등했다. 이걸 찢어버릴 것인지, 들고갈 것인지 말이다. 참고로 그 때 점수는 100점 만점에 40점. 죽도록 고민한 나는 교문에 채 도착하기도 전에 그 시험지를 갈기갈기 찢어서 버렸다. 이 사건이 내가 기억하는 내 인생에서의 첫 번째 고민이다. 결과야 어떻든 나는 떳떳한 선택을 하지는 않았다. 그 때 부터 난 쭉 고민의 바닷속을 거침없이 항해하기 시작했고, 늘상 비슷한 답을 선택했던 것 같기도 하다. 바램이 있다면 앞으로는 좀 더 현명한 선택을 할 수 있었으면 좋겠다.&lt;/p&gt;
&lt;p&gt;그 초등학교 담임 선생님은 학교 생활 기록부에 잠만 잔다고 적었고, 어머니는 기겁을 했었다. 사실 난 실제로 잠만 잤었기에 할말은 없었다. 그 사람은 어디서 무엇을 하고 있을지 문득 궁금해진다. ㅋㅋ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[나는 빠리의 택시 운전사]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/3420</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3420</guid><pubDate>Mon, 08 Nov 2010 23:56:52 GMT</pubDate><content:encoded>&lt;p&gt;참 우연이라고 하기에는 얄구진 일들이 있다. 내 기억에 의하면 아마 초등학교 때였던 것 같은데, 담임 선생님이 이 책을 읽고 와서 너스레를 떨었던 기억이 있다. 그 기억이 너무 강렬해서 였을까? 몇 해전 헌책방에서 정비석씨의 초한지를 찾아 헤매다가 개수를 채우기 위해서 눈에 띄인 이 책을 같이 집어 왔다. 몇 장 읽다가는 그 때 사온 초한지에 묻혀서 책장에 빛바랜 채로 내 기억에서 사라져 버렸다.&lt;/p&gt;
&lt;p&gt;몇 일 전이었다. 다소 책을 읽을 것 같지 않던 녀석에게 책을 빌려주기로 한 약속을 지키며 이런 저런 이야기를 하던 도중 녀석도 나에게 책을 빌려주겠다는 이야기를 한 것이었다. 그 책도 읽지 않을 것 같던 녀석이 처음 꺼낸 책 제목이 “나는 빠리의 택시 운전사”였다. 흠. 그렇다 이 책. 읽지 않고는 넘어갈 수가 없었다. 일요일에 바쁜 일들을 제쳐두고는 책을 집어들었다.&lt;/p&gt;
&lt;p&gt;책을 다시 집어 들면서 내가 제일 먼저 확인한 사실은 초판 발행일이었다. 95년으로 보아 내가 초등학교 때 들었다던 기억은 잘못된 기억임에 틀림이 없었다. 그런데 아무리 생각해도 중학교 선생님 중에는 저 책을 읽을만한 위인도 너스레를 떨었을만한 선생님도 없는데 그 때 누가 그런 이야기를 했는지는 정말 의문이다.&lt;/p&gt;
&lt;p&gt;책은 빠리를 소개하는 이야기로 시작된다. 빠리를 가봐서일까? 그 부분은 정말 흥미진진했다. 마치 다시 빠리에 있는 느낌이 들었다. 책장은 슝슝 넘어갔다. 그런데 그게 다였다. 그 다음 부터는 한 장, 한 장이 지지리도 넘기기 어려운 책이었다. 재미가 없다는 뜻이 아니다. 내용이 그랬다. 그냥 쉽게 읽어 넘기기에는 불편한 그런 내용들이었다. 마지막 장에 홍세화씨가 강조하는 똘레랑스에 관해서 설명하는 부분이 나온다. 그 부분을 읽으면서 자격지심인지도 모르겠지만 녀석이 왜 이 책을 첫 번째 책으로 낙점했는지를 조금 이해할 법도 했다.&lt;/p&gt;
&lt;p&gt;나름 다름을 인정하지 않는 세상에서 다르게 살아간다는 것이 다소간 고통을 동반한다는 사실을 나는 잘 알고 있다고 생각했었다. 나는 왼손잡이인데 교육에 의해서 오른손을 쓰게 되었다. 하지만 여전히 왼손으로 하는 일들이 많다. 왼손을 써야 할 때마다 느끼는데 세상은 온통 오른손 잡이에게 맞추어져 있어서 여간 불편한게 아니다. 하지만 녀석의 눈에는 아마도 내가 다름을 틀리다고 인식하는 사람처럼 비춰진 건 아닐까란 생각이 들었다. 나의 다름은 존중받고 싶지만 남의 다름은 틀림으로 무시해 버리는 그런 사고를 보여준 건 아닐까란 부끄러운 생각이 책장을 덮는 순간 나의 머릿속을 멤돌았다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“초보자라고 미안해할 필요는 없어요. 모든 직업에 데뷔 시기는 있어야 하는 것이니까요. 그런데 몽마르뜨르로는 꽤 중요한 길이니까 잘 알아 두세요.”&lt;/p&gt;
&lt;p&gt;“글쎄. 나도 잘은 모르오. 그런데 내가 이 제로썸 이론에 주목했던 이유는 다른 데에 있소. 자본의 논리 또는 소유의 논리의 메커니즘에 길들여진 인간들이 이젠 마음 씀씀이조차 그렇게 되었다는 거지요. 우리들은 이제 인간관계에서 다른 사람들에게 마음을 주는 것조차 아주 인색해졌다는 얘기요. 주는 것은 곧 마이너스이니까 손해보는 것, 더 나아가 패배하는 것이라고 인식하여 되도록 주진 않고 마냥 받으려고만 하는 것이지요. 그런데 원래 인간의 마음이란 샘과 같아서 주면 줄수록 더욱 충만해지고 깊어지고 또 넓어지는 것이라고 믿소.”&lt;/p&gt;
&lt;p&gt;“인간이 모두 똑같이 태어나지 않기 때문에 평등 개념이 창안되어야 했던 것이며, 인간이 모두 같은 이데올로기를 갖지 않기 때문에 인권 개념이 창안되었어야 했던 것입니다.”&lt;/p&gt;
&lt;p&gt;남민전이 너무 무모했었다고들 말한다. 그렇다. 무모했다. 하지만 나처럼 수학은 잘했지만 계산을 잘 못하는 사람에게는 무모하지 않았다. 나는 계산에 어두웠고 또 계산을 싫어했다. 나는 바보였다. 증오의 사회에 무모하게 저항했던 바보였다. 그러나 그것이 나의 실존이었고 삶이었다. 나는 내가 바보라는 것을 알고 있었던 바보였고 또 그 바보스러움을 자랑스럽게 껴안고 있었던 바보였다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;창녀 고양이라고 했던가? 세상은 그런 것 같아. 지금이 죽도록 싫지만, 지나고 나면 그 죽도록 싫어했던 지금이 죽도록 그리워 진다는 거. 그게 인생의 모순인지도 모르지.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[여친용 프로그램 ㅋㅋ~]]></title><description><![CDATA[회사 개발자가 예전에 공부할 때 만들었던 프로그램이라고 하는데, 구경 하다가 너무 재밌어서 퍼왔습니다. “사랑해”, “loving you…]]></description><link>https://jiniya.net/wp/archives/3390</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3390</guid><pubDate>Thu, 04 Nov 2010 23:56:51 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./여친용_프로그램_ㅋㅋ~.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/5d4b888663f6ba8b0261ab64ca165266/dface/%EC%97%AC%EC%B9%9C%EC%9A%A9_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8_%E3%85%8B%E3%85%8B~.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 50%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAB+UlEQVR42g2QV27bQABElyIptmXZ5TbuUqxiEYsKEyuJLdcgQBDEgB34DMn9bxD9zNcAb96Al8/fBz4XtNw324nvBGVZgq0whpksT4dmumc4TFnLyRTTmAYIm34TVK172kev4O/tZQepb4UFijwYaIaVR05gO/qagNVKivFmvk2F4oRS5NMwJiJBFodamEdHUGWdBoBj2QUOrmm1B9rurl2hZkgT5bulTIqmzrutrFRaFkmSEodwO2bbAdguFpE6bg8/z208DurxZRkX7pEkFKHrB5J13ZblkiJFDBQXuewXTYNAN/CYgUQWc/apWx7Esq//XLLbQ7lBnh8JFFuGBhCM270U3cZJqcExFqo4uZABAGApQLuZON2U1Zxvq+F5EIcj2TJ0pXrQlNaa+RBL2feKFK4TVY7M1i2SHZEkbBIwnpowwbpu+r4XR8RYtUAzPM/oS5UrUQi1RNwOnLieCK/L3f6L+hagJutnOUkgOrxh6Dpj7dr2WjMA083YZYDyrDKtS+C/tX2IrnKn5ff7+f3Xw/kH5JFUTaoy0M/05Viaps4SygTWfeYlGNUwv/lAwyhxcFddzx42slZ1fn4+X5Knw3Tu749jloOnu2YuqaZppmOJlqdf92RA4vVjePs3TXMozcg2JcaO667WTtmOz/27hLkrvK6m/wEywj+PHMkTSQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;             md 0&apos; title=&apos;&apos; src=&apos;/static/5d4b888663f6ba8b0261ab64ca165266/dface/%EC%97%AC%EC%B9%9C%EC%9A%A9_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8_%E3%85%8B%E3%85%8B~.md_0.png&apos; srcset=&apos;/static/5d4b888663f6ba8b0261ab64ca165266/08678/%EC%97%AC%EC%B9%9C%EC%9A%A9_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8_%E3%85%8B%E3%85%8B~.md_0.png 190w,
/static/5d4b888663f6ba8b0261ab64ca165266/2edd7/%EC%97%AC%EC%B9%9C%EC%9A%A9_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8_%E3%85%8B%E3%85%8B~.md_0.png 380w,
/static/5d4b888663f6ba8b0261ab64ca165266/dface/%EC%97%AC%EC%B9%9C%EC%9A%A9_%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%A8_%E3%85%8B%E3%85%8B~.md_0.png 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;회사 개발자가 예전에 공부할 때 만들었던 프로그램이라고 하는데, 구경 하다가 너무 재밌어서 퍼왔습니다. “사랑해”, “loving you”같은 메시지를 화면에 막 뿌려주는 기능이 전부인 심플한 프로그램인데, 여친님께 바치면 대박 효과를 볼 수 있을 것으로 사료되는 프로그램입니다. 사랑하는 여친 컴퓨터에 살포시 시작 프로그램으로 등록해 주세요. ㅋㅋㅋ~ 실행 파일은 아래 경로에서 다운로드 받으실 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/files/loveyou.zip&quot;&gt;http://www.jiniya.net/files/loveyou.zip&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;참고로 제작자 블로그는 &lt;a href=&quot;http://stdcall.tistory.com/&quot;&gt;http://stdcall.tistory.com/&lt;/a&gt; 입니당. 예의상 홍보는 해주는 센스 ㅋㅋㅋ~ 윈도우 프로그래밍을 처음 배울 때 개발한 것 같아서 다소 의도하지 않은 효과들이 나타날 수 있습니다. 근데 그게 더 프로그램의 재미를 더해주는 것 같아요. 153k로 가장 여친을 즐겁게 해줄 수 있는 프로그램이 아닐까요? 참고로 여친 안계신 분은 직접 띄워놓고 감상하셔도 정신 건강에 좋을 것 같아요.&lt;/p&gt;
&lt;p&gt;리누스 토발즈가 첨에 “I love …”을 화면에 막 출력하는 프로그램을 작성하고 뿌듯해 했다는 글이 떠오르는 프로그램이었습니다.&lt;/p&gt;
&lt;p&gt;원 저작자 분께서 쿨하게 소스 코드까지 공개해 주셨습니다. 고쳐 쓰실 분들은 수정해서 사용하시면 되겠습니다. ㅋㅋ~&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&amp;lt;windows.h&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;pragma&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token function&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;linker&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/subsystem:windows&quot;&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
LRESULT CALLBACK &lt;span class=&quot;token function&quot;&gt;WndProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HWND&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;UINT&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;WPARAM&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;LPARAM&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
HINSTANCE g_hInst&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
HWND hWndMain&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
LPCTSTR lpszClass&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Class&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; APIENTRY &lt;span class=&quot;token function&quot;&gt;WinMain&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HINSTANCE hInstance&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;HINSTANCE hPrevInstance
&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;LPSTR lpszCmdParam&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; nCmdShow&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
HWND hWnd&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
MSG Message&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
WNDCLASS WndClass&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
g_hInst&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;hInstance&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

WndClass&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cbClsExtra&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
WndClass&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;cbWndExtra&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
WndClass&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hbrBackground&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HBRUSH&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;COLOR_WINDOW&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
WndClass&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hCursor&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;LoadCursor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;IDC_ARROW&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
WndClass&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hIcon&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;LoadIcon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;IDI_APPLICATION&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
WndClass&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hInstance&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;hInstance&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
WndClass&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lpfnWndProc&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;WndProc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
WndClass&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lpszClassName&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;lpszClass&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
WndClass&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;lpszMenuName&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
WndClass&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;CS_HREDRAW &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; CS_VREDRAW&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;RegisterClass&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;WndClass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

hWnd&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CreateWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;lpszClass&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;lpszClass&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;WS_OVERLAPPEDWINDOW&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
CW_USEDEFAULT&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;CW_USEDEFAULT&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;CW_USEDEFAULT&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;CW_USEDEFAULT&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HMENU&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;hInstance&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;ShowWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hWnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;SW_HIDE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;Message&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;TranslateMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;Message&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;DispatchMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;Message&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;Message&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;wParam&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

LRESULT CALLBACK &lt;span class=&quot;token function&quot;&gt;WndProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HWND hWnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;UINT iMessage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;WPARAM wParam&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;LPARAM lParam&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
HDC hdc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
PAINTSTRUCT ps&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;//  HWND hWin;&lt;/span&gt;
HFONT hFontEdit&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
HFONT oldFont&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;szName&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;사랑해~&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;I LOVE YOU&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;니가 좋아^^&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;♡&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Loving you&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; Wx&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; Wy&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;iMessage&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WM_CREATE&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;

hWndMain&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;hWnd&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;SetTimer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hWnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WM_TIMER&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;MessageBox&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hWnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;그만하까??&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;끝내기&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;MB_OK&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;PostQuitMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
Wx&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetSystemMetrics&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SM_CXSCREEN&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
Wy&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetSystemMetrics&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SM_CYSCREEN&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

hWnd &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetDesktopWindow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//바탕화면의 윈도우&lt;/span&gt;

hdc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;GetWindowDC&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hWnd&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//바탕화면에 그릴 준비&lt;/span&gt;

hFontEdit&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CreateFont&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1800&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;DEFAULT_CHARSET&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;TEXT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;고딕&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

oldFont&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;HFONT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SelectObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hdc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;hFontEdit&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;SetTextColor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hdc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;RGB&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;250&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;250&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;250&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;SetBkMode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hdc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;TRANSPARENT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

name&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;TextOut&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hdc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;Wx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;Wy&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;szName&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;szName&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;SelectObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hdc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;oldFont&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;DeleteObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hFontEdit&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;ReleaseDC&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hWnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; hdc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;DeleteObject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hdc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WM_PAINT&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
hdc&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;BeginPaint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hWnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;ps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;//      TextOut(hdc,rand()%100,rand()%100,&quot;11&quot;,2);&lt;/span&gt;

&lt;span class=&quot;token function&quot;&gt;EndPaint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hWnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt;ps&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; WM_DESTROY&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;KillTimer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hWnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;PostQuitMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;DefWindowProc&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hWnd&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;iMessage&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;wParam&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;lParam&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[존알람, 존알람, 존알람, …]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/3292</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3292</guid><pubDate>Wed, 03 Nov 2010 23:56:50 GMT</pubDate><content:encoded>&lt;p&gt;제가 보안 업계 경력을 초기에 쌓았던 잉카인터넷이란 회사에는 아주 뛰어난 팀장님이 한 분 계셨습니다. 제가 입사했을 때 직속 팀장님이셨는데, 방화벽 드라이버 개발의 전문가셨죠. 지금 제가 알고 있는 지식의 상당수는 그 팀장님께서 친히 가르쳐 주신 것들입니다. 그 때는 별 것 아니라고 생각했던 것도 지금 돌이켜보면 정말 뼈저리게 중요한 사실이었다는 것을 느낄 때가 종종 있는데 그 때마다 업력, 내공의 차이를 느끼곤 합니다. 참 웃긴 이야긴데 제가 좋아하는 하이네켄 다크나 조니워커 블루, 또는 드라이버 개발 때 사용하는 소스 인사이트 등을 저에게 전수해 주신 분도 그 분이십니다. 그런걸 보면 새삼 누굴 만나는지가 정말 중요하다는 생각이 절로 듭니다. 어쨌든 그 때 저희는 방화벽을 개발했었고 뻔질나게 존알람을 벤치마킹 했었습니다. 그 시절 존알람은 개인 PC 방화벽의 선구자적인 제품이었죠. 그 팀장님은 존알람 개발자들을 존경했었고, 저도 제품에서 뿜어나오는 장인 정신에 놀라곤 했었습니다.&lt;/p&gt;
&lt;p&gt;사설이 길었군요. 어쨌든 그랬던 존알람이 최근 저희 제품과 크래시 문제가 있었습니다. 저는 초기에 이걸 QA팀에서 잘못 보고 받아서 오진 문제로 판단을 하고 계속 요청하라고 했었는데, 그 쪽 개발팀에서 온 메일을 봤더니 크래시가 발생하는 거더군요. 그래서 좀 디버깅을 해봤는데 예전 존알람의 장인 정신을 찾기가 초큼 애매한 부분이 많았습니다. 물론 예전 방화벽도 다소 어그레시브한 형태였긴 했지만 지금 제품은 훨씬 더 어그레시브하게 프로세스를 조작하더군요.&lt;/p&gt;
&lt;p&gt;일단 존알람은 엔트리 포인트 후킹이란걸 합니다. 새로 생성되는 프로세스의 엔트리 포인트에 자신으로 이동 시키는 점프 코드를 박는 거죠. 그런데 애석하게도 저희가 만든 그 조그마한 프로세스는 엔트리 포인트는 실행 시점에 변경되도록 되어있었습니다. 당연히 존알람은 쓰레기 더미 코드를 자신의 프록시 프로시저로 복사해간 후에 점프 코드를 삽입했고, 거기를 또 우리는 신나게 원본 엔트리로 덮어 썼던 겁니다. 크래시는 당연지사죠. 엔트리에 버젓이 있는 점프 코드를 보면서 제가 한 생각은… 이건 우리껀데.. ㅋㅋ~ 어쨌든 이 문제를 해결하기 위해서 저는 존알람의 엔트리 포인트 후킹을 위한 6바이트의 nop 코드를 진입 함수 앞에 추가시켜 줬습니다.&lt;/p&gt;
&lt;p&gt;이걸로 끝이었을까요? 아닙니다. 저희가 만든 프로세스의 진입 함수가 실행 시간에 변형된다고 했는데 아마도 존알람이 그 코드를 에뮬레이팅을 하는 것 같아 보였습니다. 처음에 존재했던 쓰레기 코드를 존알람이 에뮬레이팅을 하면서 다시 크래시가 발생하는 것 같더군요. 그래서 이제는 존알람 에뮬레이터가 깔끔하게 알아볼 수 있도록 nop 코드 뒤에 바로 리턴하는 곳으로 점프하는 코드를 추가시켜 줬습니다. 그랬더니 크래시가 발생하지 않더군요.&lt;/p&gt;
&lt;p&gt;디버깅을 끝내고 커피를 마시면서 그런 생각이 들었습니다. 보안 프로그램 최고의 기술은 다른 보안 프로그램과의 충돌을 피하는게 아닐까? 요즘 정말 많은 보안 프로그램이 무분별하게 후킹을 하는 것을 보게 됩니다. 그런 것들을 보고 있자면 참 묘한 생각이 듭니다. 특히 코모도는 짱인것 같아요. 몇 개를 후킹하는지 헐킈. 문지방은 하난데 전부 거기 서서 드나드는 사람들을 감시하려고 하니 충돌을 피할 수가 없는건 어쩌면 당연한 건지도 모르겠습니다. 누군가(매트 피에트릭?) 발견한 조그만 틈 사이로 너무 많은 것들이 쏟아져 나온 게 아닐까하는 생각이 드네요. 이쯤되면 누군가가 문지방에 서지 않고도 그들을 감시할 수 있는 방법을 만들어 줄 때도 된 것 같죠? ㅎㅎ~&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[윈도우 기본 그림보기 배경색 문제]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/3068</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3068</guid><pubDate>Thu, 28 Oct 2010 23:56:49 GMT</pubDate><content:encoded>&lt;p&gt;윈도우 기본 그림보기 프로그램이 있다. 그냥 그림 파일을 더블 클릭하면 나타나는 바로 그 프로그램이다. 그런데 듀얼 모니터를 쓰는 나에게 예전부터 이상한 증상이 하나 있었다. 왼쪽 모니터에서 그림을 보면 정상적으로 보이는데 오른쪽 모니터로 옮기면 그림보기 프로그램의 배경색이 누리끼리하게 보인다는 문제였다. 물론 그 프로그램을 제외한 다른 모든 프로그램에서는 흰색이 정상적으로 표시됐다. 똑같은 삼성 22인치 모니터, 완전 똑같은 모니터 설정, 완전 똑같은 색상 설정으로 사용하고 있다. 그런데 다른 모든 흰색은 똑같이 디스플레이 되는데 유독 그 기본 프로그램만 늘 오른쪽 모니터에서 누리끼리하게 보이는 것이었다. 늘 그냥 그러려니 하고 살다고 오늘 새 컴퓨터를 셋팅하다가 이유를 알게 되었다. 다름아닌 삼성 모니터의 컬러 프로파일 셋팅 때문이었다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.sevenforums.com/music-pictures-video/8081-windows-photo-viewer-background-yellow-color-fix.html&quot;&gt;http://www.sevenforums.com/music-pictures-video/8081-windows-photo-viewer-background-yellow-color-fix.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 730px; margin-bottom: 16px;&apos; data-url=&apos;./윈도우_기본_그림보기_배경색_문제.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/7f1c8769962e17c0236c793379c55b39/a6a70/%EC%9C%88%EB%8F%84%EC%9A%B0_%EA%B8%B0%EB%B3%B8_%EA%B7%B8%EB%A6%BC%EB%B3%B4%EA%B8%B0_%EB%B0%B0%EA%B2%BD%EC%83%89_%EB%AC%B8%EC%A0%9C.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.78947368421053%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACVUlEQVR42o1R+0/aYBTt/5/st5nFxWXGZXFxOEF5WCil76/9+n5BZMnmoIAKFoq0AoO6W9gM+tNOTm6a+91z77m3xNFxae/g2/5h4e3B2Zt3ub2PF/ufKh+Oq4cn1NEp/fmM/VLkTy9RvoYvaL3CmVXJpWRPsH/kSyThWZLMVyW2IjJlLFRtjfEM3lKZli1duajtKVeu3HJQ05YyWqJviq7BQ7J+WSBsHZGlgsBSssgCRb4hSxyWBdvAhorqZJln6paBHVOVRc7QkGtrtokhFs9PCd/RBv3B8G4ImM1mcRwvFounDdardS/oBZ0Akk87SDeRpUmi6er9weBXpzufgyZdp+l6DcyQpunv5XL+OF+tVukO4CUTN2BnW223vwO73V7y+DjPsFgAl8skjq9/XveC4ObmZjQcDfr929tb8AUVSfxwWTojfFvtdjpgr9sJwjCcTCZRNI2iaDweJ3ESdIMg6N2PwjhOwtH9OBxvnS/mSbGQI1quPo3G8UMEzeLZ9GE62eFzMgLCx7YAYnh/Vyx8hcmYoYqKULc0Qd5E31I8EwFdEzmG5OhiFndo62LLVclyPhNTlUKDKmORrpPnGmJ1mdVk1sCcgXno1XQU335Bz5LbTZ2EnV1TpqsXusIpIi0wJGhU1FARAy10hTVVflu9S3B05eubyZbC1EpgBmSg35b6jpINdBTPll8pX4odLHE1mAybII6CtbHUADv/iHZkynMSxNtfhZ8v8fdCBnp1oe0THIKlKxg1MGJMTSyd5wgk1EWu9p8EjxJPwXWL+ZOjw/d/AMNP508z3BYqAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;                   md 0&apos; title=&apos;&apos; src=&apos;/static/7f1c8769962e17c0236c793379c55b39/a6a70/%EC%9C%88%EB%8F%84%EC%9A%B0_%EA%B8%B0%EB%B3%B8_%EA%B7%B8%EB%A6%BC%EB%B3%B4%EA%B8%B0_%EB%B0%B0%EA%B2%BD%EC%83%89_%EB%AC%B8%EC%A0%9C.md_0.png&apos; srcset=&apos;/static/7f1c8769962e17c0236c793379c55b39/08678/%EC%9C%88%EB%8F%84%EC%9A%B0_%EA%B8%B0%EB%B3%B8_%EA%B7%B8%EB%A6%BC%EB%B3%B4%EA%B8%B0_%EB%B0%B0%EA%B2%BD%EC%83%89_%EB%AC%B8%EC%A0%9C.md_0.png 190w,
/static/7f1c8769962e17c0236c793379c55b39/2edd7/%EC%9C%88%EB%8F%84%EC%9A%B0_%EA%B8%B0%EB%B3%B8_%EA%B7%B8%EB%A6%BC%EB%B3%B4%EA%B8%B0_%EB%B0%B0%EA%B2%BD%EC%83%89_%EB%AC%B8%EC%A0%9C.md_0.png 380w,
/static/7f1c8769962e17c0236c793379c55b39/a6a70/%EC%9C%88%EB%8F%84%EC%9A%B0_%EA%B8%B0%EB%B3%B8_%EA%B7%B8%EB%A6%BC%EB%B3%B4%EA%B8%B0_%EB%B0%B0%EA%B2%BD%EC%83%89_%EB%AC%B8%EC%A0%9C.md_0.png 730w&apos; sizes=&apos;(max-width: 730px) 100vw, 730px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;언제부턴가 느끼는 거지만 이제는 윈도우도 너무 복잡해져버린 느낌이다. 예전에 내가 운영체제의 90%를 알고 조작할 수 있었다면 이제는 한 10%도 모르는 것 같다. 거의 대부분의 설정을 모른체 그냥 디폴트로 잡혀있는 걸로 사용하는 것이다. 그러니 문제가 생겨도 원인을 알 수 없다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[유저 모드 스케쥴러 제작의 어려움]]></title><description><![CDATA[예전에 회사 프로젝트를 위해서 간단한 FCFS (first come, first service…]]></description><link>https://jiniya.net/wp/archives/144</link><guid isPermaLink="false">https://jiniya.net/wp/archives/144</guid><pubDate>Thu, 28 Oct 2010 23:56:48 GMT</pubDate><content:encoded>&lt;p&gt;예전에 회사 프로젝트를 위해서 간단한 FCFS (first come, first service) 방식의 스케줄러를 구현한 적이 있었다. 물론 스케줄러라고 하기도 뭣할 정도의 간단한 코드였는데 해당 코드를 추가하고 나서는 독립적인 작업들을 제어하기가 훨씬 쉬워졌고 코드도 깔끔해졌다. 그런데 FCFS 방식에서 알 수 있듯이 실행 시간은 짧고 스케줄 주기가 긴 작업들이 주를 이룰 때는 아주 적절했으나, 실행 시간이 길고 주기가 짧은 작업이 추가되면서 주요한 작업들이 지연되는 현상이 발생하는 것을 알 수 있었다. 즉, I/O 완료 대기와 같은 작업 때문에 실제로 제 시간에 수행해야 하는 중요한 작업들이 실행이 안되는 현상이 발생한 것이다.&lt;/p&gt;
&lt;p&gt;오늘 시간이 나서 해당 코드를 라운드 로빈 방식으로 변경하는 시도를 해 보았다. 뭐 라운드 로빈이라고 어려운 작업은 아니다. 기본 전략은 이랬다. 스레드 두 개를 만든다. 하나는 실제로 스케줄링 작업이 돌아갈 스레드고(이하 워커 스레드), 다른 한 스레드는 일정 시간 주기로 작업이 돌아가는 스레드를 선점해서 스케줄링을 해주는 스레드였다. 즉, 두 번째 스레드가 퀀텀 타임아웃 인터럽트 핸들러 정도가 되는 셈이다. 작업을 교체하는 작업도 어렵지는 않다. 작업별로 스택과 컨텍스트를 저장할 공간을 만들고 작업 저장은 GetThreadContext로, 작업 교체는 SetThreadContext로 하면된다.&lt;/p&gt;
&lt;p&gt;그런데 웃기게도 이 간단해 보이는 작업은 시작부터 순조롭지 않았다. 워커 스레드를 만들었다. 해당 스레드는 당연히 WaitForSingleObject나 Sleep이라는 간단한 함수를 무한 반복하는 구조를 가지고 있다. 이제 스케줄러를 만들고 해당 스레드의 컨텍스트를 새로운 함수 위치로 변경했다. 그리고는 ResumeThread를 호출한다. 당연히 여기서 우아하게 작업 함수가 수행되면서 디버그뷰에 Job1이란 문장이 출력되길 기대했다. 1초, 10초, 30초, … 기다려도 그 메시지는 영원히 표시되지 않았다.&lt;/p&gt;
&lt;p&gt;뭔가 컨텍스트를 관리하는 작업이 잘못됐나 싶어서 꼼꼼히 살펴보았으나 잘못된 부분은 없었다. 해당 코드를 인젝션에 사용하면 깔끔하게 실행됐다. 무엇이 문제일까를 한참 고민했다. 결국 원인을 알게 되었는데 생각보다 간단한 곳에 답이 있었다. Sleep, WaitForSingleObject의 문제였다. 해당 함수를 호출해서 잠긴 스레드는 제 아무리 SuspendThread, SetThreadContext, ResumeThread를 해도 깨어나지 않는다. 해당 이벤트가 시그널이 되어야 깨어날 수 있는 것이었다. 즉, 완전한 라운드 로빈 형식의 유저모드 스케줄러를 제작하기 위해서는 커널모드 객체를 사용할 수가 없다. 아니면 적어도 그것들을 전부 래핑해서 유저모드 스케줄러에 맞도록 별도의 추상화 레이어를 제공해야 된다. 물론 이것만이 문제는 아니다. tls를 사용하는 함수를 사용한다면 실제 작업이 매핑되는 스레드는 하나이기 때문에 문제가 생긴다. 이 또한 작업별로 분리해야 한다는 결론이 난다. 물론 좀 더 세부적으로 들어가면 훨씬 더 많은 문제들이 있을 것이다. 유저모드 스케줄러의 제작은 생각보다 쉬운 일이 아니었다.&lt;/p&gt;
&lt;p&gt;윈도우에는 파이버라는 일종의 유저모드 스레드가 있다. 파이버는 스레드 시간을 나누어 실행되는 스레드보다는 좀 작은 개념이다. 그런데 이 파이버를 살펴보면 알겠지만 협업형 멀티태스킹만 구현될 수 있도록 구조가 잡혀 있다. 지금 생각해보니 이런 문제점 때문에 그렇게 만든 게 아닐까라는 생각이 든다.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[이미 슈퍼스타, 장재인…]]></title><description><![CDATA[슈퍼스타k…]]></description><link>https://jiniya.net/wp/archives/3158</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3158</guid><pubDate>Sat, 16 Oct 2010 23:56:47 GMT</pubDate><content:encoded>&lt;p&gt;슈퍼스타k2 준결승에서 장재인양이 탈락했군요. 닥치고 결승은 진출할 줄 알았기에 충격이었습니다. 나름 챙겨보는 이유가 되기도 했었고 개인적으로 좋아하기도 했었기에 조금 아쉬웠지만, 어쩌면 우승을 하지 못한 것이 그녀에겐 약이 되지 않을까란 생각을 해보았습니다. 그래도 뭔가 씁쓸한 이상한 생각들이 떠오르는건 어쩔 수 없는 이치인 것 같네요. 장재인양을 보면서 느낀 점을 몇 가지 적어 보자면 이렇습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;집중의 법칙. 낙숫물이 바윗돌을 뚫을 수 있는 이유는 한 곳만 공격하기 때문입니다.&lt;/li&gt;
&lt;li&gt;1만 시간의 법칙. 그냥 잘하는 사람은 세상에 아무도 없습니다. 그들의 엄청난 내공 뒤에는 항상 피나는 노력의 시간이 있습니다.&lt;/li&gt;
&lt;li&gt;논어 이야기. 아는 사람은 좋아하는 사람만 못하고, 좋아하는 사람은 즐기는 사람만 못하다. 개인적으로 즐기는 것과 잘하는 것은 별개라고 생각하지만, 종종 잘하는 걸 즐기는 사람들을 보게 됩니다. 그런 사람들의 파괴력은 정말 엄청난 것 같습니다.&lt;/li&gt;
&lt;li&gt;뛰어난 이론가. 뛰어난 실무자가 되기 위해서는 이론에 정통할 필요도 있습니다.&lt;/li&gt;
&lt;li&gt;말하기보다는 듣기. 특정 분야에 뛰어난 사람들은 그들이 만들어 내는 것 이상으로 더 많는 내용을 다른 곳에서 받아 들이는 경향이 있습니다. 뛰어난  화가가 다른 사람의 작품을 감상하는데 시간을 아끼지 않는다던지, 뛰어난 디자이너가 다른 사람들의 패션쇼 내지는 그런 자료들을 엄청나게 많이 수집한다던지 하는 경우죠.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;*** 앞서도 밝혔지만 이 내용은 방송을 보고 제가 개인적으로 느낀 점입니다. 그 사람이 그렇다고 단정지어 말하는 건 아닙니다. 절대로. Never.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[실수…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/3234</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3234</guid><pubDate>Sat, 09 Oct 2010 23:56:46 GMT</pubDate><content:encoded>&lt;p&gt;***영진아, 사람은 누구나 실수를 할 수 있단다.&lt;/p&gt;
&lt;p&gt;하지만 똑같은 실수를 계속 반복하는 것은 어리석은 짓이란다.***&lt;/p&gt;
&lt;p&gt;어머니께서 늘 하시던 말씀이다. 내가 잘못했을 때, 어머니께서는 항상 처음 두 번은 너그럽게 용서해 주셨다. 하지만 세 번째 똑같은 실수를 저지르면 그 때는 정말 호되게 꾸짖으셨다. 그게 어머님의 철학이었고, 교육이었다. 그런 꾸짖음 속에서 어린 시절의 나는 자연스럽게 같은 실수를 여러번 반복하면 안된다는 사실을 배우게 되었다.&lt;/p&gt;
&lt;p&gt;성인이 되던 해, 나는 어머니의 모든 잣대로부터 자유로워졌다. 어머니는 더 이상 내 삶의 모든 면들을 알 수 없었고, 판단할 수도 없는 상황이 되었다. 어머니는 그저 믿으셨다. 자식을. 그렇게 가르쳤으니 잘 하겠지.&lt;/p&gt;
&lt;p&gt;그런데 안타까운 사실은 부끄럽게도 나는 20살 이후로 해서는 안 될 실수를 너무 많이, 그것도 반복적으로 저질러 버렸다. 내 머릿속에 아직도 기억이란 이름으로 존재하고 있는 것들만 가지고 고해성사를 한다고 해도 300일을 하고도 40일 쯤은 더해야 될만큼 많은 것 같다. 그것도 똑같은 실수를. 자기 합리화란 달콤한 속삭임에 마취되어 나는 잘못을 하는지도 모른체 실수를 반복해 나갔고, 실수를 실수가 아닌 것으로 둔갑시켜 버렸다. 그런 내 자신이 너무 부끄럽고, 어머니께는 너무 죄송하다. 얼마나 더 많이 똑같은 실수를 반복할지 약간은 두렵기도 하다.&lt;/p&gt;
&lt;p&gt;내 잘못을 호되게 꾸짖어 주셨던 어머니가 그립다.&lt;/p&gt;
&lt;p&gt;진짜 이러다간 먼지처럼 살겠다. 정말.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[[리뷰] 호우시절]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/3178</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3178</guid><pubDate>Sun, 03 Oct 2010 23:56:45 GMT</pubDate><content:encoded>&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./호우시절.md_0.jpg&apos; data-alt=&apos;홀로 자체 발광하고 있는 정우성. 이건 머 남자가 봐도. …&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/839ec030b1e04627724cb615d8002dcd/e224a/%ED%98%B8%EC%9A%B0%EC%8B%9C%EC%A0%88.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 45.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAEEAv/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/aAAwDAQACEAMQAAABTkwasiDv/8QAGxAAAgIDAQAAAAAAAAAAAAAAAgMAARITMkL/2gAIAQEAAQUCWQiu8AvYE8v4n//EABURAQEAAAAAAAAAAAAAAAAAAAAR/9oACAEDAQE/AUf/xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAgEBPwGI/8QAHRAAAQMFAQAAAAAAAAAAAAAAAAECMRASQXGRof/aAAgBAQAGPwK2Bq5VCPDg3VP/xAAdEAABBAIDAAAAAAAAAAAAAAABABEhURBBYXGx/9oACAEBAAE/IYkFuUyMFST6mrdJrkX/2gAMAwEAAgADAAAAEJcf/8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQMBAT8QqX//xAAXEQADAQAAAAAAAAAAAAAAAAAAAREx/9oACAECAQE/EEukH//EAB4QAQACAQUBAQAAAAAAAAAAAAEAETEhQXGB8FGx/9oACAEBAAE/ENHI5AXll3yRFogs03jpWkUNtfbZ4cTz8zd6/Cf/2Q==&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;홀로 자체 발광하고 있는 정우성. 이건 머 남자가 봐도. …&apos; title=&apos;&apos; src=&apos;/static/839ec030b1e04627724cb615d8002dcd/e224a/%ED%98%B8%EC%9A%B0%EC%8B%9C%EC%A0%88.md_0.jpg&apos; srcset=&apos;/static/839ec030b1e04627724cb615d8002dcd/8ccab/%ED%98%B8%EC%9A%B0%EC%8B%9C%EC%A0%88.md_0.jpg 190w,
/static/839ec030b1e04627724cb615d8002dcd/ea4c8/%ED%98%B8%EC%9A%B0%EC%8B%9C%EC%A0%88.md_0.jpg 380w,
/static/839ec030b1e04627724cb615d8002dcd/e224a/%ED%98%B8%EC%9A%B0%EC%8B%9C%EC%A0%88.md_0.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;홀로 자체 발광하고 있는 정우성. 이건 머 남자가 봐도. …&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;말초 신경을 자극하는 영상, 원초적인 스토리, 저질스런 대사들로 가득한 요즘 영화 같지 않은 정말 멋진 영화입니다. 동하와 메이의 애틋한 재회가 너무 아름답게 보이더군요. 말도 못하고 서로 마음만 바라보는 그 둘 사이의 묘한 아득함에 저도 모르게 빠져들었나 봅니다. 엇갈린 추억, 못다한 말들, 지나친 배려, … 그런 일들로 누구나 데드락이 돼버린 연애사 한두 개쯤은 가지고 있잖아요. ㅎㅎ^^;;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&apos;gatsby-resp-image-figure&apos; style=&apos;margin-bottom: 16px;&apos; data-url=&apos;./호우시절.md_1.jpg&apos; data-alt=&apos;Do you remember?&lt;br&gt;호우시절이네&lt;br&gt;두보의 시에 나오는 말이야&lt;br&gt;‘좋은 비는 때를 알고 알고 내린다’는 뜻이야&lt;br&gt;꽃이 펴서 봄이 오는 걸까 아니면 봄이 와서 꽃이 피는 걸까
&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/778490b17029aaa4ecbe7852e58e5062/e224a/%ED%98%B8%EC%9A%B0%EC%8B%9C%EC%A0%88.md_1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 45.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAJABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAMEAQL/xAAXAQADAQAAAAAAAAAAAAAAAAAAAQID/9oADAMBAAIQAxAAAAGdXcbNHmV//8QAHBAAAQMFAAAAAAAAAAAAAAAAAgABAxESEzEz/9oACAEBAAEFApHIXzFEraouZoNf/8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQMBAT8BR//EABYRAQEBAAAAAAAAAAAAAAAAAAABEf/aAAgBAgEBPwGtf//EABwQAAEEAwEAAAAAAAAAAAAAAAEAAhARIjEycf/aAAgBAQAGPwIUaasT1u4PibH/xAAaEAACAwEBAAAAAAAAAAAAAAABEQAhQRCx/9oACAEBAAE/IVYJZKjhcdLTe+j+8//aAAwDAQACAAMAAAAQzP8A/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQARMf/aAAgBAwEBPxAM5BS//8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAx/9oACAECAQE/EEuyxv/EABwQAAEFAQEBAAAAAAAAAAAAAAEAESExcZGBof/aAAgBAQABPxAZN6QB8bnUAKpO3ZMISiLtBXyVTIV+l//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;Do you remember?&lt;br&gt;호우시절이네&lt;br&gt;두보의 시에 나오는 말이야&lt;br&gt;‘좋은 비는 때를 알고 알고 내린다’는 뜻이야&lt;br&gt;꽃이 펴서 봄이 오는 걸까 아니면 봄이 와서 꽃이 피는 걸까
&apos; title=&apos;&apos; src=&apos;/static/778490b17029aaa4ecbe7852e58e5062/e224a/%ED%98%B8%EC%9A%B0%EC%8B%9C%EC%A0%88.md_1.jpg&apos; srcset=&apos;/static/778490b17029aaa4ecbe7852e58e5062/8ccab/%ED%98%B8%EC%9A%B0%EC%8B%9C%EC%A0%88.md_1.jpg 190w,
/static/778490b17029aaa4ecbe7852e58e5062/ea4c8/%ED%98%B8%EC%9A%B0%EC%8B%9C%EC%A0%88.md_1.jpg 380w,
/static/778490b17029aaa4ecbe7852e58e5062/e224a/%ED%98%B8%EC%9A%B0%EC%8B%9C%EC%A0%88.md_1.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;
    &lt;figcaption class=&apos;gatsby-resp-image-figcaption&apos;&gt;&lt;p&gt;Do you remember?&lt;br&gt;호우시절이네&lt;br&gt;두보의 시에 나오는 말이야&lt;br&gt;‘좋은 비는 때를 알고 알고 내린다’는 뜻이야&lt;br&gt;꽃이 펴서 봄이 오는 걸까 아니면 봄이 와서 꽃이 피는 걸까&lt;/p&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;그닥 영화 대사를 기억하는 편은 아닌데, 비를 피해 처마 밑에서 메이가 했던 저 대사는 영화가 끝나고도 계속 떠오릅니다. 그리고 메이가 저 장면에서 동하에게 건낸 한 마디, Do you remember? 크레딧이 다 올라가고 나면 저 대사의 출처인 두보의 시 전문이 나오는데, 참 운치가 느껴지는 시네욤.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;봄 밤에 내리는 반가운 비&lt;br&gt;
&lt;br&gt;
– 두보&lt;br&gt;
&lt;br&gt;
좋은 비는 그 때를 알고 내리니&lt;br&gt;
&lt;br&gt;
봄이 되어 내리네&lt;br&gt;
&lt;br&gt;
이 밤 바람 따라 몰래 들어와&lt;br&gt;
&lt;br&gt;
소리없이 만물을 적시고 있네&lt;br&gt;
&lt;br&gt;
들길에는 구름이 드리워 어둑하고&lt;br&gt;
&lt;br&gt;
강위에는 조각배 등불만 외로이 떠있네&lt;br&gt;
&lt;br&gt;
새벽이 되어 붉게 반짝이는 곳을 보니&lt;br&gt;
&lt;br&gt;
금관성(청두)이 온통 꽃으로 물들어 있구나&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;영화가 끝나고 나니 기다렸다는 듯이 하늘에서 비가 옵니다. 세차게 내리는 빗물을 메이가 그랬듯 손으로 받치고 있으니 ‘호우시절’같았던 추억들이 떠오르기도 하고, 세상사에는 참 시기라는 것이 무시 못할 만큼  중요하다는 생각이 들기도 합니다. 피천득 선생님께서 아사코와의 인연을 두고 수필집에 적으셨던 그 말씀도 새록새록 머릿속을 파고드네요.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;그리워하는데도 한 번 만나고는 못 만나게 되기도 하고, 일생을 못 잊으면서도 아니 만나고 살기도 한다. 아사코와 나는 세 번 만났다. 세 번째는 아니 만났어야 좋았을 것이다.&lt;/p&gt;
&lt;p&gt;– 인연, 피천득&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;배경이 된 영상도 너무 아름답습니다. 꼭 한 번 가보고 싶네요. 어쨌든 저에겐 간만에 정말 멋진 영화였습니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[포토월 제작기]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/3108</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3108</guid><pubDate>Sun, 05 Sep 2010 23:56:44 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;너무 많은 분들이 궁금해 하시는 것 같아서 추가합니다.&lt;br&gt;
&lt;br&gt;
&lt;strong&gt;자석은 어디서 파나용?&lt;/strong&gt;&lt;br&gt;
지마켓에서 팝니다. 구로공구상가 같은데 가셔서 직접 사셔도 됩니다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;철지는 어디서 파나용?&lt;/strong&gt;&lt;br&gt;
지마켓에서 팝니다. 구로공구상가 같은데 가셔서 직접 사셔도 됩니다.&lt;br&gt;
&lt;br&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;벽에는 멀로 붙이나요?&lt;/strong&gt;&lt;br&gt;
전 3M 커맨드 테이프로 붙였는데요. 대형을 못사고 중형을 사서 붙였더니 장마철되면 가끔 떨어질 때가 있더군요. 못, 피스를 쓰지 않는 방법 중에는 커맨드 테이프가 갑인것 같습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;금요일 아침에 냉장고 옆 벽면을 보다가 그 휑한 느낌이 싫어서 뭔가를 붙여보고 싶다는 생각이 들었습니다. 그러다 문득 든 생각 포토월. 인터넷 찾아보니 자료는 엄청 많더군요. 특히 &lt;a href=&quot;http://www.makingphotowall.co.kr/&quot;&gt;이 사이트&lt;/a&gt; 강좌가 많은 도움이 되었습니다. 여러가지 방법이 있는데 대표적인 두 가지 방법이 빨랫줄에 빨래집게를 이용하는 것과 철지에 자석을 이용하는 방법이 있습니다. 개인적으로 치렁치렁 달려 있는걸 별로 좋아하지 않아서 철지에 자석으로 붙이는 포토월을 만들어야 겠다는 생각을 했습니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./포토월_제작기.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/7ef38f83bd695eabe806a2db21a7b91c/e224a/%ED%8F%AC%ED%86%A0%EC%9B%94_%EC%A0%9C%EC%9E%91%EA%B8%B0.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAMEAv/EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAFm4HwExX//xAAaEAACAwEBAAAAAAAAAAAAAAAAAQIREgMT/9oACAEBAAEFAl1deksuVGKG3lzP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAHRAAAQQCAwAAAAAAAAAAAAAAAQAQIUECETFxkf/aAAgBAQAGPwKvFAHbRlygK03/xAAbEAACAwEBAQAAAAAAAAAAAAAAAREhMVFBgf/aAAgBAQABPyFpnFFkYGzPcCjr+HYQq6nQimveo//aAAwDAQACAAMAAAAQSw//xAAWEQADAAAAAAAAAAAAAAAAAAAAARH/2gAIAQMBAT8QjIz/xAAWEQADAAAAAAAAAAAAAAAAAAAAARH/2gAIAQIBAT8QqKj/xAAdEAEBAAICAwEAAAAAAAAAAAABEQAhMUFRYYHR/9oACAEBAAE/EDqLzUSa08z8wuvKp2LtnibPmPAbFsvaefWKWqr6SuActtO02OOYILGpt5jM/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;        md 0&apos; title=&apos;&apos; src=&apos;/static/7ef38f83bd695eabe806a2db21a7b91c/e224a/%ED%8F%AC%ED%86%A0%EC%9B%94_%EC%A0%9C%EC%9E%91%EA%B8%B0.md_0.jpg&apos; srcset=&apos;/static/7ef38f83bd695eabe806a2db21a7b91c/8ccab/%ED%8F%AC%ED%86%A0%EC%9B%94_%EC%A0%9C%EC%9E%91%EA%B8%B0.md_0.jpg 190w,
/static/7ef38f83bd695eabe806a2db21a7b91c/ea4c8/%ED%8F%AC%ED%86%A0%EC%9B%94_%EC%A0%9C%EC%9E%91%EA%B8%B0.md_0.jpg 380w,
/static/7ef38f83bd695eabe806a2db21a7b91c/e224a/%ED%8F%AC%ED%86%A0%EC%9B%94_%EC%A0%9C%EC%9E%91%EA%B8%B0.md_0.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;준비물은 이렇습니다. 소스 사진, ND 자석, 폼보드 하나, 철지 2장, 시트지, 3M 접착 스프레이, 자, 커터칼. 이게 끝입니다. 사진은 컴퓨터에 있는 것 중에 몇 장을 추렸습니다. 컴퓨터에 썩고 있던 것들을 인화해서 보니 느낌이 새롭더군요. 폼보드, 3M 접착 스프레이, 자, 커터칼은 회사 밑의 문구점에 쉽게 구했습니다.&lt;/p&gt;
&lt;p&gt;결국 철지와 자석을 구하는게 초큼 난감했습니다. 물론 인터넷으로 주문하는게 가장 편한데 저는 급하게 구하느라 오프라인으로 파는 곳을 알아봤습니다. 인터넷에 찾아보니 대한자석이라는 곳에서 많이들 사시는 것 같더군요. 홈페이지를 가보니 구로공구상가에 지점이 있다고 해서 오늘 낚시 갔다가 오는 길에 공구상가를 들렸습니다. 공구상가가 어찌나 큰지… ㅠㅠ~ 찾아 찾아 홈페이지에 있던 A블럭 6동 130호를 갔는데 대한자석이 없습니다. 전화해보니 청계천쪽으로 통합됐다는 청천벽력같은 대답만 해주더군요. 이뭐병 같은 시츄에이션인지. 날씨는 또 왜케 더운지…&lt;/p&gt;
&lt;p&gt;허탕치고 집에 돌아오려고 블록을 지나 나오는데 xx 자석 같은 가게들이 많이 보이더군요. 혹시나 해서 물어보니 판다고 하더라고요. 조금 안타까운 현실은 600 사이즈 롤 형태로된 600×1000 짜리 철지를 사려고 했는데 그런 건 없다고 합니다. 롤 형태는 500×15000 짜리만 있다고 해서, 그냥 500×400 짜리 두 개 샀습니다. 나눠서 붙이면 중간에 빈틈이 있더라고 사진을 무리 없이 붙일 수 있다고 생각했거든요. 어차피 사진 귀퉁이에 자석 붙일 곳에만 철지가 있으면 되니깐염.&lt;/p&gt;
&lt;p&gt;해보고 느낀 몇 가지 팁을 적어보면 이렇습니다. 1). 3M 스프레이 접착제 뭔가 그럴싸해 보이지만 손에 묻으면 순간 접착제처럼 끈끈하게 달라 붙습니다. 따라서 스프레이 작업할 때에는 장갑 있다면 장갑 끼고 하는게 좋을 것 같네요. 저는 조금 묻어서 비누로 긁어내느라 고생했습니다. 2). 시트지 붙일 때 기포 없이 붙이려면 분무기에 퐁퐁과 물을 섞은 것을 미리 시트지 바를 곳에 뿌려 두고 시트지 붙이면 기포없이 붙일 수 있습니다. 그거 말고는 뭐 없습니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./포토월_제작기.md_1.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/57789a1cacb5a9796043fb6f0c03fa84/e224a/%ED%8F%AC%ED%86%A0%EC%9B%94_%EC%A0%9C%EC%9E%91%EA%B8%B0.md_1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 75.26315789473684%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIDBP/EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAFp7IDmHJf/xAAbEAACAgMBAAAAAAAAAAAAAAABAgMRABASIf/aAAgBAQABBQJj6dGJqMLXw4z/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAbEAABBAMAAAAAAAAAAAAAAAAAARARMVGh4f/aAAgBAQAGPwIlcP0rZ//EABsQAAICAwEAAAAAAAAAAAAAAAABESExQVGB/9oACAEBAAE/IblPPYKdNKgaUuUPvO+MRotB1kno/9oADAMBAAIAAwAAABC0P//EABYRAAMAAAAAAAAAAAAAAAAAAAEQEf/aAAgBAwEBPxCFf//EABYRAQEBAAAAAAAAAAAAAAAAAAABEf/aAAgBAgEBPxDFj//EABwQAQEAAgMBAQAAAAAAAAAAAAERADEhQWFx0f/aAAgBAQABPxBoCiApGv3BwSmkXt5iACjHRlnVQgBCSe5UEKheRvq8mMDId2d/M//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;        md 1&apos; title=&apos;&apos; src=&apos;/static/57789a1cacb5a9796043fb6f0c03fa84/e224a/%ED%8F%AC%ED%86%A0%EC%9B%94_%EC%A0%9C%EC%9E%91%EA%B8%B0.md_1.jpg&apos; srcset=&apos;/static/57789a1cacb5a9796043fb6f0c03fa84/8ccab/%ED%8F%AC%ED%86%A0%EC%9B%94_%EC%A0%9C%EC%9E%91%EA%B8%B0.md_1.jpg 190w,
/static/57789a1cacb5a9796043fb6f0c03fa84/ea4c8/%ED%8F%AC%ED%86%A0%EC%9B%94_%EC%A0%9C%EC%9E%91%EA%B8%B0.md_1.jpg 380w,
/static/57789a1cacb5a9796043fb6f0c03fa84/e224a/%ED%8F%AC%ED%86%A0%EC%9B%94_%EC%A0%9C%EC%9E%91%EA%B8%B0.md_1.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;완성한 모습입니다. 당초 계획은 세로로 세워서 냉장고 옆 벽면에 붙이려고 했는데, 철지 나눠 붙이는 부분 계산을 잘못해서 세로로 세우니 사진 하나 붙여야하는 공간에 철지가 하나도 없는 안습한 시츄레이션이 연출됐습니다. 그래서 그냥 가로로 다른 곳에 붙여야 할 것 같네요. 책장 뒷면과 침대 옆 벽면 중에 어디다 붙일까 고민하고 있습니다. 사족을 하나 더 붙인다면 저처럼 철지를 나눠 붙이실 생각이시라면 미리 나눠진 조각을 그려보고 사진 크기로 계산해 보는게 실패하지 않는 지름길일 것 같네요.&lt;/p&gt;
&lt;p&gt;어쨌든 만들어보니 생각보다 재밌습니다. 걸어 두면 좀 덜 휑하겠죠. ㅎㅎ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[xfav 0.9.5]]></title><description><![CDATA[회사 PC를 업그레이드 했습니다. i7 960, 6gb ram, sata3 hdd, gtx460 굳~ 64비트 윈도우를 설치해야겠죠. Windows 7 6…]]></description><link>https://jiniya.net/wp/archives/3099</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3099</guid><pubDate>Fri, 03 Sep 2010 23:56:43 GMT</pubDate><content:encoded>&lt;p&gt;회사 PC를 업그레이드 했습니다. i7 960, 6gb ram, sata3 hdd, gtx460 굳~ 64비트 윈도우를 설치해야겠죠. Windows 7 64비트를 설치했습니다. 드라이버 설치 안해도 대부분 하드웨어를 다 자동으로 잡아주네욤. 속도도 빠르구욤. 컴파일 시간이 쾌적해졌습니다. 여튼 64비트 업글 기념으로 xfav도 같이 업그레이드를 했습니다. 64비트로 포팅 작업을 했습니다. 이제부터 64비트 윈도우에서도 사용할 수 있습니다. 새로운 버전은 아래 경로에서 다운로드 받으시면 됩니다. xfav의 정체가 궁금하신 분들은 &lt;a href=&quot;http://jiniya.net/wp/archives/2821&quot;&gt;이 글을&lt;/a&gt; 참고하세요.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/bins/xfav/xfav32.0.9.5.zip&quot;&gt;32비트 윈도우용 xfav32.0.9.5.zip&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/bins/xfav/xfav64.0.9.5.zip&quot;&gt;64비트 윈도우용 xfav64.0.9.5.zip&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;이런 퐌타스틱한 기능이 추가되었습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kill All Windows&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;현재 보고 있는 탐색기 윈도우를 제외한 나머지 모든 윈도우를 한방에 닫아줍니다.&lt;/p&gt;
&lt;p&gt;해보니 IE도 같이 닫히는 부작용이 있습니다. ㅠㅜ.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Find Window&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;경로가 시작이 특정 메뉴와 일치하는 것을 찾아줍니다.&lt;/p&gt;
&lt;p&gt;이 메뉴를 선택하면 다시 팝업 메뉴가 뜹니다. 거기서 이동할 경로를 선택하면 됩니다. 그러면 해당 경로로 시작하는 탐색기 윈도우를 찾아서 띄워줍니다. 예를들면 이런겁니다. c:\utils\aaa 폴더를 탐색중인 탐색기 창이 있을 때 c:\utils 메뉴를 선택하면 해당 창을 보여주는 겁니다.&lt;/p&gt;
&lt;p&gt;다음 사항이 수정되었습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;찾은 윈도우가 최소화된 경우 복원을 시켜주지 않던 문제가 수정되었습니다. 이제 최소화된 윈도우도 제대로 찾아서 표시해 줍니다.&lt;/li&gt;
&lt;li&gt;윈도우 찾을 때 순서를 메겨서 돌아가면서 찾도록합니다. 이제, 메뉴 버튼을 사용해서 비슷한 윈도우를 순서대로 방문하는 것이 가능해졌습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[진실의 입.]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/3034</link><guid isPermaLink="false">https://jiniya.net/wp/archives/3034</guid><pubDate>Tue, 24 Aug 2010 23:56:42 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./진실의_입_.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/447a5711eb76bd85ff4f58297e349283/e224a/%EC%A7%84%EC%8B%A4%EC%9D%98_%EC%9E%85_.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 66.84210526315789%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQBAgMF/8QAFgEBAQEAAAAAAAAAAAAAAAAAAQAC/9oADAMBAAIQAxAAAAF3mWV0SZhf/8QAGxAAAwACAwAAAAAAAAAAAAAAAQIDABIhMjP/2gAIAQEAAQUCtcgI216elicXhn7f/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFREBAQAAAAAAAAAAAAAAAAAAEBH/2gAIAQIBAT8Bh//EABoQAQEAAgMAAAAAAAAAAAAAAAEAAhARImH/2gAIAQEABj8C6litlDzD5r//xAAcEAACAwADAQAAAAAAAAAAAAAAAREhMUGBsdH/2gAIAQEAAT8h4iZL9Kw/SHYMrA6geitCUnO2f//aAAwDAQACAAMAAAAQwO//xAAXEQADAQAAAAAAAAAAAAAAAAAAARFB/9oACAEDAQE/EE9Kf//EABcRAAMBAAAAAAAAAAAAAAAAAAABESH/2gAIAQIBAT8QcYQ//8QAGxABAQADAQEBAAAAAAAAAAAAAREAITFBYYH/2gAIAQEAAT8QAdAqggmoxUNp0bQS5dtbeO0dSLe+/mRgbB8VwroeGf/Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 0&apos; title=&apos;&apos; src=&apos;/static/447a5711eb76bd85ff4f58297e349283/e224a/%EC%A7%84%EC%8B%A4%EC%9D%98_%EC%9E%85_.md_0.jpg&apos; srcset=&apos;/static/447a5711eb76bd85ff4f58297e349283/8ccab/%EC%A7%84%EC%8B%A4%EC%9D%98_%EC%9E%85_.md_0.jpg 190w,
/static/447a5711eb76bd85ff4f58297e349283/ea4c8/%EC%A7%84%EC%8B%A4%EC%9D%98_%EC%9E%85_.md_0.jpg 380w,
/static/447a5711eb76bd85ff4f58297e349283/e224a/%EC%A7%84%EC%8B%A4%EC%9D%98_%EC%9E%85_.md_0.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt; 진실의 입. 입구에 있던 마차.&lt;/p&gt;
&lt;p&gt;경주마도 아니면서 눈 가리개를 하고 있다.&lt;/p&gt;
&lt;p&gt;앞만 보고 달리란 거다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 450px; margin-bottom: 16px;&apos; data-url=&apos;./진실의_입_.md_1.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/9b5bd0d75a54594456e354c8cd14b034/cb709/%EC%A7%84%EC%8B%A4%EC%9D%98_%EC%9E%85_.md_1.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 133.1578947368421%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAbABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAIDAQT/xAAXAQADAQAAAAAAAAAAAAAAAAAAAQID/9oADAMBAAIQAxAAAAHueAiAgr3Fas5kRV//xAAcEAACAgIDAAAAAAAAAAAAAAABAgAhETIDIjH/2gAIAQEAAQUCTWcu6msx9gazCbTyOe3/xAAWEQADAAAAAAAAAAAAAAAAAAAAARD/2gAIAQMBAT8BFf/EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EABcQAAMBAAAAAAAAAAAAAAAAAAABECD/2gAIAQEABj8C0qoz/8QAGRABAQEBAQEAAAAAAAAAAAAAAAERMSGh/9oACAEBAAE/IfENZLZWtXaVFrWR8C9U7P/aAAwDAQACAAMAAAAQDO1D/8QAGBEBAQADAAAAAAAAAAAAAAAAAAERITH/2gAIAQMBAT8QtVplOP/EABcRAQEBAQAAAAAAAAAAAAAAAAABESH/2gAIAQIBAT8QizrFf//EAB0QAQACAgMBAQAAAAAAAAAAAAEAESExQWGxkcH/2gAIAQEAAT8QdM79ndzEnaGDiUM1n1l4Z+xXeaAgKnZ+xl9xlKdHkSkuIaYTZHHhP//Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 1&apos; title=&apos;&apos; src=&apos;/static/9b5bd0d75a54594456e354c8cd14b034/cb709/%EC%A7%84%EC%8B%A4%EC%9D%98_%EC%9E%85_.md_1.jpg&apos; srcset=&apos;/static/9b5bd0d75a54594456e354c8cd14b034/8ccab/%EC%A7%84%EC%8B%A4%EC%9D%98_%EC%9E%85_.md_1.jpg 190w,
/static/9b5bd0d75a54594456e354c8cd14b034/ea4c8/%EC%A7%84%EC%8B%A4%EC%9D%98_%EC%9E%85_.md_1.jpg 380w,
/static/9b5bd0d75a54594456e354c8cd14b034/cb709/%EC%A7%84%EC%8B%A4%EC%9D%98_%EC%9E%85_.md_1.jpg 450w&apos; sizes=&apos;(max-width: 450px) 100vw, 450px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;진실의 입 들어가면 오른쪽에 보이는 뭔가.&lt;/p&gt;
&lt;p&gt;먼소린진 모르겠지만… ㅎㅎ~&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; margin-bottom: 16px;&apos; data-url=&apos;./진실의_입_.md_2.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/51ba8f662ab191c5cf00f6521e4aac1d/e224a/%EC%A7%84%EC%8B%A4%EC%9D%98_%EC%9E%85_.md_2.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 66.84210526315789%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAIBAwQF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAcjVKdUkX//EABoQAAICAwAAAAAAAAAAAAAAAAERAAIhIjL/2gAIAQEAAQUCocFEUGiQcpx//8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQMBAT8BJ//EABYRAQEBAAAAAAAAAAAAAAAAAAABEf/aAAgBAgEBPwGsf//EABcQAQEBAQAAAAAAAAAAAAAAAAABESH/2gAIAQEABj8CuuIxiP/EABoQAAMAAwEAAAAAAAAAAAAAAAABESExQYH/2gAIAQEAAT8hVRsFl4tF2zg9jt0co35n/9oADAMBAAIAAwAAABCwD//EABcRAQADAAAAAAAAAAAAAAAAAAABESH/2gAIAQMBAT8Qli3/xAAWEQADAAAAAAAAAAAAAAAAAAABECH/2gAIAQIBAT8QCp//xAAbEAEAAwEBAQEAAAAAAAAAAAABABEhMUFhwf/aAAgBAQABPxASZuGvOx3d4XjE9wYpXJur45GpmJa/keBorP/Z&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;       md 2&apos; title=&apos;&apos; src=&apos;/static/51ba8f662ab191c5cf00f6521e4aac1d/e224a/%EC%A7%84%EC%8B%A4%EC%9D%98_%EC%9E%85_.md_2.jpg&apos; srcset=&apos;/static/51ba8f662ab191c5cf00f6521e4aac1d/8ccab/%EC%A7%84%EC%8B%A4%EC%9D%98_%EC%9E%85_.md_2.jpg 190w,
/static/51ba8f662ab191c5cf00f6521e4aac1d/ea4c8/%EC%A7%84%EC%8B%A4%EC%9D%98_%EC%9E%85_.md_2.jpg 380w,
/static/51ba8f662ab191c5cf00f6521e4aac1d/e224a/%EC%A7%84%EC%8B%A4%EC%9D%98_%EC%9E%85_.md_2.jpg 600w&apos; sizes=&apos;(max-width: 600px) 100vw, 600px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;진실의 입. 거짓말을 한 사람이 저 입에다 손을 집어 넣으면 진실의 입이 손을 끊어버린다고 한다.&lt;/p&gt;
&lt;p&gt;인생이 구라다보니 차마 겁나서 집어 넣지는 못했다. 이런 입들은 그냥 막아야지… ㅋㅋ~&lt;/p&gt;
&lt;p&gt;언젠가는 모든 진실을 말할 수 있는 날이 오겠지? ㅎ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[삶과 죽음, …]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/2969</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2969</guid><pubDate>Fri, 13 Aug 2010 23:56:41 GMT</pubDate><content:encoded>&lt;p&gt;인셉션 보고 들어와서 앙드레김 선생님께서 별세하셨다는 소식을 들었습니다. 그래서 비가 이리도 세차게 내렸구나 하는 생각이 들더군요. 작년부터 정말 많은 분들이 한꺼번에 사라지는 느낌을 지울 수가 없습니다. 뭐 세월도 흐르게 마련이고, 사람도 나이가 들면 죽는 것이 당연하다지만 그래도 묘한 느낌이 듭니다. 한편으론 저에게 주어진 모래시계도 이제 모래알이 그렇게 많이 남아있지는 않다는 생각도 듭니다. 한 알 한 알 소중한 일, 소중한 사람에게 쓰도록 노력해야 겠습니다. 지금도 아름다운 순간이 흘러가고 있네요.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“타로에는 특별한 카드가 한 장 있지요. ‘이름 없는 비밀’이라는 열 세 번째 카드로 모두들 ‘죽음’이라고 부르지요. 그 카드는 한 단계의 끝을, 근원으로의 회귀를 의미합니다. 그런데 그 회귀는 끝이 아니라 새로운 시작입니다.”&lt;/p&gt;
&lt;p&gt;“도대체 무슨 얘기를 하고 싶은 겁니까?”&lt;/p&gt;
&lt;p&gt;에단이 신경질적으로 물었다.&lt;/p&gt;
&lt;p&gt;“하나의 페이지가 넘어가야 새로운 페이지를 쓸 수 있다는 겁니다.”&lt;/p&gt;
&lt;p&gt;“언제나 말도 안 되는 소리를 그럴 듯하게 꾸며서 늘어놓기를 좋아 하시는군요?”&lt;/p&gt;
&lt;p&gt;“죽음은 가장 위대한 교사지요.”&lt;/p&gt;
&lt;p&gt;시노 미츠키가 분개하는 기색 없이 말했다.&lt;/p&gt;
&lt;p&gt;“가장 위대한 교사라고요?”&lt;/p&gt;
&lt;p&gt;“우리는 마치 영원히 죽지 않는 존재처럼 살고 있어요. 삶에서 뭔가를 이루기 위해서는 우리가 필연적으로 죽어야 하는 존재라는 걸 명심해야만 합니다.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;– 사랑을 찾아 돌아오다, 기욤 뮈소&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;한 남자가 내 친구 제이미 코언에게 물었다.&lt;/p&gt;
&lt;p&gt;“사람의 가장 우스운 점은 뭐라고 생각하십니까?”&lt;/p&gt;
&lt;p&gt;코언이 대답했다.&lt;/p&gt;
&lt;p&gt;“모순이죠. 어렸을땐 어른이 되고 싶어 안달하다가도, 막상 어른이 되어서는 잃어버린 유년을 그리워해요. 돈을 버느라 건강 따위는 안중에도 없다가도, 훗날 건강을 되찾는 데 전 재산을 투자합니다. 미래에 골몰하느라 현재를 소홀히 하다가 결국에는 현재도 미래도 놓쳐버리고요. 영원히 죽지 않을 듯 살다가 살아보지도 못한 것처럼 죽어가죠.”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;– 흐르는 강물처럼, 파울로 코엘료&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;사람의 비운은 이런 것이다.&lt;/p&gt;
&lt;p&gt;모든 것을 알아낼 시간이 75년밖에 없다는 것. 그 모든 책과 세월과 아이들을 뒤에 남긴 연후보다 차라리 어릴 때에 본능적으로 더 많이 안다는 것.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;– 베리 한나&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;걷는 것은 넘어지지 않으려는 노력에 의해서, 우리 몸의 생명은 죽지 않으려는 노력에 의해서 유지된다. 삶은 연기된 죽음에 불과하다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;– 쇼펜하우어&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;“너는 네 세상 어디에 있느냐? 너에게 주어진 몇몇 해가 지나고 몇몇 날이 지났는데, 그래 너는 네 세상 어디쯤에 와 있느냐?”&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;– 맑고 향기롭게, 법정&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;한번 지나가 버린 것은 다시 되돌아오지 않습니다. 그때그때 감사하게 누릴 수 있어야 합니다. 또 달은 기약할 수가 없습니다. 이 다음 달에는 날이 흐리고 궂어서 보름달이 뜰지 말지 알 수가 없습니다. 달뿐 아니라 모든 기회가 그렇습니다. 모든 것이 일기일회입니다. 모든 순간은 생애 단 한 번의 시간이며, 모든 만남은 생에 단 한 번의 인연입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;– 일기일회, 법정&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;우리는 모두 타인의 고통 속에 태어나고, 자신의 고통 속에 죽어간다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;– 프랜시스 톰프슨&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;포유류는 모두 나이를 먹는다. 나이를 쉽게 먹지 않는 동물은 포유류보다 원시적인 것들, 상어, 악어, 갈라파고스 거북 등이다. 사람이 어째서 지금과 같은 속도로 나이를 먹는가에 대해서는 다양한 이론이 있다. 노화가 유전적으로 통제된다는 이론, 노화 속도는 종마다 제게 유리하도록 발달해왔다는 이론, 엔트로피 생성 인자가 세포를 망친다는 이론, 작은 포유류는 큰 포유류보다 대사 속도가 빠른 편이라서 수명이 짧다는 이론, 개체마다 내분비계나 면역계에 특별히 취약한 부분이 있어서 그 때문에 육체적 기능이 전반적으로 떨어진다는 이론, DNA 전사 과정에 생기는 오류가 유전적 이상으로 이어져서 죽음을 앞당긴다는 이론. 그러나 반론 없는 이론이 하나도 없고, 우리가 왜 늙는지 아는 사람이 아무도 없다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;– 우리는 언젠가 죽는다, 데이비드 실즈&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;우리에게 주어진 시간은 영원하지 않습니다. 시간의 잔고에는 늙음과 젊음이 따로 없습니다. 한번 지나간 시간은 다시 되돌릴 수가 없습니다. 그러므로 순간순간을 헛되이 보내지 마십시오. 하루하루 충만한 삶이 되도록 노력해야 합니다. 스스로 자기 삶을 다져야 합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;– 한 사람은 모두를 모두는 한 사람을, 법정&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;전에도 우리는 이와 같이 모였었다. 그러나 그때는 지금 어디로 갔는가. 또한 그때 그 사람은 어디에 있는가. 지금의 우리는 그때의 우리가 아니다. 새로운 우리들이다. 강물은 항상 그곳에 있기에 어느 때나 같은 물이지만, 순간마다 새로운 물이다. 우리가 살아가는 일도 날마다 그날이 그날이고 같은 시간 같지만, 늘 새로운 날이다. 그것을 자각해야 한다. 하루하루 새롭게 시작해야 한다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;– 한 사람은 모두를 모두는 한 사람을, 법정&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[갤럭시s 루팅이야기]]></title><description><![CDATA[안드로이드가 개방형 OS…]]></description><link>https://jiniya.net/wp/archives/2890</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2890</guid><pubDate>Tue, 10 Aug 2010 23:56:40 GMT</pubDate><content:encoded>&lt;p&gt;안드로이드가 개방형 OS라 그런지 자료는 참 많은 것 같습니다. 개발자라 안되면 직접 해볼 수도 있으니 재미가 두배는 더 있는 것 같습니다. 여튼 스마트 폰이라면 루팅이 간지죠. 이미 자료가 너무 많이 있고 안정화도 상당한 수준이라 클릭클릭만 하시면 별 무리없이 설치하실 수 있습니다. “갤럭시 루팅” 따위로 검색하면 자료가 정말 많은데 제가 참고한 자료는 아래 사이트에 있습니다. 간단하면서도 핵심만 잘 설명해둔 것 같네요. 이 자리를 빌어 패치를 제작하고 올려주시는 분들에게 정말 고맙다는 말씀을 드리고 싶네요. 그것도 공짜로 말이죠. 진짜 대단하신 분들입니다. ㅎㅎ^^;;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://matpclub.com/board/index.html?id=tipn&amp;#x26;no=65&quot;&gt;http://matpclub.com/board/index.html?id=tipn&amp;#x26;no=65&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.matpclub.com/board/index.html?id=tipn&amp;#x26;no=55&quot;&gt;http://www.matpclub.com/board/index.html?id=tipn&amp;#x26;no=55&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;사람들이 루팅만하면 속도가 빨라진다고 알고 있는데 실제로 속도 향상은 I/O 패치를 해야 합니다. 기존에 방식은 MicroSD 패치로 외장 마이크로SD 카드에서 읽고 쓰도록 해서 속도를 빠르게 하는 방식이었는데요, 최근에 내장 메모리에 ext 파일 시스템을 한 파일로 생성해서 읽고 쓰는 방식으로 해서 속도를 향상시키는 패치가 나왔습니다. 아래 사이트에 관련 자료가 있구요. 물론 클릭클릭하면 끝납니다. dd로 포맷해서 파일 생성하는 부분이 좀 오래 걸립니다. &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://matpclub.com/board/index.html?id=tipn&amp;#x26;no=80&quot;&gt;http://matpclub.com/board/index.html?id=tipn&amp;#x26;no=80&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;기존 MicroSD 패치를 적용하면 1700점 정도 점수대에서 오락가락 하는 것 같은데 내장 메모리 패치를 하고 나니 2000점은 가뿐이 넘어주는군요. I/O 점수가 무려 7000점이 넘습니다. 프로요 업데이트가 되고 CPU 속도가 제 능력을 발휘하면 3000점도 사뿐이 넘을 것 같네요. 참고로 패치 전에 제 갤s 벤치 점수는 800점 초반에서 오락가락 했었습니다. 장족의 발전이죠. &lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 480px; margin-bottom: 16px;&apos; data-url=&apos;./갤럭시s_루팅이야기.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/fbcaa1fa2f1982f21e9fbc4bac8737d2/a3e66/%EA%B0%A4%EB%9F%AD%EC%8B%9Cs_%EB%A3%A8%ED%8C%85%EC%9D%B4%EC%95%BC%EA%B8%B0.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 166.8421052631579%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAhABQDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAMEAQUG/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAHmMZFlggq6HqJISwr0zAjAK//EAB8QAAEDAwUAAAAAAAAAAAAAAAIAAQMEEjEQExQiI//aAAgBAQABBQJguW3apOpR4mkvJE/hodPKQ8SZPSzMmwyJf//EABURAQEAAAAAAAAAAAAAAAAAABEg/9oACAEDAQE/ASv/xAAXEQADAQAAAAAAAAAAAAAAAAABICEx/9oACAECAQE/ATsb/8QAIRAAAgADCQAAAAAAAAAAAAAAAAECETIQEiAhM2FxgZH/2gAIAQEABj8Cq9NVIko58Gbl2bLCldZSUMVv/8QAHxAAAgEEAgMAAAAAAAAAAAAAAREAECExQWGhcYGR/9oACAEBAAE/ISlqxBMLs+oRsis4RUQC2kRJgVg3RSPJFnUEkAdzmfDCCf4E6E3mU//aAAwDAQACAAMAAAAQcy9M+A//xAAYEQEAAwEAAAAAAAAAAAAAAAABEBEgQf/aAAgBAwEBPxBXYW8f/8QAGBEBAAMBAAAAAAAAAAAAAAAAAQARMSD/2gAIAQIBAT8QS1UMgbx//8QAIhABAAIBBAAHAAAAAAAAAAAAAQARIRAxQVFhcYGhsdHw/9oACAEBAAE/ELcAhyUwdQchHFjbusxsMg3PDaM07FtQx1FqKQ+Dt9YzipKYdi9tGDPmwjTTOKxLLr9HhOOhd/ZPavjS2fKf/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;   s       md 0&apos; title=&apos;&apos; src=&apos;/static/fbcaa1fa2f1982f21e9fbc4bac8737d2/a3e66/%EA%B0%A4%EB%9F%AD%EC%8B%9Cs_%EB%A3%A8%ED%8C%85%EC%9D%B4%EC%95%BC%EA%B8%B0.md_0.jpg&apos; srcset=&apos;/static/fbcaa1fa2f1982f21e9fbc4bac8737d2/8ccab/%EA%B0%A4%EB%9F%AD%EC%8B%9Cs_%EB%A3%A8%ED%8C%85%EC%9D%B4%EC%95%BC%EA%B8%B0.md_0.jpg 190w,
/static/fbcaa1fa2f1982f21e9fbc4bac8737d2/ea4c8/%EA%B0%A4%EB%9F%AD%EC%8B%9Cs_%EB%A3%A8%ED%8C%85%EC%9D%B4%EC%95%BC%EA%B8%B0.md_0.jpg 380w,
/static/fbcaa1fa2f1982f21e9fbc4bac8737d2/a3e66/%EA%B0%A4%EB%9F%AD%EC%8B%9Cs_%EB%A3%A8%ED%8C%85%EC%9D%B4%EC%95%BC%EA%B8%B0.md_0.jpg 480w&apos; sizes=&apos;(max-width: 480px) 100vw, 480px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 480px; margin-bottom: 16px;&apos; data-url=&apos;./갤럭시s_루팅이야기.md_0.jpg&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/fbcaa1fa2f1982f21e9fbc4bac8737d2/a3e66/%EA%B0%A4%EB%9F%AD%EC%8B%9Cs_%EB%A3%A8%ED%8C%85%EC%9D%B4%EC%95%BC%EA%B8%B0.md_0.jpg&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 166.8421052631579%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAhABQDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAMEAQUG/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAHmMZFlggq6HqJISwr0zAjAK//EAB8QAAEDAwUAAAAAAAAAAAAAAAIAAQMEEjEQExQiI//aAAgBAQABBQJguW3apOpR4mkvJE/hodPKQ8SZPSzMmwyJf//EABURAQEAAAAAAAAAAAAAAAAAABEg/9oACAEDAQE/ASv/xAAXEQADAQAAAAAAAAAAAAAAAAABICEx/9oACAECAQE/ATsb/8QAIRAAAgADCQAAAAAAAAAAAAAAAAECETIQEiAhM2FxgZH/2gAIAQEABj8Cq9NVIko58Gbl2bLCldZSUMVv/8QAHxAAAgEEAgMAAAAAAAAAAAAAAREAECExQWGhcYGR/9oACAEBAAE/ISlqxBMLs+oRsis4RUQC2kRJgVg3RSPJFnUEkAdzmfDCCf4E6E3mU//aAAwDAQACAAMAAAAQcy9M+A//xAAYEQEAAwEAAAAAAAAAAAAAAAABEBEgQf/aAAgBAwEBPxBXYW8f/8QAGBEBAAMBAAAAAAAAAAAAAAAAAQARMSD/2gAIAQIBAT8QS1UMgbx//8QAIhABAAIBBAAHAAAAAAAAAAAAAQARIRAxQVFhcYGhsdHw/9oACAEBAAE/ELcAhyUwdQchHFjbusxsMg3PDaM07FtQx1FqKQ+Dt9YzipKYdi9tGDPmwjTTOKxLLr9HhOOhd/ZPavjS2fKf/9k=&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;   s       md 0&apos; title=&apos;&apos; src=&apos;/static/fbcaa1fa2f1982f21e9fbc4bac8737d2/a3e66/%EA%B0%A4%EB%9F%AD%EC%8B%9Cs_%EB%A3%A8%ED%8C%85%EC%9D%B4%EC%95%BC%EA%B8%B0.md_0.jpg&apos; srcset=&apos;/static/fbcaa1fa2f1982f21e9fbc4bac8737d2/8ccab/%EA%B0%A4%EB%9F%AD%EC%8B%9Cs_%EB%A3%A8%ED%8C%85%EC%9D%B4%EC%95%BC%EA%B8%B0.md_0.jpg 190w,
/static/fbcaa1fa2f1982f21e9fbc4bac8737d2/ea4c8/%EA%B0%A4%EB%9F%AD%EC%8B%9Cs_%EB%A3%A8%ED%8C%85%EC%9D%B4%EC%95%BC%EA%B8%B0.md_0.jpg 380w,
/static/fbcaa1fa2f1982f21e9fbc4bac8737d2/a3e66/%EA%B0%A4%EB%9F%AD%EC%8B%9Cs_%EB%A3%A8%ED%8C%85%EC%9D%B4%EC%95%BC%EA%B8%B0.md_0.jpg 480w&apos; sizes=&apos;(max-width: 480px) 100vw, 480px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;체감 속도가 많이 궁금하실 것 같은데요. 사실 패치 전과 비교하는게 우스운 수준입니다. 교보 이북 앱을 사용해서 책을 보는데 전에는 로딩이 상당히 길었습니다. 페이지 넘김도 상당히 오래 걸렸구요. 그런데 이제는 뭐 슝슝 실행됩니다. 다른 부분에서 버벅임도 많이 줄었구요. 프로요 업데이트가 정말 기대됩니다. 9월 달에는 제발 좀 해줬으면 좋겠네요.&lt;/p&gt;
&lt;p&gt;아직 사용한지 2주가 채 되지 않은것 같지만 써 본 소감은 꽤 괜찮은 물건이라는 생각이듭니다. 사람들이 갤s를 뭐 언플, 국내용이라면서 폄하하는데 전 사용하면서 크게 불편한 점은 없었습니다. 물론 사용하는게 지메일, 트위터, 주식, 가계부, 이북이 전부라서 그런지는 모르겠네요. 개인적인 생각입니다만 게임보다 기계 가지고 노는 걸 좋아하시는 분들이라면 갤s를 추천해 드리고 싶네욤. 전 애플이 좀 더 나아지려면 더 많은 부분을 공개해야 한다고 생각합니다. 그 부분은 워즈니악 아저씨도 지적을 했던 부분이죠.&lt;/p&gt;
&lt;p&gt;덧) 루팅을 해야 하나 말아야 하나 고민하시는 분들이 계실 것 같습니다. 스마트폰을 스마트폰으로 사용하고 계시다면 하는게 좋을 것 같습니다. 종종 일반인들이 그런 것까지 할 필요가 있느냐, 버벅임도 못 느낀다, 라고 말씀하시는 분들이 계시는데 빠른 걸 안써봐서 그런 겁니다. 빠른 걸 써보면 아 그게 버벅이는 거였구나, 라고 자연스레 느끼게 됩니다. 망할 블랙 스크린 보는 횟수가 좀 줄어듭니다. 벤치 점수딸 이상의 값어치를 합니다. 실제 체감 속도는 2.x배 이상입니다. 물론 뭐 전화만 하시는 분들이라면 별로 권해드리고 싶지는 않네요.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[갤럭시s 내장앱 지우기.]]></title><description><![CDATA[갤럭시s…]]></description><link>https://jiniya.net/wp/archives/2883</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2883</guid><pubDate>Tue, 10 Aug 2010 23:56:39 GMT</pubDate><content:encoded>&lt;p&gt;갤럭시s를 사서 첫 부팅을 시키면 정말 덕지덕지 내장 앱들이 잔뜩 깔려있습니다. 흠, 뭐 앱 설치하고 이런 걸 잘 못하시는 분들에게는 그게 도움이 되겠지만 그렇지 않은 사람들에게는 그게 오히려 독이 되는 것 같습니다. 똑같은 프로그램인데도 성능 떨어지고, 디자인 구린 것들이 많기 때문이죠. ㅋㅋ~ 어쨌든 그래서 루팅하면 젤 먼저 하는 작업이 요론 내장앱들을 정리하는 작업입니다.&lt;/p&gt;
&lt;p&gt;내장앱은 기본적으로 /system/app에 들어있습니다. 들어가면 정말 말도 안되게 많은 앱들이 있는 걸 보실 수 있을 거예요. 어떻게 보시는지 모르신다구요. ls /system/app 하시면 됩니다. 그런데 다 필요없다고 함부로 지우시면 쪼다 크리 맞는 수가 있습니다. 먼저가신 분들이 친히 정리해 놓으신 자료가 있으니 그걸보고 지우시는게 한결 마음이 편합니다. 아래 글타래는 그런 목록을 정리해둔 자료입니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.matpclub.com/board/index.html?id=tipn&amp;#x26;asort=&amp;#x26;smode=both&amp;#x26;skey=%B3%BB%C0%E5&amp;#x26;no=7&quot;&gt;http://www.matpclub.com/board/index.html?id=tipn&amp;#x26;asort=&amp;#x26;smode=both&amp;#x26;skey=%B3%BB%C0%E5&amp;#x26;no=7&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;삭제하는 방법은 주로 파일을 삭제하라고 되어 있는데 외국 포럼을 찾아보니 pm이란 명령어를 사용해서 지우는게 좋다고 나와 있더라고욤. 그래서 요기서는 그걸로 지우는 방법을 간단히 설명드릴까 합니다. Root explorer다, 뭐 핸폰에 있는 쉘 프롬프트로 지워라, 등등 방법은 정말 많은데요. 젤 편한 방법은 adb를 이용하시는 방법입니다. 구글에 뭐 adb 설치 이런식으로 쳐보면 자료가 많으시니 adb 연결은 알아서 각자 하시면 될 것 같구욤.&lt;/p&gt;
&lt;p&gt;adb shell로 들어가면 젤 먼저 나오는 프롬프트는 당연히 $예욤. 우리가 보고 싶은 거는 #이죠.  su치면 한방에 넘어가시는 분들도 계시겠지만 잘 안되시는 분들도 계실거예요. 저도 여기서 삽질을 좀 했는데요. 스크린락을 걸어두면 넘어가지질 않습니다. 따라서 환경설정 가셔서 스크린락같은거는 해제한 다음에 su하셔야 합니다. 해제하고 su하면 핸폰창에 루트 권한을 허용하겠냐고 묻는 창이 뜹니다. 그러면 살포시 allow 눌러주시면 되겠습니다.&lt;/p&gt;
&lt;p&gt;#을 본다음 다음으로 확인해야 하는 거는 system 디렉토리가 rw로 마운트되었는지 확인하는 겁니다. ro로 마운트되어 있으면 당연히 삭제가 안됩니다. ro로 되어 있다면 아래 명령어를 입력해서 rw로 변경해 주시면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;mount -o remount rw /system&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;여기까지 오면 이제 내장앱을 삭제할 준비는 모두 되었습니다. /system/app에서 지우고 싶은 것들을 마구 지울 수 있습니다. 앞서 설명드렸던 pm을 사용하는 방법을 간단히 설명드리겠습니다. 예를들어 A00000000D.apk 파일을 삭제하고 싶다면 다음과 같이 명령어를 입력합니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;pm list packages -f | grep A00000000D&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;입력해서 결과가 아무거도 없다면 해당 프로그램은 아직 설치가 안된겁니다. 그런 경우에는 파일만 삭제하시면 됩니다. 설치가 되었다면 뭔가 메시지가 출력될겁니다. 대충 “파일이름=앱이름” 요론 식인데요 = 다음에 있는 앱이름을 기억해 둡니다. 그리고는 아래 명령어로 삭제를 하시면 됩니다. com.skt.skaf.A00000000D가 앱이름입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;pm uninstall com.skt.skaf.A00000000D&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;이렇게 지울려면 뭐 한 세월이겠죠. ㅋㅋ~ 그럴 때는 스크립트의 도움을 받으면 편리합니다. 여러분의 편의를 위해서 한방에 지우는 스크립트를 한번 만들어 봤습니다. 소스는 다음과 같구요. 텍스트 파일은 &lt;a href=&quot;http://www.jiniya.net/files/android/clean_app.txt&quot;&gt;여기서 다운로드&lt;/a&gt; 받으실 수 있습니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;#&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;system&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;bin&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;sh


mount &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;o remount rw &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;system


&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;e &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;system&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;app&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;useless &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;  

then  

    mkdir &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;system&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;app&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;useless  

fi


&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; args in &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/A00000000D.apk com.skt.skaf.A00000000D&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/A00000000E.apk com.skt.skaf.A00000000E&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/A000Z00040.apk com.skt.skaf.A000Z00040&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/andSisWidget3-signed.apk com.neomtel.android.SisWidget&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/Dlna.apk com.sec.android.app.dlna&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/DrmProvider.apk com.providers.drm&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/l000400002.apk com.skt.skaf.l000400002&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/l001f00002.apk com.skt.skaf.l001f00002&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/l001mtm091.apk com.skt.skaf.l001mtm091&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/Melon.apk com.iloen.melon&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/MiniDiary.apk com.sec.android.app.minidiary&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/SamsungWidget\_CalendarClock.apk com.sec.android.widgetapp.calendarclock&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/SisoDrmProvider.apk com.sec.android.providers.drm&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/SKAFCore.apk com.skt.skaf.skafcore&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/skafLauncher.apk com.android.skafLauncher&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/thinkdroid.apk com.tf.thinkdroid.samsung&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/TService.apk com.sec.android.TService&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/VideoTutorial.apk com.sec.android.app.videotutorial&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/Weather.apk com.weathernews.weather&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/WeatherWidget.apk com.weathernews.weatherwidget&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/Z0000OMPDL.apk com.skt.skaf.Z0000OMPDL&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/Z0000UP000.apk com.skt.skaf.Z0000UP000&quot;&lt;/span&gt; \  

    &lt;span class=&quot;token string&quot;&gt;&quot;/system/app/SamsungWidget\_Mirror.apk com.sec.android.widgetapp.mirror&quot;&lt;/span&gt;  

&lt;span class=&quot;token keyword&quot;&gt;do&lt;/span&gt;  

    set $args


    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;e $&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;  

    then  

        echo Remove $&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;  

        mv $&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;system&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;app&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;useless  

        pm uninstall $&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;  

    fi  

done&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;그럼 다운받은 스크립트를 실행하는 방법은 간단합니다. c 루트에 해당 파일이 있다고 생각하면 다음과 같이 입력하면 됩니다. 정상적으로 실행되면 메시지가 출력되면 삭제가 진행될 겁니다. 삭제하는데 몇 초씩 걸리기 때문에 아주 순식간에 끝나지는 않습니다. 물론 목록에 있는 파일이 이미 모두 지워진 경우에는 바로 끝납니다. 불필요한 파일은 /system/app/useless에 백업되어 있습니다. 필요하실 때에 다시 /system/app으로 옮겨서 설치해서 사용하시면 됩니다.&lt;/p&gt;
&lt;p&gt;**adb push c:\clean_app.txt /skttmp/clean_app.txt&lt;/p&gt;
&lt;p&gt;adb shell&lt;/p&gt;
&lt;p&gt;su&lt;/p&gt;
&lt;p&gt;sh /skttmp/clean_app.txt**&lt;/p&gt;
&lt;p&gt;덧) 스크립트를 제작하시는 분들은 crlf 주의하세요. DOS용 crlf 형태로 저장하면 스크립트가 제대로 실행이 되지 않더군요. 그것 때문에 또 한 2시간 삽질했습니다. ㅠㅠ~&lt;/p&gt;
&lt;p&gt; 2
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[Dependency Walker는 무엇에 쓰이는 물건일까?]]></title><description><![CDATA[Dependency Walker는 모듈의 의존성 정보를 알아내는 도구다. 비주얼 스튜디오(Visual Studio) .NET 2003 버전을 사용한다면 설치 디렉터리 밑에 Common7\Tools\Bin 디렉터리에서 depends.exe…]]></description><link>https://jiniya.net/wp/archives/2878</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2878</guid><pubDate>Mon, 09 Aug 2010 23:56:38 GMT</pubDate><content:encoded>&lt;p&gt;Dependency Walker는 모듈의 의존성 정보를 알아내는 도구다. 비주얼 스튜디오(Visual Studio) .NET 2003 버전을 사용한다면 설치 디렉터리 밑에 Common7\Tools\Bin 디렉터리에서 depends.exe를 실행하면 된다. 자주 사용하는 유틸리티이기 때문에 바탕화면이나 시작 메뉴 등에 등록해 놓고 사용하면 편리하다. 혹시 depends.exe가 없다면 홈페이지(&lt;a href=&quot;http://www.dependencywalker.com&quot;&gt;http://www.dependencywalker.com&lt;/a&gt;)에서 최신 버전을 다운로드 받으면 된다. 캡처한 화면은 Dependency Walker를 실행해서 MFC71.dll을 불러온 화면이다.&lt;/p&gt;
&lt;p&gt;Dependency Walker는 말 그대로 의존성을 검사하는 도구다. 직접 만든 실행 파일(EXE) 내지는 동적 연결 라이브러리를(DLL) 구동하는데 필요한 파일이 무엇인지 체크 하는 도구라고 생각하면 된다. 개발자 컴퓨터에서 잘 동작하던 실행 프로그램이 다른 곳에 설치하면 DLL이 없다면서 실행이 되지 않는 문제가 종종 발생하곤 한다. 이러한 경우에 어떤 DLL들이 필요한지 살펴보고 그것들을 같이 배포해야 문제가 발생하지 않는다. 하지만 DLL을 제작하는 프로젝트 내에서 직접 어떤 라이브러리를 가져다 썼고 어떤 것들을 같이 배포해야 하는지 찾기란 쉬운 작업은 아니다. 그런 작업을 한눈에 보기 쉽게 해주는 것이 Dependency Walker의 역할이다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://www.imaso.co.kr/data/article/depends_capture.jpg&quot; alt=&quot;&quot; title=&quot;dependency walker&quot;&gt;&lt;/p&gt;
&lt;p&gt;위의 캡쳐 화면을 보면 화면이 총 다섯 개의 부분으로 분할된 것을 알 수 있다. 그럼 지금부터 각각의 영역이 어떠한 것을 의미하는지 살펴보도록 하자. 위에서 아래로 왼쪽에서 오른쪽으로 살펴보자.&lt;/p&gt;
&lt;p&gt;왼쪽 위에 있는 영역은 현재 열려있는 파일과 의존 관계에 있는 파일들을 표시하는 창이다. 지금 MFC71.DLL을 열어둔 상태이므로 가장 위쪽에 MFC71.DLL이 표시되어 있다. 트리 구조에서 그것의 자식으로 표시된 DLL들이 MFC71.DLL을 구동하기 위해서 필요한 DLL임을 알 수 있다. MSVCR71.DLL, KERNEL32.DLL, GDI32.DLL등이 필요함을 알 수 있다. 그런 자식 DLL을 클릭하면 자식 DLL을 구동하는 데 필요한 DLL이 표시된다. 모듈을 선택한 후 엔터 키를 누르면 해당 모듈을 다시 별도의 Dependency Walker 창에서 불러와서 표시해 준다.&lt;/p&gt;
&lt;p&gt;오른 쪽으로 붙어 있는 창에는 왼쪽에서 선택한 DLL(MSVCR71.DLL)에서 MFC71.DLL이 임포트 해서 사용하고 있는 함수 목록이 나타나 있다. C라고 나와 있는 것은 C타입의 함수라는 의미다. 옆에 있는 Ordinal 칼럼은 함수가 Ordinal에 의해서 링크 되었는지를 표시한다. N/A라고 표시된 것은 이름에 의해서 링크 되었다는 의미다. 다음에 나타나 있는 Hint는 해당 함수에 대한 힌트 값으로 운영체제 내부적으로 사용된다. 그 옆에 나타나 있는 Function은 함수의 이름을 나타낸다. C++ 함수인 경우 오른쪽 버튼을 눌러 Undecorate C++ Functions를 선택하면 이름 장식(mangling)된 것을 해제한 원형을 표시해 준다.&lt;/p&gt;
&lt;p&gt;그 창 아래 있는 것은 왼쪽에서 선택한 DLL(MSVCR71.DLL)에서 익스포트 하고 있는 함수 목록이다. 각 칼럼은 함수 익스포트 타입, Ordinal, Hint 값, 함수 이름, Entry Point를 나타낸다. 이 창과 위에 있는 창에서는 함수를 선택하고 엔터 키를 누르면 해당 함수의 도움말 페이지가 열린다.&lt;/p&gt;
&lt;p&gt;캡쳐한 화면은 사용된 모듈들의 세부 정보를 나타낸다. 파일 크기, 속성, 버전과 같은 개별 파일에 대한 세부 정보를 확인 할 수 있다. 이 창을 통해서 우리가 알 수 있는 정보는 MFC71.DLL을 배포할 때에는 MSVCR71.DLL도 같이 배포해야 함을 알 수 있다. 아래쪽으로 죽 나타나 있는 DLL들은 전부 시스템 기본 DLL 이기 때문에 별도로 배포할 필요가 없다.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[xfav 0.9.3]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/2821</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2821</guid><pubDate>Sat, 07 Aug 2010 23:56:37 GMT</pubDate><content:encoded>&lt;p&gt;저는 탐색기를 좀 난삽하게 사용합니다. 이 폴더, 저 폴더 열어놓고 사용하다보니 항상 열려있는 탐색기가 수두룩하죠. 그래서 토탈 커맨더같은 유틸리티를 쓰긴 하는데 그래도 탐색기가 손에 익어서 잘 적응이 안되더라고욤. 토탈 커맨더에 보면 즐겨찾기 기능이 있는데 참 유용합니다. 그래서 탐색기에 유사한 기능을 추가해주는 프로그램을 만들어 봤습니다.&lt;/p&gt;
&lt;p&gt;xfav는 토탈 커맨더의 즐겨찾기 기능을 탐색기에 추가해 주는 유틸리티입니다. 탐색기로 자주 이동하는 폴더를 좀 더 손쉽게 바로바로 즉시 이동시켜주는 기능을 합니다. 이제는 더 지능적이 되어서 열려있는 탐색기 창 중에 이동하려는 창이 있으면 바로 찾아서 띄워줍니다. 저처럼 탐색기를 사용하시는 분들에게는 유용할 것 같습니다.&lt;/p&gt;
&lt;p&gt;프로그램은 아래 경로에서 다운로드 받으시면 됩니다. 별도의 설치 과정은 필요 없으며, xfav.exe를 실행하면 그 위치에서 실행됩니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/bins/xfav/xfav.0.9.3.zip&quot;&gt;http://www.jiniya.net/bins/xfav/xfav.0.9.3.zip&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;덧) 제가 사용하는 windows 7 32bit에서만 실행해 보았습니다. windows xp sp3 32bit에서도 동작한다고 합니다. 다른 운영체제는 잘 모르겠네요. 그리고 64bit 운영체제에서는 동작하지 않을 것으로 사료됩니다. 해보진 않았습니다. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;사용법&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;프로그램 사용법은 간단합니다. xfav.exe를 실행시키시면 됩니다. 정상적으로 동작하면 다음부터 탐색기에서 esc 키를 누르면 아래와 같은 xfav 메뉴가 나타납니다. Up은 현재 폴더의 상위 폴더로 이동시켜주는 기능을 합니다. esc, ` 연속기로 바로 상위 폴더로 이동하실 수 있습니다. Command Prompt 메뉴는 현재 폴더 위치에서 명령 프롬프트를 실행하는 기능을 합니다. esc, c로 바로 이용하실 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 231px; margin-bottom: 16px;&apos; data-url=&apos;./xfav_0_9_3.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/7b601c7bdc15a32771d29d3bfc9446a0/1fdc3/xfav_0_9_3.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 79.47368421052632%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAIAAACZeshMAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB0UlEQVR42oVTa3eiMBT0//+i+oH2KIqKEqTLqvgILu9XEiAo7bcdSx/u1nWHc5Jwc+dk5uamFwRBnudpmjLOijzP8iz9H5IkAcX3/R4mKWVVVj8sa7ffe7/8uq7LsqyqCmMpRNn9XAEBULIsu5DfssVmtfb8IIqi9qVtpESwaZrT6dScMDflFYQQ2IWEdzLnbL1ZL4lpmcv5dG4urflMJ4Qs9MVEmyyXlugk3CTjn1J62O1d6m43zoFSz/OPLt06258rYM05Fx/AGuLh/FN2iVDBCoyoHDIYY9iq3sR/yv7uOatrKThT1eFopBkLgxBjOtOm2uyh399T93w+gyCbRjbyo4h/yeb86LqQGoZhHMdYx5AVJ0EYBP4l6B2Pnu8zxv8kZ1ktJWds+DTQZ3Nd1xeETMYaMYlpmOPxRFVHtv08UB4f+koUJ12Brk+WcIpSJUkaRyHjAiYhta5q3BjsXUbIlt9ldydzNlCehuroUVGCOAVT3MLtq0L2K/Dy2p7b9976N67JnediqmmmZdnPdp4X9/lfZFxXJ5IeDusV2sxBVNzFV5MURYEGRoAYhuPs2ra9tPVdgImKwm/PdV08Brwv27Y3Gwcv1Md3F0gGhVL6Gw52ZvOD0uXFAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;xfav 0 9 3 md 0&apos; title=&apos;&apos; src=&apos;/static/7b601c7bdc15a32771d29d3bfc9446a0/1fdc3/xfav_0_9_3.md_0.png&apos; srcset=&apos;/static/7b601c7bdc15a32771d29d3bfc9446a0/08678/xfav_0_9_3.md_0.png 190w,
/static/7b601c7bdc15a32771d29d3bfc9446a0/1fdc3/xfav_0_9_3.md_0.png 231w&apos; sizes=&apos;(max-width: 231px) 100vw, 231px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;다음으로 나오는 Add to favorites, Remove the current folder, Reload 메뉴는 각각 즐겨찾기 폴더를 추가하고, 삭제하고, 설정 파일을 다시 로딩하는 기능을 합니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 369px; margin-bottom: 16px;&apos; data-url=&apos;./xfav_0_9_3.md_1.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/d7529785b8163395f6ce35227058193b/d8ad8/xfav_0_9_3.md_1.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 55.263157894736835%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB4ElEQVR42m2QW2/TQBCF/dt5q8Qz8AYS4glUqapaSmmSguLYsZ31Nb7UcS6O46j1eq+O4yZBYp2KigpG345GO3OkmSN9vhpcyc6tHnb0oKPa5z/Bac/51As/9uL3nfjNufnhJvqipGdaemGk3+31NUi7r0/kk1eXb99JXd33kiycrcP52p9mTrw0gqXq57Kf98d5F0z7XqbdFUb8YCaFNy/dObTd2PciBYTS+G7uWHa2WlGCKSEIlaIo4cOG07pinBEBo5i1XQFqM+P1tvaTpRRM5oHvDzUNAKBphmmajusOh+LD8MYBoQxjgsmLwBhXnEVJKplBUtcbhNsBhBA+9kQN2yjJ/0IMbCpuh3PJCqacElhAWBRiZyxeCTFGjFKBOORfhLrmzI1TyXAnvh8Cy3W9sdjTcsaW4y6yHBNaYgLRC8ojsMSMMjsSYi9JszyMZwXm292varvbNPtnto/75g+irh8Pgk1zaHYHU4h1b1pVFWpdoYQ+w57IEVsivoAkRXxVtqbAEkEoPCcjX9wcpfum5pwJD/6mqnhTsdE9/5byU3txvdoOM5TNJgNZVhU1z1I7WkpnN6oKvL7uyEeUkasA74mB4XRV60K2vg6sS8XuDu0fCrhVQE8Z9XX7rKP9BiYoRE8uOGpwAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;xfav 0 9 3 md 1&apos; title=&apos;&apos; src=&apos;/static/d7529785b8163395f6ce35227058193b/d8ad8/xfav_0_9_3.md_1.png&apos; srcset=&apos;/static/d7529785b8163395f6ce35227058193b/08678/xfav_0_9_3.md_1.png 190w,
/static/d7529785b8163395f6ce35227058193b/d8ad8/xfav_0_9_3.md_1.png 369w&apos; sizes=&apos;(max-width: 369px) 100vw, 369px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Add to favorites 메뉴부터 알아보도록 합시다. 이 메뉴를 선택하면 다음과 같은 대화상자가 출력됩니다. 제목란에 메뉴에 표시될 제목을 입력하고 OK 버튼을 누르시면 됩니다. 추가되는 폴더는 탐색기가 현재 보고 있는 폴더입니다. 따라서 특정 폴더를 추가하기 위해서는 해당 폴더로 이동한 다음 Add to favorites 메뉴를 선택하시면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 231px; margin-bottom: 16px;&apos; data-url=&apos;./xfav_0_9_3.md_2.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/e216e80a86d906e8b5752f7b529e496c/1fdc3/xfav_0_9_3.md_2.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 88.94736842105263%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAIAAADUsmlHAAAACXBIWXMAAAsTAAALEwEAmpwYAAABxUlEQVR42o1TaZOiMBD1//+h3dmpXRWM3Cg4W8Mh7BoJYQQSDmFGP01b2Snn0JVXRVUn1Z3X/V4zIoTkeZ6maZIkvvfo+f7TAOx2OygcFUXRdV1G6cPD6vfKVTSNcd7UN9A0TVmWI6AV527f7QHdvhoAyAfWUzE8wxm3DdPzvDiKgZZz/i+LVyK+ygwRpAS+j5OEUtr1fdO0Z+zbpm2uM7dtWRSO4xiabpoWkpFuGOpc0TVNQaosSYvFkjF+vW3OQXBKUppSvMGnmNIsy7Y4iaLI94PzIF+LoW0wgGZU2ACXEMATVV2BiND7fwRrWVlI08lshizLXtiWqs51Rf9+92Md/+m7HnLF+JeZQTqMt3mRC5CEwA1ILfhhmC0GNRPG2GVmeSIpiqqrmmFacxlZtmkbtiSj6URarVzp1/jb3X1CqBDok8/sbxwTkm43m5JxmPMkRFWJbps31PVlq/Lx/c8Zmk/HY0KfIEnIyz/itDTvi+ETS3M8Hl8Azy/n94etZ1uWhYKQYVnOYgle1bfqP88cBkEQButwnefFUGZQv+97zpmzXIZhdDgc2gEARUGCEcYY1hA8dF03CEMwFf7y9BZgeTHGr11A1zuSpxq7AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;xfav 0 9 3 md 2&apos; title=&apos;&apos; src=&apos;/static/e216e80a86d906e8b5752f7b529e496c/1fdc3/xfav_0_9_3.md_2.png&apos; srcset=&apos;/static/e216e80a86d906e8b5752f7b529e496c/08678/xfav_0_9_3.md_2.png 190w,
/static/e216e80a86d906e8b5752f7b529e496c/1fdc3/xfav_0_9_3.md_2.png 231w&apos; sizes=&apos;(max-width: 231px) 100vw, 231px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;즐겨찾기가 추가되면 위 그림에 나와 있는 것처럼 esc를 눌렀을 때 메뉴 항목에 표시됩니다. 메뉴를 선택하면 해당 폴더로 바로 이동시켜 줍니다. 현재 열려있는 탐색기 창 중에 이동하려는 폴더를 보고 있는 창이 있으면 해당 창을 열어줍니다. 없는 경우에는 현재 탐색기 창의 탐색 위치를 해당 폴더로 이동시켜줍니다. 제목을 입력할 때 한 가지 팁을 드리면 “&amp;#x26;1. Dev”와 같이 등록하면 메뉴에서 단축 번호를 사용하실 수 있습니다. 저렇게 등록했다면 해당 메뉴를 esc, 1로 바로 선택하실 수 있습니다.&lt;/p&gt;
&lt;p&gt;Remove the current folder는 현재 탐색기가 보고 있는 폴더를 즐겨찾기에서 제거하는 기능을 합니다. 따라서 특정 즐겨찾기 항목을 제거하기 위해서는 해당 폴더로 이동한다음 Remove the current folder를 사용하시면 됩니다.&lt;/p&gt;
&lt;p&gt;Reload는 설정 파일인 xfav.ini를 새로 로딩하고 싶은 경우에 사용하시면 됩니다. ini 파일을 직접 편집하는 경우에 유용합니다.&lt;/p&gt;
&lt;p&gt;프로그램을 종료하고 싶으시면 Exit를 선택하시면 됩니다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[프로그래머의 길, 멘토에게 묻다]]></title><description><![CDATA[진짜 오랜만에 진득하게 앉아서 책을 읽은 것 같습니다. 30…]]></description><link>https://jiniya.net/wp/archives/2833</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2833</guid><pubDate>Sat, 07 Aug 2010 23:56:36 GMT</pubDate><content:encoded>&lt;p&gt;진짜 오랜만에 진득하게 앉아서 책을 읽은 것 같습니다. 300페이지도 안되는 분량인데 잡생각하면서 읽다보니 생각보다 오래 걸렸네요. 책 내용은 그냥 제목처럼 신입 개발자가 어떻게 빠르게 숙련된 개발자가 되는지에 관한 것입니다. 일부는 참 공감 가는 것들도 있고, 일부는 완전 저랑은 반대 생각을 가지고 있는 것도 있고 그렇네요. 가볍게 읽으실 수 있는 내용입니다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“그대가 이미 가득 차 있는 잔을 가지고 내게 온다면, 어찌 그대에게 마실 것을 드릴 수가 있겠소?”&lt;/p&gt;
&lt;p&gt;전반적인 이해력은 서로 다른 여러 수준의 경험이 상호 연관될 때 더욱 높아질 수 있다. 그 무엇도 당연하게 여기지 않는 신참들과, 알 것은 다 안다고 생각하는 고참들이 더 자주 밀접하게 소통할 때가 거기에 해당한다. – 칼 와익, 칼린 로버츠&lt;/p&gt;
&lt;p&gt;어떻게 만들어야 하는지 잘아는 무언가를 만들어보는 시간을 가져라. 그리고 그 경험을 바탕으로 당신이 얼마만큼의 길을 왔고 지금 현재 역량은 어느 정도인지 깨달아라.&lt;/p&gt;
&lt;p&gt;그는 사이드 프로젝트에 뛰어들었고 구할 수 있는 것은 뭐든지 읽기 시작했다.&lt;/p&gt;
&lt;p&gt;정말로 프로그래밍을 잘 하게 된다는 것은 일생의 과업이며, 지속적인 배움의 연속으로 이루어지는 대담한 계획이다. – 존 제프리즈 외&lt;/p&gt;
&lt;p&gt;프로그래머가 일하는 모습을 본 적이 있는 사람이라면, 자기 방식대로 일할 수 있는 기회가 주어졌을 때 프로그래밍은 그 자체로 가장 큰 동기를 부여한다는 것을 알 것이다. – 제랄드 와인버그&lt;/p&gt;
&lt;p&gt;돈을 벌기 위한 소프트웨어와, 만들기에 재미나는 소프트웨어 사이에는 서로 겹치는 부분이 그다지 많지 않다. (중략)  당신이 돈을 벌고자 한다면, 너무 지저분해서 누구든 공짜로는 해결하려 들지 않는 그런 문제를 안고 씨름해야 할 때가 많다. – 폴 그레이엄&lt;/p&gt;
&lt;p&gt;“숙련됨은 연습을 중단하는 그 시점부터 퇴보하기 시작한다.” 당신이 프로그램을 짜지않는 하루하루마다 숙련공으로 가는 길은 점점 더 멀어져 간다.&lt;/p&gt;
&lt;p&gt;(용꼬리의 …) 부작용은, 적극적으로 기술을 연마하지 않으면 결국은 자신에 대해서 상심할 수 있다는 점이다.&lt;/p&gt;
&lt;p&gt;오로지 동료와 가까이서 같이 일할 때만 배울 수 있는 그런 세세한 기법들이 있게 마련이다. 이런 기법들은 가르치기에는 너무 뻔해 보여서 잘 언급되지 않지만, 그런 것들이 쌓였을 때의 효과는 크다.&lt;/p&gt;
&lt;p&gt;어떤 일이든 간에 사랑하지 않고서는 정말로 잘 할 수가 없다. 그리고 당신이 해킹을 사랑한다면 필연적으로 자신만의 프로젝트를 하게 될 것이다. – 폴 그레이엄&lt;/p&gt;
&lt;p&gt;프로그래머가 되고자 준비하는 가장 좋은 방법은 프로그램을 짜는 것이며, 다른 사람들이 작성한 뛰어난 프로그램을 공부하는 것이다. 나 같은 경우에는 컴퓨터 과학 센터의 쓰레기장에 가서 버려진 운영체제 코드 리스팅을 건지곤 했다. – 빌 게이츠&lt;/p&gt;
&lt;p&gt;“Programmers at Work”에서 빌 게이츠는 이렇게 말했다.&lt;/p&gt;
&lt;p&gt;“프로그래밍 능력을 테스트하는 가장 좋은 방법 중 하나는, 프로그래머에게 30페이지 정도의 코드를 건네주고서 그 사람이 얼마나 빨리 그 코드를 통독하고 이해하는지 보는 것이다.”&lt;/p&gt;
&lt;p&gt;2003년 이래로 복잡한 알고리즘을 구현할 때 불변식을 의도적으로 사용하기 위해서 ‘절대 디버거를 쓰지 않는’ 태도에서 ‘테스트 주도 개발’을 훈련하는 쪽으로 돌아섰다.&lt;/p&gt;
&lt;p&gt;소프트웨어 개발 분야에서 무엇이 모여 숙달됨을 이루는지 우리가 정확히 알지는 못하지만, 어떤 것이 상관없는지는 알고 있다. 천재이거나, 운이 좋거나, 부유하거나, 유명해지는 것이 당신을 마스터로 만들어 주지는 않는다. 이런 것들은 장인정신에 꼭 필요한 것이 아니다. 소프트웨어 개발의 모든 측면을 아우르는 기술과, 그 기술을 전수해서 우리 분야가 앞으로 나아갈 수 있게 하는 능력, 그것이 장인정신의 핵심이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[워드프레스 설정에 관한 소고]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/2767</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2767</guid><pubDate>Thu, 05 Aug 2010 23:56:35 GMT</pubDate><content:encoded>&lt;p&gt;예전에는 설치형 블로그를 써도 플러그인도 만들어 쓰고, 툴도 변경해서 쓰고 했었는데, 워드프레스는 워낙 추상화가 잘 되 있어서 건드릴게 없습니다. 관리자 페이지에서 업그레이드 버튼만 누르면 다해주니깐 너무 편하더라고욤. 근데 그러다보니깐 자연스레 관리자 페이지에서 할 수 없는 일들에 대해서는 문외한이 됐습니다. 더불어 블로그도 자연스레 안습한 상태가 되어갔죠. 좀 때빼고 광낼 필요가 있을 것 같아서 주말에 작업을 했습니다. 링크 깨진 것도 많고, 여기저기 다르게 링크된 것도 많고 그렇드라고욤. 작업하다 삽질, 내지는 몰라서 고생한 부분만 따로 정리해 보았습니다. 비슷한 문제를 겪으신다면 감히 일말의 도움이라도 되지 않을까 생각해봅니당 ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#0. 펌링크 관련&lt;/strong&gt;워드프레스 설정 창에 가면 Permalinks라고 메뉴가 있습니다. 여기서 펌링크 주소 스타일을 지정할 수 있는데요. 디폴트는 /?page=2 이런 식으로 ?가 들어간 초큼 안습한 주소죠. 이걸 이쁘게 /page/2 이런 식으로 바꾸려면 아래 있는 다른 메뉴를 선택하시면 됩니다. 물론 모든 설정이 깔끔하게 되어 있다면 메뉴 선택을 하는 것만으로도 주소가 변경되지만 그렇지 않다면 조금 작업을 해야 합니다. 다음 순서로 작업을 하면 됩니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;서버가 아파치의 mod_rewrite 기능을 지원하는지 알아봅니다. 지원하지 않으면 그냥 이 기능은 못씁니다.&lt;/li&gt;
&lt;li&gt;워드프레스 설치 디렉터리로 이동하셔서 .htaccess 파일을 만들고 권한을 웹에서 수정할 수 있도록 해줍니다.&lt;/li&gt;
&lt;li&gt;이제 워드프레스에 가서 자신이 정하고 싶은 펌링크 주소를 설정합니다.&lt;/li&gt;
&lt;li&gt;잘 되는지 테스트 해봅니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;그런데 문제는 종종 이렇게 해도 한글 주소에서 문제가 발생하는 경우가 있습니다. 제가 사용하는 서버도 이상하게 한글 페이지만 안되더라고요. 그래서 간단한 php 파일을 만들어 테스트 해보니 인코딩 문제라는 생각이 들었습니다. 쿼리로 날라온 것과 서버에서 변환한 코드 값이 서로 다르더라구요. 이런 경우에는 앞서 만든 .htaccess 파일에 아래와 같은 문장을 추가해 주시면 됩니다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;IfModule mod\_url&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;c&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;  

    ServerEncoding UTF&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;  

    ClientEncoding EUC&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;KR  

&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;IfModule&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;이 문제로 진짜 몇 시간 삽질을 했는데 검색 키워드도 마땅찮아 자료도 잘 못찾고 있었습니다. 그러다 아래 페이지에서 보고는 해보고 바로 문제를 해결했습니다. 이럴 때 정말 고맙죠.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://mygony.com/archives/1681&quot;&gt;http://mygony.com/archives/1681&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1. 인덱스 페이지를 최신 글로 지정&lt;/strong&gt;워드프레스를 쓰시는 분들은 아시겠지만 인덱스 페이지와 개별 글을 보는 페이지가 분리되어 있습니다. 인덱스 페이지에서는 글의 일부 내지는 전부를 볼 수 있고, 코멘트를 달거나 일부만 보이는 경우에 글의 전체를 보려면 다시 글 제목을 클릭해서 해당 글만 보이는 페이지로 이동해야 합니다. 그런데 저는 이게 참 못마땅 하더라고요. 원래 쓰던 태터툴즈가 안그래서 그랬는지도 모르겠습니다. 그래서 인덱스 페이지를 태터툴즈처럼 한 글씩 보면서 코멘트도 달  수 있고 하도록 만드는 방법을 찾았습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://wordpress.org/support/topic/automatically-redirect-from-indexphp-to-singlephp&quot;&gt;http://wordpress.org/support/topic/automatically-redirect-from-indexphp-to-singlephp&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[php]&amp;#x3C;?php&lt;/p&gt;
&lt;p&gt;query_posts($query_string.’&amp;#x26;posts_per_page=1′);&lt;/p&gt;
&lt;p&gt;the_post();&lt;/p&gt;
&lt;p&gt;wp_redirect(get_permalink(), ‘302’);&lt;/p&gt;
&lt;p&gt;return;&lt;/p&gt;
&lt;p&gt;?&gt;[/php]&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2. 다음뷰, 믹시 위젯 달기&lt;/strong&gt;다음뷰는 참. 저걸 쓰라는 건지 말라는 건지 의심이 들더군요. 글 하나씩 퍼가는 거는 사람 할 짓이 아니잖아요. 근데 또 외부 블로그는 딱히 믹시처럼 퍼갈 수도 없게 되어 있는 것 같았습니다. 이런 고민 때문에 관련 기능을 가진 플러그인을 찾아봤는데요. 몇 개 해봐도 다들 잘 동작을 하지 않더라고요. 그러다가 알게된 아래 플러그인으로 한방에 해결했습니다. 메타 블로그 위젯입니다. 좀 짱이예욤.&lt;/p&gt;
&lt;p&gt;메타 블로그 위젯&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://082net.com/2009/996/metablog-widgets-plugin-v02/&quot;&gt;http://082net.com/2009/996/metablog-widgets-plugin-v02/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3. 트랙백 주소 표시&lt;/strong&gt;스킨에 트랙백 주소 표시가 안된다는 사실을 알게 되었어욤. 스킨에 트랙백 주소를 추가하고 싶으신 분들은 trackback_url이라는 스킨 함수를 사용하시면 됩니다. 아래와 같이 스킨 파일에 원하는 부분에 추가하시면 트랙백이 출력된답니다.&lt;/p&gt;
&lt;p&gt;트랙백 주소: &lt;?php trackback\_url(); ?&gt;&lt;/p&gt;
&lt;p&gt;사용자 편의를 위해서 자동으로 복사해 주는 기능을 추가하고 싶으신 분들은 아래 페이지를 참고하시면 도움이 될 것 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://raftwood.net/blog/1326&quot;&gt;http://raftwood.net/blog/1326&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[어려운 문제, 컴파일 타임 문자열 난독화]]></title><description><![CDATA[바이너리에서 문자열 리터럴을 숨기기 위해서 아래 링크에 나온 것과 같은 테크닉을 많이 사용합니다. http://www.gamedev.net/community/forums/topic.asp?topic_id=52826…]]></description><link>https://jiniya.net/wp/archives/1371</link><guid isPermaLink="false">https://jiniya.net/wp/archives/1371</guid><pubDate>Thu, 05 Aug 2010 23:56:34 GMT</pubDate><content:encoded>&lt;p&gt;바이너리에서 문자열 리터럴을 숨기기 위해서 아래 링크에 나온 것과 같은 테크닉을 많이 사용합니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.gamedev.net/community/forums/topic.asp?topic_id=528265&quot;&gt;http://www.gamedev.net/community/forums/topic.asp?topic_id=528265&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;그런데 이런 방법을 써보신 분들은 아시겠지만 이게 아주 많이 억수로 귀찮습니다. 모든 문자열 리터럴을 일일이 저렇게 인코딩한 형태로 만드는 것도 일이고, 유지보수도 힘들어지죠. 저렇게 난독화된 문자열이 해독되는 경우에 다른 것으로 치환하는 일도 쉽지 않습니다.&lt;/p&gt;
&lt;p&gt;제가 늘 생각하던 것은 다음과 같은 방법으로 문자열 리터럴을 컴파일 타임에 자동으로 인코딩 시킬 수는 없을까? 하는 것이었습니다. 그럼 참 편할 것 같았거든요. 나중에 고칠 때도 Start 해시 값만 변경하면 다른 바이너리로 인코딩이 자동으로 될테니까 말이죠.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;Obfuscator&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0x10221337&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0xA30624DD&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CompileTimeEncode&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Hello&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x10221337&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0xA30624DD&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;물론 아무리 생각해봐도 이렇게 만들 수 있는 방법이 떠오르지 않는 것이 문제입니당. 혹시 이 문제를 아주 우아하게 해결할 수 있는 방법을 아시는 분 계신가욤? 찾아보니 D언어는 아래와 같은 퐌타스틱한 방법을 제공하는 것 같군요.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.digitalmars.com/d/archives/digitalmars/D/learn/compile_time_string_manipulation_7225.html&quot;&gt;http://www.digitalmars.com/d/archives/digitalmars/D/learn/compile_time_string_manipulation_7225.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;덧) 물론 프리프로세서를 만들어서 데이터 파일에서 코드를 생성하도록 만들 수도 있습니다. 본문 내용은 그냥 지적 호기심입니다. C++에서 템플릿 메타 프로그래밍, 매크로나 기타 다른 방법들을 동원해서 컴파일 타임에 문자열 조작이 가능한지 말이죠.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[AsmView, x86 심플 디스어셈블러]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/2706</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2706</guid><pubDate>Tue, 03 Aug 2010 23:56:33 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&apos;gatsby-resp-image-wrapper&apos; style=&apos;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 546px; margin-bottom: 16px;&apos; data-url=&apos;./AsmView,_x86_심플_디스어셈블러.md_0.png&apos;&gt;
      &lt;a class=&apos;gatsby-resp-image-link&apos; href=&apos;/static/2b1c23320f3af7b3b03c76bf8a6f68fa/8c78b/AsmView%2C_x86_%EC%8B%AC%ED%94%8C_%EB%94%94%EC%8A%A4%EC%96%B4%EC%85%88%EB%B8%94%EB%9F%AC.md_0.png&apos; style=&apos;display: block&apos; target=&apos;_blank&apos; rel=&apos;noopener&apos;&gt;
    &lt;span class=&apos;gatsby-resp-image-background-image&apos; style=&quot;padding-bottom: 94.73684210526315%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAIAAAAf7rriAAAACXBIWXMAAA7DAAAOwwHHb6hkAAADMElEQVR42nVT2XbbNhDl//9G08ekJ31I4xPZkmzJ3DeQ4AouorhJpLiLWhwrGclp3T50DsiDA8yde+cCoCaMOefNe8b4wnqfnuzPTHinVd+M/i+t/shnH7nsE5//IWz+lMsvqJpoxYNIJguF/vBh+tvvFIs8RSPYiSVEZBwIWkji1l03ZN04UQ3DTzovbkncwMRPWrKGlWaVtshJKWwR4pLQJ/dmd2eNp+OhGw79MF7Hfmz7wdCxZZmrVaghhHU9TRLDMADj+BHlR2mWJp7nJ5tyOL50fX84nk7n89uAadM0dV13XVffAiawUhaFRUIqSvLdbpfnmzSO+647jIfL5fLj/+Nt93g4uP7qytz3wDeAeB1pYbjK0vz19R/85e/8/8Tr9xcSxpQdxMdx37bdHmIYmrqpq+p8Pr+R/Bt3eY8f319O2F1R8Dm25bgkjmMCrftBewvf96uqiqLIJSTwfdgpd7tfnTdN29YGiSjVJJPJt+XzM/HIbDb7eveV5YWyLDmegyRZkuZPi8Vy8UwzpmkCAQDBsF1ZiJoDYG82m4qiZFoWLwiO49iOu91uFVWF+nAqi+US6brjuEEQgJAbbVtst5xiXsHT6YMgikjTljRTVzV0Dv6LkgRJUFEQBDhnzw+KohjAFHAFvmonY/IOxoYJJHmeQwZ4JivKjRnPHx9VVbUdZ7WK8jwDI6Bo37Wmt6YQyJ4+cDwPJDTLQldJkqRpKoPsprFMk2ZYFSHQH63XmzyH61GU5dB3N7B1ZYZuLdtmOR56NkwzWsfXnpsWY306m0uyBJ6D4Q5cSs+Pk2w/9O9gkA0YSVZc191st6BNluUrs2WB2YAD/4tim8FNzHOgBmbDiyjN9gHMsBzI1jEGwXCQkCopCpwJ2Ov5XhiGWZbBIpSDunDQN9nR9ZLc30+gMd0wZvMnQRS8wN8UBS+Iu6pSVOWZYWmGXtI0GA4BvzTLu661g4TyohS2EFLDIOB5zsA6CDyMex1r47h3HUuSRAyvEal5lp7hxY57GKdxWGUF9cghTtZYSeMUnRaRgl1ZtyXN4hVdwQ6PDEbSeAXzigF/UTNFZEq6rej2nEM/Ae4950DGn6JTAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;&gt;&lt;/span&gt;
  &lt;img class=&apos;gatsby-resp-image-image&apos; alt=&apos;AsmView  x86           md 0&apos; title=&apos;&apos; src=&apos;/static/2b1c23320f3af7b3b03c76bf8a6f68fa/8c78b/AsmView%2C_x86_%EC%8B%AC%ED%94%8C_%EB%94%94%EC%8A%A4%EC%96%B4%EC%85%88%EB%B8%94%EB%9F%AC.md_0.png&apos; srcset=&apos;/static/2b1c23320f3af7b3b03c76bf8a6f68fa/08678/AsmView%2C_x86_%EC%8B%AC%ED%94%8C_%EB%94%94%EC%8A%A4%EC%96%B4%EC%85%88%EB%B8%94%EB%9F%AC.md_0.png 190w,
/static/2b1c23320f3af7b3b03c76bf8a6f68fa/2edd7/AsmView%2C_x86_%EC%8B%AC%ED%94%8C_%EB%94%94%EC%8A%A4%EC%96%B4%EC%85%88%EB%B8%94%EB%9F%AC.md_0.png 380w,
/static/2b1c23320f3af7b3b03c76bf8a6f68fa/8c78b/AsmView%2C_x86_%EC%8B%AC%ED%94%8C_%EB%94%94%EC%8A%A4%EC%96%B4%EC%85%88%EB%B8%94%EB%9F%AC.md_0.png 546w&apos; sizes=&apos;(max-width: 546px) 100vw, 546px&apos; style=&apos;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&apos; loading=&apos;lazy&apos; decoding=&apos;async&apos;&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;직업 특성상 어셈 코드 볼 일이 많습니다. 직접 실행 파일을 분석하는 경우도 있지만 알 수 없는 곳에서 긁혀온 바이트 코드들을 분석하기도 하는데요. 매번 그런 걸 분석할 때마다 수동으로 하다가 불편해서 하나 만들어 봤습니다. 헥사 코드를 넣으면 디스어셈블된 코드를 보여주는 유틸리티입니다.&lt;/p&gt;
&lt;p&gt;16, 32, 64비트 코드로 디스어셈블을 해서 보실 수 있구요. 시작 주소와 코드를 넣고 디스어셈블 버튼을 누르시면 됩니다. Config에서 글꼴을 설정하시면 좀 더 이쁘게 결과를 보실 수 있어요. 입력되는 헥사 코드 형태는 0xaa, aa, aah와 같은 형태를 인식합니다. 구분은 콤마, 스페이스 등으로 하시면 됩니다. 물론 붙여서 하거나 헥사 값으로 인식되지 않는 다른 문자들로 구분을 하셔도 됩니당.&lt;/p&gt;
&lt;p&gt;사용해 보시고 싶으신 분들은 &lt;a href=&quot;http://www.jiniya.net/bins/AsmView/AsmView.2010.8.3.87.exe&quot;&gt;여기서 다운로드&lt;/a&gt; 받으시면 됩니다. 즐디어셈하세욤~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[김연아 초콜릿 동영상…]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/2759</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2759</guid><pubDate>Mon, 02 Aug 2010 23:56:32 GMT</pubDate><content:encoded>&lt;p&gt;국민 여동생 연아양이 어제 초콜릿에 출연했다고 하는군요.&lt;/p&gt;
&lt;p&gt;스포츠 스타지만 그동안 발군의 노래 실력으로 대중을 깜짝 놀라게 한적이 많았죠.&lt;/p&gt;
&lt;p&gt;이번에도 어김없군요. 이러니 우리가 어찌 사랑하지 않을 수 있겠습니까? ㅋㅋ~&lt;/p&gt;
&lt;p&gt;세상은 참 불공평합니다.&lt;/p&gt;
&lt;p&gt;그래서 더 재미난건지도 모르겠습니다.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[일부일처 – 속거나 속이거나]]></title><description><![CDATA[어제 다큐멘터리를 한 편 보았습니다. 2006년도에 MBC에서 방송된 인간의 짝짓기에 관한 내용을 담은 다큐멘터리입니다. 2부로 구성되어 있는데…]]></description><link>https://jiniya.net/wp/archives/2688</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2688</guid><pubDate>Mon, 02 Aug 2010 23:56:31 GMT</pubDate><content:encoded>&lt;p&gt;어제 다큐멘터리를 한 편 보았습니다. 2006년도에 MBC에서 방송된 인간의 짝짓기에 관한 내용을 담은 다큐멘터리입니다. 2부로 구성되어 있는데 1부 제목이 “일부일처 – 속거나 속이거나”입니다. 내용이 참 재미있더군요. 그래서 여기에 일부 내용을 소개해 볼까 합니다. 비슷한 주제에 관심이 있으신 분들은 꼭 찾아서 보시길 바랍니다. 다큐 내용도 지루하지 않게 꾸며져 있어서 시간 가는 줄 모르고 볼 수 있지 않을까 싶네욤.&lt;/p&gt;
&lt;p&gt;제가 가장 흥미를 느꼈던 부분은 일부일처를 중독이라는 관점으로 설명한 내용이었습니다. 두 가지 종류의 쥐를 가지고 실험한 내용이 나오는데 비슷한 쥔데 한 쪽은 일부일처를 무지하게 잘 지키고, 다른 한 종의 쥐는 방만한 생활을 한다고 합니다. 그래서 둘을 놓고 뇌 사진을 찍어서 비교를 해보니 일부일처를 잘 지키는 쥐의 뇌는 코카인에 중독된 것과 같은 상태였다고 합니다. 즉 한 명의 상대에게 완전히 중독된 것이죠. 이를 역으로 이용해서 일부일처를 하지 않는 쥐를 똑같은 중독 상태로 만들었더니 일부일처를 하게 되었다고 합니다. 그러면서 사람의 바람끼를 통제할 수 있는 약을 만들수도 있지 않을까라는 드립을 살짝 칩니다. 놀랍죠? ㅋ~ 저는 이제껏 연애를 뭐 7년 했다, 8년 했다, 이런 분들 이야기를 들으면 참 대단하다는 생각을 많이 했습니다. 어떻게 저렇게 긴 시간을 서로 사랑했을까, 라는 의문을 가졌죠. 그런데 중독의 관점에서 풀어보면 정말 쉽게 이해가 됩니다. 이건 좀 여담이긴 하지만 저는 개인적으로 장기 연애의 또 다른 한 팩트는 관성이라고 생각합니다. 사람들은 이를 풀어서 ‘정이 들어서…’라고 이야기하죠.&lt;/p&gt;
&lt;p&gt;또 다른 재미난 이야기는 우리가 흔히 궁금해하는 사랑의 유통기간에 관한 내용입니다. 중간에 어떤 여성 학자가 말하는 내용에서 짧게 언급되는데요. 낭만적인 사랑의 유효기간에 관한 연구가 지금까지 딱 두 번 진행되었는데 둘 다 결론이 1-3년으로 났다고 하더군요. 그런 연구를 어떻게 했는지도 궁금하긴 하지만, 어쨌든 결론으로 나온 데이터는  의미있는 수치가 아닐까라는 생각을 해봤습니다. 보통 많은 사람들이 그렇게 느낄 것 같기도 하구욤.&lt;/p&gt;
&lt;p&gt;2부에서는 일부다처를 믿고 실행에 옮긴 분들을 인터뷰하기도 합니다. 거기서 일부다처로 살아온 한 여성 분이 그러더군요. 자기는 남편이 항상 자기 옆에 계속 있는 것이 너무 싫다고요. 어디론가 좀 가버렸으면 좋겠는데 일부일처의 생활을 한다면 항상 옆에 있으니 자기 시간은 하나도 가질수가 없다는 이야기를 했습니다. 일부다처가 되면 자연스레 남편의 시간이 분할되니 그녀의 개인 시간은 보장되는 셈이었겠죠. 그런데 참 이런 생각으로 일부다처를 한다면 어처구니가 없는게 아닐까라는 생각이 들었습니다. 남편이 너무 불쌍하자나요. 맨날 쉬지도 못하고 돌아가면서 시간을 할애해야 하는 남편은? ㅇㅇ?&lt;/p&gt;
&lt;p&gt;결혼 제도가 서서히 사라지면서 전통적인 형태의 가정이 해체되고, 새로운 가정의 형태가 등장하는 사례로 유럽권 국가들이 소개되는데요. 이것도 좀 흥미롭습니다. 4년 전 다큐임에도 유럽이 이렇게 자유스럽다는 사실에 좀 놀랐다고 할까요? 2명 중 한 명 꼴로 혼외 가정에서 자라고 있다는 사실은 정말 충격적입니다. 결혼을 하지 않는 것을 당연하게 생각하고, 아이를 낳고도 결혼을 하지 않는 가정이 많다고 하더군요. 대부분의 인터뷰 내용을 보면 결혼을 굉장히 어렵게 내지는 중요한 문제로 생각을 하고 있어서 못한다는 느낌이 많이 들었습니다. 파리에서 혼자 아이들을 키우는 싱글맘 인터뷰 내용이 조금 인상 깊었는데요. 10년 넘게 동거를 하는 남자에게 배신을 당했다고 했습니다. 그래서 아이들을 혼자 키우는데, 그녀가 말하길 아이들을 키우는 건 키우는 거지만 자기에게도 사랑이 필요하다는 이야기를 하더군요. 결국 사람은 누군가 의지할 사람이 필요하니까요.&lt;/p&gt;
&lt;p&gt;끝나면서 ‘줌마넷’이라는 동호회(??) 분들이 모이셔서 담소를 나누는 장면이 나오는데 한 아줌마가 아이들을 모두 국가가 책임져 준다면 굳이 결혼이라는 제도가 있어야 할 필요가 있을까, 라는 질문을 하더군요. 평소 저도 같은 생각이었습니다. 아직 결혼 제도가 유지하고 있는 가장 큰 틀은 양육 때문이겠죠.&lt;/p&gt;
&lt;p&gt;저는 개인적으론 결혼이라는 제도에 대해서 그렇게 호의적이지 않습니다. 사랑하는 두 남녀가 만나서 같이 모여 사는 것은 좋다고 생각하지만 평생을 살아야 한다는 점, 잘못된 선택을 바로잡기 위한 비용이 엄청나게 크다는 점. 우리 사회에 국한된 이야기이긴 하지만 결혼 후에 동반되는 각종 집안의 경조 문화가 x2가 아닌 ^2가 된다는 점 때문입니다. 앞서 파리 여성의 인터뷰처럼 누구나 의지할만한 반려자를 필요로하다는 생각에는 동의합니다. 하지만 결혼이라는 것이 그 답이라는 사실에는 회의이라는 것이죠. 제가 보기에는 결혼은 그걸 공고히 하는 제도라기 보다는 그것을 가로막는 허들같은 느낌이 더 많이 들더군요. 흔히 사람들이 하는 말처럼 결혼은 현실이니까요.&lt;/p&gt;
&lt;p&gt;다른 관점에서 생각을 해보자면 이렇습니다. 앞서 쥐들의 예에서처럼 중독이 일부일처라는 제도를 유지하는 핵심 역할을 한다고 생각해봅시다. 그렇다고 했을 때 만약 그 중독의 개인차가 있다면 결혼이라는 제도가 중독성이 약한 사람들에게는 정말 가혹한 제도가 아닐까라는 생각입니다. 최근에 읽은 테드 창의 “당신 인생의 이야기”라는 책에는 이런 내용이 있습니다. “외모 지상주의에 관한 소고”라는 제목의 단편인데요. 저자는 외모 지상주의를 타파하기 위해서 칼리라는 장치를 고안합니다. 사물을 보더라도 거기에 대한 감정적인 변화가 없어지도록 만드는 장치입니다. 뇌의 특정 부위를 억제시켜서 예쁘다, 못생겼다라는 판단을 못하도록 만드는 겁니다. 비슷한 장치가 이 중독에도 똑같이 적용될 수 있겠죠. 쥐 실험을 한 사람들이 생각한 것처럼 중독을 공고히 해주는 약물을 개발하는 것도 가능할 겁니다. 그 약을 사용한다면 약한 중독성을 가진 사람들이 결혼이라는 제도에서 문제를 일으킬 확률도 줄어들겠죠. 하지만 그런 것이 만들어진다면 과연 좋은 걸까요?&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[로마, 여유를 즐기다.]]></title><description><![CDATA[SG108956  뽀쁠로 광장에서. 사자야 물을 뿜으렴. 이 날 우리의 컨셉은 여유, 멋대로 하기. 로마인의 친절함을 너무 과도하게 느낄 수 있었던 하루였다. 6.25 또 새로운 로마의 하루가 시작됐다. P가 밥먹으로 가자고 하는걸 3…]]></description><link>https://jiniya.net/wp/archives/2632</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2632</guid><pubDate>Sun, 01 Aug 2010 23:56:30 GMT</pubDate><content:encoded>&lt;p&gt; &lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4849298312/&quot; title=&quot;SG108956&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4114/4849298312_7a3dd37e1c_b.jpg&quot; alt=&quot;SG108956&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;뽀쁠로 광장에서. 사자야 물을 뿜으렴. 이 날 우리의 컨셉은 여유, 멋대로 하기.&lt;/p&gt;
&lt;p&gt;로마인의 친절함을 너무 과도하게 느낄 수 있었던 하루였다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;6.25&lt;/p&gt;
&lt;p&gt;또 새로운 로마의 하루가 시작됐다. P가 밥먹으로 가자고 하는걸 30분만 더 있다 가자고 했다. 30분은 정말 게눈감추듯이 사라졌다. P가 다시 깨우길래 내려가서 아침을 먹었다. 올라오는 길에 숙소를 2틀 연장했다. 75유로 내고나니 55유로 남았다. 덴장. 핡~&lt;/p&gt;
&lt;p&gt;오늘은 정말 움직이기 싫은 하루였다. 아침먹고 올라와서도 계속 쳐지는 그런 하루다. P에게 일정을 짜라고 하고는 옷 정리, 디카 정리를 했다. 창밖의 햇살은 그렇게 원하던 쨍한 날이었지만 그것이 나를 더 힘들게 했다. 햇살이 너무 강해서 나가기가 두려웠다. 10시 30분쯤 청소 아저씨가 들어왔다. 어디서 왔냐는 말에 한국에서 왔다고 하자, 여느 유럽인들처럼 축구 이야기를 시작한다. 한국 축구 잘한다. 이탈리아, 프랑스 탈락했다는 이야기를 한다. 몰랐는데 방 청소를 정말 꼼꼼하게 잘해줬다. 계속 누워 뒹굴거리다 P가 일정을 다 짰다는 말에 씻고 나갔다. 왁스를 듬뿍 발랐다. P도 따라 바른다. 그리곤 미친척하고 출동했다. 역시 햇살은 쩔었다. 선글라스를 끼고 있어도 눈이 아팠다.&lt;/p&gt;
&lt;p&gt;지하철로 가다가 밥 시간인것 같아서 어제 말했던 셀프 서비스 레스토랑에서 스파게티와 거위고기 요리로 추정되는 것과 자두를 먹었다. 거위가 젤 비쌌는데 젤 구렸다. 너무 비렸다. 사실 닭인줄 알고 샀다. ㅠㅠ~ 비려도 너무 비렸다. 중국에서 먹었던 그 거위 간 요리가 떠올랐다. 젤 싼 자두가 젤로 맛있었다. 점심(11.4유로) 점심먹고 메트로로 가서 일일권을 끊었다. P가 가진 지폐가 안되서 고생하다 결국 자판기서 초콜릿을 샀다. 나중에 알게 된 사실이지만 일일권 기계는 5유로 지폐만 먹었다.&lt;/p&gt;
&lt;p&gt;A라인을 타려고 가는데 길이 막혀서 갈수가 없었다. 뭐 때문인지 공근같은(공익근무) 애들이 A라인으로 가는 길을 막고 있었다. 버스타고 가자고 올라가는 에스컬레이터를 탔는데 갑자기 방송이 나오고 사람들이 박수치고 환호하는 것이 아닌가? 공근같은 애들이 철수하며 다시 지나가게 해줬다. 그래서 다시 내려갔다. 방송을 이탈리아 말로만 해줘서 알 길이 없었다. 어쨌든 신도림같은 상태의 역에서 뽀쁠로 광장행 열차에 올라탔다.&lt;/p&gt;
&lt;p&gt;광장 역에 내리니 piazza ppoplou(??) 표지판이 있었다. 버거킹이 보여서 일단 화장실을 갔다가 광장으로 향했다. 광장은 그냥 광장이었다. 분수가 있고 쌍둥이 교회가 있었다. 인증샷 좀 찍고 실망한 마음으로 트레비 분수로 이동했다. 가다가 자라(zara) 매장이 있어 들어가봤다. 생각보다 옷은 쌌는데 저주받은 몸매에 어울리는 핏은 아니었다. 자라 매장은 세발자국에 하나씩, ENERGY 매장도 정말 많았다.&lt;/p&gt;
&lt;p&gt;아이폰 신공으로 겨우 트레비 분수에 도착했다. 분수는 정말 캐감동이었다. 진짜 건물과 분수가 절묘하게 어울려 있었다. 특히 석상이 없는 곳에 아무렇게나 깎아 놓은듯한 부분도 자세히 살펴보면 정교하게 물의 흐름을 계산해둔 것처럼 보였다. 그냥 아름다웠다. 그만큼 사람도 쩔게 많았다. 한참 동안 분수를 보고는 메트로까지 걸어갈 힘이 없어서 빤떼온 간다는 버스를 근처 정류장에서 탔다. 그런데 방향이 반대였다. 너무 덥고 피곤해서 그냥 가보자고 했다.&lt;/p&gt;
&lt;p&gt;버스가 테베레 강 근처로 가길래 그냥 내렸다. 어차피 강에도 한번은 와볼 생각이었던 참이니 잘됐다. 우리가 내린 곳은 비토리오 에마누엘레 2세 기념 다리였다. 다리 기둥에 앉아서 좀 쉬었다. 그리고는 다리 구경을 하다 바로 옆이 천사의 성이란 사실을 알게 되었다. 이런 걸 소 뒷걸음 치다가 쥐잡는 격이라든가. 어쨌든 천사의 성과 다리를 구경했다. 성안은 별로일 것 같아 드가진 않았다. 다리의 천사상이 참 멋있었다. 특히 십자가 든 녀석이 맘에 들었다. 구경하고 나와서는 오는 버스에 빤떼온 가냐고 물었다. 근처로 간다고 한다. 한 외국인이 친절하게 내리는 역까지 알려줘서 어렵지 않게 빤떼온을 찾아갔다. 빤떼온은 뭐 신을 모신 곳이라고 하는데 그저 그랬다. 실내 의자에서 P는 피곤해서 잠이 들었다. P가 오늘 일정은 끝이라고 가자고 했다. 그러자고 했다.&lt;/p&gt;
&lt;p&gt;집으로 가는 길에 나보나 광장 표지판을 보게됐다. 불현듯 그곳도 가봐야 한다는 생각에 한참을 걸어갔다. 그런데 이게 대박이었다. 한마디로 베리 굳. 뭐랄까 몽마르뜨 같은 예술인듯의 광장이었다. 마술사도, 비보이도, 화가도, 동상 놀이를 하는 사람도 있었다. 분수도 멋있었다. 광장이 너무 액티브해서 시간 가는 줄 모르고 구경했다. 8시가 되서야 집에 가는 버스를탔다. 아무거나 오는 버스에 떼르미니 가냐고 물었더니 갈아타야 한다고, 갈아타는 지점을 알려준다고 타라고 했다. 올라타니 한 할머니가 과도하게 친절하게 어디서 내리는지 몇 번을 타야 하는지 알려주셨다. 거기서 갈아타고 떼르미니까지 쉽게 갔다.&lt;/p&gt;
&lt;p&gt;P가 저녁을 책에 있는 생선 요리 집에서 먹자고 했다. 그러자 했다. 한참을 헤매다 지나가는 할아버지에게 여쭤봤더니 가게까지 안내해 주시고는 친절하게 축구를 볼 수 있는 자리까지 잡아 주셨다. 한국에서 왔다니 또 축구 이야기를 빠뜨리지 않는다. 유럽인들은 축국에 미쳤다. 음식은 맛있었다. 봉골레 스파게티?, 베스, 샐러드, 맥주 푸지게 먹고 나왔다. 저녁(24.5유로) 그리곤 기분좋게 집으로 왔다. 힘들고 피곤해서 야경은 그냥 포기했다. 그래도 숙소에 들어오니 11시였다. 일찍자고 내일 바티칸 투어를 준비하기로 했다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[미스테리어스한 VC++ 2010]]></title><description><![CDATA[집에서는 VC++ 2010을 사용합니다. 참 좋네요. 새로나온 툴답게 일단 UI…]]></description><link>https://jiniya.net/wp/archives/2589</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2589</guid><pubDate>Fri, 30 Jul 2010 23:56:29 GMT</pubDate><content:encoded>&lt;p&gt;집에서는 VC++ 2010을 사용합니다. 참 좋네요. 새로나온 툴답게 일단 UI가 먹어줍니다. ㅋㅋㅋ~ 스플래시 간지도 쫌 있구욤. 근데 바뀐게 여럿 있는데 오늘 알아낸 두 가지를 알려 드릴까 합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;도구 =&gt; 옵션에서 설정하던 프로젝트 대화상자가 없어졌습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/vs1.png&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/vs1.png&quot; alt=&quot;&quot; title=&quot;vs1&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;예전 설정 화면으로 들어가면 이렇게 사라졌다는 휑한 메시지만 보여줍니다. 그래도 이거라도 남겨놔서 사라졌다는 사실은 알 수 있게 해놨네요. 역시 똑똑한 애들은 달라요 ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/vs2.png&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/vs2.png&quot; alt=&quot;&quot; title=&quot;vs2&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;이사간 위치는 여깁니다. 프로젝트 설정 대화상자에 있어욤. 근데 그러면 매 프로젝트마다 다 일일이 설정해야 하느냐? 라고 한다면 꼭 그렇지는 안겠죠? 프로퍼티 시트라는 새로운 기능을 사용하면 되는거 같은데 해보지는 않았습니다. 아래 페이지에 설명이 나와 있어요.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.gockelhut.com/2009/11/visual-studio-2010-property-sheets-and.html&quot;&gt;http://blog.gockelhut.com/2009/11/visual-studio-2010-property-sheets-and.html&lt;/a&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;이게 좀 NG니다. Visual C++ 설정 창에서 사용할 수 있는 예약어 중에 $(ConfigurationName)이 있는데요. Debug지, Release지 빌드명을 지정해주는 역할을 했습니다. 그게 사라진 것 같아요. 예전 프로젝트를 컨버팅하면 $(ConfigurationName)이 Debug, Release 이 따위로 하드 코드된 문자열이 들어가네요. 새로 프로젝트를 생성해서 $(ConfigurationName)을 추가해봐도 동작하지 않습니다. 헐킈. 그러면 빌드별로 일일이 지정해야 하는걸까요? 왓 더 헬이군요. 아시는 분은 답변 좀 부탁드려욤.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;$(ConfigurationName)은 $(Configuration)으로 바뀌었군요. 다른 변화된 매크로들을 보고 싶으신 분들은 아래 페이지를 참고 하시면 도움이 될 것 같아요.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;이전 버전 빌드용 매크로&lt;/strong&gt; &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/c02as0cs(VS.71).aspx&quot;&gt;&lt;strong&gt;http://msdn.microsoft.com/en-us/library/c02as0cs(VS.71).aspx&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;VS 2010 빌드용 매크로&lt;/strong&gt; &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/c02as0cs.aspx&quot;&gt;&lt;strong&gt;http://msdn.microsoft.com/en-us/library/c02as0cs.aspx&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;이상 놀라운 VC++ 2010의 세상이었습니다. 역시 SP1은 나오고 쓰는게 진리일까욤? ㅋㅋ~&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[wchar_t 옵션]]></title><description><![CDATA[Visual C++의 옵션에 보면 wchar_t를 내장 타입으로 지정할지 말지 결정하는 옵션이 있다(C/C++ -> Language…]]></description><link>https://jiniya.net/wp/archives/2585</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2585</guid><pubDate>Fri, 30 Jul 2010 23:56:28 GMT</pubDate><content:encoded>&lt;p&gt;Visual C++의 옵션에 보면 wchar_t를 내장 타입으로 지정할지 말지 결정하는 옵션이 있다(C/C++ -&gt; Language 부분에 있음). 보통 내장타입으로 사용되는데 종종 내장타입으로 사용하지 않는 경우가 있다. 다른 회사에서 … 그럴 때 소스를 제공할 때에 wchar_t를 사용하면 에러가 발생한다. 타입을 별도로 지정해야 한다면 unsigned short로 지정해서 줘야 한다. 근데 또 욱긴건 unsigned short로 지정하면 내장 타입으로 사용하도록 한 경우에 wchar_t랑 호환이 되지 않는다. 한마디로 x같은 상황이 연출된다. 그렇다면 벤더에 소스를 공급해야 하고, 소스에는 wchar_t를 써야 하고, 벤더의 컴파일 옵션과는 상관없이 우아하게 컴파일되게 하고 싶을 때 어떻게 하면 될까?&lt;/p&gt;
&lt;p&gt;음. 여러가지 방법이 있을 수 있겠지만 첫 번째 방법은 __wchar_t 타입을 사용하는 것이다. 이 타입은 해당 옵션에 상관없이 항상 정의된다. 다른 방법으로는 Visual C++ 옵션을 전처리기로 탐지하는 방법이 있다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifdef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;\_NATIVE\_WCHAR\_T\_DEFINED  &lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; wchar\_t mywchar\_t&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;else&lt;/span&gt;  &lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;short&lt;/span&gt; mywchar\_t&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;맞다. 결국 wchar.h를 포함하고 wchar_t를 사용하면 된다. wchar.h를 따라 들어가면 위와 같은 전처리기 문장이 crtdefs.h에 정의되어 있다. 그런데 문제는 그 wchar.h를 특정 네임스페이스에서 인클루드하는 요상한 분들도 계신다는 점이다. 즉, 우리가 만드는 거 외에는 모든 것이 다 존재할 수 없다고 가정하고 작성해야 한다면 저런 코드를 사용하는게 정신 건강에 좋다.&lt;/p&gt;
&lt;p&gt;이 wchar_t 옵션에 관한 자세한 설명은 아래 페이지에 아주 상세히 설명되어 있다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/dh8che7s(VS.71).aspx&quot;&gt;http://msdn.microsoft.com/en-us/library/dh8che7s(VS.71).aspx&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; 3
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[황당하거나, 멍청하거나…]]></title><description><![CDATA[#…]]></description><link>https://jiniya.net/wp/archives/2539</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2539</guid><pubDate>Thu, 29 Jul 2010 23:56:27 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;#0.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF3908.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF3908.jpg&quot; alt=&quot;&quot; title=&quot;DSCF3908&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;집에서 편하게 영화를 즐기던 중, 갑자기 의자가 뒤로 꽈당하고 넘어졌다. 헐킈. 하마터면 뇌진탕으로 골로 갈 뻔 했다. 보니 의자 다리가 저렇게 부러진게 아닌가. 연결 부위도 아니고 저 다리가 부러진게 참 어이가 없다. 더욱이 내가 그닥 무게가 많이 나가지도 않는데 말이다. 그나마 목 받침이 있어서 뇌진탕은 면했다는… 잠시 에어론체어가 좋다는 소리에 혹 했다가 가격을 보고는 G마켓 최저가로 새 의자를 구입했다. 에어론체어는 정말 가격이 토나왔다. 언젠가는 앉아봐야지 ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#1.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/?p=1307&quot;&gt;지난 번에 신나게 RexTech 그래픽 카드를 씹은 적이 있다&lt;/a&gt;. 어떻게 어떻게 설정해서 쓰고 있었는데 ATI 그래픽 카드 드라이버를 업데이트한 다음에는 그것 조차도 여의치가 않았다. 그래서 매번 부팅할 때마다 AMD GPU 클럭 유틸리티로 그래픽 카드 클럭을 고정해서 사용했다. 그러다 오늘 컴터를 켰는데 너무 열받는게 아닌가, 그러다 문득 든 생각. VGA 케이블을 한 번 연결해 보까? (이때까지는 그냥 닥치고 DVI로 사용하고 있었음) 그래서 한 번 연결해 봤는데 아무 문제도 없다. 헐킈… 이 때까지 완번 ㅂㅅ짓 한거구만 ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#2.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;머리를 깎아야지, 깎아야지 마음을 먹고 있었는데 정말 미용실 갈 시간이 없었다. 맨날 늦거나 아니면 약속있거나 이래서 근 2주를 못가다가 오늘 드디어 타이밍을 잡았다. 아무도 없을 미용실을 상상하면서 신나게 집 앞 미용실로 향했다(미용실에서 죽치는 것만큼 시간 아까운 것도 없는 것 같다). 그런데 문 앞에서 좌절을 하고야 말았다. 26일부터 29일까지 휴가란다. 하필 29일까지. 덴장. 가는 날이 장날이라더뉘… ㅠㅠ~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#3.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;베프라 부를만한 고등학교 친구 녀석들이 몇 명 있는데 한 놈이 알 수 없는 번호로 전화했다. 누구세요? 하는데 이 놈이 또 젤 시러하는 ‘누구게?’ 드립을 치는게 아닌가. 한참을 못맞추자 서로 뻘쭘해진 상황. 그러다 이름을 들었는데 헐킈. 그 놈 목소리가 아닌데. 목소리가 너무 부드러워 졌다. 설 때 합창단 한다는 소리는 들었는데. 미안한 마음에 성악해서 목소리가 바낀것 같다면서 그래서 못 알아들었다는 드립을 좀 쳤다. 앨범을 냈다는데 한 장 사줘야 겠다. 10년 넘게 들은 그 목소리를 어떻게 까먹을 수가 있지? 아니 어떻게 목소리가 그렇게 부드럽게 바뀔수가 있지? ㅎㅎ~ 내가 못 알아들은게 아니라 목소리가 바뀐게 확실한 것 같다. 내 생각이지만… ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#4.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;술자리에서 찜질방에서 고삐리들의 삐리리 현장을 목격한 이야기를 하면서 놀고 있었다. 한참을 그 이야기를 하면서 웃고 떠드는데 한 사람이 나보고 보지도 않은 이야기를 실제처럼 말한다면서 태클을 걸었다. 그려려니 하고 넘겼다. 안봤으면 그런 일이 실제하지 않는다고 생각할 수도 있으니깐 말이다. 이번에는 다른 술자리. 비슷한 주제가 올라왔는데 여기 사람들은 그런 걸 안해본 사람도 있냐며, 안해본게 멍청한거 아니냐는 분위기다. 여기서는 그런 거를 한번도 본 적이 없다고 말하는 것도 구라고, 그런 것을 한 번도 해본 적이 없다고 말하는 것은 더구라가 되는 상황이었다. 참 요지경이다. 세상에는 그런 삐리리를 안해본 사람도 엄청 많을 수 있지 않겠는가? 여튼 너무 자신이 본 것, 한 것만 믿지는 말도록 하자. 세상에는 정말 다양한 사람이 있고, 자신이 생각지도 못한 방식으로 살아가는 사람도 많으니깐 말이다.&lt;/p&gt;
&lt;p&gt;개발자들도 이런 경향이 왕왕 있다. 신입 개발자들한테 그렇게 짜면 쪼다된다는 이야기를 해주면, 자기는 그런 경우를 겪지 않았고 코드가 지금도 자기 PC에서 잘 돌아간다면서 절대로 그 말을 믿지 않는다. 꿀밤을 한 백대쯤 쥐어박아야 겨우 고칠까 말까한다. 똥인지 된장인지 겪어 본 것만 믿는다는 것이다. 세상에 그것만큼 멍청한 것도 없다. 똑똑하다면 남의 말도 조금은 귀담아 들을 필요가 있다. 그리고 중요한 것은 오픈 마인드? ㅋㅋ~ 그나저나 혈기 왕성한 나이에, 돈은 없고, 아리따운 여친님은 계시다면 답 딱 나오는거 아닌가? ㅎㅎ~&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;#5.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;#3에 나온 녀석과 다른 녀석 하나가 고등학교 때 맨날 쉬는 시간이면 내 자리로 와서 둘이서 싸웠다. 그 당시 나는 소위 학교에서 스타를 조금 하는 부류에 속했다. 내기를 해서 단 한 번도 져본 적이 없었다. 그 때는 말이다. 지금은 단 한 번도 못 이긴다. 어쨌든 이 놈들은 둘 다 그렇게 잘하지는 않았는데 그 당시에 중수 정도는 되었다. 그런 둘이서 맨날 싸우는 거는 이런 식이었다. “울트라리스크랑 아콘이랑 싸우면 누가 이겨?” 울트라 공격력이 얼마고, 아콘이 얼마고 방어력이 얼마고, 체력이 얼마니깐 뭐가 이긴다는 식으로 상호 반대 입장에서 이야기를 하는 것이었다. 그리고는 나에게 판결을 해달라는 듯이 쳐다보면 나는 항상 뻥찌는 표정을 짓곤 했다. 사실 스타를 하는데 지금도 같은 생각이지만 그 딴 공격력, 1대 1의 상황이 중요한 건 아니니깐 말이다.&lt;/p&gt;
&lt;p&gt;개발자 중에도 요론 사람들이 있다. 소위 아주 사소한 문제에 집착하는 사람들이다. 그런 사람들은 아웃풋은 하나도 없고 책을 읽으면 첫 장을 못 넘긴다는 공통된 특징을 가지고 있다. 아주 사소한 문법, 아주 사소한 설명 하나에 집착해서 이건 이렇고 저건 저렇고 탁상공론을 펼친다. 그러면서 소위 자기가 똑똑하다는 것을 어필하려고 한다. 하지만 그런 사람치고 제대로된 개발을 하는 사람을 본 적이 없다. 개발에 있어서 그들이 집착하는 그런 사소한 것들은 앞서 내 친구들이 집착했던 공격력과 하나도 다를 바가 없기 때문이다. 좋은 개발을 하려면 그런 게 아니라 전체적인 구조를 이해하고 그것을 구성하는 것에 몰입하는 것이 훨씬 더 좋은 방법이다. 더 안타까운 사실은 그렇게 사소한 것에 집착하는 사람치고 그 사소한 것을 제대로 알고 있는 사람도 거의 없다는 점이다. 우주인 아키텍터와 더불어 이런 개발자는 제거 0순위다. 사소한 것에 집착하지 말자. 큰 그림을 그리는 것이 중요하다.&lt;/p&gt;
&lt;p&gt;그리고 시작하는 사람들을 위해서 잠깐 조언을 하나 하면 그냥 이해가 되지 않아도 끝까지 쭉 가보는 것이 좋다는 사실이다. 끝을 보면 앞에서 이해가 되지 않았던 부분도 자연스럽게 하나의 고리로 연결되기 때문이다. 이렇게 두세번 보는 게 좋지 한장을 가지고 하나도 남김없이 다 이해하고 넘어가겠다고 생각하는 것은 참 나쁜 습관이다.&lt;/p&gt;
&lt;p&gt;비슷한 풍경이 오락실에서도 흔히 벌어지는데 오락실에서 연결을 하지 않고 항상 1차부터 시작하는 녀석들이 있다. 그런 놈치고 끝판을 보는 녀석은 거의 없다. 과감하게 연결해서 그 상황을 이겨내고 다음 거를 봐야 자연스럽게 실력이 조아진다. 연결안하고 처음부터 하는 사람들의 공통된 특징은 딱 첫 판까지만 잘한다는 거다. 물론 1000명 중에 한 두명씩 한번에 끝판을 깨는 기염을 토하는 신들린 아이들이 있기는 하다.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[소리통 2010.7.28.313]]></title><description><![CDATA[초간단 MP…]]></description><link>https://jiniya.net/wp/archives/2487</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2487</guid><pubDate>Wed, 28 Jul 2010 23:56:26 GMT</pubDate><content:encoded>&lt;p&gt;초간단 MP3 플레이어, &lt;a href=&quot;http://www.jiniya.net/tt/tag/%EC%86%8C%EB%A6%AC%ED%86%B5&quot;&gt;소리통&lt;/a&gt;이 업데이트 되었습니다. 꼭 원고 쓸 때나 다른 할 일이 있을 때면 이상한 데 정신이 팔리게 마련이죠. 시험 기간에 안보던 소설책이 재밌어 지고 그런 삘이랄까요? 여튼 지난 주에 켜켜이 낡은 노트북에서 소스 코드를 찾아서 다시 컴파일이 되게 만들었습니다. 집에 컴퓨터가 거의 동영상 플레이어로만 쓰다 보니 조금 아깝드라고욤. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;제가 마지막으로 작업하던 당시 버전이 2007.11.8.293이더군요. 근 3년 지났네요. 코드가 새삼스럽습니다. ㅎㅎ~ 아직도 버그가 많지만 알려주시면 수정할 때 최대한 고치도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;사용해 보고 싶으신 분들은&lt;/strong&gt; &lt;a href=&quot;http://www.jiniya.net/files/soritong/soritong.2010.7.28.313.zip&quot;&gt;&lt;strong&gt;여기서 파일을 다운로드&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;하시면 됩니다.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;변경 내용&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;각종 잡다한 버그 수정&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;mms 스트림 재생 기능 추가 (윈미플이 설치되어 있어야 합니다.)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;audio/x-mpegurl 인식 기능 추가&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;일부 pls url이 재생이 되지 않던 문제 수정&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/s3.png&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/s3.png&quot; alt=&quot;&quot; title=&quot;s3&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;미플 처럼 포커스를 잃게 되면 프레임이 없어지는 기능이 추가되었습니다.&lt;/p&gt;
&lt;p&gt;항상 위로 띄어놓고 있으면 좀 더 작은 크기를 차지합니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/s2.png&quot; alt=&quot;&quot; title=&quot;s2&quot;&gt;&lt;/p&gt;
&lt;p&gt;앨범 기능이 추가되었습니다. 머 앨범마다 이름 붙이고 이런 복잡한 기능은 없구요.&lt;/p&gt;
&lt;p&gt;그냥 10개 앨범이 있습니다. 앨범마다 목록을 별도로 저장할 수 있습니다.&lt;/p&gt;
&lt;p&gt;빨간 저 부분에 현재 보고 있는 앨범 번호가 나옵니다.&lt;/p&gt;
&lt;p&gt;앨범 이동은 어떻게 하느냐구요? 0-9 숫자 키로 이동하시면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/s1.png&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/s1.png&quot; alt=&quot;&quot; title=&quot;s1&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;음악방송과 라디오를 들을 수 있는 추가 되었습니다.&lt;/p&gt;
&lt;p&gt;메뉴에서 음악방송/라디오 듣기를 선택하시면 됩니다.&lt;/p&gt;
&lt;p&gt;메뉴 골르면 위와 같은 대화상자가 뜹니다. 선택해서 들으시면 됩니다. &lt;/p&gt;
&lt;p&gt;주소 모르시는 분들에게 도움이 될 것 같네욤.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;덧) 컬투쑈는 여전히 진짜 너무 욱기네요….&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[콜로세움 3종 세트, 닥치고 크다.]]></title><description><![CDATA[DSCF3192  콜로세움 안에서. 저기서 구경했던 그 많은 로마인들의 기운이 느껴지는 것 같기도 하다. 6.2…]]></description><link>https://jiniya.net/wp/archives/2439</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2439</guid><pubDate>Sat, 24 Jul 2010 23:56:25 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4822697547/&quot; title=&quot;DSCF3192&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4141/4822697547_f1b1d1a1a5_b.jpg&quot; alt=&quot;DSCF3192&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;콜로세움 안에서. 저기서 구경했던 그 많은 로마인들의 기운이 느껴지는 것 같기도 하다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;6.24&lt;/p&gt;
&lt;p&gt;로마의 이튿날이 밝았다. 라스베가스 보이는 떠났다. 킴은 공항의 항공편 상태를 알아보러 나갔다. 나는 씻었다. 나탈리는 열차 티켓을 가지고 고민한다. 나는 아침을 언제 먹을지 고민한다. 나탈리에게 물으니 아침이 포함되어 있지 않다고 한다. 분명 방 티켓을 끊을 때는 포함이라고 들은 것 같은데. 쉣꿀이네. 37.5유로에 이뭐병… ㅠㅠ&lt;/p&gt;
&lt;p&gt;&lt;em&gt;이제 여행도 막바지다. 그러다보니 슬슬 기운도 빠지게 마련이다. 무엇을 느꼈는지 돌아본다. 그저 기념물 앞에서 인증샷 찍기에 바쁜 여행은 아니었나 하는 반성도 해본다. 앞으로 10년 무엇을 하며 살지에 대한 진지한 고민은 못해본 것 같아 많이 아쉽다. 어쩌면 애초에 이번 여행은 그런 것과는 거리가 먼 것이었는지도 모르겠다. 이제 3일 밤이 남았다. 돌아가면 다시 모든 것이 현실이 되겠지. 휴~ 오래 쉰만큼 휴유증도 클 것 같은 걱정이 벌써 앞선다. 무엇을 생각했는지, 무엇을 느꼈는지가 없다. 현실로 돌아가는 게 싫은 건지도 모르겠다. 이건 뭐 refresh가 아니라 refree인듯한 느낌이. 가장 무서운 사실은 어쩌면 내가 방향을 잃었을지도 모른다는 점이다.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;P가 킴과 함께 들어왔다. 밥 안먹냐고 물어본다. 인제 인나서 씻고 있었다고 말하고 공짜냐고 물어봤다. 그렇단다. 나탈리 멍미?… 내려가서 밥을 먹었다. 밥먹고 밖으로 나갔다. 일단 메트로 일일권을 끊었다(4유로). 그러고는 P 계획대로 치르코 마시오로 향했다. 예전에 대전차 경기장으로 사용된 곳이라고 했다. 그런데 지금 느낌은 그냥 횡한 운동장이었다.&lt;/p&gt;
&lt;p&gt;진실의 입 쪽으로 걸어갔다. 햇살이 너무 강했다. 진실의 입에는 사람들이 사진을 찍으려고 줄을 서 있었다. 진실의 입에서 인증샷을 찍고 성당 안을 구경했다. 그냥 성당이었다. 나와서 치르코마시오 쪽으로 다시 걸어갔다. 햇살이 너무 강해서 사진 찍기도 빡쎘다. 중간에 그늘에 누워서 좀 쉬었다.&lt;/p&gt;
&lt;p&gt;P가 다시 일정을 확인했다. 여기갈까 저기갈까 자꾸 묻기에 걍 콜로세움이나 가자고 했다. 걸어서 콜로세움까지 갔다. 중간에 목이 말라서 물을 2유로에 사서 마셨다. 콜로세움 줄은 제법 길었다. 12유로를 내고 입장했다. 내부는 외부보다는 좀 더 감동스러웠다. 크다. 오래됐다는 생각이 들었다. 너무 컸다. 구경하고 나와서 밥을 먹었다. 떼르미니 가서 먹으려다 그냥 앞에 노점상에서 핫도그와 콜라를 사먹었다(9유로). 핫도그는 먹을만 했다. P는 피자를 먹었는데 맛이 없다고 했다. 그늘이 없어 먹기가 지랄맞았다.&lt;/p&gt;
&lt;p&gt;먹고나서는 필라티노 언덕으로 갔다. 출구는 입장 불가로 막혀 있어서 옆길로 올라갔다. 그리로도 갈 수 있을 줄 알았다. 언덕을 한참 올라가니 작은 성당이 하나 있다. 뭔가 대단한 건줄 알고 가보니 산프란체스코 성당이다. 들어가니 조용한 음악이 나오고 있었다. 그래서 그런지 분위기가 매우 엄숙하게 느껴졌다. 근데 결국 아무것도 아니었다. 다시 내려와서 먼길을 걸어 필라티노 입구로 향했다. 제법 멀었다. 입구로 들어와서 화장실을 갔다. 왼쪽은 필라티노, 오른쪽은 포로 로마노였다.&lt;/p&gt;
&lt;p&gt;일단 필라티노로 갔다. 언덕으로 올라가면서 사진을 찍었다. 계속 돌아보는데 정말 말도 안되게 컸다. 결국 아우구스투스 집까지 보고 모든걸 포기하고 포로 로마노로 향했다. 날도 더운데 그늘도 없어 정말 구경하기 힘들었다. 몸이 힘드니 마음도 힘들었다. 포로 로마노는 정말 그냥 인증샷 찍듯이 구경만하고 나왔다. 그나마 인증샷도 찍기가 힘들어 걍 멋대로 찍었다. 사진 찍는 것도 일이란 사실을 새삼 느꼈다. 이렇게 개념없이 구경했는데도 12시에 입장해서 6시에 나왔다. 너무 힘들어 집으로 와서 씻고 밥을 먹었다. P가 싸온 햇반, 신라면, 카레, 짜장, 고추장, 김으로 주방에서 만찬을 즐겼다. 정말 맛있었다. 먹고는 떼르미니 역으로 가서 수박과 자두를 사먹었다. 쩔었다. 힘들어 둘 다 집에와서 쉬다가 10시에 다시 나왔다.&lt;/p&gt;
&lt;p&gt;스페인 광장으로 향했다. 역에 내려서 또 사람들 안가는대로 가서 개병신됐다. 공항 트레일같이 엄청 긴 걸 한 세네개 탔는데 밖으로 나가니 고속도로였다. 헐킈. 다시 원점으로 와서 사람들 많이 가는 곳으로 따라갔다. 자연스럽게 스페인 계단이 나왔다. 그런데 그저 그랬다. 야경이 쩐다고 했는데 구라였다. 인증샷 찍고 계단 끝에서 엘리베이터 타고 돌아왔다. 스페인 계단에 앉아서 맥주나 한 잔 할라고 찾아봤는데 진짜 아무거도 없었다. 3미터에 하나씩 편의점이 있는 우리나라는 정말 축복받은 세상이다.&lt;/p&gt;
&lt;p&gt;나탈리 가는 날이라 맥주나 같이 마실겸 오는 길에 CONAD에 들려서 맥주를 네 병 샀다. 그런데 들어오니 둘 다 뻗어서 쿨쿨 자고 있다. 그래서 나가서 먹으려고 손씻고 나왔다. 아참 들오는 길에 공용 통장에서 180유로를 찾아 90유로씩 나눴다. 일단 숙박을 연장하기위해 리셉션으로 갔다. P에게 도와 달라고 징징거리던 여자 아이가 다른 한국 남자와 베드 버그로 싸우고 있었다. 그러다 우연찮게 인사를 하게 되서 넷이서 같이 맥주를 마셨다.&lt;/p&gt;
&lt;p&gt;남자는 전공이 컴공이라고 했다. 헐. 졸업하고 취직하기 전에 마지막 여행을 하는 거라고 한다. 어디 취직했냐고 묻자 가산디지털 단지에 있는 LG전자라고 한다. 난 구로디지털단지에서 일한다고 반갑다고 했다. 친한 학교 선배가 그 LG전자에 다닌지가 오래되었다는 이야기를 했다. 세상 참 좁다는 생각이 들었다. 여자 아이는 취직이 안되서 유럽으로 나온 거라고 했다. 4월에 출국했는데 지금까지 여행하고 있다는 이야기에 깜짝 놀랐다. 자기는 산전수전 다 겪었다면서 한국으로 돌아가면 모든 걸 다 용서할 수 있을 거라는 이야기를 했다. 그리스 폭동 때 사람들 죽는 걸 옆에서 보았다고 했다. 온갖 유럽 사태를 몸소 체험했다면서 푸념을 늘어놓았다. 좀 안되보여서 나는 유레일 분실 드립을 좀 쳐줬다. 그러니 사연 없는 사람이 없다며 너스레를 떤다. 그렇게 늦게까지 술마시고 이야기하며 놀다가 올라와서 잤다. 정말 피곤에 쩔은 하루였다. 자기 전에 P에게 말했다. 내일은 도저히 바티칸 투어를 못할 것 같다고, 모레 가자고. P는 한국 축구 응원을 하고 싶어서 내일 바티칸, 모레 응원을 하고 싶은 눈친데 양보해 주었다. 정말 피곤했다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[로마 입성]]></title><description><![CDATA[DSCF2964 로마로 가는 기차 안에서,.. 정말 좋았다… 토나오게… 6.23 호스텔 아이들이 부스럭거리는 소리에 일어났다. 9시 체크아웃의 압박. 아이들이 씻는 동안 눈을 좀 더 붙였다. 8시 3…]]></description><link>https://jiniya.net/wp/archives/2365</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2365</guid><pubDate>Sat, 24 Jul 2010 23:56:24 GMT</pubDate><content:encoded>&lt;p&gt; &lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4823244386/&quot; title=&quot;DSCF2964&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4080/4823244386_a2a880c9d2_b.jpg&quot; alt=&quot;DSCF2964&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;로마로 가는 기차 안에서,.. 정말 좋았다… 토나오게…&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;6.23&lt;/p&gt;
&lt;p&gt;호스텔 아이들이 부스럭거리는 소리에 일어났다. 9시 체크아웃의 압박. 아이들이 씻는 동안 눈을 좀 더 붙였다. 8시 30분쯤이 되서야 침대에서 내려왔다. 잽싸게 씻고는 짐을 정리했다. 나가던 아이들이 들어오더니 어디서 왔냐고 묻는다. 한국에서 왔다고 하고는 체크아웃하고 나왔다. Brek에 아침을 먹으로 들렀다. 빵 두개를 샀다. 유럽에서 먹은 빵 중에 제일 맛있었다. 유럽에도 부드러운 빵이 있다는 사실에 감동했다. 먹고나도 기차 시간이 좀 있어서 밀렸던 여행 일지를 썼다. 밀렸던 이틀치를 다 쓰고는 역으로 향했다. 베니스를 떠난다는 사실이 못내 아쉽다.&lt;/p&gt;
&lt;p&gt;역에 도착해서는 깜짝 놀랬다. 히밤 티켓이 없는 것이 아닌가. 할 수 없이 다음 시간 티켓을 끊었다. 그러다 한번 더 놀란다. 핡 73유로. 이뭐병. 그래서 그 다음 느린 열차를 보니 43유로다. 한 30유로 차이. 시간이 돈이라는 생각에 대인배스럽게 빠른 열차표를 끊었다. 이로써 유레일을 잃어서 거짐 그 만큼의 돈을 까먹게 되었다. 굳. 그래도 그 덕에 얻는 2등석의 경험과 베니스의 하루는 좋았다. ㅋ~&lt;/p&gt;
&lt;p&gt;로마 오는 시간은 오래 걸리지는 않았다. 11시 열찬데, 3시 정도에 도착했다. 오는 길에 앞에 덩치 큰 놈이 앉은거 빼고는 괜찮았다. 그런데 3시간도 무척이나 지겹게 느껴졌다. 음악을 듣다, 자다, 로마 공부하다, 그러다가 도착했다. 떼르미니역. P와 만나기로한 맥도날드 위치를 확인하고는 숙소를 찾았다. 묵으려고 한 호스텔이 지도와 동일한 곳에 있었는데 입구가 달라 조금 애를 먹었다. 25유로 방을 포함한 싼 방은 하나도 없고, 37.5유로가 젤 싼 방이었다. 다른 곳 알아보기도 귀찮아서 그냥 2틀만 끊었다. 근데 결제를 하려니 현금만 된단다. 헐킈. 숙박비 75유로, 열쇄 보증금 10유로 주고나니 75유로 남는다. 방으로 올라갔다. 37.5유로 스럽게 방은 어제보다 훨씬 좋다. 베드가 4개 밖에 없고 공간도 제법 넓었다. 샤워 시설도 쓸만했다.&lt;/p&gt;
&lt;p&gt;짐풀고 나왔다. 맥으로 가서 밥을 먹었다. 맥치킨레전드 세트를 시켰다. 레전드는 개뿔. 7.5유로로 그냥 배만 채웠다. 먹고 있으니 맞은 편에 자체 발광하는 생명체가 접근해온다. 맥치킨 마요네즈가 한참을 손에 묻도록 쳐다보고 있었다. 고상하게 컴퓨터를 꺼낸다. 지구 생명체가 맞는지 하는 의심이 드는 순간 자리를 옮겨, 옮기더니 이제는 내 자리에서 노트북 화면이 보이는 곳으로 이동했다. 한글 윈도 비스타 핡~ X-note 핡. 무선랜을 잡는데 잘 안되나 보다. 하다가 안되니 재부팅을 한다. ㅋㅋ~ 가서 고상하게 컴퓨터의 무선랜을 잡아주려다가 말았다. 어쨌든 아웃스탠딩했다.&lt;/p&gt;
&lt;p&gt;나가 돌아뎅기기엔 시간이 애매하고(17:00) 덥기도해서 숙소를 와서 샤워를 하고 누워서 사진 찍은걸 보고 있었다. 조금 있으니 문소리가 나더니 나탈리가 들어온다. 아르헨티나에서 왔다고 한다. 자기가 로마를 잘 안다면 다 물어보라고 한다. 안다고 하는데도 콜로세움을 가려면 뭘타고 어디서 내리면 되는지를 설명한다. 참고로 로마는 메트로가 고작 2개다. 몇 일 있었냐니 일욜부터 있었다고 한다. 다음으로는 베니스를 간다는 말에 내가 오늘 거기서 왔다고 했다. 놀라면서 막 이것 저것 묻는다. 그냥 쉽다고 알려줬다. 싼말코를 어떻게 가는지, 진짜 미로 같은지 물어본다. 헬이라고 말해줬더니 그럴줄 알았다는 표정을 짓는다. 그러다 생각나서 거금 2유로 짜리 베니스 지도를 선물로 줬다. 좋아라 한다. 저녁에 콜로세움을 간다고 같이 가자고 했다. 그러자고했다.&lt;/p&gt;
&lt;p&gt;나탈리가 샤워하러 들어간 사이 또 한 명의 여자가 들어온다. 킴벌리. 옆 침대가 비었냐는 질문에 사람이 있는 것 같다는 표정을 지어 보이자 2층 침대로 간다. 캐나다 벤쿠버에서 왔다는 말에 10년 전에 그 곳을 가보았다는 이야기를 해주었다. 스탠리 파크가 좋았다고. 킴은 내일 파리로 간다고 했다.&lt;/p&gt;
&lt;p&gt;나탈리에게 P가 오면 같이 콜로세움을 가자고 하고는 P를 만나러 다시 떼르미니 역으로 왔다. 녀석이 제 때 와야 할텐데 걱정이다. 피사의 사탑은 잘 갔다 왔을지… 19:41 이번이나 다음 열차에 제발 타고 있어라. 이건 완죤 물가에 애를 내려놓은 느낌이구만…&lt;/p&gt;
&lt;p&gt;맥도날드 앞으로 P가 왔다. 내가 엄한데서 찾고 있었나보다. 하루만에 보는데도 제법 반갑다. P를 데리고 호스텔로 향했다. 호스텔에 와서 돈계산을 하고 방을 배정 받아서 이동했다. 방을 배정받고 있는데 나탈리가와서 옆에 Bar에 가 있을테니 준비되면 그리로 오라고 했다. 그러겠다고 하고는 P 방으로 올라가서 짐을 풀고 옷을 갈아입고 나왔다.&lt;/p&gt;
&lt;p&gt;일단 P가 돈을 찾아서 나한테 주었다. 그리고는 옆에 Bar로 향했다. 나탈리와 킴이 다른 남자 둘과 밥을 먹고 있다. 우리고 옆에 테이블을 붙이고 앉았다. 맥주, 피자를 시켰다. 나중에 돈계산을 나탈리가 다하고 N빵을 했다. 이뭐병. 한 6유로 더썼다. 그리고는 나탈리와 킴벌리랑 콜로세움을 갔다. 야경찍고 걸어다니면서 놀았다. 그리고는 환타 하날 먹고 집으로 들어왔다. 샤워하고 아이팟 충전기를 빌리러 P에게 갔다. P 혼자 뻘쭘하게 2층에 앉아있다. 빌려서 방에다 충전 시키고는 P를 구출하러 다시 갔다. 애들 때문에 못 씻고 있다고 했다. 내가 있을테니 씻고 오라고 했다. 앉아 있으니 애들이 어디서 왔냐고 묻는다. 한국에서 왔다고 하자 한 명이 몇 해 전에 부산을 가봤다고 한다. 부산에서 태어났다는 말과 함께 와인을 한 잔 얻어 마시게 되었다. 좀 있으니 P가 씻고 온다. 간단한 통성명 외에는 애들 대화에 끼어들 틈이 없다. 대충 무슨 말을 하는지는 알겠는데 — 깔때기이론은 전 세계에서 통한다는 사실을 알게 되었다. — 말을 하기가 쉽지 않았다. 적당히 P도 분위기에 적응한 것 같아서 두고는 방으로 돌아왔다. 킴벌리가 파리 공항 파업으로 재수 없으면 하루 더 있어야 할 수도 있다고 한다. 자야겠다…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[라우터부넨, 슈타우프바흐 폭포]]></title><description><![CDATA[DSCF1733 기차타고 라우터부넨으로 가다보면 요롷게 폭포가 보입니다. 슈타우프바흐 폭포예욤. 라우터부넨에서 걸어갈만한 거리에 있답니다. 유럽에서 두 번째로 큰 낙차폭을 자랑한다고 합니다. SG10761…]]></description><link>https://jiniya.net/wp/archives/1953</link><guid isPermaLink="false">https://jiniya.net/wp/archives/1953</guid><pubDate>Sat, 24 Jul 2010 23:56:23 GMT</pubDate><content:encoded>&lt;p&gt; &lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4756786871/&quot; title=&quot;DSCF1733&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4095/4756786871_d89fd461af_b.jpg&quot; alt=&quot;DSCF1733&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;기차타고 라우터부넨으로 가다보면 요롷게 폭포가 보입니다.&lt;/p&gt;
&lt;p&gt;슈타우프바흐 폭포예욤. 라우터부넨에서 걸어갈만한 거리에 있답니다.&lt;/p&gt;
&lt;p&gt;유럽에서 두 번째로 큰 낙차폭을 자랑한다고 합니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4822578629/&quot; title=&quot;SG107614&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4094/4822578629_aa5c17e97e_b.jpg&quot; alt=&quot;SG107614&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;라우터부넨에 내려서 역을 나오면 이렇습니다. 뒤로 보이는 폭포로 갈꺼예욤.&lt;/p&gt;
&lt;p&gt;길을 가르쳐줬던 안내원 말에 의하면 1km 정도라는데 생각보다 멀답니다.&lt;/p&gt;
&lt;p&gt;가따와따 한시간 넘게 걸리는 것 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1787.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1787&quot;&gt;&lt;/p&gt;
&lt;p&gt;쭉 걸어가다보면 이렇게 공동묘지가 나와요.&lt;/p&gt;
&lt;p&gt;여기가 보이면 거의 다 왔다는 겁니다.&lt;/p&gt;
&lt;p&gt;비석들이 그들이 살다간 인생처럼 다양한게 참 인상적이었어요.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1786.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1786.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1786&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;반대편을 바라보면 이렇게 폭포로 올라가는 길이 있어요.&lt;/p&gt;
&lt;p&gt;밑에서 사진찍고 가지말고 꼭 올라가 보세요.&lt;/p&gt;
&lt;p&gt;올라가는 길이 초큼 빡쎄긴 합니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4822578603/&quot; title=&quot;SG107653&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4134/4822578603_50acc4184a_b.jpg&quot; alt=&quot;SG107653&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;중간 정도에서 인증. ㅎㅎ~&lt;/p&gt;
&lt;p&gt;폭포가 점점 다가오죠. ~&lt;/p&gt;
&lt;p&gt;폭포 올라가는 마지막 길은 초큼 빡쎄욤.&lt;/p&gt;
&lt;p&gt;비도 오고 우산 들고 올라가면서 디카로 찍기가 쉽지는 않았습니다. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;근데 멍청하게 동영상을 별로 안찍어바서 세워서 찍는 바람에 쪼다됐네욤 ㅠㅠ~&lt;/p&gt;
&lt;p&gt;폭포 정상에 올라가면 이렇게 되어 있어요.&lt;/p&gt;
&lt;p&gt;폭포가 떨어지는 안쪽에서 바깥쪽을 바라볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1772.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1772.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1772&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;그렇게 높진 않지만 그래도 끝까지 들어가서 밖을 보고 있으면 나름 뿌듯해욤.&lt;/p&gt;
&lt;p&gt;폭포에, 빗물에, 흠~ 그냥 물바다죠.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF17681.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF17681.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1768&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;물에, 구름에, 장관입니다.&lt;/p&gt;
&lt;p&gt;멋있어요.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4822578567/&quot; title=&quot;SG107631&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4119/4822578567_d6bb5e804a_b.jpg&quot; alt=&quot;SG107631&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;멍때리기.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4822707653/&quot; title=&quot;DSCF1756&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4143/4822707653_b859c8c290_b.jpg&quot; alt=&quot;DSCF1756&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;라우터부넨을 들렸다면 슈타우프바흐 폭포 정도는 꼭 가보도록 합시다.&lt;/p&gt;
&lt;p&gt;폭포 인증. 끝.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[비를 맞다.]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/2126</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2126</guid><pubDate>Tue, 20 Jul 2010 23:56:22 GMT</pubDate><content:encoded>&lt;p&gt;집을 나서는데 날씨가 꾸리꾸리한게 그렇드라고, 우산을 챙길까 말까 고민을 좀 했어. 그러다 그냥 나갔어. 까지꺼 와봤자 얼마나 오겠어 하는 생각으로 말이야. 지하철을 타고 한 시간 쯤 갔을까, 역을 나오니 비가 부슬부슬 내리기 시작하드라고. 편의점에서 우산을 살까 잠시 망설이다가 그냥 맞으면서 걷기로 했어. 아직은 비가 그리 많이 내리지는 않았거든…&lt;/p&gt;
&lt;p&gt;병원에 도착해서 예약 접수증을 제출하고는 기다리는 동안 혈압도 재고, 몸무게도 달고, 키도 재보고 그러고 놀았어. 그런데 당췌 이놈의 혈압이 떨어지질 않는거야. 보통 3-4번 재면 그래도 한 번쯤은 정상으로 나오기 마련인데 독으로 안떨어지드라고. 그러다 의사 선생님을 만나게 되었지. CT 보는게 불안불안 하드라. 그러다가 던지는 말, 그리고 이어진 통화, 그리고 전해온 더 놀라운 소식.&lt;/p&gt;
&lt;p&gt;예약을 하고는 병원을 나섰어. 비가 아직 총총 오고 있드라고. 이번에는 고민도 하지 않고 역으로 걸었어. 고민을 할 상황이 아니었거든. 역으로 가는데 갑자기 비가 미친듯이 내리기 시작했어. 그런데 비를 맞는지도 모르고 뛰지도 않고는 그 비를 다 맞고 그냥 걸었어. 물에 빠진 생쥐 꼴로 그 비를 홀딱 다 맞은거지. 약국에 들어가니 아줌마가 미친놈 보듯이 쳐다 보드라고. 내가 봐도 재정신인 상태는 아니었어.&lt;/p&gt;
&lt;p&gt;다시 한 시간을 걸려서 집으로 왔어. 여름이라 그런지 옷은 생각보다 금방 마르더라. 디지털단지역에 내리니 그쳤다고 생각했던 비가 이제는 정말 홍수라도 날 것처럼 세차게 내리고 있는게 아니겠어. 너무 어이가 없었어. 출구로 나가면서 한참을 고민했지. 이거 지금이라도 우산을 사야할까? 그러다 미친척하고 비를 맞기로 결심했어. 그냥 오기로 끝까지 우산을 사지 않을 참이었거든. 정말 많이 내렸어. 비가. 하늘에 구멍이라도 뚫린 것처럼 비가 쏟아지는데 그걸 다 맞고 있으니깐 내 마음에도 그만한 크기의 구멍이 뚫릴 것만 같았어. 아니면 내 마음에 뚫린 구멍으로 그 많은 비가 내리고 있는건 아닐까, 라는 생각도 들었어. 그렇게 굵은 빗방울로 매섭게 떨어지는 비를 한참을 맞고 나니깐 비를 맞는다는 표현을 왜 쓰는지를 알 것 같은 느낌이었어.&lt;/p&gt;
&lt;p&gt;알아. 언젠가는 이 비도 그친다는 걸. 그리고 쨍쨍하게 맑은 날이 올거라는 사실도. 그런데 조금 무서운 건 그 시리도록 화창한 날이 올 때 까지 내가 비를 좀 더 맞아야 할지도 모른다는 사실이야. 지금보다 더 큰 비를 맞아야 할지도 모른다는 생각에 눈물이 나더라. 산전수전 다 겪었다고 생각했던 건 가장 큰 착각이었어. 난 그냥 온실 속에서 잘 관리된 화초에 불과했거든. 오늘을 잊지 못할것 같아.&lt;/p&gt;
&lt;p&gt;2010.07.16&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;덧) 물어보시는 분이 좀 계셔서 올립니다. 제가 아픈건 아니구요. 제가 검진을 받은 것도 아니구, 엄마 대신 병원에 소견을 들으러 간 겁니다. 걱정할 만큼 심각한 일이 있는건 아니구요. 그냥 비맞고 감상에 취해서 몇 자 끄적여 본 거예욤… 낚시하려는 생각은 아니었는데 은근 물어보시는 분들이 많네욤… 죄송합니다… ^^;;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[“Visual C++ 파워풀 개발 테크닉” 세미나 발표자료]]></title><description><![CDATA[지난 주 토요일에 있었던 “Visual C++ 파워풀 개발 테크닉” 세미나 발표 자료입니다. 비가 와서 많이 안오실 줄 알았는데 정말 많이 오셨더군요. 헐킈. 발표 자료는 CRT…]]></description><link>https://jiniya.net/wp/archives/2373</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2373</guid><pubDate>Tue, 20 Jul 2010 23:56:21 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/crt1.png&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/crt1.png&quot; alt=&quot;&quot; title=&quot;crt&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;지난 주 토요일에 있었던 “Visual C++ 파워풀 개발 테크닉” 세미나 발표 자료입니다. 비가 와서 많이 안오실 줄 알았는데 정말 많이 오셨더군요. 헐킈. 발표 자료는 CRT 관련 내용이구요. 세미나 때 시간 관계상 다루지 못했던 부분에 대한 자료도 추가되어 있습니다. 보시는데 참고하라고 발표 때 사용했던 잉크는 그대로 유지해 두었습니다.&lt;/p&gt;
&lt;p&gt;같은 주제로 다음 달 마소 기사가 연재될 계획이니깐, 혹시 관심 있으신 분들은 해당 기사도 챙겨 보시면 이해하시는데 도움이 많이 될 것 같네요. (그나저나 원고를 빨리 써야 하는데 큰 일 이군요… ㅠㅠ~)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/files/crt.pptx&quot;&gt;발표자료 다운받기&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[아드리아해, 그리고 부라노]]></title><description><![CDATA[DSCF2554 아드리아해. 누워서 하늘을 바라보던 그 때 기분을 잊을 수가 없다. 6.22 또 베네치아의 하루가 밝았다. P가 피렌체로 가는 날이다. 씻고 정리하고 10시쯤 나왔다. P…]]></description><link>https://jiniya.net/wp/archives/2264</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2264</guid><pubDate>Sun, 18 Jul 2010 23:56:20 GMT</pubDate><content:encoded>&lt;p&gt; &lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4804389545/&quot; title=&quot;DSCF2554&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4096/4804389545_0acb406903_b.jpg&quot; alt=&quot;DSCF2554&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;아드리아해. 누워서 하늘을 바라보던 그 때 기분을 잊을 수가 없다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;6.22&lt;/p&gt;
&lt;p&gt;또 베네치아의 하루가 밝았다. P가 피렌체로 가는 날이다. 씻고 정리하고 10시쯤 나왔다. P는 역으로 나는 첫날 간 호스텔로 향했다. 방이 있냐고 물으니 하루 자는 건 있다고 했다. 23유로에 묵기로 했다. 결제하고 다시 호텔로 왔다. 짐 정리를 하고 나갈 채비를 한다. 11시에 맞춰 체크아웃을 하고 호스텔로 향했다. 아줌마가 아직 준비가 덜 됐다고 좀 기다리라고 한다. 12시쯤 방을 안내 받고 짐을 풀고 리도로 향했다.&lt;/p&gt;
&lt;p&gt;리알토에서 리도행 2번 배를 탔다. 날씨는 정말 쩔었다. 해수욕하기에 좋은 날씨였다. 지중해에 몸을 담을걸 생각하며 배를 탔다. 맑은 날의 베니스는 또 다른 느낌이었다. 물살을 가르고 한참을 가서야 리도에 도착했다. 여긴 베니스와는 사뭇 다른 분위기였다. 휴양지삘이 강했다. 해수욕장으로 향했다. 쭉 직선으로 걸어가면 나온다. 그리 멀진 않다. 해수욕장에 도착해서는 일단 주위를 한번 둘러 보았다. 음. 머랄까 우리나라 동해와는 조금 달라 보인다. 동해 + 서해의 느낌이랄까? 여기저기 탑오프 하시고 일광욕을 즐기시는 분들이 보였다. 둘러 보고는 해수욕을 즐기기 위해 락커룸을 찾았다. safety-box가 있다는 곳으로 가 안내원에게 물으니 safety-box가 없다는 대답만 한다. 고민에 휩싸였다. 복대(여권+현금), 가방(현금+카드+etc …)를 어떡할 것인가? 게다가 생각해보니 수건을 챙겨오지 않았다. 이래저래 고민됐다. 다시 해변으로 가서 무릎까지만 들어가봤다. 깊지도 않고 물은 따땄했다. 어쩌지하고 고민하다 그냥 생각없이 지르기로 했다. 1유로 내고 탈의실로가서 수영복으로 갈아입고 가방과 조리는 해변가에 던져놓고 입수했다. 좋다. 지중해에 몸을 담근 느낌. 바다가 근데 정말 무지 얕았다. 한참을 들어가도 허리밖에 오지 않았다. 땅짚고 헤엄치는 기분이 이런걸까? 한참 물속에 놀다 가방이 신경쓰여 다시 나왔다. 가방 옆에 앉아 지평선 끝자락을 보고 있으니 정말 행복하다. 발으로 오는 바닷물이 따뜻한게 기분이 좋다. 염분이 별로 없었다. 그대로 누워서 하늘을 보니 정말 예술이다. 바로 잠들었다. 30분쯤 지났을까? 가방 생각에 일어나보니 그대로 있었다. 다시 입수해서 한참을 놀다나와 씻고(1유로), 탈의실(1유로)내고 리도 역으로 왔다. 정말 행복한 3시간 이었다. 리도에서 로마 광장으로 와서 내리고 거기서 무라노행 42번을 타고 무라노로 향했다.&lt;/p&gt;
&lt;p&gt;6시. 무라노에 내려서 섬 여기 저기를 구경했다. 유리로 유명한 곳 답게 여기저기 유리로 만든 것들이었다. 그런데 너무 늦게 가서 그런지 모두 문을 닫고 없었다. 섬 전체가 마치 유령섬처럼 느껴졌다. coop이 있길래 들어가 봤더니 사람들이 있긴 했다. 다이제스트같은 과자를 하나 샀다. 나머지를 둘러 보고는 Faro 선착장 등대 옆에서 바다를 보고 있었다. 그냥 한가롭다. 돌아가는 배를 타려고 했는데 실수로 부라노행 배를 탔다. 실수지만 정말 행운이었다. 부라노는 베네치아 본 섬. 무라노와는 달리 진짜 거기 사는 사람들이 있었다. 아이들이 뛰어놀고 있었고, 집집마다 사람이 있었다. 그리고 섬도 가장 아름다웠다. 감히 말할 수 있다. 무라노 갈 시간 있으면 그냥 부라노로 가자. 진리다. 가는 길도 멋지고 섬도 정말 전체가 하나의 조깅용 트랙처럼 되어 있다.&lt;/p&gt;
&lt;p&gt;배가 고파서 과자를 먹으며 걸어 다녔다. 목이 마른데 물이 없었다. 당근 슈퍼도 없었다. 늘 봐왔던 물을 뿜은 계수대에서 관광객들이 물을 마신다. 식수였던 것이다. 그래도 찝찝해서 마시지 않고 있었다. 그 동네 꼬마가 마시는 걸 보고는 결국 마셨다. 그냥 물 맛이었다. 섬을 다 돌아보고는 F.teNove행 LN배에 탔다. 지는 노을이 정말 아름다웠다. 석양이 지는 밤바다를 40분 달려 본 섬에 도착했다. 숙소에 들어가서 수영복을 널어 놓고는 나왔다. 마땅히 저녁을 먹을만한 곳이 없었다. 과자를 하도 먹어서 배는 고프지 않아 게토레이 한 병을 사들고 리알토로 향했다. 베니스의 마지막 밤이란 사실이 못내 아쉽다. 밤의 리알토는 한마디로 굳이었다. 야경을 찍고, 다리에 오르니 익숙한 음악이 들려온다. 할아버지가 앰프를 틀어놓고 같이 생음악 연주를 하고 있었다. 싼말코쪽 야경을 찍으며 다리에서 물길을 바라보고 있으니 정말 행복했다. 언젠가 좋아하는 사람이 생긴다면 꼭 다시 와보고 싶다는 생각이 들었다. 곳곳에 연인들이 염장질을 하고 있었기 때문이었다. 하염없이 서서 있고 싶었지만 도미토리라 너무 늦으면 민폔거 같아서 들어갔다. 민폐였다. 벌써 두 놈이 하염없이 자고 있었다. 씻고 수건 널고 잤다. 모기가 엄청 물어 뜯었다. 도미토리가 그렇지 머?…&lt;/p&gt;
&lt;p&gt;잘려고 눕는데 한 놈이 더 들어오더니 그 자리를 자기가 먼저 찜했다고 한다. 침대위에 아무것도 없다는 표정을 짓자 옆 테이블 위의 책을 가리킨다. 결국 다른 침대로 가서 잠을 잤다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;베니스는 이번 여행에서 가장 인상적인 곳이었다. 유럽에서 단 한 곳만 간다면 어디를 가야 합니까, 라고 누가 나에게 묻는다는 닥치고 베니스를 가라고 말해주고 싶다. 베니스는 다른 곳이다. 말뚝을 박아서 도시를 세웠다는 자체부터가 특이하다. 차가 한 대도 다니지 않고 모든 교통 수단이 배라는 점도 독특하다. 게다가 길도 꼬불꼬불 완전 미로처럼 되어 있다. 여튼 다녀보면 하나도 특이하지 않은 게 없다. 하나부터 열 가지가 모두 이상하게 느껴지는 도시다. 가장 특이했던 곳, 그리고 가장 인상 깊었던 곳, 그리고 가장 좋았던 곳이었다. 리도에서 해변에 누워서 하늘을 바라볼 때의 그 기분은 아직도 잊을 수가 없다. 정말 행복한 순간이었다. 내 인생에 다시 그런 시간이 올까 싶다. 오게 만들어야지 ㅋㅋ~&lt;/p&gt;
&lt;p&gt;전설적인 프랑스 주가 폭등 사태를 불러온 존 로의 무덤을 찾아가 보고 싶었는데 그러지 못했다는 사실이 조금 아쉽다. 미리 조사를 해서 갔어야 했는데 현지에서 찾기란 생각보다 쉽지 않았다.&lt;/p&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[베네치아, 낮을 보다.]]></title><description><![CDATA[DSCF2119 리알토의 아침. 비가 와서 그런지 우중충하다. 6.21 베네치아의 아침이 밝았다. 여전히 비가 내린다. 물의 도시답게 가벼운 물비린내가 난다. 숙박비를 걷으며 P에게 어쩔건지 물어본다. P…]]></description><link>https://jiniya.net/wp/archives/2260</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2260</guid><pubDate>Sun, 18 Jul 2010 23:56:19 GMT</pubDate><content:encoded>&lt;p&gt; &lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4804978086/&quot; title=&quot;DSCF2119&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4074/4804978086_9fe07206b2_b.jpg&quot; alt=&quot;DSCF2119&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;리알토의 아침. 비가 와서 그런지 우중충하다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;6.21&lt;/p&gt;
&lt;p&gt;베네치아의 아침이 밝았다. 여전히 비가 내린다. 물의 도시답게 가벼운 물비린내가 난다. 숙박비를 걷으며 P에게 어쩔건지 물어본다. P는 내일 피렌체로 가겠다고 한다. 그러라고 했다. 당일 숙박비를 걷어 호텔을 하루 더 연장한 다음 밖으로 나갔다. 바포레또 일일 이용권을 끊어야했다. 그전에 일단 산타루치아 역으로 가서 여행 정보를 제공하는 곳이 없나 살펴 보았다. 없다. 밖으로 나와 나는 36h, P는 24h 이용권을 끊었다. 거기서 파는 맵도 하나 샀다(2유로).&lt;/p&gt;
&lt;p&gt;처음 수상 버스를 탈 때 좀 우왕좌왕했다. 배로 다니는 버스 시스템이 익숙하지 않았아서였다. 반대로 가는 배라고 반대편에서 타는게 아니라 다른 선착장에서 타는 거였다. 어쨌든 찾아찾아 리알토행 2번 버스를 탔다. 이지 유럽에 82번 이라고 되어 있는데 오타인것 같다. 리알토 다리에 내리니 사람이 정말 많았다. 인증샷을 찍고 좀 구경하다 싼말코 광장으로 향했다. 어제 헤매면서 밤에 보았던 을씨년스러운 분위기와는 완전 달랐다. 사람도 많았고, 너무 북적됐다. 사자상에서 사진찍고, 비둘기 구경 좀 하다 싼말코 성당 줄을 섰다. 자연스럽게 보물실 줄로 가버려 4유로내고 보물실을 보게 되었다. 사실 보물은 그닥 흥미로운 것이 없었지만, 2층에서 1층을 볼 수 있다는 것과 2층 테라스로 나가서 싼말코 광장을 볼 수 있다는 점이 좋았다. 보물실 보고 내려가서 성당 구경하고 나와서 탄식의 다리로 가서 인증샷을 찍었다. 당연히 사람이 많았다. 탄식의 다리 사진찍기 전에 밥을 먹으로 레스토랑을 갔다. P는 해물 스파게티, 난 피자를 시켰다. 스파게티는 비싼데 정말 조금 나왔다. 피자는 정말 크게 나와서 빵 끝 부분은 모두 버렸다. 그래도 배가 터질 것 같았다.&lt;/p&gt;
&lt;p&gt;다음으로 간 곳은 싼 조르지오 마조레 성당이었다. 배에서 내려 인증샷 찍고 안으로 들어갔다. 싼 마르코 성당이 관광지 같은 분위기라면 여기는 조금 성당 같았다. P는 50센트를 내고 초를 사서 이쁜이가 편지 보내주길 기도했다. 나와서 싼타 마리아 살루떼 성당으로 향했다. 배에서 내려 인증샷을 찍고 들어가려 하는데 5시 30분 마감이라고 끝났다고 했다. 시계를 보니 5시 31분이었다. 성당 옆으로 바다와 인접한 곳으로 걸어갔다. 개구리를 들고 있는 동상이 하나 있었다. 사람들이 사진을 찍길래 우리도 찍었다. 헉, 그런데 그 동상을 총든 군인이 지키고 있었다. 동상에 접근 하려 하자 못하게 막았다. 살루떼 역 전망은 정말 끝내줬다. 앉아서 멍하니 바다를 구경하다 집으로 귀환했다.&lt;/p&gt;
&lt;p&gt;빌라에 들러 먹을걸 사고 맥도날드가서 오줌 싸고, 아참 P는 WC에 낚여 1.5유로 내고 화장실을 썼다. 리알토에서 다시 배를 타고 집으로 갔다. 집에서 0.6유로에 산 물을 열어보니 탄산수다. 덴장. ㅠㅠ. 정비 좀 하고 야경 찍을 겸 삼각대 챙겨 저녁을 먹으로 Brek에 갔다. 난 파스타, P는 스파게티를 먹었다. 그리고는 Zillete 역으로 향했다. P는 또 무섭다, 막차 끊기면 어쩌냐는 드립을 쳤다. Zillete에 내려 전망 좋다는 호스텔로 가서 내일 방이 있냐고 물었다. 지금은 없고 내일 누가 취소하면 생긴다고 한다. 그래서 야경이나 찍으로 나왔다. 끝쪽에서 찍으려고 가니 군사 지역처럼 접근을 못하도록 해 놓았다. 어쩔 수 없이 거기서 Zillette 역 쪽으로 오면서 야경을 찍었다. P는 의자에 카메라를 놓고 셀카놀이에 여념이 없었다. 나보고도 셀카나 찍으라고 한다. 난 멋진 야경을 찍고 싶었다. 내사진은 넘치게도 많았다. 근데 야경은 별로였다. 포인트가 좋지 않았다.&lt;/p&gt;
&lt;p&gt;그리고 배를타고 다시 로마광장에 내렸다. 어제 헤맬때 길을 물었던 바에 가서 술이나 한 잔 하려고 했다. 술집을 찾아 나섰다. P의 GPS 덕에 바텐이 동그라미 쳐 준 곳까진 어렵지 않게 찾아갔다. 그러나 그 바를 다시 찾기는 쉽지 않았다. P의 징징 드립이 시작되려해서 그량 학생들 많은 곳에서 맥주를 한 잔했다. 테이크아웃으로 사고는 밖에 빈자리가 있어 앉으니 플라스틱 컵 가지고는 앉지 말라고 했다. 그제야 왜 그 많은 학생들이 다 스탠딩으로 술을 마시고 있는지 알게 되었다. 맥주를 다 마시고 집으로 귀환했다.&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded></item><item><title><![CDATA[베네치아, 미로를 헤매다.]]></title><description><![CDATA[DSCF2935 리알토의 야경. 찍는대로 작품이다. 6.2…]]></description><link>https://jiniya.net/wp/archives/1482</link><guid isPermaLink="false">https://jiniya.net/wp/archives/1482</guid><pubDate>Sun, 18 Jul 2010 23:56:18 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4803317075/&quot; title=&quot;DSCF2935&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4141/4803317075_00bc09851f_b.jpg&quot; alt=&quot;DSCF2935&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;리알토의 야경. 찍는대로 작품이다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;6.20…&lt;/p&gt;
&lt;p&gt;일찍 일어났다. 이탈리아로 건너가는 날이다. 아침을 먹으로 갔는데 어제랑 메뉴가 똑같아 별로 입맛이 나질 않았다. 가볍게 한 접시에 시리얼만 조금 먹고 올라와서 짐을 쌌다. 이상하게 옷 뿐인데도 가방이 자꾸 허전해진다. 뭔가 이상하다.&lt;/p&gt;
&lt;p&gt;인터라켄 동역에서 베른행 열차를 탔다. 26chf다. P는 편지를 써서 이쁜이에게 전해 준다고 했는데 베비스 문을 열지 않았다. 편지를 문틈에 끼워놓고 왔다고 한다. 스위스 프랑이 좀 남아서 기념품을 사려고 했는데 마땅한 것이 보이지 않았다. 카우벨 작은 것은 너무 조악했고, 큰 것은 60chf가 넘었다. 베른에 와서는 약간 당황했다. 전에 내린 역과 달랐기 때문이다. 국제선, 국내선이 나뉘어 있는 것 같은 느낌이었다. 베른에 와서 밀라노행 티켓을 샀다. 97chf나 했다. 사지 않고 lost 드립을 함 더 하려다가 그냥 샀다. 자업자득이라 생각했다. 고생해봐야 담부터 더 잘 챙기지 않을까? ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;시간이 너무 많이 남아 베른역 지하 상가를 구경했다. 근 2시간 가량 남았다. 점심을 버거킹을 먹자고 하니 P가 다른 걸 먹고 싶다고 했다. 결국 베른역 처음 도착했을 때 먹었던 Suse Grill로 향했다. P는 중국집에서 25chf를 주고 오리 고기와 밥이 나오는 걸, 난 첫 날 먹은 소시지를 먹었다. P는 중국 향신료 때문에 고생하다 결국 고추장을 뿌려서 먹었다. 소시지는 먹을만했다. 밀라노행 열차는 2등석에 탔다. 이번 여행에서 처음 타보는 2등석이다. 1등석과는 분위기가 사뭇 다르다. 사람 사는 냄새가 난다고나 할까? 나는 마주 앉는 창가에 걸렸는데 옆에는 인도 여자, 앞에는 인도계로 보이는 아줌마와 아이. 대각선에는 수염을 잔뜩기른 키아누 리브스를 닮은 아저씨가 앉았다. 그 아저씨는 노트북으로 영화를 보는 중이다. 반대편 창가에 앉은 여자가 굉장히 아웃스탠딩하다. 맥라이언을 좀 닮은 것 같다. 옆에 아가씨는 남자와 함께 탔는데 남자는 입석인지, 자리에 앉아 있다 뺏기고 밖으로 나간다.&lt;/p&gt;
&lt;p&gt;밀라노 내리자마자 표 끊고 베네치아행 열차에 탔다. 이번에는 2등석임에도 자리가 좋다. 베네치아에 도착을 했다. 3일권을 끊으려고 여기 저기 물어 봤으나 아는 사람이 없다. 인포에 물었더니 일요일이라 모두 문을 닫았다며 살 수가 없다고 한다. 2번 버스가 와서 기사에게 물으니 1회권을 1.8유로에 판다고 했다. 두장을 사서 베네치아 Piazzale Roma에 내렸다. 다리를 하나 건너니 산타루치아 역이 나온다. 원래 묵으려고 했던 Ostello 호스텔을 찾아 나섰다. 생각보다 매우 엄청 찾기 힘들었다. 물어물어 겨우 찾았다. 그런데 문을 닫았다. 벨을 눌러도 대답이 없다. 다른 외국인 두 명이 온다. 헤매긴 마찬가지다. 그러다 결국 안에 있는 사람이 이야기를 해줘서 관리인이 나왔다. 다른 외국인 두 명은 예약을 하고 와서 방으로 갔지만 우리는 자리가 없었다. 다른 싼 곳 두 곳 위치를 적어 주었다. 결국 저렴한 25유로 호텔에 묶게 되었다. 싼 것 치고는 괜찮은 편이다. 아줌마가 그렇게 강조하는 private bath room도 나쁘지 않았다.&lt;/p&gt;
&lt;p&gt;바로 저녁을 먹으로 나갔다. 책에 있는 Brek으로 향했다. 사람들이 축구를 본다고 난리다. 이런 식의 서비스는 첨 해봐서 어떻게 먹는지를 몰라 물어봤다. 그냥 골라 담은 다음 계산하고 먹으면 된다고 한다. 난 스테이크, 스파게티, 샐러드를 먹었다. 도합 14.5유로 밖에 되지 않는다. 맘에 든다. 맛도 그럭저럭 괜찮았다. 밥먹고 와서 베네치아 탐사를 나섰다. 첨에는 빌라에 들려서 먹을걸 좀 사려고 했다. 그런데 가다보니 문을 닫은 것이 아닌가? 돌아가기 싫어서 반대로 돌자고 했다. 그렇게 몇 번 생각없이 이동하다, 그냥 생각없이 길을 잃었다. 헤매기 시작했다. P의 아이폰에 GPS가 들어왔을 때 우리 위치는 안습이었다. GPS 신공으로 겨우 큰 길로 다시 찾아 나왔다.&lt;/p&gt;
&lt;p&gt;술집이 보여서 거기서 맥주를 한 잔 했다. 12시에 문닫는 삘이 나서 나왔다. 문제는 그 때 부터 시작됐다. 아이폰 밧데리가 나가면서 졸지에 산마르코 광장 근처를 헤매게 된 것이다. 허접한 지도 하나, 그래도 대충 방향을 맙춰 움직이기 시작했다. 리알토 다리 근처, 산뽈로 성당, 싼토마 근처에서 물어보고 중간에 온갖 곳을 다 거쳤다. 결국 2시간을 헤매서 3시가 다 되어서야 호텔에 도착할 수 있었다. P는 화가 났다. 난 정말 재밌었는데…&lt;/p&gt;
&lt;p&gt;내일 그 중국어 배운다는 바텐이 있던 술집을 가봐야겠다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[부모,…]]></title><description><![CDATA[목요일, 어머니께서 간만에 서울에 오셨습니다. 정기적으로 받으시는 CT 촬영이 금욜날이었거든요. 집에 오셔서 저녁을 드시고 집 청소에 여념이 없습니다. 그냥 좀 쉬라고 하셔도 그저 청소를 하십니다. 다음 날 CT…]]></description><link>https://jiniya.net/wp/archives/2275</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2275</guid><pubDate>Sat, 10 Jul 2010 23:56:17 GMT</pubDate><content:encoded>&lt;p&gt;목요일, 어머니께서 간만에 서울에 오셨습니다. 정기적으로 받으시는 CT 촬영이 금욜날이었거든요. 집에 오셔서 저녁을 드시고 집 청소에 여념이 없습니다. 그냥 좀 쉬라고 하셔도 그저 청소를 하십니다. 다음 날 CT 촬영하는 병원을 따라 나섰습니다. 그런데 전날 먹은 삼겹살이 체했는지 속이 영 편치가 않더군요. 병원에 도착해서는 상태가 좀 심했습니다. 앉아 있는데도 식은 땀이 나고 토할 것 같고 그렇더군요. 한마디로 상태가 완전 메롱이었습니다. 그러다보니 본의 아니게 어머니께 짜증을 좀 부렸습니다. 그런데 참 부모라는 것이 무엇인지 체혈에 CT 촬영에 여기저기 주사 바늘을 꽂으시고도 제 걱정만 하시는 겁니다. 겨우겨우 몸을 추스려 어머니 내려가시는 걸 보고는 집으로 돌아왔습니다.&lt;/p&gt;
&lt;p&gt;집으로 돌아와서는 상태가 좀 더 심해졌습니다. 결국 종일 누워서 병원놀이 하고 말았습니다. 그 사이에도 어머니 전화가 몇 통 더 왔습니다. 밥은 먹었는지, 약은 챙겨 먹었는지, 아프지는 않은지 걱정이 많이 되었나 봅니다. 저도 서울, 부산을 자주 다녀서 알지만 젊은 사람도 그 길을 1박 일정으로 다니는 게 쉽지가 않습니다. 몹시 피곤하죠. 게다가 뱅기도 아닌 버스를 타고 내려 가셨으니 (갓뎀 아산병원이 강변역 바로 옆에 있습니다) 피곤이 훨씬 더 하시겠죠. 그런데도 그냥 하나 있는 아들 걱정에 바리바리 전화를 하시는걸 보니 제가 참 불효자란 생각이 많이 들었습니다.&lt;/p&gt;
&lt;p&gt;일원을 주면서도 계산기를 두드리는 게 자식이라면, 자신의 모든 것을 댓가 없이 주면서도 자식 걱정을 하는 게 부모라는 이름을 가진 사람들 같습니다. 오래 전에 인터넷에서 보았던 한 글귀가 떠오르더군요.&lt;/p&gt;
&lt;p&gt;살아 계실 때 효도합시다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;옛날에 한 청년이 살았다.&lt;/p&gt;
&lt;p&gt;청년은 아름다운 여인을 만나 사랑에 빠졌다.&lt;/p&gt;
&lt;p&gt;여인은 청년에게 별을 따다 달라고 말했다.&lt;/p&gt;
&lt;p&gt;청년은 기꺼히 별을 따다 주었다.&lt;/p&gt;
&lt;p&gt;여인은 청년에게 달을 따다 달라고 말했다.&lt;/p&gt;
&lt;p&gt;이번에도 청년은 사랑하는 그녀를 위해 달을 따다 주었다.&lt;/p&gt;
&lt;p&gt;이제 청년이 더 이상 그녀에게 줄 것이 없게 되었을 때,&lt;/p&gt;
&lt;p&gt;여인이 말했다.&lt;/p&gt;
&lt;p&gt;네 부모님의 심장을 꺼내 와..&lt;/p&gt;
&lt;p&gt;많은 고민과 갈등을 했지만 결국 청년은 부모님의 가슴 속에서 심장을 꺼냈다.&lt;/p&gt;
&lt;p&gt;청년은 부모님의 심장을 들고 뛰기 시작했다.&lt;/p&gt;
&lt;p&gt;오직 그녀와 함께 할 자신의 행복을 생각하며,&lt;/p&gt;
&lt;p&gt;달리고 또 달렸다…&lt;/p&gt;
&lt;p&gt;청년이 돌부리에 걸려 넘어졌을 때 청년의 손에서 심장이 빠져 나갔다.&lt;/p&gt;
&lt;p&gt;언덕을 굴러 내려간 심장을 다시 주워 왔을 때,&lt;/p&gt;
&lt;p&gt;상저와 흙투성이가 된 심장이 조용히 말했다.&lt;/p&gt;
&lt;p&gt;.&lt;/p&gt;
&lt;p&gt;.&lt;/p&gt;
&lt;p&gt;.&lt;/p&gt;
&lt;p&gt;얘야… 많이 다치지 않았니?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt; 0
 0&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;</content:encoded></item><item><title><![CDATA[[cpp] 증감 연산자로 살펴보는 sequence point의 개념]]></title><description><![CDATA[아래 프로그램의 실행 결과는 무엇인가? 흔히 초급 C…]]></description><link>https://jiniya.net/wp/archives/2235</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2235</guid><pubDate>Wed, 07 Jul 2010 23:56:16 GMT</pubDate><content:encoded>&lt;p&gt;아래 프로그램의 실행 결과는 무엇인가?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; c &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  

&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; r &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; a&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;b &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; c&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  

&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;“&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;d\n”&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; r&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;흔히 초급 C언어 강좌에서 자주 시험 문제로 등장하는 것이다. 전위형 증감 연산자와 후위형 증감 연산자의 차이를 이해하고 있는지를 묻는 문제다. 이러한 문제를 골똘히 생각해본 독자라면 한번쯤 다음과 같은 값들의 결과는 어떻게 되는지를 두고 고민해 본적도 있을 것이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;r &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;k &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; k&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  

a&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;k&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;k&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위 구문의 합당성을 완전히 이해하기 위해서는 C와 같은 명령형 프로그래밍 언어의 특징을 알아야 한다. 명령형 프로그래밍 언어는 변수의 값을 바꾸는 명령이 모인 것을 프로그램으로 간주한다. 따라서 값의 변경, 내지는 상태를 변경하는 순서와 규칙이 중요하다. 왜냐하면 결국은 그 순서에 의해서 프로그램의 결과가 결정되기 때문이다.&lt;/p&gt;
&lt;p&gt;이런 이유로 명령형 언어에서는 값의 변경이 완료된 지점, 내지는 모든 사이드 이펙트가 처리된 지점을 정의하고 있다. 그것이 바로 sequence point다. 모든 값의 변경은 이러한 sequence point를 기준으로 처리된다. C언어에서는 다음과 같은 것들을 sequence point로 정의하고 있다.&lt;/p&gt;
&lt;p&gt;1. 함수 호출&lt;/p&gt;
&lt;p&gt;2. 논리적 AND(&amp;#x26;&amp;#x26;), 논리적 OR(||), 삼항연산자(?), 콤마연산자(,)&lt;/p&gt;
&lt;p&gt;3. 선언문의 완료&lt;/p&gt;
&lt;p&gt;4. 표현식의 완료&lt;/p&gt;
&lt;p&gt;5. 함수 리턴&lt;/p&gt;
&lt;p&gt;C언어 표준은 sequence point와 관련해서 아래와 같은 제약 사항을 명시하고 있다. 한 오브젝트는 두 인접한 sequence point 사이에서 값을 최대 한 번만 변경할 수 있으며, 그렇게 변경된 값은 최종적으로 저장될 대상의 값을 결정하기 위한 용도로만 참조될 수 있다는 말이다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이러한 관점에서 앞서 제기했던 두 구문은 C언어 표준에 부합하지 않는다는 것을 알 수 있다. “r = ++k + k++”의 경우에는 인접한 두 sequence point 사이에서 k 값의 변경이 두 번 발생했기 때문에 표준에 부합하지 않는 문장이고, 따라서 이 연산의 결과는 보장할 수 없다. “a[k] = ++k”의 경우에는 변경된 k값이 최종적으로 저장될 대상의 값을 결정하기 위한 목적이 아닌 배열 인덱스의 용도로 사용되었기 때문에 표준의 두 번째 요건을 충족시키지 않는다. 따라서 이 또한 정의되지 않은 행동이고, 이 연산의 결과는 보장되지 않는다.&lt;/p&gt;
&lt;p&gt;그렇다면 다음과 같은 printf 문장은 어떨까?&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%d %d %d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; j&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;del&gt;앞서 살펴본 C언어 sequence point 정의에서 콤마 연산자는 하나의 sequence point를 형성한다고 나와있다. 따라서 이 경우에는 정상적으로 값이 계산된다.&lt;/del&gt; 이 코드는 정의되지 않은 동작이다. 함수 인자 사이에는 시퀀스 포인트가 없고 평가 순서가 미정이므로, 두 인접한 시퀀스 포인트 사이에서 j가 두 번 이상 변경되기 때문이다. 정의된 동작으로 작성하려면 아래와 같이 콤마 연산자를 단일 인자 안에서 사용해야 한다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; j&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;주의! 쉼표와 콤마 연산자는 다르다.&lt;br&gt;
함수 인자 목록의 쉼표(,) 는 인자 구분자일 뿐이며 시퀀스 포인트를 만들지 않는다.&lt;br&gt;
시퀀스 포인트를 만드는 것은 콤마 연산자 (e1, e2) 이다. 콤마 연산자는 왼쪽 피연산자 평가가 끝나고 시퀀스 포인트가 생긴 뒤 오른쪽을 평가한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;반면에 다음과 같은 구문은 인접한 두 sequence point 사이에 값을 두 번 변경하는 것이 되므로 부당한 것이다.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;%d\n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;j &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;j&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;일반적으로 C/C++ 개발자들이 알고 있는 것처럼 값의 변경 단위는 구문 단위로 이루어지지는 않는다. 값의 변경 단위는 sequence point라는 것을 단위로 이루어지며, 표준에서는 두 인접한 sequence point 사이에 발생할 수 있는 사이드 이펙트에 관한 제약사항을 분명하게 명시하고 있다. 이러한 복잡한 내용을 모두 피하고 싶다면 가급적 증감 연산자는 분리된 구문으로 작성하는 것이 좋다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[버전 매크로]]></title><description><![CDATA[비주얼 C++을 이용해 프로젝트를 처음 만들게 되면 stdafx.h…]]></description><link>https://jiniya.net/wp/archives/2215</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2215</guid><pubDate>Tue, 06 Jul 2010 23:56:15 GMT</pubDate><content:encoded>&lt;p&gt;비주얼 C++을 이용해 프로젝트를 처음 만들게 되면 stdafx.h에는 다음과 같이 알 수 없는 전처리기 구문이 생성된다. 기초 서적에서 이와같은 부분을 별도로 설명하지 않기에 대부분의 사람들은 그저 그냥 생성된 구문이겠거니 하고 넘어가게 된다. 하지만 이 부분에 대해서 정확하게 이해하지 못하고 넘어가는 경우, 최신 API를 사용하려고 할 때에 나타나는 컴파일 에러에 당황할 수 있다. 그렇다면, 이번 기회를 통해 간단하게 복습하는 기분으로 다음의 전처리기 구문에 대해 살펴보도록 하자.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifndef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;WINVER&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;WINVER&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;0x0400&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifndef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;_WIN32_WINNT&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;_WIN32_WINNT&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;0x0400&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifndef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;_WIN32_WINDOWS&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;_WIN32_WINDOWS&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;0x0410&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifndef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;_WIN32_IE&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;_WIN32_IE&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;0x0400&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;#define은 개발자라면 많이 접하고, 익히 알고 있을 것이다. 상수를 선언하는 것이다. 위에서 제일 첫 번째 나온 WINVER부분을 보면 WINVER를 0x0400으로 정의하고 있다는 것을 알 수 있다. 따라서 앞으로 소스의 모든 WINVER는 0x0400으로 치환된다.&lt;/p&gt;
&lt;p&gt;#define 위에 있는 #ifndef, #endif는 조건부 컴파일을 하는 전처리기다. #ifndef는 뒤에 나오는 상수가 선언되지 않은 경우, 다음 부분을 컴파일할 것이라는 것을 말한다. 첫 번째 블록은 결과적으로 WINVER가 선언되지 않은 경우에 WINVER를 0x0400으로 정의하는 일을 한다. 만약 코드가 아래와 같이 되어 있다면 WINVER 값은 무엇이 될까?&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;cpp&quot;&gt;&lt;pre class=&quot;language-cpp&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;WINVER&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;0x0500&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;ifndef&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;WINVER&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;WINVER&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;0x0400&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;token directive keyword&quot;&gt;endif&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;위의 경우 #ifndef를 만나기 전에 WINVER가 정의되어 있기 때문에 #ifndef부터 #endif까지는 컴파일이 되지 않는다. 따라서 WINVER는 0x0500이 된다.&lt;/p&gt;
&lt;p&gt;그렇다면, 이제 위에서 정의된 네 개의 상수가 어떤 의미를 가지는 것들인지 알아보도록 하자. 처음으로 나온 WINVER는 윈도우의 버전을 나타낸다. 즉, 어떤 버전 이상의 윈도우 플랫폼을 겨냥한 프로그램을 개발할지를 나타낸다고 생각하면 된다.&lt;/p&gt;
&lt;p&gt;다음으로 나오는 _WIN32_WINNT의 경우는 윈도우NT계열의 운영체제의 버전을 나타낸다. NT 계열 운영체제로는 윈도우NT, 2000, XP, 2003등이 있다. _WIN32_WINDOWS는 9x 계열 운영체제의 버전을 나타낸다. 9x 계열의 운영체제로는 윈도우95, 98, ME가 있다. 마지막으로 나오는 _WIN32_IE는 인터넷 익스플로러의 버전을 나타낸다.&lt;/p&gt;
&lt;p&gt;이러한 것들을 헤더에서 정의해 주는 이유는 사용할 API의 한계를 결정짓기 위해서다. 윈도우 API의 경우 새로운 운영체제가 나오거나, 새로운 인터넷 익스플로러가 출시될 때마다 추가되는 경향이 있다. 최신 운영체제에서만 지원하는 API를 사용한 경우 그 운영체제보다 아래의 버전에서는 해당 프로그램이 동작하지 않는다는 이야기다.&lt;/p&gt;
&lt;p&gt;예를 들면 InterlockedExchangeAdd란 API는 윈도우 98부터 사용할 수 있다. 윈도우 95에는 해당 API가 존재하지 않는 것이다. 따라서 윈도우 95에서 동작하는 프로그램을 만든다면 위 API는 사용해서는 안 된다. 윈도우 API는 수천 가지도 넘게 존재하고 앞으로도 계속 추가될 것이다. 이러한 API 하나하나에 대한 지원정보를 프로그래머가 일일이 구분해서 사용한다는 것은 매우 힘든 일이다. 그래서 프로그램을 개발할 때에 위와 같은 매크로를 통해서 이 프로그램이 동작할 수 있는 하한선을 정의함으로써 그 보다 더 높은 시스템만 지원하는 API는 컴파일 시 포함되지 않게 하는 것이다. 이로써 프로그래머가 해당 시스템에선 사용할 수 없는 API를 쓰는 실수를 하게 된다면 컴파일러는 오류를 발생시켜 알려줄 수 있는 것이다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;플랫폼&lt;/td&gt;
&lt;td&gt;버전 매크로&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows “Longhorn”&lt;/td&gt;
&lt;td&gt;_WIN32_WINNT &gt;= 0x0600 WINVER &gt;= 0x0600&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows Server 2003&lt;/td&gt;
&lt;td&gt;_WIN32_WINNT &gt;= 0x0502 WINVER &gt;= 0x0502&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows XP&lt;/td&gt;
&lt;td&gt;_WIN32_WINNT &gt;= 0x0501 WINVER &gt;= 0x0501&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows 2000&lt;/td&gt;
&lt;td&gt;_WIN32_WINNT &gt;= 0x0500 WINVER &gt;= 0x0500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows NT 4.0&lt;/td&gt;
&lt;td&gt;_WIN32_WINNT &gt;= 0x0400 WINVER &gt;= 0x0400&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows ME&lt;/td&gt;
&lt;td&gt;_WIN32_WINDOWS &gt;= 0x0500 WINVER &gt;= 0x0500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows 98&lt;/td&gt;
&lt;td&gt;_WIN32_WINDOWS &gt;= 0x0410 WINVER &gt;= 0x0410&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows 95&lt;/td&gt;
&lt;td&gt;_WIN32_WINDOWS &gt;= 0x0400 WINVER &gt;= 0x0400&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internet Explorer 7.0&lt;/td&gt;
&lt;td&gt;_WIN32_IE &gt;= 0x0700&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internet Explorer 6.0 SP2&lt;/td&gt;
&lt;td&gt;_WIN32_IE &gt;= 0x0603&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internet Explorer 6.0 SP1&lt;/td&gt;
&lt;td&gt;_WIN32_IE &gt;= 0x0601&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internet Explorer 6.0&lt;/td&gt;
&lt;td&gt;_WIN32_IE &gt;= 0x0600&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internet Explorer 5.5&lt;/td&gt;
&lt;td&gt;_WIN32_IE &gt;= 0x0550&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internet Explorer 5.01&lt;/td&gt;
&lt;td&gt;_WIN32_IE &gt;= 0x0501&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internet Explorer 5.0, 5.0a, 5.0b&lt;/td&gt;
&lt;td&gt;_WIN32_IE &gt;= 0x0500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internet Explorer 4.01&lt;/td&gt;
&lt;td&gt;_WIN32_IE &gt;= 0x0401&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internet Explorer 4.0&lt;/td&gt;
&lt;td&gt;_WIN32_IE &gt;= 0x0400&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Internet Explorer 3.0, 3.01, 3.02&lt;/td&gt;
&lt;td&gt;_WIN32_IE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</content:encoded></item><item><title><![CDATA[블로그 옮겼습니다.]]></title><description><![CDATA[블로그를 옮긴지 일년이 넘은것 같은데 아직도 여기로 링크가 되어 있어서 이곳으로만 오는 분들이 계신 것 같네요. "블로그 접었어?"라는 질문을 하시는뎀, 뭐라고 답변을 드려야할지 ㅋㅋ~ 여튼 새로운 주소는 아래와 같습니다. http://www…]]></description><link>https://jiniya.net/tt/807</link><guid isPermaLink="false">https://jiniya.net/tt/807</guid><pubDate>Tue, 06 Jul 2010 12:46:00 GMT</pubDate><content:encoded>&lt;p&gt;블로그를 옮긴지 일년이 넘은것 같은데 아직도 여기로 링크가 되어 있어서 이곳으로만 오는 분들이 계신 것 같네요. &quot;블로그 접었어?&quot;라는 질문을 하시는뎀, 뭐라고 답변을 드려야할지 ㅋㅋ~ 여튼 새로운 주소는 아래와 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.jiniya.net/wp&quot;&gt;http://www.jiniya.net/wp&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;혹시 즐겨찾기를 사용하시는 분이라면 &lt;a href=&quot;http://www.jiniya.net&quot;&gt;http://www.jiniya.net&lt;/a&gt;을 추가해 두시면 됩니다. 해당 주소로 가시면 알아서 자동으로 이동시켜 줍니다. &lt;a href=&quot;http://www.jiniya.net/tt&quot;&gt;http://www.jiniya.net/tt&lt;/a&gt;를 추가해놓고 지금까지 방문하신 것 같더군요. 헐킈~~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[베비스]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/2174</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2174</guid><pubDate>Mon, 05 Jul 2010 23:56:14 GMT</pubDate><content:encoded>&lt;p&gt;퐁듀의 명가 베비스를 소개합니다. ^^;;&lt;/p&gt;
&lt;p&gt;아저씨 쑈맨십이 압권이예요. 근데 날마다 틀린거 같아요.&lt;/p&gt;
&lt;p&gt;이튿날은 일본 단체 손님인 것 같았는데 뭔가 심심했다능 ㅠㅠ~&lt;/p&gt;
&lt;p&gt;고기 퐁듀, 치츠 퐁듀, 초콜릿 퐁듀가 있습니다.&lt;/p&gt;
&lt;p&gt;고기 퐁듀를 추천해 드리고 싶네욤.&lt;/p&gt;
&lt;p&gt;그닥 비싸진 않아요.&lt;/p&gt;
&lt;p&gt;인터라켄 가신다면 꼭 한 번 가보세욤.&lt;/p&gt;
&lt;p&gt;참고로 얼짱 알바도 있답니다. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;아저씨의 호른 연주 이어지는 광란의 분위기 ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4763740234/&quot; title=&quot;DSCF1682&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4097/4763740234_3d064a3f49_b.jpg&quot; alt=&quot;DSCF1682&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;다들 의자위로 올라가고 있는 시츄에이션…&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4763740164/&quot; title=&quot;DSCF1685&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4097/4763740164_9250a6673a_b.jpg&quot; alt=&quot;DSCF1685&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;기차놀이… 같이 움직이면서 찍다보니 흔들린거 밖에 엄네요.&lt;/p&gt;
&lt;p&gt;이거도 동영상 찍었는데 세이브를 한다는게 전원을 꺼버린 ㅠㅠ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4763101885/&quot; title=&quot;DSCF1669&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4137/4763101885_db1b2551ee_b.jpg&quot; alt=&quot;DSCF1669&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;첫 날에 먹은 고기 퐁듀, 뭔가 나름 푸짐하죠.&lt;/p&gt;
&lt;p&gt;저 냄비에 들어 있는 거는 그냥 기름입니다.&lt;/p&gt;
&lt;p&gt;거기다 고기를 넣어서 익혀 먹는 거예요.&lt;/p&gt;
&lt;p&gt;우리는 기름이 소슨줄 알고 찍어 먹어 봤다는 헐킈… ㅠㅠ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4763101759/&quot; title=&quot;DSCF1984&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4081/4763101759_a600f7a304_b.jpg&quot; alt=&quot;DSCF1984&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;이튿날 먹은 치츠 퐁듀. 헐빈한 식탁. 핡~ 치즈 맛도 그닥. 누린내가 제법 납니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4763740102/&quot; title=&quot;DSCF1994&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4134/4763740102_1e44318846_b.jpg&quot; alt=&quot;DSCF1994&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;베비스에 우리도 천 원 짜리 한 장 붙이고 왔어요. 어떤 거냐구요? ㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4763740056/&quot; title=&quot;DSCF1995&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4097/4763740056_bd2764a4ab_b.jpg&quot; alt=&quot;DSCF1995&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;가운데 있는 요곱니다.  매직이 없어서 볼펜으로 썼더니 글자가 안보여요 ㅋ~&lt;/p&gt;
&lt;p&gt;담에 갈 때까지 있겠죠?&lt;/p&gt;</content:encoded></item><item><title><![CDATA[판타스틱 융프라우요흐]]></title><description><![CDATA[SG107808  여긴 어디? 탑오브유럽, 3571m 융프라우요흐. 6.19… 날이 밝았다. 아침을 먹자는 P의 이야기에 일어나서 0층 레스토랑에 차려진 아침을 먹었다. 하룻밤에 200chf…]]></description><link>https://jiniya.net/wp/archives/1480</link><guid isPermaLink="false">https://jiniya.net/wp/archives/1480</guid><pubDate>Mon, 05 Jul 2010 23:56:13 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4756785827/&quot; title=&quot;SG107808&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4137/4756785827_c90496ee6e_b.jpg&quot; alt=&quot;SG107808&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;여긴 어디? 탑오브유럽, 3571m 융프라우요흐.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;6.19…&lt;/p&gt;
&lt;p&gt;날이 밝았다. 아침을 먹자는 P의 이야기에 일어나서 0층 레스토랑에 차려진 아침을 먹었다. 하룻밤에 200chf가 넘는 호텔 치고는 먹을게 부실했다. 시리얼과 이상한 베이컨 구운 것처럼 보이는 걸로 배를 채웠다. 빵은 모두 딱딱했다. 이런 빵을 먹는 유러피언들을 이해할 수 없다. 증말. ㅋ~&lt;/p&gt;
&lt;p&gt;아침먹고 잽싸게 융프를 올라가기 위해서 인터라켄 동역으로 향했다. 비가 추적추적 제법 내렸다. 비가 너무 많이 내려서 나도 어쩔 수 없이 우산을 들고 나갔다. 날씨는 춥고 비는 내리고 완전 쩔었다. 하지만 융프 외에는 달리 할 게 없었다. 과감하게 13만원짜리 융프 왕복 티켓을 끊었다. 역으로 들어가서는 처음에 P가 그냥 시간표 뒷 페이지를 보면서 자연스레 라우터부넨행 열차를 타는 가닥이 잡히고 있었다. 그런데 갑자기 옆에 한국 사람이 말을 걸어 오더니 형광펜 운운하면서 그란델행을 타는게 맞냐고 물어본다. 그래서 자연스레 우리도 형광펜에 집착하게 되었고 그 일행과 함께 그란델행 열차에 올라탔다. 출발까지는 5분도 남지 않았다. 책을 펼친다. 올라갈 땐 라우터부넨으로 올라가라고 되어있다. P와 나는 광속으로 내려서 라우터부넨행으로 갈아탔다. 역무원이 그란델로 올라가는 곳에 형광펜을 칠해 주는데 그대로 하면 쪼다된다.&lt;/p&gt;
&lt;p&gt;라우터부넨으로 올라가서 폭포를 보러 갔다. 가까운 줄 알았는데 제법 멀었다. 폭포는 엄청 컸다. 폭포 속으로 올라 갈 수 있는 길이 있어서 끝까지 올라 갔는데 제법 힘들었다. 디카놀이 좀하다 다시 역으로 돌아왔다. 클라이네 샤이덱을 거쳐 융프로 올라갔다. 올라가는 길은 무지하게 추웠고 흰색 밖에는 보이질 않았다. 도착한 융프는 정말 멋졌다. 밖에는 눈보라가 치는데 안은 쩔게 아늑했다. 바로 무료 컵라면 쿠폰으로 라면을 한사리 하고는 융프에서 밖으로 나가서 눈내리는 곳에서 사진찍고 놀았다. 레알 눈이었다. 순백의 눈 그 자체. 흐린데도 너무 흰색이라 눈이 부셨다.&lt;/p&gt;
&lt;p&gt;사진 찍는데 분위기가 업되서 이상한 외국인 아저씨와도 같이 사진을 찍고 이메일을 교환했다. 서로 사진을 보내 주기로 철썩같이 약속을 했는데 그 아저씨 이메일 주소가 너무 어려웠다. 나와서 얼음 궁전을 관람하고는 다른 외부로 연결된 곳으로 가서 또 디카놀이를 했다. 그러다보니 세 시간이 그냥 지났다. 세상에서 가장 높은 우체통에다 엽서도 한 장 써서 보냈다. 우왕 굳~&lt;/p&gt;
&lt;p&gt;그렇게 진탕 놀다보니 춥기도 춥고, 피곤하기도 피곤했다. 내려오는 길은 그냥 닥치고 자고, 기차타고 내려왔다. 비도오고 해서 하이킹은 접었다.&lt;/p&gt;
&lt;p&gt;인터라켄 도착해서 P가 노래를 부르던 치즈 퐁듀를 먹으로 베비스를 다시 찾았다. 치즈 퐁듀는 정말 별로 였다. 치즈에다 빵을 찍어 먹는게 전부였다. 빵, 치즈, 끝. 화가난 우리는 다른 걸 시켜서 추가로 먹었다. 밥을 기대하고 시켰는데 감자가 나왔다. 덴장.&lt;/p&gt;
&lt;p&gt;P가 이뿌다던 알바랑 사진 함 찍게 해주려고 아무리 기다려도 알바는 나오질 않았다. 마지노선을 정하고 기다리던 중 드디어 출현. “Execuse me”로 풀링하는데 다른 알바가 덥썩 와버렸다. 그래서 계산해 달라고 하는데 정작 이쁜이는 들어가 버리는게 아닌가. 다시 나왔을 때 안되겠다 싶어서 직접가서 사진 좀 찍자고 이야기했다. 이쁘다고 하니까 엄청 좋아하는 눈치다. 여자들이란 ㅋㅋㅋ… 이로써 P에게 졌던 주당 마을 빚은 갚았다. 언제 마치냐고 물어보려다 오반것 같아서 말았다. 태국에서 왔다는데 P는 태국삘을 좋아하는 것 같다. &lt;/p&gt;
&lt;p&gt;저녁에 P가 쏜데서 봉춤보러 갔다. 풀버전을 봤는데 별 감흥도 없었다. 어제 이야기 했던 우크라이나 아가씨가 다시 온다. 뮤직 페스티벌에 갔냐면서 오늘은 어떠냐고 묻는다. 안갔다고 하니, 왜 안갔냐고 하루종일 호텔에 있었냔다. 융프를 갔다니깐 초큼 놀라는 눈치다. 자기는 아직 안가봤다고 어땠냐고 묻길래. fantastic이라고 대답해줬다. 그러면서 다시 묻는 말, 오늘은 술을 사줄 생각이 있냔다. 난 얻어먹는거라고 돈이 없다고 했더니 이제는 협박을 한다. 니가 안사주면 혼자 쓸쓸하게 술을 마셔야 하는데 괜찮겠냔다. 괜찮다니 알았다고는 돌아간다. 한참을 술을 마시는데 갑자기 다른 우크라이나 여성이 I want  shampagne이라고 외친다. 그러더니 우리한테 와서 계속 샴빠인, 샴빠인 이러는게 아닌가. 말하는건 귀여웠는데 돈 없어서 패스…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;라우터부넨으로 올라가라는 이야기가 폭포를 볼 수 있기 때문이다. 내려올 때 봐도 된다고 생각하면 초큼 오산이다. 올라가는데만 2시간 정도 걸린다. 위에서 바로 내려와도 힘들어서 보기가 쉽지 않다. 올라가면서 설레임이 있을 때 보도록 하자. 절대 형광펜 낚시에 걸려들진 말자.&lt;/p&gt;
&lt;p&gt;융프라우요흐는 생각보다 엄청 춥다. 사람들이 실내에 있다고 별로 안춥다고 하는데 실내에만 있을거면 별로 그닥 올라가는 보람을 느끼기 힘들다. 눈밭에서 한번 구르고 싶다면 따시게 입고 가도록 하자.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[루째른에서 인터라켄까지]]></title><description><![CDATA[DSCF1481 루째른 역입니다. DSCF1488 나무로 만든 오래된 다리, 카펠교예용. 그냥 다리입니당. DSCF1475 짐들고 여행하는건 정말 빡쎄욤. DSCF1479 카펠교 위에 이렇게 되어 있습니다. DSCF149…]]></description><link>https://jiniya.net/wp/archives/2106</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2106</guid><pubDate>Mon, 05 Jul 2010 23:56:12 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4073/4756768081_7d35dea2cf_b.jpg&quot; alt=&quot;DSCF1481&quot;&gt;&lt;/p&gt;
&lt;p&gt;루째른 역입니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4757378970/&quot; title=&quot;SG107178&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4143/4757404920_aba70e2b5e_b.jpg&quot; alt=&quot;DSCF1488&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;나무로 만든 오래된 다리, 카펠교예용. 그냥 다리입니당.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4136/4757405360_73e4d837c6.jpg&quot; alt=&quot;DSCF1475&quot;&gt;&lt;/p&gt;
&lt;p&gt;짐들고 여행하는건 정말 빡쎄욤.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4073/4756768717_13002110be_b.jpg&quot; alt=&quot;DSCF1479&quot;&gt;&lt;/p&gt;
&lt;p&gt;카펠교 위에 이렇게 되어 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4082/4757404858_f63fcba173_b.jpg&quot; alt=&quot;DSCF1495&quot;&gt; &lt;/p&gt;
&lt;p&gt;카펠교 구경하고 시간이 없어서 바로 유람선 탔어욤. 인증해야죠. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4757404968/&quot; title=&quot;DSCF1522&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4101/4757404968_d5ac0b170e_b.jpg&quot; alt=&quot;DSCF1522&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;유람선에서 찍은 거랍니당. 저런데 살면 참 좋겠다 싶어요.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4756768225/&quot; title=&quot;DSCF1524&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4134/4756768225_5c8f75ff27_b.jpg&quot; alt=&quot;DSCF1524&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;비가 오지게 많이 왔습니다. 구름이 산을 먹고 있어요. 실제로는 정말 더 멋졌습니다. 그 운치란 ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4756767921/&quot; title=&quot;ㅇDSCF1547&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4096/4756767921_ac8bed0a3c_b.jpg&quot; alt=&quot;ㅇDSCF1547&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;유람선 위에서 찍은 거예욤. 호수가 정말 깨끗해요.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4756767995/&quot; title=&quot;SG107323&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4141/4756767995_b4aeb2f06d_b.jpg&quot; alt=&quot;SG107323&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;유람선 위에서 인증 ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4077/4756768437_77264bee89_b.jpg&quot; alt=&quot;DSCF1594&quot;&gt;&lt;/p&gt;
&lt;p&gt;Gibswil에서 인터라켄 가는 열차를 기다리고 있습니당.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4756768299/&quot; title=&quot;DSCF1592&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4100/4756768299_29c541c273_b.jpg&quot; alt=&quot;DSCF1592&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;배고파서 케밥박스에 맥주를 먹었어요. 그럭저럭 먹을만 했습니당.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4757404790/&quot; title=&quot;SG107514&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4074/4757404790_667e00de4a_b.jpg&quot; alt=&quot;SG107514&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;기차 설정 샷… P 아이디어 ㅋㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4756768333/&quot; title=&quot;DSCF1630&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4123/4756768333_5469d978ee_b.jpg&quot; alt=&quot;DSCF1630&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;여행은 그냥 멍때리는거죠. ㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4756768399/&quot; title=&quot;DSCF1595&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4120/4756768399_606ffc35bb_b.jpg&quot; alt=&quot;DSCF1595&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4756768485/&quot; title=&quot;DSCF1610&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4141/4756768485_b814be39e5_b.jpg&quot; alt=&quot;DSCF1610&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;정말 비가 많이 왔습니다. 그래도 기차 안에서 바라보는 풍경은 정말 멋졌어욤.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4757405210/&quot; title=&quot;DSCF1657&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4115/4757405210_25a44b3205_b.jpg&quot; alt=&quot;DSCF1657&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4756768549/&quot; title=&quot;DSCF1661&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4099/4756768549_e6ac916db0_b.jpg&quot; alt=&quot;DSCF1661&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;브리엔쯔 지나면서 나온 호수, 그냥 굳이죠 ~&lt;/p&gt;</content:encoded></item><item><title><![CDATA[비밀]]></title><description><![CDATA[85년도에 출판된 이 책을 초등학교 때 아주 인상깊게 읽었던 기억이 난다. 엄마가 어딘가에서 찾아내 끼워둔 것을 다시 꺼내 보게 되었다. 근 2…]]></description><link>https://jiniya.net/wp/archives/2132</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2132</guid><pubDate>Mon, 05 Jul 2010 23:56:11 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF3878.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF3878.jpg&quot; alt=&quot;&quot; title=&quot;DSCF3878&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;85년도에 출판된 이 책을 초등학교 때 아주 인상깊게 읽었던 기억이 난다. 엄마가 어딘가에서 찾아내 끼워둔 것을 다시 꺼내 보게 되었다. 근 20년 만에 다시 책을 보니 느낌이 참 새롭다. 그 때 태양이 점점 커져서 결국은 지구를 삼킬 수도 있다는 사실에 굉장히 경악했던 기억도 나고, 한 참 후에나 일어난다는 사실을 인지하고는 다시 안심했던 기억도 난다. 어쨌든 나는 이 책을 읽고는 내가 정말 태양계에 있는 모든 비밀을 다 알아 냈다는 뿌듯한 생각을 조금 가졌었다. 물론 그 나이에 이해할 수 없는 내용이 더 많았고, 저 책이 모든 비밀을 담고 있는 것이 아님에도 말이다.&lt;/p&gt;
&lt;p&gt;세상에는 참 많은 비밀들이 있고, 그 중에는 정말 알고 싶은 것들도 많다. 도대체 그들은 어떻게 그렇게 말도 안되게 창조적인 생각을 해냈을까? 그들의 그런 직관과 통찰은 도대체 어디서 나온 것일까? 그것이 내가 요즘 알고 싶은 가장 큰 비밀이다. 그냥 책 제목을 보다 이런 생각이 들었다.&lt;/p&gt;
&lt;p&gt;코페르니쿠스는 모든 사람들이 다 태양이 돈다고 하던 시절에 지구가 돌아야 모든 문제가 쉽게 풀린다는 사실을 알았다. 갈릴레이는 무거운 물체가 먼저 떨어진다는 상식을 깨고 사탑 실험을 통해서 그렇지 않다는 사실을 밝혀냈다. 뉴턴은 사과가 떨어지는 것을 보고 지구가 사과를 끌어 당기는 건 아닐까라는 생각을 했고, 아인슈타인은 누구도 생각하지 않던 빛의 속도로 움직이면 어떻게 되는지를 상상하면서 시공간이라는 새로운 세계를 창조했다. 호킹은 블랙홀 속으로 모든 물체가 빨려 들어가 사라진다는 사실에서 그것을 역으로 돌리면 빅뱅이 된다는 사실을 눈치챘다. 그리고 그로부터 그 특이점에서 우주가 창조되었을지도 모른다는 생각을 해냈다.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[베른]]></title><description><![CDATA[SG107051 짠. 여기가 바로 스위스입니다. 그냥 놀라워요~ DSCF1410 다리예욤. 생각보다 엄청 높아요. DSCF1417 공원쪽으로 올라가다 본 베른 풍경. DSCF1425 베른이 괜히 베른이 아니죠. 레알 곰입니다. SG10711…]]></description><link>https://jiniya.net/wp/archives/2085</link><guid isPermaLink="false">https://jiniya.net/wp/archives/2085</guid><pubDate>Sat, 03 Jul 2010 23:56:10 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4757345256/&quot; title=&quot;SG107051&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4074/4757345256_d43188fa78_b.jpg&quot; alt=&quot;SG107051&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;짠. 여기가 바로 스위스입니다. 그냥 놀라워요~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4757345810/&quot; title=&quot;DSCF1410&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4073/4757345810_1f66fe5234_b.jpg&quot; alt=&quot;DSCF1410&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;다리예욤. 생각보다 엄청 높아요.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4757345852/&quot; title=&quot;DSCF1417&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4096/4757345852_b76e74c143_b.jpg&quot; alt=&quot;DSCF1417&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;공원쪽으로 올라가다 본 베른 풍경.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4757345520/&quot; title=&quot;DSCF1425&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4117/4757345520_cf3633b7c0_b.jpg&quot; alt=&quot;DSCF1425&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;베른이 괜히 베른이 아니죠. 레알 곰입니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4757345310/&quot; title=&quot;SG107117&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4099/4757345310_cf5be4f216_b.jpg&quot; alt=&quot;SG107117&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;곰인증도 해주시공 ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4756708549/&quot; title=&quot;SG107141&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4097/4756708549_5a8c5875df_b.jpg&quot; alt=&quot;SG107141&quot;&gt;&lt;/a&gt;  &lt;/p&gt;
&lt;p&gt;스위스하면 또 시계 빼놓을 수 없지 않겠습니까?&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4757345770/&quot; title=&quot;DSCF1428&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4122/4757345770_0e48186ef1_b.jpg&quot; alt=&quot;DSCF1428&quot;&gt;&lt;/a&gt;  &lt;/p&gt;
&lt;p&gt;머리 하나로 세상을 평정한 세기의 학자, 아인슈타인 집입니다.&lt;/p&gt;
&lt;p&gt;사고 실험이라는 유명한 말도 아인슈타인이 만들어낸 것이라고 하는군요.&lt;/p&gt;
&lt;p&gt;어쨌든 머리를 써야겠죠. 머리를…&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4080/4757345684_4d5b15514c_b.jpg&quot; alt=&quot;DSCF1437&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4098/4757345612_3d7b7ea3aa_b.jpg&quot; alt=&quot;DSCF1436&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4756742359/&quot; title=&quot;DSCF1432&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4116/4756742359_7e048039ea_b.jpg&quot; alt=&quot;DSCF1432&quot;&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;생가내 풍경입니다. 참 좁아요.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4757378970/&quot; title=&quot;SG107178&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4115/4757378970_09b4f47ff3_b.jpg&quot; alt=&quot;SG107178&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;아인슈타인 선생님과 접신중… ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4079/4756708831_4d6e1309f3_b.jpg&quot; alt=&quot;DSCF1447&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/51703583@N04/4756708939/&quot; title=&quot;DSCF1448&quot;&gt;&lt;img src=&quot;http://farm5.static.flickr.com/4118/4756708939_771e93805e_b.jpg&quot; alt=&quot;DSCF1448&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;이런 창고 같은 데 상점이 있더군요. 드가보진 않았어요.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[베른에서 인터라켄까지…]]></title><description><![CDATA[6.1…]]></description><link>https://jiniya.net/wp/archives/1475</link><guid isPermaLink="false">https://jiniya.net/wp/archives/1475</guid><pubDate>Sat, 03 Jul 2010 23:56:09 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img src=&quot;http://cfile23.uf.tistory.com/original/151366104C2F062040F8CD&quot; alt=&quot;&quot; title=&quot;스위스 유람선에서&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;6.18…&lt;/p&gt;
&lt;p&gt;아침에 베른 역에 다시 갔다. 유레일을 재발급 받을 수 있는지 알아보기 위해서 였다. 안내원의 대답은 심플했다. 다시 사야 한단다. 저런. 그래서 옆에 있는 아이에게 리옹역에 전화해서 알아봐 줄 수 있냐고 하자 냉정하게 전화 번호도 모른다는 대답만 한다. 호텔로 와서 낙심하고 있다가 이왕 이렇게 된 거 별 수 없겠다는 생각이 든다. 그냥 마음을 비우기로 했다. 그래봐야 100만원 더 쓰는 것 아니겠는가?&lt;/p&gt;
&lt;p&gt;계획대로 아인슈타인 생가로 향했다. kramgee(?) 49를 지도상의 49번인 줄 알고 완전 엉뚱한 곳으로 갔다. 산으로 올라 올라 가는데 이상한 공원 이었다. 도무지 이상해서 벤치에 앉아 있는 아저씨에게 물어 뽰더니 친절하게 가르쳐 주신다. 지도를 들고 있는 게 관광객 처럼 보였다. 공원에서 내려 오면서 곰있는데 구경하고, 시계 앞에서 인증샷 찍고 아인슈타인 생가로 향했다. 생가는 정말 생각보다 볼 게 없었다. 세기의 학자가 이런 곳에 살았다는 사실을 믿을 수가 없었다. 정말 좁았다. 내가 사는 원룸보다 좁았다. 어쨌든 6chf 내고 볼만하진 않았다. 윗층에서 E=mc^2을 말하는 아인슈타인 음성을 들었다는 정도. 내려오니 아랍계 여자 둘이서 물어본다. 아인슈타인 생가가 어떠냐고, 내가 대답했다. nothing to see. 루째른행 티켓은 35chf다. 덴장.&lt;/p&gt;
&lt;p&gt;*여행 근 일주일 째, 3개국 째, 다시 나에게 질문을 던져본다.&lt;/p&gt;
&lt;p&gt;무엇을 느꼈을까? 내가 이 여행에서 얻고 싶었던 건 무엇일까? 돌아가서 무엇을 해야 할까? 무엇이 좋은 선택일까? 앞으로 10년은 뭘 하면서 살아야 하는 걸까? 그냥 단지 포토 포인트 앞에서 사진을 찍는 것이 전부일까? 다른 건 무엇이 있을까? 답을 찾기란 쉽지않다.*&lt;/p&gt;
&lt;p&gt;루째른 역에서 알프나흐슈타트행 유람선을 탔다. 25chf. 시간이 조금남아 카펠교를 구경했다. 나무로 만든 다리가 이렇게 오래 버틸 수 있다는 사실에 새삼 놀란다. 시간이 30분 밖에 없어 빈사의 사자상은 볼 수가 없었다. 다리를 건너 유람선 선착장으로 돌아와서 유람선을 탔다. 비가 추적추적 내리는 날씨, 유람선은 정말 운치있었다. 뷰가 작살이다. 호수는 바닥이 보일 정도로 물이 깨끗했다. 그냥 쩔었다. 알프나흐슈타트 역에서 Gibswil을 거쳐 인터라켄으로 갔다. 아, 유람선에서 어리버리한 한국인 남자를 만났다. P에게 길을 잘 모른다고 인터라켄까지만 따라가도 되냐고 했다. 조금 따라오더니 그는 결국 루째른으로 돌아갔다. 골든패스 파노라마 열차와 일반 열차의 차이는 크지 않았다. 창문이 크다는 정도?&lt;/p&gt;
&lt;p&gt;인터라켄에 도착해서는 호텔에 짐을 풀고 퐁듀를 먹으로 갔다. 호텔 인포가 추천해준 베비스에 갔는데 정말 좋았다. 주인인지 알바인지 아저씨 쑈맨십이 쩔었다. 고기 퐁듀를 시켜놓고 어떻게 먹는지 몰라 점원에게 물어보자 샤브샤브처럼 먹으라고 하는 것 같다. 그러고 나서도 버벅대자 옆에 아줌마들이 웃으면서 어떻게 먹는지를 가르쳐준다. 초큼 쪽팔렸다. 몇 살이냐고 묻는 말에 30이라고 하니 굉장히 놀라는 눈치다. 어려 보인단다. 그러면서 묻는 말. 자기는 몇 살 처럼 보이냐길래 36정도는 돼 보이는데 이뿌게 twenty-six라고 서비스 해줬다. 고맙다고 악수를 청한다. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;아저씨가 스위스 전통 호른을 들고 나와 불어보라고 분위기를 조장한다. P가 나가서 불어 보았으나 제대로 된 소리는 나질 않았다. 워낙 순식간에 벌어진 일이라 사진을 찍어주지 못해 초큼 미한하다. P뒤에 시도한 사람들은 대부분 소리가 났다. 아저씨의 호른 연주가 이어지고 나서는 다들 의자위에 올라가라고 한다. 그러고는 춤추고 난리도 아니었다. 이어서는 유딩때나 했었던 기차 놀이(앞 사람 어깨를 잡고 길게 늘어져서 막 움직이며 노는 것)를 했다. 그리곤 계산하고 나왔다. 원래 그런건지 콜라 2개 값이 계산되지 않았다. 그래서 빛의 속도로 나왔다. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;나와서 인터라켄 시내를 돌아다니다 호텔로 돌아왔다. P가 나이트를 가보자는 말에 호텔 아래 나이트를 갔다. 우리나라 나이트같은 분위기는 아니고 호텔 펍에 약간의 퇴폐를 곁들인 분위기였다. 맥주 2개를 시켰다. 개당 무려 14chf. 뒤에서는 봉춤 쑈를 하고 그랬다. 옆에 우크라이나 여자가 말을 붙여온다. 그래서 이것 저것 노가리를 풀었다. 한국 교육과 여행에 관한 이야기를 주로 했는데, 자기가 스위스를 굉장히 잘 안다며 베른이나 루째른을 가면 자기가 가이드를 해주겠다는 이야기를 한다. 그래서 내가 이미 다 갔다 왔다고 하고는 다음은 이탈리아로 간다고 했다. 어쨌든 대화가 된다는 사실에 나도 초큼 놀랐다. 대화가 무르익을 무렵 녀석이 본색을 드러낸다(참고로 직업 여성임). 자기도 술을 마시고 싶단다. 딱잘라 말했다. 돈 없다고 ㅋㅋ~ 유레일 잃어버려서 기차 값에 돈 수억 쏟아부었노라고 ㅎㅎㅎ~ 그러자 즐거웠다며 악수를 청하고는 돌아간다. 이번 여행에서 일행이 아닌 단일 대상과 나눈 가장 긴 대화였다.&lt;/p&gt;
&lt;p&gt;방에서는 스파를 못간 아쉬움을 욕조에서 달랬다. 욕조가 커서 무척 기분이 좋았다. 하룻밤에 200chf가 넘는 호텔이라면 이정도는 되야지. 암.~&lt;/p&gt;
&lt;p&gt;아참 Gibswil에서 기다릴 때 배가 고파서 옆에 테이크아웃 가게에 가서 케밥박스에 맥주를 먹었다. 13chf에 먹을만 했다. 퐁듀는 34chf 였는데 밥과 감자튀김이 찌라시로 나와 둘이 먹을만한 수준이었다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;그렇다. 여기저기서 웅성거리는 소리가 들리는 듯 하다. 이렇게 멍청한 일정을 누가 짰느냐, 라는 소리가 들린다. ㅋㅋ~ 일정이 이렇게 된 이유는 딱 하나였다. 베른의 아인슈타인 생가가 너무 가보고 싶었기 때문이었다. 베른에서 유레일 분실 시에도 사실은 루째른에서 저 멍청한 일정대로 할 필요는 없었다. 좀더 합리적인 사람이라면 쑨역(?)에서 유람선을 타고 인터라켄을 들어가는 방법을 생각했을 것이다. 그러고 싶었으나 골든패스 파노라마 열차에 대한 환상과 기존에 일정을 저렇게 잡아서 P에게 피해를 주고 싶지 않았다. 어쨌든 알프나흐슈타트행 유람선은 환상이었다. 골든패스 파노라마 열차는 글쎄…&lt;/p&gt;</content:encoded></item><item><title><![CDATA[크기만 큰 루브르…]]></title><description><![CDATA[6/1…]]></description><link>https://jiniya.net/wp/archives/1473</link><guid isPermaLink="false">https://jiniya.net/wp/archives/1473</guid><pubDate>Sat, 03 Jul 2010 23:56:08 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;6/17…&lt;/p&gt;
&lt;p&gt;파리를 떠나는 날이다. 오늘은 루브르 박물관을 갔다. 역시 기대를 져버리지 않고 엄청난 규모를 보여줬다. 광장 앞 피라미드에서 기념 촬영을 몇 번 하고 들어갔다. 아참 아침에 개삽질을 했다. 추배를 민박에 놔두고 온 줄 알고 루브르 근처까지 갔다가 다시 민박집으로 돌아갔다. 근데 민박집으로 가서 아무리 뒤져도 추배는 나오지 않았다. 잃어버렸다 생각하고는 광장히 상심해서는 루브르를 갔다.&lt;/p&gt;
&lt;p&gt;루브르에 들어가서는 규모에 놀랐다. 커도 커도 너무 컸다. 인간의 탈을 쓰고 다 본다는게 불가능해 보였다. 결국 팜플렛에 있는 유명 작품 위주로만 봤다. 투어를 이용하지 않아서 우리 멋대로 헤매면서 봤다. 그러니 자연히 동선에 군더더기가 많고, 길을 잃기 쉽상이었다. 나와서 다시 짐정리를 하다 가방에 있는 추가 배터리를 발견했다. 기분이 정말 굳. 나와서는 이상한 샌드위치 하나를 먹고 리옹역에서 베네치아까지 티켓을 예약하고 스위스로 향했다.&lt;/p&gt;
&lt;p&gt;리옹역에서 열차 예약을 하다 유레일 패스를 잃어버렸다. 처음에는 별 일 아니라 생각했으나 별 일 이었다. 파리에서 스위스까지는 역장 아저씨의 친절로 무료로 갈 수 있었다는 사실에 감사하면서 위안을 삼았다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;단지 모나리자 때문에 가시는 거라면 레알 말리고 싶은 곳입니다. 루브르를 가신다면 체력을 온전히 보전하시고 가세욤. 그리고 투어를 하지 않는다면 나눠주는 오디오 설명서의 가이드를 따르세요. 몇 가지가 있는데요, 유명 작품 위주로 보는거. 왕궁 가이드 머 이렇게요. 그냥 유명 작품 위주로 보는 걸로 하심이 문안한 것 같습니다. 그걸 하지 않으면 무지하게 돌아다니게 될 겁니다. 안그래도 큰데 동선 꼬이면 두 번, 세 번 왔던데 또 가는 불상사가 발생할 수 있어요. 여러분이 무엇을 상상하든지 그 이상의 크기를 경험하게 될 겁니당.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/SG106847.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/SG106847.jpg&quot; alt=&quot;&quot; title=&quot;SG106847&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;루브르 박물관, 역시 분수는 기본 안주. 디폴트.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1369.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1369.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1369&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;루브르의 상징 유리 피라미드. 모든 행자들이 찍고 간다는 바로 그 포토 포인트.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/SG106892.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/SG106892.jpg&quot; alt=&quot;&quot; title=&quot;SG106892&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;일단 모나리자 직행. 설명 세팅하는 중. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1381.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1381.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1381&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;그 유명한 모나리자입니다.&lt;/p&gt;
&lt;p&gt;저 쪼막만한 그림을 나무테 위치도 아닌 그보다 2-3미터 뒤에서나 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;휠체어 탄 경우에 저 나무테 위치에서 볼 수 있습니다. 헐~&lt;/p&gt;
&lt;p&gt;한 쪽 벽면을 통째로 차지하고 있는데요.&lt;/p&gt;
&lt;p&gt;루브르에서 사람들이 가장 많이 모이는 벽면이 아닌가합니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1379.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1379.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1379&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;줌신공. 유리에 비친 무수히 많은 얼굴들 보이시죠.&lt;/p&gt;
&lt;p&gt;스푸마토 기법은 개뿔… 그림을 볼 수가 없습니다. 볼 수가. 교과서가 나아요.&lt;/p&gt;
&lt;p&gt;하도 플래시 터트리고 사진 찍는 사람들이 많아서 옆에 가드에게 물어봤습니다.&lt;/p&gt;
&lt;p&gt;이거 레알 진품이셈? 그렇다는 군요. 헐 더 기가막혀서 재차 따져 물었습니다.&lt;/p&gt;
&lt;p&gt;진품인데 왜 당췌 플래시 터트리는 애들을 놔두는 것이냐? 가드의 답변이 가관입니다.&lt;/p&gt;
&lt;p&gt;우리는 두 명이다. 저거 플래시 터트리고 찍는 사람은 수백명이다. 우리가 어쩌겠냐? 어쩔 수 없다.&lt;/p&gt;
&lt;p&gt;이상 세기의 작품을 지키는 가드의 답변이었습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1388.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1388.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1388&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;전쟁의 여신 니케.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1383.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1383.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1383&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;비너스, 알흠답다는 말 말고 다른 말들은 필요가 없죠. 쩌는군요.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/SG106929.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/SG106929.jpg&quot; alt=&quot;&quot; title=&quot;SG106929&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;진심 사랑합니다. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1385.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1385.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1385&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;제일 크다는 스핑크스. 근데 왜 여기 있을까요?&lt;/p&gt;
&lt;p&gt;이집트보다 더 많은 이집트 유물을 보유하고 있다는 루브르랍니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1386.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1386.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1386&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;가장 오래된 조각 작품. 신석기 것으로 추정된답니다. 멍때리는 표정이 압권입니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1390.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1390.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1390&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1391.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1391.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1391&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;큐피트는 진짜 화살통을 가지고 있었습니다. 아름답지 않습니까? 뒤테가 그냥. 토나오네요. ㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/SG106936.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/SG106936.jpg&quot; alt=&quot;&quot; title=&quot;SG106936&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;일단 작품 발견하면 오디오 설명부터 ㅋ~&lt;/p&gt;
&lt;p&gt;근데 설명이 너무 단순해서 실망했어요.&lt;/p&gt;
&lt;p&gt;전 유명한 작품은 그래도 서프라이즈 정도 수준은 기대를 했었거든요.&lt;/p&gt;
&lt;p&gt;대한항공이 협찬한다는 사실에 좀 놀랐습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/SG106940.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/SG106940.jpg&quot; alt=&quot;&quot; title=&quot;SG106940&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;먼지도 모르고, 그냥 인증이나 하는. 무식한 행자들…&lt;/p&gt;
&lt;p&gt;루브르는 너무 커서 쉽게 지친답니다. 너무 커요. 흐미~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/SG106980.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/SG106980.jpg&quot; alt=&quot;&quot; title=&quot;SG106980&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;뻘쭘하네요.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[에펠탑]]></title><description><![CDATA[…]]></description><link>https://jiniya.net/wp/archives/1833</link><guid isPermaLink="false">https://jiniya.net/wp/archives/1833</guid><pubDate>Sat, 03 Jul 2010 23:56:07 GMT</pubDate><content:encoded>&lt;p&gt;천재 건축가 에펠이 설계했다는 에펠탑. 온니 철근으로 구성해서 더 유명하다죠. 에펠탑 건축에는 엄청난 분량의 철근이 사용되었다고 하는데요. 에펠탑보다 철근을 더 많이 쓰는게 있을까 싶기도 합니다. 참고로 요즘 만들어지는 초 거대 입자 가속기들은 에펠탑보다 더 많은 철근을 사용한다고 그러더군요. 남산타워(ㅋㅋ), 도쿄타워, 씨애틀의 스페이스 니들등을 가봤는데 에펠탑이 젤 특이했습니다. &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/SG106744.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/SG106744.jpg&quot; alt=&quot;&quot; title=&quot;SG106744&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;일단 인증하고 ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/SG106747.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/SG106747.jpg&quot; alt=&quot;&quot; title=&quot;SG106747&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;안어울리는 군인님들께서 너무 많아서 다소 당황했어요.&lt;/p&gt;
&lt;p&gt;테러라도 나는 줄 알았답니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1240.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1240.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1240&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;줄이 이렇게 길어요. 괜히 인증한 것 같아요. 줄이나 빨리 설 것을. ㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF12441.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF12441.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1244&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;이런 엘레베이터를 타고 갑니다. 걸어가진 않으니 너무 걱정하지 마세요. ㅋㅋ~&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1253.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1253.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1253&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1256.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1256.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1256&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1268.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1268.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1268&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2층에 내려서 보면 참 높구나 생각듭니다. 파리 시내가 한 눈에 보이죠.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1287.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1287.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1287&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1329.jpg&quot;&gt;&lt;img src=&quot;http://jiniya.net/wp/wp-content/uploads/2010/07/DSCF1329.jpg&quot; alt=&quot;&quot; title=&quot;DSCF1329&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;하지만 3층을 올라간다면 그건 높이도 아니었구나. 여기가 에펠탑이구나 하는 생각이 절로 듭니다.&lt;/p&gt;
&l