검색결과 리스트
글
[C/C++] typedef 함수 포인터 구현원리
최근 안드로이드 프레임워크를 공부하다보니 JAVA는 물론 JNI를 통해 연결되는 C/C++ 코드들에 대해 빠삭하게 공부를 하고 있습니다. 정말이지 흔히 쓰는 저 언어들에 슬슬 도가 트고 있지 않은가 싶을정도로 자신의 실력에 대해 자만심이 들기도 할 정도입니다.
소스코드들을 공부하는 과정에서 어려운 부분이 있다면 바로 흔히 사용하지 않는 방식으로 구현된 소스코드를 해석하는 때라고 생각합니다. 특히 수업시간에는 이론만 알고 넘어가는 함수 포인터라는 생소한 개념이 쓰였을 때는 처음엔 이것의 정체 조차 모르는 경우도 허다하지요.
본론으로 들어가기에 앞서 간단한 소스코드를 통하여 함수 포인터에 대한 기념을 알아보도록 하겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #include<stdio.h> void (*ptrfunc)(int); void testprint(int n){ printf("Number : %d\n", n); } int main(){ testprint(100); ptrfunc = testprint; ptrfunc(77); return 0; } | cs |
위의 결과 출력을 보시면 대략적인 함수 포인터의 동작 원리를 이해하실 수 있을 것이라 생각합니다.
여기서 잠시 코드를 좀 더 자세히 설명 드리도록 하겠습니다.
void (*ptrfunc)(int);
함수 포인터는 위에서 보시는 바와 같은 구조로 이루어져 있습니다. 각 부분의 기능은 다음과 같습니다.
return값의 자료형 (*포인터 함수의 이름) (인자값)
함수 포인터를 사용하실 때 주의하실 점은 함수 포인터가 이용하고자 하는 함수의 return값의 자료형과 인자값의 자료형 및 갯수가 일치해야 사용할 수 있다는 점입니다. 다음 코드를 확인해 봅시다.
ptrfunc = testprint;
함수 포인터에 사용하고자 하는 함수의 이름을 입력합니다. 위 과정을 통해 기존 포인터와 같이 함수의 주소값이 포인터에 저장됨으로서 해당 함수 포인터는 자신이 가지고 있는 주소값의 함수와 같은 기능을 구현하게 됩니다.
다음으로 typedef가 사용된 함수 포인터에 대해 살펴보도록 합시다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #include<stdio.h> typedef void (*ptrfunc)(int); void testprint(int n){ printf("Number : %d\n", n); } int main(){ testprint(100); ptrfunc elecs; elecs = testprint; elecs(77); return 0; } | cs |
위에서 설명하였던 소스코드에 typedef를 적용하여 보았습니다. typedef문이 이곳에서는 어떻게 적용되고 있는지 살펴보도록 합시다.
보시는 대로 기존에 있던 함수 포인터가 선언된 부분 앞쪽에 typedef가 선언되어 있는 모습을 보고 계십니다. typedef문은 빈번하게 사용되는 소스코드가 복잡하거나 길 경우 이를 간결하게 사용하기 위한 목적으로 사용되는데요 함수 포인터에서의 typedef문은 지금껏 보았던 typedef문과는 약간 사용되는 방법이 다르지만 결국은 사용되는 목적은 같습니다.
다음으로 typedef 함수 포인터가 응용되는 부분을 보여드리도록 하겠습니다.
ptrfunc elecs;
응용이라고 말씀드려서 뭔가 거창한 걸 하려나 하겠습니다만 사실 typedef로 선언된 함수 포인터는 위에서 보시는 바와 같이 매우 간결하게 쓰이고 있음을 아실 수 있습니다. ptrfunc로 정의된 typedef문의 함수 포인터를 elecs라는 이름의 함수 포인터 하나를 만들었다고 보시면 됩니다. 쉽게 설명해서 함수포인터인 변수 하나가 생겼다고 생각하시면 됩니다. 아직도 이해가 안되신다면 아래의 간단한 소스코드를 보시면 아하! 하고 이해하실 겁니다.
int elecs;
elecs = 199;
이제 감이 오시는지요? 그렇습니다! typedef문으로 선언된 함수 포인터는 마치 자료형을 선언하는 것과 같이 간단하게 함수 포인터 변수를 선언한다고 생각하시면 되는 것입니다! 혹시나 해서 아직도 이해하지 못하신 분들을 위해 저 위에 typedef 함수 포인터가 실제로는 어떻게 구현되어 있는지 보여드리겠습니다.
void (*elecs)(int);
위에서 보시는 바와 같이 ptrfunc 부분이 elecs로 치환된 것이라고 생각하시면 제 설명을 정확히 이해하시는 것입니다!
혹시 typedef 함수 포인터의 원리에 대해 알고자 하셔서 오신 분들이라면 포스팅을 여기까지만 읽어주셔도 자신의 실력으로 함수 포인터를 활용하실 수 있으리라 생각합니다. 아래에서 부터는 다소 어려우니 기죽지 마시고 이렇게 활용되고 있구나 하는 생각으로 읽어주셨으면 합니다.
그렇다면 이제 실전에서 사용되고 있는 코드를 보도록 하겠습니다. 아래의 소스코드는 안드로이드 내에서 구현된 함수 포인터 입니다. 언어는 C++로 구성되어 있습니다만 함수포인터를 설멍하는데 큰 어려움은 없을 것입니다. 소스는 다음과 같습니다.
/frameworks/av/camera/CameraBase.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | template <typename TCam, typename TCamTraits> sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId, const String16& clientPackageName, int clientUid) { ALOGV("%s: connect", __FUNCTION__); sp<TCam> c = new TCam(cameraId); sp<TCamCallbacks> cl = c; status_t status = NO_ERROR; const sp<ICameraService>& cs = getCameraService(); if (cs != 0) { TCamConnectService fnConnectService = TCamTraits::fnConnectService; status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid, /*out*/ c->mCamera); } if (status == OK && c->mCamera != 0) { c->mCamera->asBinder()->linkToDeath(c); c->mStatus = NO_ERROR; } else { ALOGW("An error occurred while connecting to camera: %d", cameraId); c.clear(); } return c; } | cs |
여기서 참으로 특이한 구조의 소스코드를 만나게 되었습니다.
TCamConnectService fnConnectService = TCamTraits::fnConnectService;
이제 이 부분이 어떻게 구현되었는지 자세히 보도록 합시다.
/frameworks/av/include/camera/CameraBase.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | template <typename TCam> struct CameraTraits { }; template <typename TCam, typename TCamTraits = CameraTraits<TCam> > class CameraBase : public IBinder::DeathRecipient { public: typedef typename TCamTraits::TCamListener TCamListener; typedef typename TCamTraits::TCamUser TCamUser; typedef typename TCamTraits::TCamCallbacks TCamCallbacks; typedef typename TCamTraits::TCamConnectService TCamConnectService; .... } | cs |
위 코드를 통하여 다음과 같은 사실을 알아내었습니다.
TCamConnectService로 정의된 부분이 CameraTraits<TCam>::TCamConnectService와 동일하다는 것을 알고 다음으로 CameraTraits에 대해 확인해 보도록 하겠습니다.
/frameworks/av/include/camera/Camera.h
1 2 3 4 5 6 7 8 9 10 11 12 | template <> struct CameraTraits<Camera> { typedef CameraListener TCamListener; typedef ICamera TCamUser; typedef ICameraClient TCamCallbacks; typedef status_t (ICameraService::*TCamConnectService)(const sp<ICameraClient>&, int, const String16&, int, /*out*/ sp<ICamera>&); static TCamConnectService fnConnectService; }; | cs |
위 코드에서 정말 요상하게 친구가 하나 보이는군요.
typedef status_t (ICameraService::*TCamConnectService)(const sp<ICameraClient>&,
위에서 배운 바와 같이 해당 코드는 typedef 함수 포인터입니다. 다만 포인터 함수의 이름이 참으로 독특한데 이는 멤버 포인터라는 C++에서 사용되고 있는 기능입니다. 멤버 포인터에 대해 좀 더 자세히 알고 싶으신 분은 아래 포스팅을 참조해 주시기 바랍니다.
http://showmiso.tistory.com/210
바로 그 아래에는 typedef로 선언된 함수 포인터에 대한 변수를 static으로 선언되었음을 확인하실 수 있습니다.
이제 여기서 다시 앞에서 확인하였던 선언문을 다시 한 번 보도록 합니다.
위 소스코드는 TCamConnectService로 선언된 typedef 함수 포인터를 가진 변수명 fnConnectService 안에 TCamTratis::fnConnectService 함수의 주소값을 넣겠다는 의미로 이해해 주시면 되겠습니다. 그렇다면 여기서 TCamTratis::fnConnectService 함수는 어떻게 구현되었는지 찾아보도록 하겠습니다.
/frameworks/av/camera/Camera.cpp
1 2 | CameraTraits<Camera>::TCamConnectService CameraTraits<Camera>::fnConnectService = &ICameraService::connect; | cs |
Camera.cpp 소스 코드 내에서 'CameraTraits<Camera>::fnConnectService' 라는 이름의 포인터 함수 변수가 선언되었고 해당 포인터 함수에 ICameraService::connect 함수의 주소를 넣어준다고 이해하시면 되겠습니다.
/frameworks/av/include/camera/ICameraService.h
1 2 3 4 5 6 7 8 9 10 11 12 | class ICameraService : public IInterface { public: .... virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId, const String16& clientPackageName, int clientUid, /*out*/ sp<ICamera>& device) = 0; .... } | cs |
/frameworks/av/camera/ICameraService.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | class BpCameraService: public BpInterface<ICameraService> { public: BpCameraService(const sp<IBinder>& impl) : BpInterface<ICameraService>(impl) { } .... // connect to camera service (android.hardware.Camera) virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId, const String16 &clientPackageName, int clientUid, /*out*/ sp<ICamera>& device) { Parcel data, reply; data.writeInterfaceToken(ICameraService::getInterfaceDescriptor()); data.writeStrongBinder(cameraClient->asBinder()); data.writeInt32(cameraId); data.writeString16(clientPackageName); data.writeInt32(clientUid); remote()->transact(BnCameraService::CONNECT, data, &reply); if (readExceptionCode(reply)) return -EPROTO; status_t status = reply.readInt32(); if (reply.readInt32() != 0) { device = interface_cast<ICamera>(reply.readStrongBinder()); } return status; } .... } | cs |
드디어 우리는 connect 함수를 찾아내는 데 성공하였습니다. 이로서 함수 포인터가 정의 되는 과정을 모두 살펴보았습니다. 마지막으로 이 기나긴 여정을 코드로 간결하게 요약하자면 다음과 같습니다.
TCamConnectService fnConnectService = TCamTraits::fnConnectService;
위 코드는 아래와 같이 변동이 됨을 확인하실 수 있습니다.
status_t (ICameraService::*TCamConnectService)(const sp<ICameraClient>&,
TCamConnectService = &ICameraService::connect;
위의 코드를 처음 보시는 분들은 이 시점에서도 모두 이해가 안 되실 수 있습니다. 하지만 위 코드에서 일정 부분 만이라도 이해하셨다면 여러분들은 성공하신 겁니다!
'프로그래밍 팁' 카테고리의 다른 글
| [C/C++]thread 조건변수 다루기 - pthread_cond_broadcast() (0) | 2015.09.01 |
|---|---|
| [JAVA]JDWP(Java™ Debug Wire Protocol) (0) | 2015.08.21 |
| [Java] Error 혹은 Debug시 등장하는 method인 access$000 (0) | 2015.08.20 |
| [JAVA]윈도 CMD를 통해 자바 Command Line 명령어 활용하기 (0) | 2014.10.04 |
| [JAVA] 간단한 파일 입출력(FILE I/O) 구현 (0) | 2014.09.10 |
설정
트랙백
댓글
글
컴퓨터가 대기모드 되자마자 바로 풀릴 때 해결방법
최근에 노트북에 문제가 생긴 듯 하여 프로그램을 업데이트 하는 김에 BIOS를 최신버전으로 교체한 후 컴퓨터를 껏다 켜보았습니다. 이전과는 그다지 달라진 점은 보이지 않았습니다만 평상시 때와 같이 노트북을 닫았는데 이상하게도 노트북이 대기모드에 들어가자마자 바로 풀리는 것이 아닙니까! 그것도 노트북이 접혀있는 상태 그대로 말이지요!
참으로 골치가 아파오더군요. 기껏 새로운 BIOS를 적용시켜 줬건만 평소에 쓰던대로 못하게 된게 참으로 골치가 아파오더군요. 원인이 대체 무엇인지 알 수 없어 일단은 절전모드 설정과 관련된 자료들을 살펴보았습니다.
우선 자신의 컴퓨터에 절전모드에서 깨어나게 하는 기능들에 대해 알아보도록 합니다. 먼저 컴퓨터의 CMD창을 열어서 다음과 같이 검색해 주시면 되겠습니다. CMD는 Windows7 기준으로 시작메뉴를 누른 후 'cmd'라고 입력하시면 되겠습니다.
powercfg -devicequery wake_armed
일단 위와 같이 자신의 컴퓨터를 깨우게 되는 기능들이 쭉 나오고 있습니다. HID의 경우 거의 대부분이 자신의 컴퓨터에 연결된 마우스로 추정하시면 될 듯 합니다.
일단 제 컴퓨터의 상황상 마우스가 범인일 확률이 높아졌습니다. 안그래도 마우스가 고장나서 최근에 새로 구매했었는데 왠지 새로 구매한 마우스에 해당 기능을 가지고 있는 듯 해 보이는 것이었지요. 그래서 노트북에서 마우스의 연결을 해제한 후 절전모드에 들어가 보았습니다.
이럴수가! 역시나 마우스가 범인이었습니다! 마우스를 빼고 절전모드에 돌입하더니 노트북 덮개를 열기 전까지 컴퓨터는 절전모드를 계속 유지하고 있음을 확인하였습니다.
그렇다면 이제부터는 마우스가 연결된 상태에서도 노트북이 절전모드에서 깨어나지 않도록 한다면 문제를 해결할 수 있을 듯 합니다! 그래서 이번에는 마우스가 절전모드에 개입하지 않도록 설정하는 방법에 대해 알아보도록 합니다!
먼저 시작메뉴를 여신 후 자신의 컴퓨터 속성 메뉴로 들어갑니다. 시작메뉴를 클릭하신 후 '컴퓨터' 메뉴에서 오른쪽 마우스 클릭 후 '속성(R)'을 클릭하시거나 'Windows키 + pause' 버튼을 동시에 누르면 바로 보실 수 있습니다.
그 다음 장치괸리자로 들어갑니다.
그 다음 장치관리자에서 자신의 기기에 해당하는 부분을 마우스 오른쪽을 클릭하신 후 '속성(R)'을 선택합니다.
'전원관리' 탭으로 이동하신 후 '이 장치를 사용하기 위해 컴퓨터의 대기 모드를 종료할 수 있음(O)'의 체크를 해제하신 후 확인 버튼을 눌러줍니다.
이제 자신의 컴퓨터에서 설정된 대기모드들을 확인해 봅니다.
powercfg -devicequery wake_armed
보시는 바와 같이 HID가 해제되어있는 것을 확인하실 수 있습니다. 이제 자신의 컴퓨터의 절전모드가 문제없이 동작되는 것을 확인하실 수 있으실 겁니다!
'공대생의 팁' 카테고리의 다른 글
| 공유기에 연결된 Linux(Ubuntu) 컴퓨터를 외부에서 원격 데스크톱 연결을 통해 조작하기 (6) | 2015.05.07 |
|---|---|
| TIZEN 소스코드 빌드 gbs가 설치되지 않을 때 수동으로 설치하기 (0) | 2015.05.02 |
| 우분투에서 인터넷창을 통해 윈도 미디어 플레이어 관련 영상 보는 방법 (0) | 2015.04.04 |
| 우분투 사용중 안보이거나 깨진 언어가 나올 때 언어 설치방법 (0) | 2015.03.26 |
| 티스토리 블로그를 반년간 하면서... (0) | 2015.03.12 |
설정
트랙백
댓글
글
우분투에서 인터넷창을 통해 윈도 미디어 플레이어 관련 영상 보는 방법
불과 10년 전만 해도 인터넷 환경으로 동영상을 인터넷 창을 통해 실시간으로 감상하는 일은 쉽지 않았습니다. 지금에 비해 인터넷 속도가 고화질의 동영상을 실시간으로 받아보기에는 매우 느렸으며, 동영상 스트리밍을 운영하는 사이트들은 상당한 트래픽 압박 때문에 동영상을 전문적으로 하려던 사이트는 거의 전무하다 싶었지요.
하지만 2005년 2월 유튜브가 인터넷 세계에 등장하면서 부터 인터넷 창을 통한 실시간 동영상 서비스라는 매력적인 사업이 발전하기 시작하였습니다. 유튜브가 등장한 이래로 한국 내에서도 mncast 등 동영상 스트리밍을 전문으로 하는 사이트들이 우후죽순 생겨났으나 위에서 어마어마한 트래픽을 감당하기엔 비용을 감당하기 어려워 순식간에 역사속에서 사라지고 맙니다. 그 덕분에 국내에서 동영상을 전문으로 다루는 사이트는 사실상 유튜브 뿐이라 해도 할 말이 없는 상황이 되어 버렸습니다.
유튜브가 이렇게 성공할 수 있었던 이유는 사용자의 컴퓨터 환경에 전혀 구애받지 않고 어디에서든 재생할 수 있는 flv라는 플래시 비디오 기법을 통해 저용량으로 간편하게 동영상을 공유하는 방법을 사용하였습니다. 그 덕분에 이전에 AVI와 같은 동영상을 통째로 제공하던 사이트들은 이러한 간편함에 매료되어 유튜브를 사용하게 되었고 그 덕에 현재 유튜브는 전 세계 사람들이 동영상을 공유하기 위해 찾아오는 사이트로 우뚝 서게 되었습니다.
.. 아 서론이 참으로 길었습니다. 두말하면 잔소리가 되겠습니다만 유튜브는 참으로 훌륭한 동영상 공유 사이트가 아닌가 싶습니다. 이렇게 현대에는 유튜브와 같이 동영상을 편하게 감상할 수 있는 환경이 구축되어 있는 경우가 많습니다만, 과거에 만들어진 국내의 몇몇 사이트들은 현재까지도 자체 동영상을 웹페이지에 직접 제공하는 사례가 종종 있습니다. Windows 운영체제를 사용하시는 분들이라면 약간의 대기시간만 있다면 동영상을 그나마 보실 수 있습니다만 우분투와 같은 리눅스의 경우 Windows 기반으로 만들어진 동영상을 보는게 쉽지 않습니다. 동영상을 시청하려 하게 되면 다음과 같은 화면이 우리를 맞이해 주기 때문이지요.
그렇습니다! 과거의 사이트들은 거의 대부분이 Windows 환경의 컴퓨터를 기준으로 하여 사이트를 만들다 보니 위와 같이 Windows Media Player 기반의 영상들은 바로 볼 수 없는 불편함을 가지고 있습니다. 그렇다면 이제 우분투를 통해 이러한 영상을 볼 수 있는 방법에 대해 알려드리도록 하겠습니다.
먼저 자신의 우분투 환경에 맞는 우분투 소프트웨어 센터를 실행합니다.
위 화면에서 마우스 커서가 있는 검색창 부분을 다음과 같이 입력해주세요.
'GStreamer'
검색시 다음과 같은 화면을 보실 수 있습니다. GStreamer는 Windows Media Player 환경에서 실행할 수 있는 동영상을 linux에서도 실행할 수 있도록 해줍니다. 이제 위에 보이는 저 3개를 모두 설치해 줍니다.
먼저 첫 번째인 'GStreamer ffmpeg' 비디오 플러그인을 설치해주신 다음
나머지 2개의 코덱도 설치해주시면 되겠습니다.
설치후 인터넷창을 종료하신후 다시 실행하시면 동영상이 원활하게 돌아가고 있는 것을 보실 수 있을 것입니다.
'공대생의 팁' 카테고리의 다른 글
| TIZEN 소스코드 빌드 gbs가 설치되지 않을 때 수동으로 설치하기 (0) | 2015.05.02 |
|---|---|
| 컴퓨터가 대기모드 되자마자 바로 풀릴 때 해결방법 (0) | 2015.04.05 |
| 우분투 사용중 안보이거나 깨진 언어가 나올 때 언어 설치방법 (0) | 2015.03.26 |
| 티스토리 블로그를 반년간 하면서... (0) | 2015.03.12 |
| [VMware] NX / XD is required. The processor must support and it must be enabled in the BIOS. (0) | 2015.02.21 |
