반응형

C : 구조체를 네임스페이스처럼 사용하기

알게된 배경

리눅스 시스템에서 네트워크 프로그래밍을 공부할 때 참조한 책이 하필 C로 설명이 되어 있는 책이었다. 덕분에 C++과 달리 요즘에는 자료를 찾기 힘들기 때문에 필요한 정보를 처리하기 위해서 직접 함수를 만들어야 하는 경우가 많았다.

 함수가 많아지면 발생되는 문제는 역시 작명문제이다. 그러나 C는 네임스페이스나 클래스 기능이 제공되지 않기 때문에 구조체(struct)와 포인터의 조합으로 비슷하게 흉내내서 구현할 수 있다.

 그러나 타이핑 해야할 양이 급증하게 되므로 가능하면, C로 코딩해야 하는 상황을 최대한 벗어나길 바란다.


간략한 원리

구조체가 전역으로 선언이 되어 있어야 하며, 함수들은 포인터로 연결되어 있어야 한다. 그리고 이렇게 선언된 구조체는 외부 참조가 가능하도록 선언을 해야 네임스페이스 혹은 클래스처럼 사용할 수 있다.


구현 예시

예시로 문자열의 뒤쪽의 단어가 일치하는지 검사하는 함수를 구조체내의 함수로 구현한다. 확장자가 포함된 파일이름의 확장자 검사하는 용도로 사용될 수 있다.

헤더파일)

// ns_util.h
#pragma once

typedef enum{ false, true } bool;

struct ns_util_tools
{
    bool (*isHasBackword(const char* str, const char* backword);
};
// 아래의 struct가 존재하니 이 헤더파일을 인클루드 하면 사용할 수 있음
extern const struct ns_util_tools ns_util;

C파일)

// ns_util.c
#include <string.h>
#include "ns_util.h"
bool ns_util__isHasBackword(const char* str, const char* backword)
{
    int str_len, backword_len;
    int i;
    str_len = strlen(str);
    backword_len = strlen(str);
    for(i=0; i<backword_len; ++i)
    {
        if(str[str_len -i] != backword[backword_len -i])
            return false;
    }
    return true;
}
// 실제로 네임스페이스 처럼 사용될 구조체
const struct ns_util_tools ns_util = {
    .isHasBackword = ns_util__isHasBackword
};


다른파일에서 호출)

// main.c
#include <stdio.h>
#include "ns_util.h"

int main(int argc, char* argv[])
{
    char* str = "main.exe";
    if(ns_util.isHasBackword(str, ".exe"))
        printf("%s is exe file!!", str);
    else
        printf("%s is What is?", str);

    return 0;
}



 이로써 C로써도 충분히 객체지향으로 코딩이 가능하다는 것을 알 수 있다. 그렇지만, C로 프로젝트 진행하는 것은 가능하면 피하고 싶다.

반응형
반응형

C++ : 네임스페이스

정리하게 된 배경

 네임스페이스는 C와 C++의 표준함수의 가장 큰 차이점을 보이는 기능중 하나이다. 때문에 명확히 알고 활용을 해야 하기 때문에 정리한다.

 기초이지만, 중요한 개념이기도 하다. 또한, 학교나 학원 그리고 혼자 공부하는 사람입장에서는 예제에서 많이 적용하기 않기 때문에 의외로 활용을 못하는 초보 프로그래머를 많이 볼 수 있다.


개념

 프로그램이 커지고 복잡해지면서, 작명의 한계(?)로 인해서 발생되는 문제를 해결하기 위한 개념으로 등장을 했다. 이후 자바스크립트(JavaScript)나 파이썬(Python) 같은 스크립트계열 언어에서는 모듈이라는 이름으로 발전한다.

 C++에서는 네임스페이스(namespace)를 통해서 같은 이름의 클래스(class)명이나 함수(function)명을 선언 및 정의가 가능해졌다. 때문에 이로 인해 프로그래머들은 작명의 스트레스가 줄게 되었다.


사용방법

 네임스페이스는 클래스를 선언하는 방식과 비슷하게 namespace 키워드 바로 뒤에 선언하고자 하는 네임스페이스 명을 붙여서 선언을 하고 나서 중괄호 안에서 선언 및 정의를 하면 된다.

// A.h
namespace hg
{
    class A
    {
        // ...
        void func();
    }
}

네임스페이스의 내부에 선언 및 정의된 것들(함수, 변수, 클래스 등)을 호출하여 사용할 경우에는 앞에서 선언한 네임스페이스 이름 뒤에 "::" 붙여서 선언할 수 있다.


// A.cpp
// 클래스의 함수정의
#include "A.h"

void hg::A::func()
{
    // ...
}
// main.cpp
// 클래스의 함수호출
#include "A.h"

int main(int argc, char* argv[])
{
    hg::A a;
    a.func();
    return 0;
}

 사용할때 마다 네임스페이스 이름을 매번 적는 것은 상당한 노동과 타이핑양이 많기 때문에 기본적으로 네임스페이스 이름을 사용중인 상태를 나타내는 using 키워드를 사용하면 된다.


// A.cpp
// 클래스의 함수정의
#include "A.h"
using namespace hg;

void A::func()
{
    // ...
}
// main.cpp
// 클래스의 함수호출
#include "A.h"
using namespace hg;

int main(int argc, char* argv[])
{
    A a;
    a.func();
    return 0;
}

네임스페이스의 내부에 선언 및 정의된 것들(함수, 변수, 클래스 등)을 호출하여 사용할 경우에는 앞에서 선언한 네임스페이스 이름 뒤에 "::" 붙여서 선언할 수 있다.

 여기서 using namespace hg;의 유효범위는 해당 키워드가 사용된 파일내에서는 유효하다. 즉, 다른 cpp(혹은 cc) 파일에서는 다시 using 키워드를 사용해서 네임스페이스 사용중임을 알려야 한다.


주의 할점

 개념이 잡힌 사람에게는 당연한 말이 겠지만, using 키워드를 이용한 네임스페이스 선언을 할 경우 헤더 파일에서는 사용하지 않는 것이 정석이다. 따라서 네임스페이스는 정의는 보통 헤더 파일에서 된다. 그리고 using 키워드의 경우 헤더의 클래싀 정의 할 경우에 사용된다. 여러 네임스페이스에서 정의된 것들은 같이 써야 될 경우 가능하면, using은 사용하지 않는 것이 좋다.

 헤더파일에서 using을 쓰면 안되는 이유는 논리적으로 헤더파일은 cpp파일에서 include 될때마다 포함되는데, 이는 include 하는 cpp 마다 강제로 using 키워드를 사용한것처럼 되어버리기 때문에 사실상 네임스페이스가 없는 것처럼 되어 버린다.


추가사항

 헤더파일을 include 할 경우 C와 C++의 몇 가지 차이점이 있는데, C의 stdio.h의 경우 C++에서는 cstdio로 include하게 된다. 이 뿐만 아니라 기존의 C 표준 헤더 파일들 앞에 'c'를 붙어 있는 것을 알 수 있다.

 이 두 헤더 파일간의 차이는 바로 네임스페이스의 존재의 차이가 있다. C에서는 네임스페이스 키워드가 없지만, C++에서는 네임스페이스가 있어서 표준함수 네임스페이스인 std내에 표준함수들이 정의 되어 있다.(물론 C에는 네임스페이스가 없어도 있는 것처럼 사용할 수 있다.)

반응형

+ Recent posts