전문가를 위한 C Flipbook PDF

https://www.hanbit.co.kr/store/books/look.php?p_code=B6135642963

100 downloads 109 Views 5MB Size

Recommend Stories


Porque. PDF Created with deskpdf PDF Writer - Trial ::
Porque tu hogar empieza desde adentro. www.avilainteriores.com PDF Created with deskPDF PDF Writer - Trial :: http://www.docudesk.com Avila Interi

EMPRESAS HEADHUNTERS CHILE PDF
Get Instant Access to eBook Empresas Headhunters Chile PDF at Our Huge Library EMPRESAS HEADHUNTERS CHILE PDF ==> Download: EMPRESAS HEADHUNTERS CHIL

Story Transcript

전문가를 위한

C

전문가를 위한 C 동시성, OOP부터 최신 C, 고급 기능까지! 극한의 C를 마주하려는 여행자를 위한 가이드북 초판 1쇄 발행 2022년 10월 12일 지은이 캄란 아미니 / 옮긴이 박지윤 / 펴낸이 김태헌 펴낸곳 한빛미디어 (주) / 주소 서울시 서대문구 연희로2길 62 한빛미디어(주) IT출판부 전화 02 – 325 – 5544 / 팩스 02 – 336 – 7124 등록 1999년 6월 24일 제 25100 – 2017–  000058호 / ISBN 979  – 11 –  6921 –  034 –8

93000

총괄 전정아 / 책임편집 서현 / 기획·편집 정지수 / 교정 박지영 베타리더 강수연, 권성민, 박수빈, 사지원, 손승하, 이승표 디자인 표지 최연희 내지 박정화 / 전산편집 이경숙 영업 김형진, 김진불, 조유미 / 마케팅 박상용, 송경석, 한종진, 이행은, 고광일, 성화정 / 제작 박성우, 김정우 이 책에 대한 의견이나 오탈자 및 잘못된 내용에 대한 수정 정보는 한빛미디어(주)의 홈페이지나 아래 이메일로 알려주십시오. 잘못된 책은 구입하신 서점에서 교환해드립니다. 책값은 뒤표지에 표시되어 있습니다. 한빛미디어 홈페이지 www.hanbit.co.kr / 이메일 [email protected]

© HANBIT MEDIA INC. 2022. Copyright ©Packt Publishing 2019. First published in the English language under the title ‘Extreme C – (9781789343625)’ This translation is to be published and sold by permission of Packt Publishing, the owner of all rights to publish and sell the same. 이 책의 저작권은 Packt Publishing과 한빛미디어(주)에 있습니다. 저작권법에 의해 보호를 받는 저작물이므로 무단 복제 및 무단 전재를 금합니다.

지금 하지 않으면 할 수 없는 일이 있습니다. 책으로 펴내고 싶은 아이디어나 원고를 메일 ( [email protected] ) 로 보내주세요. 한빛미디어(주)는 여러분의 소중한 경험과 지식을 기다리고 있습니다.

동시성, OOP부터 최신 C, 고급 기능까지! 극한의 C를 마주하려는 여행자를 위한 가이드북

전문가를 위한

C

캄란 아미니 지음 박지윤 옮김

베타리더 후기

실무만으로 채울 수 없는 부분을 채워주는 책. 주니어에게 너무 좋은 책입니다. 강수연, 임베디드 소프트웨어 개발자

C 언어를 오랫동안 사용한 개발자라도 이 책에서 다루는 다양한 지식을 익숙하게 사용하거나 모든 내용을 사용해본 개발자는 많지 않을 겁니다. 단순히 C 언어의 기능을 나열하는 것이 아 닌, 실행 파일부터 메모리 구조, 테스트에 이르기까지 C 언어를 다루는 시니어 개발자에게 필 요한 내용을 담았습니다. 그만큼 이 책은 전문성도 갖추고, 가독성도 훌륭한 완벽한 책입니다. 이 책은 C 언어 초중급 개발자를 전문가 수준으로 끌어올릴 수 있는 내용으로 가득 차 있습니 다. 탄탄한 예제와 상세한 설명, 다양하지만 꼭 필요한 내용을 담아 C 언어 시니어 개발자가 될 수 있는 훌륭한 이정표 역할을 합니다. 지금까지 읽어본 많은 C 언어 도서 중 꼭 읽어야 할 필 독서로 추천합니다. 손승하, 삼성전자

C++11만 사용하다가 이 책을 접하며 C 언어도 C11을 시작으로 모던modern C로 변화가 이루 어지고 있다는 사실을 알게 되었습니다. 이 책을 읽으며 인상적이었던 부분은 C11 이후의 변 화뿐만 아니라 C 언어의 특성과 활용을 좀 더 깊이 있게 다룬다는 점이었습니다. 예를 들면 C 언어를 C++과 비슷하게 사용하려면 어떻게 표현할 수 있는지, 소스 코드가 최종적으로 플랫 폼에서 실행되기까지의 과정을 상세하게 설명합니다. C 언어는 다른 언어와 통합하기 쉬운 언 어인데 이와 관련된 내용도 다루며 C 언어로 작성한 라이브러리를 다른 언어와 연동해보는 연 습도 매우 유용했습니다. 모던 C뿐만 아니라 C 언어가 실행 파일로 변환되는 과정과 C++ 언 어와의 비교 및 유사하게 사용하는 방법 그리고 표준 C 언어 등 다양한 주제를 생각해볼 수 있 는 책이라 읽는 내내 도움이 많이 되었습니다. 이승표, 게임 서버 프로그래머

4

C의 기본 문법을 익힌 후에 C로 어떤 것을 할 수 있는지, 코드가 어떤 방식으로 작동하는지 자 세히 안내하는 책입니다. 업무에 즉각적으로 도움이 되는 설명으로 가득 차 있습니다. 자세한 설명과 예제를 직접 실행해보며 코드가 작동 가능한 실행 파일로 생성되는 과정을 이해할 수 있었습니다. 특히 동시성을 다루는 5부에서는 단계별 작업을 코드 박스를 통해 세세하게 설명 하고, 헷갈리는 용어와 개념도 자세히 설명해 명확하게 내용을 정리할 수 있었습니다. 또한 빌 드 시스템에 대해서도 간략히 소개하며, 그 덕분에 실제로 프로젝트에 포함된 파일들이 어떤 역할을 하는지도 알 수 있었습니다. C 언어의 기본 문법을 익힌 후, 좀 더 빨리 이 책을 접했더 라면 실력이 더 빨리 늘었을 거라 생각합니다. 권성민, 스마트레이더시스템 선임연구원

절차지향 프로그래밍 언어인 C 언어를 이용해 객체지향 프로그래밍을 시도하는 부분이 매우 흥미로웠습니다. C 언어는 객체지향이 될 수 없다는 것을 인정하고 시작하지만, 그럼에도 불구 하고 이를 구현하기 위해 객체지향의 특성에서부터 세심하게 접근합니다. 그 결과 각 특성을 C 언어로 최대한 유사하게 구현했으며, 저 스스로도 객체지향 프로그래밍의 본질을 깊이 들여다 볼 수 있는 기회였습니다. 그 외에도 C 언어를 이용해 심도 있는 다양한 주제를 제시하고 설명 함으로써, 많은 C 언어 개발자에게 도전의 기회를 제공하는 책입니다. 박수빈, 엔씨소프트 개발자

C 프로그래밍 언어에 대한 매우 자세한 설명과 고급 활용법뿐만 아니라 컴파일 언어의 특징(컴 파일러), 그리고 프로그램이 작성되는 운영체제를 포함해 광범위한 내용을 다루는 책입니다. 이 책에서 설명하는 내용은 다른 프로그래밍 언어를 사용할 때도 충분히 도움 되는 내용이며, 특히 C++을 주로 사용하고 있다면 반드시 읽어야 합니다. 사지원, 카카오모빌리티

5

지은이·옮긴이 소개

지은이

캄란 아미니 Kamran Amini

임베디드 및 커널 전문 개발자. 이란의 여러 유명 회사에서 시니어 엔지니어, 아키텍트, 컨설 턴트, CTO로 근무했습니다. 2017년에는 유럽으로 건너가 제퍼슨 Jeppesen, 아데코 Adecco, 톰 톰 TomTom, 액티브비디오 네트웍스 ActiveVideo Networks와 같은 명망 높은 회사에서 시니어 아키텍 트 겸 엔지니어로 근무했습니다. 암스테르담에 머무르는 동안 이 책을 집필했으며 주된 관심 분야는 컴퓨터 이론, 분산 시스템, 머신러닝, 정보 이론, 양자 컴퓨터입니다. 직업적 커리어를 쌓으면서 천문학과 행성학도 공부합니다. 우주의 초기 발생, 블랙홀의 기하학, 양자장론, 끈 이 론 분야에 학술적 관심을 두고 있습니다.

옮긴이

박지윤 [email protected]

판교의 한 프런트엔드 개발자. C 언어에 관심이 있는 프런트엔드 개발자라니, 하나만 잘하기에 도 벅찬 인생이지만 이 책의 저자만큼이나 관심사가 넓은 편입니다. 언젠가 웹 공간에 원하는 비주얼과 사운드를 펼쳐 놓을 수 있기를 희망하며 관련 공부를 하고 있습니다. C 언어에 대한 관심은 사운드/오디오 개발에서 비롯했습니다. 우주에 대해 캄란 아미니만큼 학술적 관심이 있 지는 않지만, 블랙홀에 대한 최신 소식이 나오면 찾아보거나, 물리학자 카를로 로벨리Carlo Rovelli 의 신간이 나오면 사서 읽어보곤 합니다.

6

리뷰어 소개

리뷰어

알리악바르 아바시 Aliakbar Abbasi

여러 기술과 프로그래밍 언어를 사용하며 6년 이상의 개발 경험이 있는 소프트웨어 개발자이 자 OOP, C/C++, 파이썬 전문가. 기술 서적으로 주로 학습하며 소프트웨어 개발에 대한 지식 을 넓히고 있습니다. 요즘은 암스테르담에서 아내와 함께 지내며 톰톰 TomTom에서 시니어 소프 트 엔지니어로 근무합니다.

리뷰어

로힛 탈워커 Rohit Talwalkar

C, C++, 자바 분야의 아주 숙련된 소프트웨어 개발자. 유료 RTOS (실시간 운영체제), 윈도 우, 윈도우 모바일 장치 그리고 안드로이드 플랫폼에서 애플리케이션, 드라이버 및 서비스를 개발합니다. 뭄바이의 명망 있는 인도 공과대학교에서 기술 학사를 취득했으며 컴퓨터 과학 석 사 학위가 있습니다. 모토로라와 블랙베리에서 근무했으며, 지금은 혼합현실(MR ) 안경을 만 들고 공간 컴퓨팅을 전문으로 하는 매직 리프 Magic Leap에서 애플리케이션 개발 리드 엔지니어 로 일합니다. 브라이언 오버랜드 Brian Overland의 『C++ for the Impatient (참을성 없는 사람을 위한 C++)』의 리뷰에 참여하기도 했습니다.

7

옮긴이의 말

C 언어라는 만만치 않은 주제에 원서 제목에는 ‘익스트림(Extreme )’까지 붙은 데다, 원서 기 준 무려 800여 페이지에 달하는 책이 첫 번역서라니! 작업을 시작할 때는 부담감이 컸지만, 페 이지를 넘길수록 반드시 넘어보고 싶은 산이 되었습니다. 이 책은 C 개발자가 아니더라도 한 번은 읽어보면 좋을 내용으로 가득했습니다. 저자는 이 책의 대상 독자를 C 언어 전문가가 되고자 하는 사람으로 보았지만, 저는 초보자가 시니어가 될 때까지 옆에 두고 계속 보아도 좋은 책이라고 생각합니다. C 언어 그 자체뿐만 아 니라 C 언어와 컴퓨터의 역사, 객체지향, 커널, 스레드, 프로세스, 다른 언어와의 통합에 이르 기까지 그야말로 여러 주제를 폭넓게 다룹니다. 그만큼 C 언어가 IT 기술에 미치는 영향이 방 대하다는 증거이며, C 언어가 아직도 건재한 이유겠지요. C 언어를 전문으로 다루지 않는 사 람이라도 여러 개념과 역사를 훑고 싶다면 이 책은 유용하리라고 봅니다. 역자는 한 사람이지만 번역하는 과정에서 결코 혼자 하는 일이라 생각지 않았습니다. 사실 어 떤 일이든 혼자 할 수 있는 일은 거의 없을 겁니다. 본업인 개발도 그렇고요. 여러분이 혼자 이 책을 읽게 되더라도, 이를 매개로 많은 사람과 연결될 수 있기를 바라고, 이를 통해 더 좋은 일, 더 재미있는 일을 하실 수 있기를 바랍니다. 책을 작업하는 동안 편집자님들의 수고가 컸는데 옮긴이만 혼자 글을 남기려니 머쓱하네요. 정 지수 편집자님, 박지영 실장님, 이 지면을 빌려 감사의 인사를 전합니다. 그리고 작업을 끝까지 믿고 맡겨주신 서현 팀장님, 한빛미디어 측에도 감사드립니다. 박지윤

8

이 책에 대하여

현대 사회에서 우리는 매일 놀라운 기술과 마주합니다. 기술의 발전으로 불과 수십 년 전에는 상상할 수도 없었던 호사와 행복을 누리고 있습니다. 자율주행이 현실이 되는 시대를 살고 있 으며 물리학 및 기타 과학 분야가 진보하면서 현실을 인식하는 방식도 변하고 있습니다. 양자 컴퓨터가 이제 막 걸음마를 시작했다는 뉴스, 블록체인 기술과 암호화폐에 관한 소식, 다른 행 성을 개척한다는 뉴스를 접합니다. 놀랍게도 이런 다양한 혁신의 뿌리는 단 몇 가지 핵심 기술 에 있습니다. 이 책은 핵심 기술 중 하나인 C를 다룹니다. 필자는 고등학교 1학년 때 C++로 프로그래밍을 시작했습니다. 당시 학교에서 2학년 대상의

2D 축구 시뮬레이션 팀에 가입하면서 C++에 이어 리눅스와 C를 알게 되었습니다. 그때는 C와 유닉스의 중요성을 잘 몰랐습니다. 하지만 점차 여러 프로젝트를 통해 C와 유닉스에 대한 경험을 쌓았고, 관련 교육을 들으며 C와 유닉스의 중요한 역할과 위치를 이해했습니다. C에 대 해 알면 알수록 C의 매력에 빠지게 되었고, 마침내 필자의 관심을 사로잡았던 이 언어의 전문 가가 되기로 결심했습니다. 또한 지식을 널리 전파하고 사람들에게 C의 중요성을 알리는 지지 자가 되기로 했습니다. 이 책은 그러한 결심의 결과물입니다.

C는 죽은 언어라는 오해와 일부 기술 전문가들의 무시에도 불구하고, 티오베 TIOBE에서 확인할 수 있는 티오베 지수1는 이를 반증합니다. C는 자바와 함께 지난 15년간 가장 인기 있는 언어 였습니다. 그리고 최근 몇 년 동안 인기가 더 높아지고 있습니다. 필자는 여러 BSD 유닉스 계열과 리눅스, 윈도우를 포함한 다양한 플랫폼에서 C, C++, 고Go, 자바, 파이썬을 사용해 수년간 개발 및 설계 경험을 쌓았고, 그 결과 이 책을 쓰게 되었습니다. 이 책의 주요 목표는 독자의 스킬을 한 단계 높이는 것입니다. C를 사용할 때 한 단계 더 나아 갈 수 있도록 하고, 애써 경험한 내용을 실용적으로 적용하기 위함입니다. 쉬운 여정은 아닐 것 입니다. 그래서 이 책의 원서 제목을 『Extreme C』라고 지었습니다. C로 향하는 여정이 이 책의 핵심 주제이므로 다른 프로그래밍 언어에 관해 논쟁하지는 않겠습니다. 실용적인 책이 되기를 바라지만, 실제 적용과 관련된 핵심 이론도 꽤 많이 설명해야 합니다. 이 책에는 실제 시스템에 1 https://www.tiobe.com/tiobe-index

9

서 마주할 상황을 대처하는 방식을 다루는 예제가 가득합니다. 이런 무거운 주제를 다룰 수 있게 되어 매우 영광입니다. 이토록 의미 있는 주제로 집필하게 된 것도 정말 큰 기쁨입니다. 이 기쁨과 놀라움은 첫 책을 쓸 수 있도록 격려해준 앤드루 왈드 론 Andrew Waldron 덕분입니다. 또한 이 여정을 한 장 한 장 함께한 개발 편집자 이언 휴 Ian Hough에게도 깊은 감사를 전합니다. 지치지 않고 피드백해준 동료 알리아크바르 아바시 Aliakbar Abbasi, 키쇼어 리트 Kishor Rit, 가라프 가바스 Gaurav Gavas, 베로니카 파이스 Veronica Pais 그리고 이 책을 준비하고 출판하는 데 최선의 노 력을 기울여준 소중한 분들에게 감사를 전합니다. 여러분을 이 긴 여정에 함께 할 동반자로 초대합니다. 이 책을 읽으면서 변화가 증명되기를, 여 러분이 C를 새로운 시선으로 볼 수 있기를, 그리고 이 과정을 거쳐 더 나은 개발자가 될 수 있 기를 바랍니다.

대상 독자 C와 C++ 개발에 관해 최소한의 지식을 가진 독자를 위해 썼습니다. C/C++ 주니어와 중급 엔 지니어가 주요 독자입니다. 이 정도 지식이라면 이 책을 최대한 활용할 수 있으며 자신의 전문 지식도 최대한 사용할 수 있습니다. 책을 읽고 나서 시니어 엔지니어로 거듭날 수 있기를 바랍 니다. 더불어 도전 의식을 북돋우고, 더 높은 연봉과 훨씬 더 유의미한 직무를 맡을 수 있기를 바랍니다. 일부 주제는 시니어 C/C++ 엔지니어에게도 유용합니다. 하지만 시니어 엔지니어라 면 대부분의 주제는 익히 알고 있을 것이며 몇 가지 세부 사항 정도가 유용할 것입니다. 이 책은 학생과 연구자에게도 유용한 내용을 다룹니다. 컴퓨터 과학, 소프트웨어 엔지니어링, 인공지능, 사물 인터넷(IoT ), 천문학, 입자 물리학, 우주학과 같은 과학이나 공학 분야의 학 사, 석사, 박사 과정을 밟는 학생뿐만 아니라 해당 분야의 연구자라면 이 책을 통해 C/C++, 유닉스 계열 운영체제, 관련 프로그래밍 스킬을 향상할 수 있습니다. 이 책은 복잡한 원격 제어 장치, 시뮬레이션, 빅데이터 처리, 머신러닝, 딥러닝 등을 수행하거나, 멀티스레드 또는 멀티프

10

로세스 시스템에서 작업하는 엔지니어와 과학자에게도 유용합니다.

다루는 내용 이 책은 7부 part로 구성됩니다. 각 부에서는 C 프로그래밍의 특정 측면을 다룹니다. 1부에서는

C 프로젝트를 빌드하는 방법, 2부에서는 메모리, 3부에서는 객체지향에 초점을 맞춰 설명하 고, 4부에서는 주로 유닉스와 C의 관계를 살펴봅니다. 5부에서는 동시성을, 6부에서는 프로세 스 간 통신을 다루며, 마지막으로 7부에서는 테스트 및 유지 보수에 관해 다룹니다. 다음은 총

23개 장의 핵심 주제를 요약한 내용입니다.

1부 C 프로젝트 빌드 1장 필수 요소: C에서 찾아볼 수 있는 필수 요소를 소개합니다. 이 요소들은 C를 사용하는 방식에 중대



한 영향을 미칩니다. 이 책 전반에 걸쳐 이러한 기능을 자주 사용할 예정입니다. 주요 주제는 전처리 및 매크로를 정의하는 지시자, 변수와 함수 포인터, 함수 호출 메커니즘 그리고 구조체입니다. 2장 소스 코드에서 이진 파일로: C 프로젝트를 빌드하는 방법에 관해 설명합니다. 전체 파이프라인 및



개별 파이프라인 구성 요소의 관점에서 컴파일 파이프라인을 상세히 배워봅니다. 3장 목적 파일: 컴파일 파이프라인을 사용해 빌드한 이후의 C 프로젝트 결과물을 살펴봅니다. 목적 파



일과 그 다양한 종류를 소개합니다. 또한 목적 파일 내부를 들여다보고 어떤 정보를 추출할 수 있는지 알 아봅니다.

2부 메모리 4장 프로세스 메모리 구조: 프로세스 메모리 레이아웃을 들여다봅니다. 메모리 레이아웃에 어떤 세그먼트



가 있는지, 그리고 정적 메모리 레이아웃과 동적 메모리 레이아웃이 뜻하는 바가 무엇인지도 살펴봅니다. 5장 스택과 힙: 스택과 힙 세그먼트를 구체적으로 다룹니다. 스택과 힙 변수를 설명한 뒤 그 수명을 C에



서 관리하는 방법을 이야기합니다. 힙 변수에 관한 모범 사례를 알아보고 힙 변수를 관리하는 방법도 살 펴봅니다.

11

3부 객체지향 6장 OOP와 캡슐화: C의 객체지향을 다루는 네 개 장 중 첫 번째 장입니다. 6장에서는 객체지향의 배경



이론을 살펴보고, 관련 자료에서 자주 사용하는 용어의 중요한 정의를 짚어봅니다. 7장 합성과 집합: 합성과 합성의 특수한 형태인 집합에 초점을 맞춥니다. 합성과 집합의 차이를 살펴보



고 이들의 차이를 확인할 수 있는 예제를 제공합니다. 8장 상속과 다형성: 상속은 객체지향 프로그래밍에서 가장 중요한 주제입니다. 8장에서는 두 클래스 사



이에서 상속 관계를 만드는 방법과 C에서 이를 어떻게 수행하는지 알아봅니다. 중요한 논제인 다형성에 대해서도 살펴봅니다. 9장 추상화와 C++의 OOP : 추상화에 관해 설명합니다. 구체적으로는 추상화의 자료형 및 C에서 구현



하는 방법을 논의합니다. C++의 내부를 살펴보고 객체지향이라는 개념을 C++에서 어떻게 구현하는지 예제로 알아봅니다.

4부 유닉스 10장 유닉스의 역사와 아키텍처: C와 유닉스는 서로 뗄 수 없는 관계입니다. 10장에서는 왜 C와 유닉스



가 서로 강하게 연결되어 있는지, 그리고 서로가 살아남을 수 있도록 어떻게 도왔는지 설명합니다. 유닉 스의 아키텍처도 학습하며, 운영체제가 제공하는 기능을 프로그램이 어떻게 사용하는지도 배워봅니다. 11장 시스템 호출과 커널: 유닉스 아키텍처의 커널 링을 중점적으로 살펴봅니다. 시스템 호출을 자세히



살펴보고, 리눅스에 새로운 시스템 호출을 추가해봅니다. 커널의 다양한 유형을 살펴보고, 커널 모듈이 작동하는 방식을 알아보기 위해 리눅스에 새로운 간단한 커널 모듈을 작성해봅니다. 12장 최신 C : 최신 버전의 C 표준인 C18에 관해 알아봅니다. 이전 버전인 C11과 얼마나 다른지 살펴



봅니다. 또한 C99와 비교해 새로 추가된 몇몇 특성의 예를 알아봅니다.

5부 동시성 13장 동시성: 동시성 개념을 살펴보고, 동시 환경 및 인터리빙과 같은 다양한 속성을 소개합니다. 이러한



시스템이 비결정론적인 이유와 경쟁 상태와 같은 동시성 문제가 어떻게 발생하는지 알아봅니다.

12

14장 동기화: 동시 환경에 대한 논의를 계속합니다. 동시 시스템에서 관찰할 수 있는 다양한 문제 유형



에 관해서도 논의합니다. 여러 문제 유형 중 이 책에서는 경쟁 상태, 데이터 경쟁 및 교착 상태를 다룹니 다. 이러한 문제 해결 방법과 세마포어, 뮤텍스, 조건 변수를 설명합니다. 15장 스레드 실행: 여러 스레드를 실행하고 관리하는 방법을 예제와 함께 살펴봅니다. 또한 14장에서



논의한 동시성 문제에 관한 실제 C 예제도 제공합니다. 16장 스레드 동기화: 여러 스레드를 동기화할 수 있는 기법을 알아봅니다. 중요한 주제인 세마포어, 뮤



텍스 및 조건 변수를 예제와 함께 살펴봅니다.

6부 프로세스 간 통신 17장 프로세스 실행: 새로운 프로세스를 생성 및 스폰할 수 있는 방법을 설명합니다. 또한 여러 프로세



스 사이에서 상태를 공유하는 푸시, 풀 기반 기법에 관해 논의해보고 14장에서 다뤘던 동시성 문제를 실제 C 사례로 살펴봅니다. 18장 프로세스 동기화: 동일한 머신에 탑재된 여러 프로세스를 동기화할 때 이용할 수 있는 메커니즘을



다룹니다. 프로세스-공유 세마포어, 프로세스-공유 뮤텍스, 프로세스-공유 조건 변수 기법을 살펴봅 니다. 19장 싱글 호스트 IPC와 소켓: 푸시 기반 프로세스 간 통신 기법을 다룹니다. 동일한 머신에 탑재된 프



로세스에서 사용할 수 있는 기법에 주로 초점을 맞춥니다. 소켓 프로그래밍을 소개하고, 네트워크에 있 는 서로 다른 노드에 탑재된 프로세스 사이에 채널을 설정할 때 필요한 배경도 소개합니다. 20장 소켓 프로그래밍: 예제를 통해 소켓 프로그래밍을 살펴봅니다. 여러 다양한 종류의 소켓을 지원하



는 예제를 살펴보며 논의를 지속해봅니다. 스트림 또는 데이터그램 채널에서 작동하는 유닉스 도메인 소켓, TCP, UDP 소켓을 설명합니다. 21장 다른 언어와의 통합: 공유 목적 파일로 빌드된 C 라이브러리가 로드되는 방식과 C++, 자바, 파이



썬, 고로 작성한 프로그램에서 해당 라이브러리가 사용되는 방식을 설명합니다.

13

7부 테스트와 유지 보수 22장 유닛 테스트와 디버깅: 테스트와 디버깅을 설명합니다. 여러 수준의 테스트를 소개하며, 특히 C



의 유닛 테스트 중심으로 설명합니다. C에서 테스트 스위트를 작성할 때 사용할 수 있는 라이브러리인 CMocka와 구글 테스트를 소개합니다. 디버깅의 개념과 다양한 버그를 디버깅할 때 사용할 수 있는 여 러 도구도 살펴봅니다. 23장 빌드 시스템: 빌드 시스템 및 빌드 스크립트 생성기에 관해 설명합니다. 메이크 Make, 닌자 Ninja, 바



젤 Bazel 빌드 시스템과 빌드 스크립트 생성기인 CMake를 소개합니다.

활용 방법 앞서 설명한 대로 이 책을 읽으려면 컴퓨터 프로그래밍과 관련한 최소한의 지식과 기술이 필요 합니다. 최소한의 요구 사항은 다음과 같습니다. 컴퓨터 아키텍처 지식: 메모리, CPU, 주변 장치와 그 특성을 알아야 합니다. 그리고 프로그램이 컴퓨터



시스템에서 이러한 요소와 어떻게 상호작용하는지도 알아야 합니다. 프로그래밍 기초 지식: 알고리듬이 무엇인지, 알고리듬의 실행을 어떻게 추적하는지, 소스 코드란 무엇



인지, 이진수는 무엇인지, 이와 관련된 수학 개념을 알아야 합니다. 터미널과 셸 명령어 사용법: 리눅스나 macOS 같은 유닉스 계열 운영체제의 터미널과 기초 셸 명령어



에 익숙해야 합니다. 프로그래밍 중급 지식: 최소한 하나의 프로그래밍 언어에서 사용하는 조건문, 여러 종류의 루프, 구조체



또는 클래스, C나 C++의 포인터, 함수 등과 같은 프로그래밍 주제에 대한 중급 지식이 필요합니다. 객체지향 프로그래밍 기초 지식: 객체지향 프로그래밍에 관해서는 이 책에서 상세히 다룰 예정이니 필



수는 아닙니다. 하지만 기초 지식을 알고 있다면 이 책의 3부 객체지향을 읽을 때 더 잘 이해할 수 있습 니다.

14

NOTE_ 깃허브 저장소에서 코드를 내려받아서 셸 박스에 있는 명령어를 따라 해보기를 바랍니다. 리눅스나

macOS에 설치된 플랫폼을 이용하세요. 다른 POSIX 호환 운영체제에서도 사용할 수 있습니다.2 ●

https://github.com/PacktPublishing/Extreme-C 

예제 사용 규칙 이 책에서는 코드 박스와 셸 박스를 사용합니다. 코드 박스는 C 코드 또는 의사코드 pseudo-code 를 담고 있습니다. 코드 박스의 내용을 코드 파일에서 가져올 때는 코드 파일의 이름이 박스 위 에 적혀 있습니다. 코드 박스 예제는 다음과 같습니다. 코드 박스 17-1 fork API로 자식 프로세스 생성하기(ExtremeC_examples_chapter17_1.c)

#include #include int main(int argc, char** argv) { printf("This is the parent process with process ID: %d\n", getpid()); printf("Before calling fork() ...\n"); pid_t ret = fork(); if (ret) { printf("The child process is spawned with PID: %d\n", ret); } else { printf("This is the child process with PID: %d\n", getpid()); } printf("Type CTRL+C to exit ...\n");

2 옮긴이_ 역자의 실행 환경은 우분투 18.04.6 LTS, 설치된 gcc 버전은 7.5.0입니다. 우분투는 Virtual Box에 설치했습니다. 2022년 8월 현재, 이 버전의 우분투에서 gcc 설치 시 7.5.0 버전이 선택됩니다. 필자는 gcc 7.3.0으로 실행한 결과를 제시했으나, 우 분투 18.04 LTS 환경에서 gcc 7.3.0 설치를 시도하면 7.5.0 이상 버전 설치가 필요하다는 경고가 나옵니다. 따라서 필자와 완벽히 동 일한 실행 환경을 구성하기 어려운 점을 감안해 역자의 실행 환경은 현재 대부분의 독자가 설정에 큰 어려움이 없을 gcc 7.5.0으로 택했 습니다.

15

while (1); return 0; }

이 코드는 ExtremeC_examples_chapter17_1.c 파일에 있습니다. 앞서 소개한 깃허브에 서 코드 묶음을 다운로드한 뒤 ch17-process-execution 디렉터리를 살펴보면 해당 코드 가 있습니다. 만약 코드 박스에 파일명이 없다면, 코드 묶음에서 찾을 수 없는 의사코드나 C 코드입니다. 아 래 예제를 봅시다. 코드 박스 13-1 다섯 개 명령어가 있는 간단한 작업

작업 P 1. 2. 3. 4. 5. }

{ num = 5 num++ num = num – 2 x = 10 num = num + x

코드 박스 안에는 가끔 밑줄을 치거나 굵은 글자로 표시한 것이 있습니다. 이러한 밑줄은 코드 박스 이전에 다뤘거나 이후에 다룰 코드 행입니다. 여러분의 편의를 위해 굵게 표시했습니다. 셸 박스는 여러 셸 명령어를 실행하는 동안 터미널에서 출력된 결과를 확인할 수 있습니다. 명 령어는 주로 굵은 글자로 표시되며 결과는 일반 폰트로 표시합니다. 아래 예제를 봅시다.

16

셸 박스 17-6 [예제 17-4]에서 생성한 공유 메모리 객체를 읽고 마지막으로 제거하기

$ ls /dev/shm shm0 $ gcc ExtremeC_examples_chapter17_5.c -lrt -o ex17_5.out $ ./ex17_5.out Shared memory is opened with fd: 3 The contents of the shared memory object: ABC $ ls /dev/shm $

명령어는 $ 또는 #로 시작합니다. $로 시작하는 명령어는 일반 사용자 권한으로 실행하고 #로 시작하는 명령어는 슈퍼유저로 실행합니다.  셸 박스의 작업 디렉터리는 대부분 해당 장의 디렉터리와 동일합니다. 작업 디렉터리에서 특정 디렉터리를 찾을 때는 필요한 정보를 함께 제공하니 걱정하지 마세요.

17

감사의 말

어머니 이터람 Ehteram에게 감사를 전합니다. 어머니께서는 헌신적으로 저와 형제 아슈칸 Ashkan 을 키우셨습니다. 어머니는 언제나 저를 응원하고 계신다고 확신합니다. 그리고 제 아름답고 사랑스러운 아내 아프사네 Afsaneh에게도 고마움을 전합니다. 아내는 이 책을 작업하는 내내 저 를 지원해주었습니다. 아내의 인내와 격려가 없었다면 여기까지 해내지 못했을 겁니다. 캄란 아미니

18

CONTENTS

베타리더 후기 ..................................................................................................................

4

지은이·옮긴이 소개 .........................................................................................................

6

리뷰어 소개 ....................................................................................................................

7

옮긴이의 말 ....................................................................................................................

8

이 책에 대하여 ................................................................................................................

9

감사의 말 ....................................................................................................................

PART

18

I C 프로젝트 빌드

CHAPTER

1 필수 요소 1.1 전처리기 지시자 .......................................................................................................... 37 1.1.1 매크로 ................................................................................................................ 38 1.1.2 조건부 컴파일 ...................................................................................................... 53

1.2 포인터 변수 ................................................................................................................ 57 1.2.1 문법 ................................................................................................................... 57 1.2.2 포인터 변수의 산술연산 ......................................................................................... 60 1.2.3 제네릭 포인터 ...................................................................................................... 64 1.2.4 포인터 크기 ......................................................................................................... 66 1.2.5 허상 포인터 ......................................................................................................... 67

1.3 함수 ........................................................................................................................... 70 1.3.1 함수의 구조 ......................................................................................................... 70 1.3.2 설계의 중요성 ...................................................................................................... 71 1.3.3 스택 관리 ............................................................................................................ 72 1.3.4 값에 의한 전달 vs 참조에 의한 전달 ......................................................................... 73

1.4 함수 포인터 ................................................................................................................ 76

19

CONTENTS

1.5 구조체 ........................................................................................................................ 79 1.5.1 왜 구조체인가? .................................................................................................... 79 1.5.2 왜 사용자 정의 자료형인가? ................................................................................... 80 1.5.3 구조체의 역할 ..................................................................................................... 81 1.5.4 메모리 레이아웃 ................................................................................................... 82 1.5.5 중첩 구조체 ......................................................................................................... 87 1.5.6 구조체 포인터 ...................................................................................................... 88

1.6 마무리 ........................................................................................................................ 90

CHAPTER

2 소스 코드에서 이진 파일로 2.1 표준 컴파일 파이프라인 ............................................................................................... 94 2.1.1 프로젝트 빌드하기 ................................................................................................ 96 2.1.2 1단계: 전처리 . ................................................................................................... 103 2.1.3 2단계: 컴파일 . ................................................................................................... 105 2.1.4 3단계: 어셈블리 .................................................................................................. 109 2.1.5 4단계: 링크 ....................................................................................................... 112

2.2 전처리기 ................................................................................................................... 115 2.3 컴파일러 ................................................................................................................... 120 2.3.1 추상 구문 트리 ................................................................................................... 121

2.4 어셈블러 ................................................................................................................... 123 2.5 링커 ......................................................................................................................... 124 2.5.1 링커의 작동 방식 ................................................................................................ 126 2.5.2 링커는 속을 수 있다 ............................................................................................ 135 2.5.3 C++ 네임 맹글링 ................................................................................................ 140

2.6 마무리 ...................................................................................................................... 142

20

CHAPTER

3 목적 파일 3.1 ABI .......................................................................................................................... 144 3.2 목적 파일 형식 .......................................................................................................... 146 3.3 재배치 가능한 목적 파일 ............................................................................................ 148 3.4 실행 가능한 목적 파일 ............................................................................................... 153 3.5 정적 라이브러리 ........................................................................................................ 158 3.6 동적 라이브러리 ........................................................................................................ 168 3.6.1 공유 라이브러리의 수동 로딩 ................................................................................ 173

3.7 마무리 ...................................................................................................................... 176

PART

II 메모리

CHAPTER

4 프로세스 메모리 구조 4.1 프로세스 메모리 레이아웃 .......................................................................................... 180 4.2 메모리 구조 알아보기 ................................................................................................ 182 4.3 정적 메모리 레이아웃 검사하기 .................................................................................. 183 4.3.1 BSS 세그먼트 ................................................................................................... 185 4.3.2 데이터 세그먼트 ................................................................................................. 188 4.3.3 텍스트 세그먼트 ................................................................................................. 192

4.4 동적 메모리 레이아웃 검사하기 .................................................................................. 195 4.4.1 메모리 매핑 ....................................................................................................... 196 4.4.2 스택 세그먼트 .................................................................................................... 201 4.4.3 힙 세그먼트 ....................................................................................................... 203

4.5 마무리 ...................................................................................................................... 207

21

CONTENTS

CHAPTER

5 스택과 힙 5.1 스택 ......................................................................................................................... 210 5.1.1 스택 검사하기 .................................................................................................... 211 5.1.2 스택 메모리 사용 시 주의점 .................................................................................. 219

5.2 힙 ............................................................................................................................ 224 5.2.1 힙 메모리의 할당과 해제 ...................................................................................... 225 5.2.2 힙 메모리 원칙 ................................................................................................... 235

5.3 제한된 환경에서의 메모리 관리 .................................................................................. 239 5.3.1 메모리가 제한된 환경 .......................................................................................... 240 5.3.2 성능이 더 나은 환경 ............................................................................................ 242

5.4 마무리 ...................................................................................................................... 250

PART

III 객체지향

CHAPTER

6 OOP와 캡슐화 6.1 객체지향적 사고 ........................................................................................................ 256 6.1.1 정신적 개념 ....................................................................................................... 256 6.1.2 마인드맵과 객체 모델 .......................................................................................... 258 6.1.3 코드에는 없는 객체 ............................................................................................. 260 6.1.4 객체 속성 .......................................................................................................... 262 6.1.5 도메인 .............................................................................................................. 262 6.1.6 객체 사이의 관계 ................................................................................................ 263 6.1.7 객체지향 작업 .................................................................................................... 264 6.1.8 행위를 갖는 객체 ................................................................................................ 267

22

6.2 C가 객체지향이 아닌 이유 ......................................................................................... 268 6.3 캡슐화 ...................................................................................................................... 269 6.3.1 속성 캡슐화 ....................................................................................................... 269 6.3.2 행위 캡슐화 ....................................................................................................... 272 6.3.3 정보 은닉 .......................................................................................................... 284

6.4 마무리 ...................................................................................................................... 292

CHAPTER

7 합성과 집합 7.1 클래스 간의 관계 ...................................................................................................... 296 7.2 객체 대 클래스 .......................................................................................................... 296 7.3 합성 ......................................................................................................................... 298 7.4 집합 ......................................................................................................................... 306 7.5 마무리 ...................................................................................................................... 313

CHAPTER

8 상속과 다형성 8.1 상속 ......................................................................................................................... 316 8.1.1 상속의 본질 ....................................................................................................... 317

8.2 다형성 ...................................................................................................................... 335 8.2.1 다형성 소개 ....................................................................................................... 335 8.2.2 다형성이 필요한 이유 .......................................................................................... 339 8.2.3 C에서 다형적 행위를 갖는 방법 ............................................................................. 339

8.3 마무리 ...................................................................................................................... 348

23

CONTENTS

CHAPTER

9 추상화와 C++의 OOP 9.1 추상화 ...................................................................................................................... 351 9.2 C++의 객체지향 구성물 ............................................................................................ 356 9.2.1 캡슐화 .............................................................................................................. 356 9.2.2 상속 ................................................................................................................. 360 9.2.3 다형성 .............................................................................................................. 367 9.2.4 추상 클래스 ....................................................................................................... 370

9.3 마무리 ...................................................................................................................... 372

PART

IV 유닉스

CHAPTER

10 유닉스의 역사와 아키텍처 10.1 유닉스의 역사 ..................................................................................................... 376 10.1.1 멀틱스와 유닉스 . ....................................................................................... 376 10.1.2 BCPL과 B ............................................................................................... 378 10.1.3 C로 향하는 길 ........................................................................................... 379

10.2 유닉스 아키텍처 .................................................................................................. 381 10.2.1 철학 ........................................................................................................ 382 10.2.2 유닉스 링 ................................................................................................. 384

10.3 사용자 응용프로그램에 대한 셸 인터페이스 ........................................................... 386 10.4 셸 링에 대한 커널 인터페이스 .............................................................................. 391 10.5 커널 ................................................................................................................... 398 10.6 하드웨어 ............................................................................................................. 402 10.7 마무리 ................................................................................................................ 405

24

CHAPTER

11 시스템 호출과 커널 11.1 시스템 호출 ......................................................................................................... 408 11.1.1 시스템 호출 자세히 보기 .............................................................................. 408 11.1.2 표준 C 건너뛰기: 직접 시스템 호출하기 .......................................................... 410 11.1.3 syscall 함수의 내부 ................................................................................... 413 11.1.4 리눅스에 시스템 호출 추가하기 ..................................................................... 415

11.2 유닉스 커널 ......................................................................................................... 430 11.2.1 모놀리식 커널 대 마이크로커널 ..................................................................... 431 11.2.2 리눅스 ..................................................................................................... 432 11.2.3 커널 모듈 ................................................................................................. 433

11.3 마무리 ................................................................................................................ 440

CHAPTER

12 최신 C 12.1 C11 ................................................................................................................... 442 12.2 C 표준 지원 버전 찾기 ......................................................................................... 443 12.3 gets 함수의 제거 ................................................................................................. 444 12.4 fopen 함수로의 변화 ........................................................................................... 445 12.5 경계 검사 함수 .................................................................................................... 447 12.6 값을 반환하지 않는 함수 ...................................................................................... 448 12.7 타입 제네릭 매크로 .............................................................................................. 449 12.8 유니코드 ............................................................................................................. 450 12.9 익명 구조체와 익명 공용체 ................................................................................... 457 12.10 멀티스레딩 ....................................................................................................... 459 12.11 마무리 .............................................................................................................. 459

25

CONTENTS

PART

V 동시성

CHAPTER

13 동시성 13.1 동시성 소개 ......................................................................................................... 464 13.2 병렬성 ................................................................................................................ 465 13.3 동시성 ................................................................................................................ 467 13.4 작업 스케줄러 유닛 .............................................................................................. 468 13.5 프로세스와 스레드 ............................................................................................... 469 13.6 발생 전 제약 ....................................................................................................... 471 13.7 동시성을 사용해야 하는 경우 ............................................................................... 473 13.8 공유 상태 ............................................................................................................ 481 13.9 마무리 ................................................................................................................ 487

CHAPTER

14 동기화 14.1 동시성 문제 ......................................................................................................... 490 14.2 고유한 동시성 문제 .............................................................................................. 491 14.3 동기화 이후 문제 ................................................................................................. 502 14.4 동기화 기술 ......................................................................................................... 503 14.4.1 바쁜 대기 및 스핀락 .................................................................................... 504 14.4.2 잠자기/알림 메커니즘 ................................................................................. 507 14.4.3 세마포어와 뮤텍스 ...................................................................................... 511 14.4.4 멀티프로세서 유닛 ...................................................................................... 516

14.5 스핀락 ................................................................................................................ 521 14.5.1 조건 변수 ................................................................................................. 523

26

14.6 POSIX의 동시성 .................................................................................................. 525 14.6.1 동시성을 지원하는 커널 ............................................................................... 526

14.7 멀티프로세싱 ....................................................................................................... 528 14.8 멀티스레딩 .......................................................................................................... 531 14.9 마무리 ................................................................................................................ 532

CHAPTER

15 스레드 실행 15.1 스레드 ................................................................................................................ 537 15.2 POSIX 스레드 ..................................................................................................... 540 15.3 POSIX 스레드 스폰하기 ....................................................................................... 542 15.4 경쟁 상태에 대한 예제 ......................................................................................... 548 15.5 데이터 경쟁에 대한 예 ......................................................................................... 557 15.6 마무리 ................................................................................................................ 561

CHAPTER

16 스레드 동기화 16.1 POSIX 동시성 제어 ............................................................................................. 564 16.1.1 POSIX 뮤텍스 .......................................................................................... 564 16.1.2 POSIX 조건 변수 ...................................................................................... 568 16.1.3 POSIX 장벽 ............................................................................................. 572 16.1.4 POSIX 세마포어 ....................................................................................... 575

16.2 POSIX 스레드와 메모리 ....................................................................................... 584 16.2.1 스택 메모리 .............................................................................................. 585 16.2.2 힙 메모리 ................................................................................................. 590 16.2.3 메모리 가시성 ........................................................................................... 596

16.3 마무리 ................................................................................................................ 598

27

CONTENTS

PART

VI 프로세스 간 통신

CHAPTER

17 프로세스 실행 17.1 프로세스 실행 API ............................................................................................... 603 17.1.1 프로세스 생성 ........................................................................................... 607 17.1.2 프로세스 실행 ........................................................................................... 612 17.1.3 프로세스 생성과 실행 비교하기 ..................................................................... 615

17.2 프로세스 실행 단계 .............................................................................................. 616 17.3 공유 상태 ............................................................................................................ 617 17.3.1 공유 기술 ................................................................................................. 618 17.3.2 POSIX 공유 메모리 ................................................................................... 620 17.3.3 파일 시스템 .............................................................................................. 631

17.4 멀티스레딩 대 멀티프로세싱 ................................................................................. 633 17.4.1 멀티스레딩 ............................................................................................... 633 17.4.2 싱글 호스트 멀티프로세싱 ............................................................................ 634 17.4.3 분산 멀티프로세싱 ...................................................................................... 635

17.5 마무리 ................................................................................................................ 636

CHAPTER

18 프로세스 동기화 18.1 싱글 호스트 동시성 제어 ...................................................................................... 638 18.2 기명 POSIX 세마포어 .......................................................................................... 639 18.3 기명 뮤텍스 ......................................................................................................... 643 18.3.1 첫 번째 예제 ............................................................................................. 644 18.3.2 두 번째 예제 ............................................................................................. 648

28

18.4 기명 조건 변수 .................................................................................................... 659 18.4.1 공유 메모리의 클래스 .................................................................................. 660 18.4.2 공유된 32비트 정수 카운터의 클래스 .............................................................. 664 18.4.3 공유 뮤텍스의 클래스 .................................................................................. 666 18.4.4 공유 조건 변수의 클래스 .............................................................................. 670 18.4.5 메인 로직 ................................................................................................. 674

18.5 분산된 동시성 제어 .............................................................................................. 680 18.6 마무리 ................................................................................................................ 682

CHAPTER

19 싱글 호스트 IPC와 소켓 19.1 IPC 기법 ............................................................................................................. 684 19.2 통신 프로토콜 ..................................................................................................... 686 19.2.1 프로토콜 특징 ........................................................................................... 689

19.3 싱글 호스트 통신 ................................................................................................. 691 19.3.1 파일 서술자 .............................................................................................. 692 19.3.2 POSIX 신호 ............................................................................................. 693 19.3.3 POSIX 파이프 .......................................................................................... 697 19.3.4 POSIX 메시지 큐 ...................................................................................... 700 19.3.5 유닉스 도메인 소켓 ..................................................................................... 703

19.4 소켓 프로그래밍 .................................................................................................. 704 19.4.1 컴퓨터 네트워크 . ....................................................................................... 704 19.4.2 소켓 프로그래밍 소개 .................................................................................. 718

19.5 마무리 ................................................................................................................ 724

29

CONTENTS

CHAPTER

20 소켓 프로그래밍 20.1 소켓 프로그래밍 복습 .......................................................................................... 728 20.2 계산기 프로젝트 .................................................................................................. 730 20.2.1 소스 계층 ................................................................................................. 731 20.2.2 프로젝트 빌드하기 ...................................................................................... 735 20.2.3 프로젝트 실행하기 ...................................................................................... 736 20.2.4 응용 프로토콜 ........................................................................................... 737 20.2.5 직렬화/역직렬화 라이브러리 ........................................................................ 741 20.2.6 계산기 서비스 ........................................................................................... 747

20.3 유닉스 도메인 소켓 .............................................................................................. 749 20.3.1 UDS 스트림 서버 ...................................................................................... 749 20.3.2 UDS 스트림 클라이언트 ............................................................................. 758 20.3.3 UDS 데이터그램 서버 ................................................................................ 761 20.3.4 UDS 데이터그램 클라이언트 ....................................................................... 766

20.4 네트워크 소켓 ..................................................................................................... 769 20.4.1 TCP 서버 ................................................................................................. 769 20.4.2 TCP 클라이언트 ........................................................................................ 771 20.4.3 UDP 서버 ................................................................................................ 772 20.4.4 UDP 클라이언트 ....................................................................................... 773

20.5 마무리 ................................................................................................................ 774

CHAPTER

21 다른 언어와의 통합 21.1 통합이 가능한 이유 .............................................................................................. 778 21.2 필수 자료 획득하기 .............................................................................................. 779 21.3 스택 라이브러리 .................................................................................................. 780

30

21.4 C++과 통합하기 ................................................................................................. 788 21.4.1 C++의 네임 맹글링 .................................................................................... 788 21.4.2 C++ 코드 ................................................................................................. 791

21.5 자바와 통합하기 .................................................................................................. 796 21.5.1 자바 부분 작성하기 ..................................................................................... 797 21.5.2 네이티브 부분 작성하기 ............................................................................... 802

21.6 파이썬과 통합하기 ............................................................................................... 812 21.7 고와 통합하기 ..................................................................................................... 816 21.8 마무리 ................................................................................................................ 819

PART

VII 테스트와 유지 보수

CHAPTER

22 유닛 테스트와 디버깅 22.1 소프트웨어 테스트 ............................................................................................... 824 22.1.1 테스트 수준 .............................................................................................. 825

22.2 유닛 테스트 ......................................................................................................... 827 22.2.1 테스트 더블 .............................................................................................. 836

22.3 컴포넌트 테스트 .................................................................................................. 838 22.4 C의 테스트 라이브러리 ........................................................................................ 839 22.4.1 CMocka ................................................................................................. 840 22.4.2 구글 테스트 .............................................................................................. 851

22.5 디버깅 ................................................................................................................ 856 22.5.1 버그의 종류 .............................................................................................. 858 22.5.2 디버거 ..................................................................................................... 859 22.5.3 메모리 검사기 ........................................................................................... 860

31

CONTENTS

22.5.4 스레드 디버거 ........................................................................................... 862 22.5.5 퍼포먼스 프로파일러 ................................................................................... 863

22.6 마무리 ................................................................................................................ 864

CHAPTER

23 빌드 시스템 23.1 빌드 시스템 소개 ................................................................................................. 866 23.2 메이크 ................................................................................................................ 868 23.3 CMake: 빌드 시스템이 아닙니다 .......................................................................... 876 23.4 닌자 ................................................................................................................... 882 23.5 바젤 ................................................................................................................... 884 23.6 빌드 시스템 비교하기 .......................................................................................... 888 23.7 마무리 ................................................................................................................ 889

32

에필로그 .......................................................................................................................

890

찾아보기 .......................................................................................................................

891

Part

I

C 프로젝트 빌드

1장 필수 요소: C에서 찾아볼 수 있는 필수 요소를 소개합니다. 이 요소들은 C를 사용하는 방식에 중대한 영

향을 미칩니다. 이 책 전반에 걸쳐 이러한 기능을 자주 사용할 예정입니다. 주요 주제는 전처리 및 매크로를 정 의하는 지시자, 변수와 함수 포인터, 함수 호출 메커니즘 그리고 구조체입니다. 2장 소스 코드에서 이진 파일로: C 프로젝트를 빌드하는 방법에 관해 설명합니다. 전체 파이프라인 및 개별

파이프라인 구성 요소의 관점에서 컴파일 파이프라인을 상세히 배워봅니다. 3장 목적 파일: 컴파일 파이프라인을 사용해 빌드한 이후의 C 프로젝트 결과물을 살펴봅니다. 목적 파일과 그

다양한 종류를 소개합니다. 또한 목적 파일 내부를 들여다보고 어떤 정보를 추출할 수 있는지 알아봅니다.

장

33

Part I

C 프로젝트 빌드

1장 필수 요소 2장 소스 코드에서 이진 파일로 3장 목적 파일

34

실전 자바 소프트웨어 개발

CHAPTER

1

필수 요소

이 책은 C를 이용하는 애플리케이션의 개발과 유지 보수에 필요한 기초와 고급 지식을 모두 다 룹니다. 일반적으로 프로그래밍 언어의 문법만 안다고 해서 성공적인 프로그램을 작성하기란 어렵습니다. C는 다른 언어에 비해 이 점이 더 중요합니다. 이 책에서는 대규모 소프트웨어를

C로 작성하는 데 필요한 모든 개념을 살펴봅니다. 간단한 단일 프로세스 프로그램부터 복잡한 멀티프로세스 시스템에 이르기까지 말입니다. 첫 번째 장은 C 프로그램을 작성할 때 매우 유용한 C의 특정 요소를 주로 다룹니다. 이 요소는

C로 작성할 때 자주 마주치게 될 상황과 관련됩니다. C의 모든 것을 상세히 설명하고 문법의 거의 모든 측면을 다루는 좋은 책과 튜토리얼은 많지만, 우리가 C를 더 깊게 들여다보기 전에 몇 가지 주요 특성을 먼저 알아보는 편이 더 좋습니다. 이러한 구성 요소에는 전처리기 지시자, 포인터 변수, 함수 포인터, 구조체가 포함됩니다. 이는 당연히 C보다 더 현대적인 프로그래밍 언어인 자바, C#, 파이썬 등에서도 흔히 볼 수 있는 요 소입니다. 예를 들어 자바의 참조 reference는 C의 포인터 변수와 유사합니다. 이러한 요소 및 관 련 개념은 매우 기초적이며, 이런 요소가 없다면 그 어떠한 소프트웨어도 실행될 수 없습니다. 함수 포인터를 사용해야 하는 여러 공유 라이브러리를 로딩하지 않고서는 단순한 ‘hello world’

프로그램조차도 실행할 수 없습니다. 따라서 신호등, 자동차의 중앙 컴퓨터(CPU ), 주방의 전자레인지, 스마트폰의 운영체제, 별생 각 없이 봤던 다른 장치 모두 C로 작성된 소프트웨어를 사용합니다.

1장 필수 요소

35

오늘날 우리의 삶은 C로부터 큰 영향을 받고 있으며 C가 없다면 세상은 지금과 매우 다를 겁 니다.

1장은 전문적인 C 코드를 작성하기 위한 필수 요소와 관련 개념에 초점을 맞춥니다. 그리고 심 도 있는 학습을 위해 엄선한 요소도 함께 다룹니다. 전처리기 지시자, 매크로, 조건부 컴파일: 전처리는 다른 프로그래밍 언어에서 쉽게 찾아볼 수 없는 C의



특성 중 하나입니다. 전처리에는 많은 이점이 있습니다. 매크로와 조건부 지시자를 포함한 흥미로운 활 용법을 살펴봅시다. 포인터 변수: 1.2절에서는 포인터 변수와 사용법을 알아봅니다. 포인터 변수를 잘못 사용해서 생기는 몇



가지 문제를 해결할 때 도움이 될 만한 지식을 얻을 수 있습니다. 함수: 1.3절에서는 문법 수준을 넘어 함수에 관한 모든 부분을 자세히 살펴봅니다. 문법은 사실 쉬운 부



분입니다! 이 절에서 함수를 절차적 procedural 코드를 작성하기 위한 구성 요소로 간주합니다. 여기서는 또한 함수 호출 메커니즘과 함수가 호출자 함수 the caller function로부터 인수 argument를 받는 방식에 관해 서도 설명합니다. 함수 포인터: 함수 포인터는 C의 중요한 특성 중 하나입니다. 함수 포인터는 변수 대신 기존의 함수



를 가리키는 포인터입니다. 기존의 로직에 포인터를 저장하는 능력은 알고리듬 설계에서 매우 중요합 니다. 따라서 한 절을 할애해 함수 포인터를 살펴봅니다. 함수 포인터는 동적 라이브러리 로딩부터 다형 성 polymorphism에 이르기까지 매우 다양하게 활용됩니다. 훨씬 더 많은 함수 포인터에 관해서는 다음 몇 장에 걸쳐 알아봅니다. 구조체: C 구조체는 문법이 단순하며, 간단한 아이디어를 표현할 수 있습니다. 하지만 잘 조직된 객체지



향 코드를 작성하기 위한 핵심 구성 요소이기도 합니다. 함수 포인터와 더불어 구조체의 중요성도 강조 하지 않을 수 없습니다. 이 장의 마지막 절에서 C의 구조체에 관해 알아야 할 모든 것과 구조체와 관련된 요령을 다시 살펴보겠습니다.

C의 필수 요소와 개념은 유닉스 생태계에서 중요한 역할을 합니다. C는 오래되고 문법이 까다 로운데도 불구하고, 이러한 이유로 인해 여전히 중요하고 영향력이 있습니다. C와 유닉스가 서 로 주고받은 영향에 관해서는 다음 장에서 이야기합니다. 우선 전처리기 지시자를 살펴보는 걸 로 시작해봅시다.

36

1부 C 프로젝트 빌드

NOTE_ 1장을 읽기 전 C에 이미 익숙한 상태여야 한다는 것을 명심하세요. 이번 장의 예제 대부분은 어렵

지 않지만, 다른 장으로 넘어가기 전에 C의 문법을 알고 있기를 권장합니다. 다음은 이 책을 시작하기 전에 잘 알고 있어야 할 주제들입니다. ●

컴퓨터 아키텍처 지식: 메모리, CPU, 주변 장치와 이들 특성에 관해 알아야 하며 컴퓨터 시스템에서 이러한 요소와 프로그램이 어떻게 상호작용하는지도 알아야 합니다.



프로그래밍 기초 지식: 알고리듬이 무엇인지, 알고리듬의 실행을 어떻게 추적하는지, 소스 코드란 무엇 이며 이진수는 무엇인지, 이와 관련한 산술연산은 어떻게 작동하는지 알고 있어야 합니다.



터미널과 셸 명령어 사용법: 리눅스나 macOS 같은 유닉스 계열 운영체제의 터미널과 기초 셸 명령어 에 익숙해야 합니다.



프로그래밍 중급 지식: 최소한 하나의 프로그래밍 언어에서 사용하는 조건문, 여러 종류의 루프, 구조체 나 클래스, C 또는 C++의 포인터, 함수 등과 같은 주제에 관해 중급 지식을 갖추고 있어야 합니다.



객체지향 프로그래밍 기초 지식: 객체지향 프로그래밍에 관해서는 이 책에서 상세히 다룰 예정이니 필 수는 아닙니다. 하지만 기초 지식을 알고 있다면 3부 객체지향을 읽을 때 이해하기 더 쉬울 겁니다. 

1.1 전처리기 지시자 전처리 preprocessing는 C의 강력한 구성 요소입니다. 2장에서 전처리를 충분히 살펴볼 예정이니

지금은 컴파일러로 보내기 전 소스 코드를 만들고 수정할 수 있도록 하는 과정을 전처리라고 정의하겠습니다. 이는 C의 컴파일 파이프라인이 다른 언어에 비해 최소 한 단계 이상을 더 갖 는다는 뜻입니다. 다른 프로그래밍 언어에서는 컴파일러로 소스 코드가 바로 전달되지만 C와

C++에서는 먼저 전처리를 해야 합니다. 전처리라는 추가 단계는 컴파일러로 소스 코드를 보내기 전 C 개발자가 효과적으로 소스 코드 를 바꿀 수 있다는 점에서 C (그리고 C++)를 독특한 프로그래밍 언어로 만들었습니다. 전처리 요소는 대부분의 고급 프로그래밍 언어에는 존재하지 않습니다. 전처리의 목적은 전처리 지시자를 제거하고 이 지시자를 C 코드에 의해 생성된 동일한 내용으 로 바꾸는 것입니다. 또한 컴파일러로 보낼 준비가 된 최종 소스 파일을 준비하려는 목적도 있 습니다.

1장 필수 요소

37

C 전처리기의 수행은 일련의 지시자 directive를 사용해 통제하고 영향을 줄 수 있습니다. C 지시자 는 헤더와 소스 파일 모두에서 # 문자로 시작하는 코드입니다. 이 코드는 C 전처리기에만 의미 가 있을 뿐 C 컴파일러에는 의미가 없습니다. C에는 다양한 지시자가 있는데, 그중에서도 특히 매크로를 정의할 때 사용되는 지시자와 조건부 컴파일에 사용되는 지시자가 매우 중요합니다. 다음 절에서 매크로를 알아보고, 매크로가 다양하게 사용되는 예제를 살펴봅니다. 또한 매크로 를 분석해 매크로의 장단점을 알아봅니다.

1.1.1 매크로 많이들 C 매크로를 오해하고 있습니다. 누군가는 매크로로 인해 소스 코드가 너무 복잡해져 가 독성이 떨어진다고 주장하고, 또 다른 누군가는 코드에 매크로를 사용할 경우 응용프로그램을 디버깅할 때 문제가 생긴다고 이야기합니다. 아마 이런 이야기를 직접 들어본 적도 있을 것입 니다. 하지만 어디까지가 맞는 말일까요? 매크로는 피해야 할 악일까요? 아니라면 프로젝트에 도움이 되는 이점이 있을까요? 잘 알려진 C 프로젝트라면 어느 것이든 매크로를 찾아볼 수 있다는 게 현실입니다. 그 증거로 아파치 HTTP 서버와 같은 유명한 C 프로젝트를 다운받은 뒤 grep1으로 #define을 검색해 보세요. 매크로가 사용된 파일의 목록이 보입니다. C 개발자로서 매크로에서 벗어날 방법은 없 습니다. 여러분이 매크로를 사용하지 않더라도 다른 사람의 코드에서 발견하게 될 것입니다. 그러므로 매크로가 무엇이고 이를 어떻게 다루는지 알아야 합니다.

NOTE_ grep 명령어는 문자열에서 패턴을 검색하는 유닉스 계열의 표준 셸 유틸리티 프로그램과 관련이

있습니다. 이 명령어는 해당 경로에서 모든 파일 내용의 문자열 또는 패턴을 검색할 때 사용합니다.  

매크로는 다음과 같이 다양하게 활용할 수 있습니다. 상수 정의하기



C 함수를 작성하지 않고 함수로 사용하기



1 옮긴이_ 유닉스/리눅스 문자열 검색 명령어

38

1부 C 프로젝트 빌드

루프 풀기 loop unrolling



헤더 가드 header guard



코드 생성



조건부 컴파일



매크로는 더 다양하게 활용할 수 있지만, 다음 절에서는 이 항목들을 주로 살펴보겠습니다.

매크로 정의하기 매크로는 #define 지시자를 이용해 정의합니다. 각 매크로는 이름과 사용 가능한 매개변 수 parameter 리스트를 갖습니다. 또한 값 value을 가지며, 이 값은 매크로 확장이라는 단계를 통해 전처리 단계에서 매크로의 이름으로 대체될 수 있습니다. 매크로는 #undef 지시자로 매크로 의 정의를 제거할 수 있습니다. 간단한 예제인 [예제 1-1]부터 시작해봅시다. 코드 박스 1-1 [예제 1-1] 매크로 정의하기(ExtremeC_examples_chapter1_1.c)2

#define ABC 5 int main(int argc, char** argv) { int x = 2; int y = ABC; int z = x + y; return 0; }

이 [코드 박스 1-1]에서 ABC는 정숫값이나 정수 상수 integer constant를 담는 변수가 아닙니다. 이 는 ABC라는 매크로이며 해당하는 값은 5입니다. 매크로 확장 단계 이후 C 컴파일러로 보낸 코 드의 결과물은 다음과 같습니다. 코드 박스 1-2 매크로 확장 단계 이후 [예제 1-1]에서 생성된 코드

int main(int argc, char** argv) { int x = 2; int y = 5; 2 옮긴이_ 번역 시점에는 깃허브에서 받은 코드 내 주석에 examples가 exampels로 잘못 기재되어 있습니다. ch01부터 ch04까지 이 현상이 존재하니 실습 시 참고해주세요.

1장 필수 요소

39

int z = x + y; return 0; }

[코드 박스 1-2]의 코드는 유효한 C언어 문법이므로 컴파일러에서 코드를 계속 컴파일할 수 있습니다. 앞의 예제에서 전처리기는 매크로 확장을 수행해 매크로의 이름을 값으로 간단히 바 꾸었습니다. 또한 시작하는 줄의 주석도 삭제했습니다. 이제 다른 예제인 [예제 1-2]를 봅시다. 코드 박스 1-3 [예제 1-2] 유사 함수 매크로 정의하기(ExtremeC_examples_chapter1_2.c)

#define ADD(a, b) a + b int main(int argc, char** argv) { int x = 2; int y = 3; int z = ADD(x, y); return 0; }

[코드 박스 1-3]은 [예제 1-1]과 비슷하지만 이 코드에서 ADD는 함수가 아닙니다. 이는 인 수 argument를 받는 유사 함수 매크로 function-like macro입니다. 전처리 이후의 코드 결과는 다음과 같 습니다. 코드 박스 1-4 전처리와 매크로 확장 이후 코드

int main(int argc, char** argv) { int x = 2; int y = 3; int z = x + y; return 0; }

이 코드 박스에서 볼 수 있듯이 매크로 확장이 이루어지는 방식은 다음과 같습니다. 매개변수

a로 사용된 인수 argument x는 매크로 값에 있는 a의 인스턴스로 모두 바뀌었습니다. 매개변수 b 도 마찬가지이며 b에 해당하는 y 인수에서도 그렇습니다. 모두 변환된 이후 전처리된 코드에

40

1부 C 프로젝트 빌드

서는 ADD(a, b) 대신 x + y를 얻습니다. 유사 함수 매크로는 입력 인수를 받을 수 있기 때문에 C 함수를 모방할 수 있습니다. 즉, 자주 사용되는 로직을 C 함수에 넣는 것 대신, 이 로직을 유사 함수 매크로로 명명해 사용할 수 있습 니다. 이처럼 전처리 단계에서 매크로는 자주 사용되는 로직으로 대체되며, C 함수를 새로 작성할 필 요가 없게 됩니다. 이를 더 자세히 알아보고 다음 두 가지 접근 방식을 비교해보겠습니다. 매크로는 컴파일 단계 이전에만 존재합니다. 즉, 컴파일러가 이론적으로는 매크로에 관해 아무 것도 모른다는 의미입니다. 매크로를 함수 대신 사용하려면 이 내용을 꼭 기억해야 합니다. 컴 파일러는 함수의 모든 것을 알고 있습니다. 함수는 C 문법의 일부이며 파스 트리 parse tree 내에 서 함수가 분석되기 때문입니다. 그러나 매크로는 전처리기 자체에 관해서만 알고 있는, C의 전처리기 지시자에 불과합니다. 매크로는 컴파일 이전에 코드를 생성 generate할 수 있도록 합니다. 자바와 같은 다른 프로그래밍 언어에서 이 과정을 처리하기 위해서는 코드 생성기 code generator가 필요합니다. 이런 매크로 적 용에 관해서는 예제를 살펴봅시다. 현대의 C 컴파일러는 C 전처리기 지시자를 인지하고 있습니다. 전처리 단계에 관해 컴파일러 가 아무것도 모른다고 흔히 알고 있지만, 컴파일러는 사실 전처리 단계를 알고 있습니다. 현대 의 C 컴파일러는 전처리 단계에 들어가기 이전의 소스 코드를 알고 있습니다. 다음 코드를 보 시죠. 코드 박스 1-5 선언되지 않은 식별자 오류가 발생하는 매크로 정의(example.c)

#include #define CODE \ printf("%d\n", i); int main(int argc, char** argv) { CODE return 0; }

1장 필수 요소

41

만약 이 코드를 macOS에서 클랭 clang을 이용해 컴파일한다면 결과는 다음과 같습니다. 셸 박스 1-1 매크로 정의를 나타내는 컴파일 출력

$ clang example.c code.c:7:3: error: use of undeclared identifier 'i' CODE ^ code.c:4:16: note: expanded from macro 'CODE' printf("%d\n", i); ^ 1 error generated. $

컴파일러는 매크로가 정의된 바로 그 줄에 오류 메시지를 생성합니다. 참고로 대부분의 현대 컴파일러는 컴파일 직전에 전처리 결과를 볼 수 있습니다. 예를 들어

gcc나 clang을 사용할 경우 전처리 이후 코드를 덤프 dump하기 위해 -E 옵션을 사용할 수 있 습니다. 다음 [셸 박스 1-2]는 -E 옵션의 사용법을 나타냅니다. 결괏값을 모두 싣지는 않았다 는 점을 참고해주세요. 셸 박스 1-2 전처리 단계 이후의 example.c 코드

$ clang -E example.c # 1 "sample.c"# 1 "" 1 # 1 "" 3 # 361 "" 3 ... # 412 "/Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk/ usr/include/stdio.h" 2 3 4 # 2 "sample.c" 2 ... int main(int argc, char** argv) { printf("%d\n", i); return 0; } $

이제 중요한 정의에 다다랐습니다. 변환 단위 translation unit (혹은 컴파일 단위 compilation unit )는 컴파

42

1부 C 프로젝트 빌드

일러로 전달될 준비가 된, 전처리된 C 코드입니다. 변환 단위에서는 모든 지시자가 포함 inclusion 되거나 매크로 확장으로 대체되며 단 한 줄의 긴 C 코드가 만들어집니다. 매크로에 관해 자세히 알아봤으니 조금 더 어려운 예제를 살펴보겠습니다. 이 예제는 매크로의 위력과 위험을 보여줍니다. 제 생각에는 위험하고 섬세한 것을 능숙하게 다루는 것이 극한의 개발이며, 이것이 바로 C입니다. 흥미로운 다음 예제를 확인해봅시다. 루프를 생성하는 시퀀스에서 매크로가 어떻게 사용되는 지 주목해보세요. 코드 박스 1-6 [예제 1-3] 루프를 생성하는 매크로 사용하기(ExtremeC_examples_chapter1_3.c)

#include #define PRINT(a) printf("%d\n", a); #define LOOP(v, s, e) for (int v = s; v

Get in touch

Social

© Copyright 2013 - 2024 MYDOKUMENT.COM - All rights reserved.