IBM®
메인 컨텐츠로 가기
    Korea [국가변경]    이용약관
 
 
   
        제품    서비스 & 솔루션    고객지원 & 다운로드    회원 서비스    
메인 컨텐츠로 가기

한국 developerWorks  >  AIX and UNIX  >

윈도우에서 유닉스로 이식하기, Part 2: C/C++ 이식 들여다보기 (한글)

컴파일러 속성에서 일반적으로 직면하는 문제점까지

developerWorks
문서 옵션

JavaScript가 필요한 문서 옵션은 디스플레이되지 않습니다.

영어원문

영어원문


제안 및 의견
피드백

Rahul Kardam, 선임 소프트웨어 개발자, Synapti Computer Aided Design Pvt Ltd
Arpan Sen, Technical lead, Synapti Computer Aided Design Pvt Ltd

2008 년 3 월 11 일

연재 1회에서는 마이크로소프트 비주얼 스튜디오(Microsoft® Visual Studio®) 환경에서 작업하는 전형적인 C/C++ 프로젝트 유형을 다뤘으며, 유닉스(UNIX®) 플랫폼으로 동적 라이브러리와 정적 라이브러리 버전을 이식하는 과정을 소개했습니다. 2회에서는 비주얼 C++ 프로젝트와 유닉스 환경에서 g++를 사용해서 빌드하는 과정에 사용하는 컴파일러 옵션 몇 가지를 파고 들며, 이식과 관련이 있는 g++ 속성 메커니즘을 좀더 자세히 살펴보며, 32비트 윈도우(Windows®) 환경에서 64비트 유닉스 환경으로 이식하는 과정에서 직면할지도 모르는 문제점 몇 가지를 점검합니다. 마지막으로 멀티스레드 응용 프로그램 이식에 필요한 기본적인 개념과 이 모든 기술을 하나로 합치는 예제 프로젝트로 끝을 맺겠습니다.

컴파일러 옵션 비교

비주얼 C++에서 사용하는 cl.exe 컴파일러와 GNU g++ 컴파일러에는 여러 옵션이 붙어있다. cl.exe를 컴파일 목적을 위한 단독 도구로 활용할 수도 있지만, 비주얼 C++는 컴파일러 옵션 설정을 위한 깔끔한 통합 개발 환경을 제공한다. 비주얼 스튜디오(Visual Studio®)로 개발한 소프트웨어는 종종 컴파일러나 링크 옵션을 통제하려고 컴파일러에 밀접하거나 플랫폼에 의존적인 기능을 사용하기도 한다. 컴파일러나 툴체인으로 여러 플랫폼으로 원시 코드를 이식할 때 컴파일러 옵션 이해가 중요하다. 이 절에서는 가장 유용한 컴파일러 옵션을 몇 가지 설명한다.

문자열 풀링 활성

다음 코드 조각을 살펴보자.

      char *string1= "This is a character buffer";
      char *string2= "This is a character buffer";
      

문자열 풀링 옵션(/GF)을 비주얼 C++에서 활성화하면, 문자열 단일 복사본이 실행 중에 프로그램 이미지에 보관되며, string1string2는 동일하다. g++는 비주얼 C++와 정반대로 움직이며, 기본적으로 string1string2와 똑같다는 사실에 주목하자. g++에서 문자열 풀링을 비활성화하려면 g++ 명령을 내리면서 -fwritable-strings 옵션을 붙이면 된다.

wchar_t 활용하기

C++ 표준은 wchar_t를 와이드 캐릭터 타입으로 정의한다. /Zc:wchar_t 옵션을 컴파일러에 넘기면, 비주얼 스튜디오는 wchar_t를 컴파일러 고유 타입으로 취급한다. 그렇지 않으면 windows.h와 같은 구현에 밀접한 헤더 파일이나 wchar.h와 같은 표준 헤더를 인클루드할 필요가 있다. g++는 고유 wchar_t 타입을 지원하므로 특별한 헤더를 인클루드할 필요가 없다. wchar_t 크기는 플랫폼마다 다르다. -fshort-wchar라는 g++ 옵션을 사용해 wchar_t 크기를 2바이트로 제한할 수 있다.

C++ RTTI 지원

원시 코드가 dynamic_casttypeid 연산자를 사용하지 않으면, RTTI(Run Time Type Identification) 기능이 비활성화될지도 모른다. 기본적으로 RTTI는 비주얼 스튜디오 2005에서 켜져 있다(다시 말해 /GR 스위치를 켠 상태다). /GR- 스위치는 비주얼 스튜디오 환경에서 RTTI를 비활성화한다. RTTI를 비활성화하면 실행 파일 크기를 줄여준다. dyanmic_casttypeid를 포함한 원시 코드를 컴파일할 때 RTTI를 비활성화하면 비정상 종료를 비롯한 예상치 못한 결과를 얻는다. Listing 1에 나온 코드 조각을 살펴보자.


Listing 1. RTTI 예제를 위한 코드 조각
                
      #include <iostream>
      struct A {
        virtual void f()
          { std::cout << "A::f\n"; }
        };

      struct B : A {
        virtual void f()
          { std::cout << "B::f\n"; }
        };

      struct C : B {
        virtual void f()
          { std::cout << "C::f\n"; }
        };

      int main (int argc, char** argv )
        {
        A* pa = new C;
        B* pb = dynamic_cast<B*> (pa);
        if (pb)
          pb->f();
        return 0;
        }
      

비주얼 스튜디오 IDE를 벗어나 cl.exe 컴파일러를 단독으로 실행해 이 코드 조각을 컴파일하려면 /GR 스위치를 붙여 명시적으로 RTTI 지원을 켜야 한다. cl.exe와는 달리 g++ 컴파일러는 RTTI 지원을 켜는 데 특별한 옵션이 필요하지 않다. 하지만 비주얼 스튜디오에서 제공하는 /GR 옵션과 마찬가지로 g++에도 RTTI를 명시적으로 끌 수 있는 -fno-rtti 옵션이 있다. g++-fno-rtti 옵션을 붙여 이 코드 조각을 컴파일하면 컴파일 오류가 발생한다. 하지만 cl.exe는 심지어 /GR 옵션이 없는 경우에도 이 코드 조각을 컴파일하지만 결과물을 실행하면 바로 비정상 종료로 끝난다.

예외 처리

cl.exe에서 예외 처리를 활성화하려면 /GX 컴파일러 옵션이나 /EHsc 옵션을 사용한다. 이런 옵션을 사용하지 않으면, trycatch 코드는 여전히 실행은 되지만 시스템은 throw 구문으로 지역 객체 소멸을 호출하지 않는다. 예외 처리는 성능을 희생한다. 컴파일러는 매 C++ 함수마다 스택 되감기를 위한 코드를 생성하므로 이런 요구 사항이 걸리면 크고 느린 코드를 만들어내고 만다. 성능 문제를 희생하지 못하는 특수한 프로젝트가 있기 마련이며 이런 기능을 끄고 싶을지도 모른다. 예외 처리를 비활성화하려면 원시 코드에서 모든 trycatch 블록을 제거하고 /GX- 옵션을 붙여 코드를 컴파일할 필요가 있다. g++ 컴파일러는 기본적으로 예외 처리를 활성화한다. g++-fno-exceptions 옵션을 넘기면 예외 처리를 비활성화한다. 이 옵션을 사용할 경우 try, catch, throw 키워드는 컴파일 오류를 초래할지도 모른다. 여전히 수작업으로 원시 코드 본문 중에서 try, catch 블록을 제거한 다음 이 옵션을 g++에 넘겨야만 한다. Listing 2에 나온 코드를 살펴보자.


Listing 2. 예외 처리를 보여주는 코드 조각
                
      #include <iostream>
      using namespace std;

      class A { public: ~A () { cout << "Destroying A "; } };
      void f1 () { A a; throw 2; }

      int main (int argc, char** argv ) {
        try { f1 (); } catch (...) { cout << "Caught!\n"; }
        return 0;
        }
      

직전 절에 설명한 옵션을 cl.exeg++에 넘긴 경우와 넘기지 않은 경우로 나눠서 결과를 정리했다.

  • cl.exe/GX 옵션을 넘길 경우: Destroying A Caught!
  • cl.exe/GX 옵션을 넘기지 않을 경우: Caught!
  • g++-fno-exceptions 옵션을 넘기지 않을 경우: Destroying A Caught!
  • g++-fno-exceptions 옵션을 넘길 경우: Caught!

루프 규칙

루프 규칙은 Listing 3에 제시한 코드 조각을 살펴보기 바란다.


Listing 3. 루프 규칙
                
      int main (int argc, char** argv )
        {
        for (int i=0; i<5; i++);
        i = 7;
        return 0;
        }
      

이 코드가 ISO C++ 지침에 따라 컴파일되리라 기대하지 못하는 이유는 지역 변수인 i 범위가 루프 일부로 선언되어 루프 본체에만 적용되기에 루프 바깥에서 접근하지 못하기 때문이다. 기본적으로 cl.exe는 오류 없이 이 코드를 컴파일한다. 하지만 /Zc:forScope 옵션을 cl.exe에 넘길 경우 컴파일이 실패한다. g++cl.exe와 정반대로 동작하며, 이 코드를 컴파일하면 다음과 같은 오류가 발생한다.

error: name lookup of 'i' changed for new ISO 'for' scoping

이런 동작 방식을 피하고 싶다면, 컴파일러에 -fno-for-scope 플래그를 넘기면 된다.

g++ 속성 활용하기

비주얼 C++와 GNU g++에는 언어에 비표준적인 확장이 따라온다. g++ 속성 메커니즘은 비주얼 C++ 코드에서 사용하는 플랫폼에 밀접한 기능을 이식하는 과정에 적합하다. 속성 구문은 __attribute__ ((attribute-list)) 형태이며, attribute-list는 ','로 구분된 속성 목록이다. 속성의 개별 항목은 낱말 하나이거나 낱말 하나 뒤에 괄호 내 속성을 위한 추가 매개변수가 따라올 수 있다. 이 절에서는 이식 과정에서 사용하는 몇 가지 유용한 속성을 살펴본다.

함수 호출 관례

__cdecl, __stdcall, __fastcall과 같은 비주얼 스튜디오에 밀접한 키워드를 사용해 컴파일러에 함수 호출 관례를 지시할 수 있다. 표 1에 세부 사항을 정리했다.


표 1. 윈도우 환경에서 호출 관례
호출 관례함축된 의미론
__cdecl (cl.exe 옵션: /Gd)호출된 함수로 전달하는 매개변수를 오른쪽에서 왼쪽으로 스택에 밀어넣는다. 수행이 끝나면 호출하는 함수가 스택에서 매개변수를 뽑아낸다.
__stdcall (cl.exe 옵션: /Gz)호출된 함수로 전달하는 매개변수를 오른쪽에서 왼쪽으로 스택에 밀어넣는다. 수행이 끝나면 호출된 함수가 스택에서 매개변수를 뽑아낸다.
__fastcall (cl.exe 옵션: /Gr)호출된 함수로 전달하는 매개변수를 ECX와 EDX 레지스터에 집어넣고 다른 매개변수는 오른쪽에서 왼쪽으로 스택에 밀어넣는다. 수행이 끝나면 호출된 함수가 스택을 정리한다.

g++ 속성은 동일한 호출 관례를 각각 cdecl, stdcall, fastcall로 정의한다. Listing 4는 윈도우(Windows®)와 유닉스(UNIX®) 속성 정의 스타일에서 미묘한 차이점을 보여준다.


Listing 4. 윈도우와 유닉스에서 사용하는 속성 선언 스타일
                
      비주얼 C++ 선언 방법:
      double __stdcall compute(double d1, double d2);

      g++ 선언 방법:
      double __attribute__((stdcall)) compute(double d1, double d2);
      

구조체 멤버 정렬

/Zpn 구조체 멤버 정렬 옵션은 구조체를 위한 메모리 정렬을 제어한다. 예를 들어, (기본값인) /Zp8은 8바이트 경계로, /Zp16은 16바이트 경계로 구조체를 정렬한다. Listing 5에 제시한 방법처럼 g++ 속성인 aligned를 사용해 변수 정렬을 지시할 수 있다.


Listing 5. 윈도우와 유닉스에서 구조체 멤버 정렬
                
      비주얼 C++ 선언 방식(/Zp8 스위치):
      struct T1 { int n1; double d1;};

      g++ 선언 방식:
      struct T1 { int n1; double d1;}  __attribute__((aligned(8)));
      

하지만 정렬된 속성의 유효성은 고유한 링커 제약 사항에 달려있다. 많은 시스템에서, 링커는 단지 정해진 최대 정렬값으로만 변수를 정렬할 수 있다.

비주얼 C++ declspec nothrow 속성

이 속성으로 선언된 함수와 이 함수에서 연속으로 호출하는 함수가 예외를 던지지 않는다는 사실을 컴파일러에 알려준다. 이런 기능이 전반적으로 코드 크기를 줄이는 최적화 요인으로 작용하는 이유는 기본적으로 코드가 예외를 던지지 않아도 cl.exe는 계속해서 C++ 원시 코드를 위해 스택 되감기 정보를 생성하기 때문이다. 비슷한 목적으로 Listing 6에 나오는 nothrow g++ 속성을 사용할 수도 있다.


Listing 6. 윈도우와 유닉스 환경에서 사용하는 nothrow 속성
                
      비주얼 C++ 선언 방식:
      double __declspec(nothrow) sqrt(double d1);

      g++ 선언 방식:
      double __attribute__((nothrow)) sqrt(double d1);
      

좀더 이식성이 높은 표준 정의 스타일을 따르자면 다음과 같다. double sqrt(double d1) throw ();.

비주얼 C++와 g++의 닮은 꼴

직전 예제와는 별개로 비주얼 C++와 g++ 속성에는 여러 가지 닮은 옵션이 존재한다. 예를 들어 noinline, noreturn, deprecated, naked 속성은 양쪽 컴파일러에서 모두 지원한다.

32비트 윈도우에서 64비트 유닉스 환경으로 이식할 때 생기는 잠재적인 함정

Win32 시스템에서 개발한 C++ 코드는 ILP32 모델에 기반을 두는데 int, long, 포인터 타입은 32비트다. 유닉스 시스템은 LP64 모델을 따르는데 long과 포인터 타입은 64비트지만 int 타입은 여전히 32비트다. 이런 변화는 코드를 망가뜨리는 주범이다. 이 절에서는 뒷통수를 얻어맞을지도 모르는 가장 기본적인 문제 두 가지를 간략하게 짚고 넘어간다. 32비트 시스템에서 64비트 시스템으로 이식하는 작업은 그 자체만으로도 연구 범위가 아주 넓다. 이 주제에 대한 세부 정보를 얻으려면 참고자료 절을 살펴보기 바란다.

자료 타입 크기 차이

ILP32와 LP64 모델 양쪽에서 동일한 자료 타입을 활용하는 방법은 상당히 세련된 기법이다. 일반적으로 long과 포인터 자료를 최대한 피해야 한다. 또한 sys/types.h 표준 헤더 파일에 정의한 자료 타입 활용이 일반적인 관례지만 ptrdiff_t, size_t와 같은 이 파일에 존재하는 개별 자료 타입 크기는 32비트에서 64비트 모델로 가면서 바뀌므로 주의 깊게 사용할 필요가 있다.

개별 자료 구조를 위한 메모리 요구

개별 자료 구조를 위한 메모리 요구는 컴파일러에서 구조체 멤버를 메모리에 배열하는 방법에 따라 바뀔지도 모른다. Listing 7에 나온 코드 조각을 살펴보자.


Listing 7. 결함이 있는 구조체 멤버 정렬
                
      struct s {
                int var1;  // hole between var1 and var2
                long var2;
                int var3; // hole between var3 and ptr1
                char* ptr1;
             };
      // sizeof(s) = 32 bytes
      

LP64 모델에서 long과 포인터 타입은 64비트 경계에 정렬된다. 또한 구조체 크기는 내부에 존재하는 가장 큰 멤버 크기에 정렬된다. 이 예제에서 구조체 s는 8바이트 경계에 정렬되는데 s.var2 변수 때문이다. 이럴 경우 구조체 내부에 사용하지 않는 메모리 공간이 만들어지므로 메모리 소모가 커진다. Listing 8에서 보여주는 재정렬은 구조체를 24바이트가 되도록 만든다.


Listing 8. 올바른 구조체 멤버 정렬
                
      struct s {
                int var1;
                int var3;
                long var2;
                char* ptr1;
             };
      // sizeof(s) = 24 bytes
      

멀티스레드 응용 프로그램 이식하기

기술적으로 스레드는 운영체제가 실행을 위해 스케줄하는 명령어의 연속적인 흐름이다. 양쪽 환경에서, 스레드는 프로세스 내부에 존재하며 프로세스 자원을 활용한다. 스레드에 대한 어버이 프로세스가 존재하며 운영체제가 이를 지원한다면 스레드는 독자적인 제어 흐름을 유지한다. 스레드는 독립적으로 (또는 종속적으로) 동작하는 다른 스레드와 더불어 프로세스 자원을 공유하며, 어버이 프로세스가 죽으면 함께 죽는다. 윈도우와 유닉스 환경에서 멀티스레드 프로젝트를 만들기 위해 필요한 몇 가지 대표적인 API를 소개하겠다. 인터페이스 선택은 WIN32 API를 대신해서 C 실행 라이브러리를 선택하며, 단순함과 명료함을 위해 POSIX 스레드 모델이 지원하는 루틴을 선택했다.

주의: 지면 제약으로 인해 다른 응용 프로그램 작성 방법은 세부적으로 설명하지 않겠다.

스레드 생성

윈도우에서는 C 실행 라이브러리 함수인 _beginthread() API를 사용한다. 스레스 생성이 가능한 다른 Win32 API도 존재하지만 앞으로는 단지 C 실행 라이브러리 함수만 다룰 것이다. 이름이 의미하는 바와 같이 _beginthread() 함수는 첫 번째 매개변수로 넘어간 함수 포인터가 가리키는 루틴을 수행하는 스레드를 생성한다. 이 루틴은 __cdecl C 선언 호출 관례를 따르며 void를 반환환다. 스레드가 루틴에서 돌아오면 종료된다.

유닉스에서는 pthread_create() 함수로 동일한 결과를 얻는다. pthread_create() 함수는 스레드 인수를 사용해 새로운 스레드 ID를 반환한다. 호출한 쪽에서는 이 스레드 ID를 사용해 스레드에 대한 다양한 연산을 수행할 수 있다. 스레드가 존재하는지 확인하기 위해 이 식별자를 점검하자.

스레드 소멸

_endthread() 함수는 _beginthread()가 생성한 스레드를 종료한다. 스레드는 연속적인 실행이 끝날 때 자동으로 종료된다. _endthread() 함수는 스레드 내부에서 조건 종료가 필요할 때 유용하게 쓰인다.

유닉스에서는 pthread_exit() 함수로 같은 결과를 얻는다. 이 함수는 일반적인 상황에서 연속적인 스레드 실행이 끝나지 않았을 경우에도 스레드를 종료한다. 그렇지 않다면 main()이 종료할 시점에서 자동으로 스레드들이 종료된다.

스레드에서 동기화

동기화를 위해서는 뮤텍스를 사용해야 한다. 윈도우에서는 CreateMutex()로 뮤텍스를 생성한다. CreateMutex()에서 뮤텍스 객체를 필요로 하는 함수가 사용할 핸들을 반환하는 이유는 해당 뮤텍스에 대한 모든 접근 권한을 제공해야 하기 때문이다. ReleaseMutex()는 뮤텍스를 소유하고 있는 스레드가 더 이상 뮤텍스를 필요로 하지 않을 때 시스템에서 바로 뮤텍스를 제거한다. 이 함수를 호출한 스레드에 뮤텍스 소유 권한이 없다면 함수 호출은 실패한다.

유닉스에서 뮤텍스는 pthread_mutex_init() 루틴으로 동적 생성이 가능하다. 이 메서드는 뮤텍스 객체 속성을 설정하도록 허용한다. 그렇지 않으면 pthread_mutex_t 변수를 선언할 때 정적으로 생성된다. 더 이상 사용하지 않는 뮤텍스 객체를 해제하려면, pthread_mutex_destroy()를 사용한다.

멀티스레드 응용 프로그램 실제 이식 예

이 기사 초반에 나온 정보로 무장했으니, 주 프로세스 내에서 수행하는 다양한 스레드를 사용해 콘솔에 출력하는 자그마한 예제 프로그램으로 넘어간다. Listing 9는 multithread.cpp 원시 코드다.


Listing 9. multithread.cpp 원시 코드
                
#include <stdio.h>
#include <stdlib.h>

#ifdef WIN32
  #include <windows.h>
  #include <string.h>
  #include <conio.h>
  #include <process.h>
#else
  #include <pthread.h>
#endif

#define MAX_THREADS 32

#ifdef WIN32
  void InitWinApp();
  void WinThreadFunction( void* );
  void ShutDown();

 HANDLE  mutexObject;
#else
  void InitUNIXApp();
  void* UNIXThreadFunction( void *argPointer );

  pthread_mutex_t mutexObject = PTHREAD_MUTEX_INITIALIZER;
#endif

int     threadsStarted;             // 시작된 스레드 숫자

int main()
{
  #ifdef WIN32
    InitWinApp();
  #else
    InitUNIXApp();
  #endif
}

#ifdef WIN32
void InitWinApp()
  {

  /* 뮤텍스를 생성하고 스레드 카운터를 초기화한다. */
  mutexObject = CreateMutex( NULL, FALSE, NULL );   /* Cleared */
  if(mutexObject == NULL && GetLastError() != ERROR_SUCCESS)
    {
    printf("failed to obtain a proper mutex for multithreaded application");
    exit(1);
    }
  threadsStarted = 0;
  for(;threadsStarted < 5 && threadsStarted < MAX_THREADS;
       threadsStarted++)
    {
    _beginthread( WinThreadFunction, 0,  &threadsStarted );
    }
  ShutDown();
  CloseHandle( mutexObject );
  getchar();
  }

void ShutDown()
  {
  while ( threadsStarted > 0 )
    {
    ReleaseMutex( mutexObject ); /* 스레드에게 종료하라고 지시한다. */
    threadsStarted--;
    }
  }

void WinThreadFunction( void *argPointer )
  {
  WaitForSingleObject( mutexObject, INFINITE );
  printf("We are inside a thread\n");
  ReleaseMutex(mutexObject);
  }

#else
void InitUNIXApp()
  {
  int count = 0, rc;
  pthread_t threads[5];

  /* functionC를 실행할 독립 스레드를 생성한다. */

  while(count < 5)
    {
    rc = pthread_create(&threads[count], NULL, &UNIXThreadFunction, NULL);
    if(rc)
      {
      printf("thread creation failed");
      exit(1);
      }
    count++;
    }

  // 스레드 수행이 끝날 때까지 기다려야 할 것이다. 그렇지 않으면
  // main이 끝나면 나머지 모든 스레드도 종료되기 때문이다.
  for(;count > 0;count--)
    {
    pthread_join( threads[count - 1], NULL);
    }
  // 주의: 스레드를 종료하기 위해서는, 명시적으로 pthread_exit() 함수를
  // 사용해야 하지만, 스레드가 자동으로 수행 과정에서 종료되므로,
  // 명시적으로 pthread_exit() 함수를 호출하지 않았다.
  exit(0);
  }

void* UNIXThreadFunction( void *argPointer )
  {
   pthread_mutex_lock( &mutexObject );
   printf("We are inside a thread\n");
   pthread_mutex_unlock( &mutexObject );
  }

#endif

    

multithread.cpp 원시 코드를 대상으로 다음과 같은 명령을 내려 마이크로소프트 윈도우 서비스 팩 4에서 비주얼 스튜디오 툴킷 2003으로 테스트를 마쳤다.

    cl multithread.cpp /DWIN32 /DMT /TP
    

또한 유닉스 플랫폼에서 다음과 같은 명령을 내려 g++ 컴파일러 버전 3.4.4로 테스트를 마쳤다.

    g++ multithread.cpp -DUNIX -lpthread
    

Listing 10은 양쪽 환경에서 프로그램을 수행한 결과다.


Listing 10. multithread.cpp 결과
                
    We are inside a thread
    We are inside a thread
    We are inside a thread
    We are inside a thread
    We are inside a thread
    

결론

윈도우와 유닉스 같은 완전히 다른 두 플랫폼 사이에서 이식 작업을 하려면 다방면에 능통한 지식이 필요하다. 컴파일러와 옵션 이해, DLL과 같은 플랫폼에 밀접한 기능, 스레드와 같은 구현에 밀접한 기능이 대표적이다. 이번 연재는 이식이라는 주제를 놓고 다양한 측면을 소개했다. 이 주제에 대한 좀더 심도 깊은 내용은 참고자료 항목을 살펴보기 바란다.

소셜 북마크

mar.gar.in mar.gar.in
digg Digg
del.icio.us del.icio.us
Slashdot Slashdot



참고자료

교육

제품 및 기술 얻기

토론


필자소개

Rahul Kardam은 하드웨어 설계를 위한 시뮬레이터와 같은 복잡한 C++ 기반 전자 설계 자동화 도구가 전문 분야인 선임 소프트웨어 개발자다. Kardam은 윈도우와 유닉스 플랫폼 양쪽에서 프로그래밍 경험이 있다. Kardam은 오픈 소스 소프트웨어를 손수 수선해서 자신이 만들고 있는 설계 자동화 도구를 위해 튼튼하고 확장 가능한 코드를 위한 프레임워크로 사용하는 작업을 즐긴다.


Arpan Sen은 전자 설계 자동화 업계에서 소프트웨어 개발을 이끄는 리드 엔지니어다. Sen은 솔라리스, SunOS, HP-UX, IRIX와 같은 다양한 유닉스 운영체제는 물론이고 리눅스와 마이크로소프트 윈도우 환경에서 여러 해 동안 개발했다. Sen은 소프트웨어 성능 최적화 기법, 그래프 이론, 병렬 컴퓨팅에 관심이 많다. Sen은 소프트웨어 시스템 분야에서 대학원 학위를 받았다.




기사에 대한 평가


보다 나은 서비스를 제공하기 위함이오니 잠시 짬을 내어 이 양식을 제출하여 주십시오.



아니오잘 모르겠음
 


 


12345
 



위로


IBM and AIX are registered trademarks of International Business Machines Corporation in the United States, other countries, or both. Java and all Java-based trademarks are trademarks of Sun Microsystems, Inc. in the United States, other countries, or both. Linux is a registered trademark of Linus Torvalds in the United States, other countries, or both. Microsoft, Windows, Windows NT, and the Windows logo are trademarks of Microsoft Corporation in the United States, other countries, or both. UNIX is a registered trademark of The Open Group in the United States and other countries. 기타 회사, 제품, 및 서비스명은 다른 상표나 서비스 마크일 수 있습니다.

developerWorks 콘텐트를 다른 사이트에 전재하기:
developerWorks 콘텐트에 대한 저작권은 IBM에 있습니다. IBM의 서면 허가나 원본 저자의 허락이 없이는 전재를 금합니다. 저희 콘텐트를 전재하시려면 IBM developerWorks 담당자 에게 문의하십시오.
    IBM 소개 개인정보 보호정책 문의