c언어로 객체처럼 캡슐화하기

realrise의 이미지

다른분들 소스보면
보통 모든 구조체와 전역변수 프로토타입을
헤더파일에 모두 넣으시던데요.
꼭 그렇게 해야 하는 이유가 있나요?
그걸 여쭤보는 이유는
제 생각에 헤더파일에 외부에서 사용을 허락할
함수의 프로토타입만 넣고 나머진 .c파일에 넣어서
캡슐화 효과를 내려 하기 때문입니다.
다른 모듈에서 헤더파일을 include해서
그 모듈을 사용하니까 헤더파일에 없는 함수는
호출을 못하잖아요.
자바로 따지자면 헤더파일안에 있는 함수가 public이고
소스파일안에 있는건 private이 되는 거죠.
그렇게 하는 것이 좋을 것 같은데요.
다른 소스들을 보면 그렇게 안하니까
제가 뭘 몰라서 그런 생각을 하는건가 싶기도 하고
꼭 모든 구조체와 전역변수 프로토타입을 헤더파일에
분리해야 할 특별한 이유가 없다면 자기 마음 아니겠습니까?

익명 사용자의 이미지

linkage 에 대해 많이 살펴보심이 좋을듯 싶네요. :D

realrise의 이미지

Anonymous wrote:
linkage 에 대해 많이 살펴보심이 좋을듯 싶네요. :D

구체적으로 말씀해 주셨으면 합니다.
링크에 대해서 대충은 알고 있습니다만은 문제가 없는것 같은데요.
그냥 linkage에 대해 많이 살펴보라는 말은 너무 광범위하지 않나요? 어떤 문제점을 머리속에 그리고 계시는 건지
말씀을 해주셔야 그 부분에 대해서 살펴보던지 하지요.
espereto의 이미지

꼭 그렇게 하시겠다면야 private이 될 함수들은 static으로, 나머지는 헤더파일에 프로토타입 넣고... 하면 되겠지요. static으로 선언/정의하지 않은 함수는 함수명만 일치하면 일단은 호출이 가능하나(인자들에 대한 문제가 남지만), static으로 선언/정의된 함수는 함수명을 알아도 해당 소스 파일 이외의 소스에서는 호출이 불가능하죠.

구조체야 헤더에 안 넣고 소스파일에만 넣어놔도, 외부에서 쓸 일 없게 만들면 상관없고...

그리고 다른 소스들이 그렇게 안 된 이유는, 궂이 캡슐화 할 필요가 없기 때문이겠죠.

죠커의 이미지

Herb Shutter의 pimple idiom이 도움이 될 것 같습니다.

realrise님이 바라는 방식에 가까울 것입니다.

saxboy의 이미지

realrise wrote:
다른분들 소스보면
보통 모든 구조체와 전역변수 프로토타입을
헤더파일에 모두 넣으시던데요.
꼭 그렇게 해야 하는 이유가 있나요?
그걸 여쭤보는 이유는
제 생각에 헤더파일에 외부에서 사용을 허락할
함수의 프로토타입만 넣고 나머진 .c파일에 넣어서
캡슐화 효과를 내려 하기 때문입니다.
다른 모듈에서 헤더파일을 include해서
그 모듈을 사용하니까 헤더파일에 없는 함수는
호출을 못하잖아요.
자바로 따지자면 헤더파일안에 있는 함수가 public이고
소스파일안에 있는건 private이 되는 거죠.
그렇게 하는 것이 좋을 것 같은데요.
다른 소스들을 보면 그렇게 안하니까
제가 뭘 몰라서 그런 생각을 하는건가 싶기도 하고
꼭 모든 구조체와 전역변수 프로토타입을 헤더파일에
분리해야 할 특별한 이유가 없다면 자기 마음 아니겠습니까?

헤더에 없다고 해서 링크가 되지 않는 것은 아닙니다. 단지 작은 warning을 볼 수 있겠지요.
다른분들이 계속 같은 말씀을 해주셨지만, private의 효과를 내기 위해서는 static을 사용하셔야만 합니다. 이 내용을 통틀어 C에서의 linkage라고 하는데, C에서 나름대로 꽤 어려운 편에 속하는 static, extern 의 의미를 이해하는 것이 주된 요지가 되겠지요.

덧붙여 구조체의 선언을 .c에 넣을지, .h 에 넣을지는 취향에 속한다고 생각하지만, 저는 그때 그때 편한대로 사용하는 편입니다. C++의 단점 중 하나인 대포쏘아 벼룩잡기가 C에도 그대로 적용되는 경우가 생기는 경험을 할 가능성이 높기 때문이라고나 할까요.

C로 encapsulation/polymorphism을 구현하는 것이 불가능하지는 않습니다만, void 포인터와 함수포인터가 난무하는 - 익숙하지 않다면 알아보기 힘든 코드가 되는 경우가 많지요. 사실은 저는 이런 코드를 꽤 좋아하는 편이지만...

espereto의 이미지

저는 구조체에 대해서는 철저하게 외부 노출을 피합니다.
함수도 필요한 것만 가져다 쓸 수 있게 합니다.
왜냐......

대체 몇 개 인지도 모를 수 많은 함수들과 구조체들을 바라보고 있으면 -_- 머리가 어지럽습니다.

특히나 이 구조체가 저 구조체를, 저 구조체는 요 구조체를... 그렇게 복잡하게 꼬인 구조에서 추가/수정/삭제 작업이 생기게되면 무지막지하게 고생하는, 그런 안 좋은 추억이 있어서......

어차피 복잡하게 구성될 거, 구조체... void *로 싹 바꿔버리고, 함수 안에서 캐스팅해서 쓰게 해 버렸습니다.

private 성격, 즉 static 성격의 함수들을 제외한 extern 되어야 하는 함수들만 헤더에 넣어두고, 구조체마저 숨겨버렸지요. 어차피 대부분의 데이터는 제가 작성한 함수 안에서만 쓰이니까...... 필요한 건, GetXXX, SetXXX 함수를 만들어서 값을 얻거나 변경할 수 있게 하고......

이렇게 모듈별로 나누어서 만들어두니 좀 편하군요. 구조체 꼬일일도 없고...

문제는...... 해당 모듈 바깥쪽에서 해당 모듈과 관련된 디버깅을 할 때 -_-; void *인 구조체의 내용을 보려면 무지 짜증이 나는...... ;

ㅜ.ㅜ

요즘은 그래서 모듈별로 테스트 모듈을 따로 잘~ 작성해서 디버깅합니다.

덕분에 버그 발생 빈도는 많이 줄은 듯.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.