'분류 전체보기'에 해당되는 글 126건

  1. 2010.01.20 Copy propagation
  2. 2010.01.08 Semaphore 이용환 Download 완료 확인
  3. 2010.01.08 식사하는 철학자 동기화
  4. 2010.01.08 Reader / Writer 동기화
  5. 2009.12.11 WebKit Smart Pointer (RefPtr, PassRefPtr)
  6. 2009.11.30 Ubuntu Packages
  7. 2009.11.06 [C++] Virtual Function에 Access
  8. 2009.11.02 Windows7 System 예약 파티션 없이 설치
  9. 2009.11.01 Keycode remapping
  10. 2009.10.31 Trac + SVN 설치
  11. 2009.10.28 [Linux] ps STATE CODES
  12. 2009.10.14 [C/C++] 컴파일 타임에 ASSERT 시키기
  13. 2009.09.30 [C/C++] Hamming weight
  14. 2009.09.17 [C/C++] enum 내부에서의 macro 사용
  15. 2009.09.11 Firefox 다운로드 후 바이러스 검사 비활성화
  16. 2009.09.11 Google 친구들의 goto 피하기
  17. 2009.09.11 ASCII CODE 표
  18. 2009.09.10 [C/C++] Copy constructor, Copy assignment
  19. 2009.09.10 같은 종류의 프로그램을 하나의 단추로 표시
  20. 2009.09.10 [C/C++] const
  21. 2009.09.06 [C/C++] Shift 연산자
  22. 2009.09.03 [C++] Class Member Function 의 저장과 호출
  23. 2009.09.01 [Win32] WM_COMMAND
  24. 2009.08.14 [C/C++] _strdup
  25. 2009.08.13 OS 관련 Site
  26. 2009.08.12 Cygwin 한글 설정
  27. 2009.08.09 [COM/C++] offsetofclass 매크로
  28. 2009.08.03 [MFC/C++] GetSafeHwnd()
  29. 2009.07.30 [C++] 내부 클래스에서 외부 클래스의 Function에 접근
  30. 2009.07.01 Emacs에서 ^M 제거

Copy propagation

CS/Common 2010. 1. 20. 10:45
원문 : Wiki

In compiler theory, copy propagation is the process of replacing the occurrences of targets of direct assignments with their values. A direct assignment is an instruction of the form y = x, which simply assigns the value of x to y.

From the following code:

y = x
z = 3 + y

Copy propagation would yield:

z = 3 + x

Copy propagation often makes use of reaching definitions, use-def chains and def-use chains when computing which occurrences of the target may be safely replaced. If all upwards exposed uses of the target may be safely modified, the assignment operation may be eliminated.

Copy propagation is a useful "clean up" optimization frequently used after other optimizations have already been run. Some optimizations require that copy propagation be run afterward in order to achieve an increase in efficiency.
:

Semaphore 이용환 Download 완료 확인

CS/Common 2010. 1. 8. 07:10
원문 : Stanford iTunesU Programming Paradigm 17강

int DownloadSingleFile(const char* server, const char* path);
int DownloadAllFiles(const char* server, const char* files[], int n)
{
	int totalBytes = 0;

	Semaphore lock = 1;
	Semaphore childrenDone = 0;

	for (int i=0; i < n; ++i)
	{
		ThreadNew("DownloadSingleFile", DownloadSingleFile, 4, server, files[i], &
		totalBytes, lock, childrenDone);
	}
	for (int i=0; i < n; ++i)
	{
		// wait return.
		SemaphoreWait(childrenDone);
	}

	return totalBytes;
}

void DownloadHelper(const char* server, const char* path, 
	int* returnButes, Semaphore lock, Semaphore parentToSignal)
{
	int bytesDownloaded = DownloadSingleFile(server, path);
	SemaphoreWait(lock);
	*numBytes += bytesDownloaded;
	SemaphoreSignal(lock);
	SemaphoreSignal(parentToSignal);
}
:

식사하는 철학자 동기화

CS/Common 2010. 1. 8. 06:48
원문 : Stanford iTunesU Programming Paradigm 17강

Semaphore forks[5] = {1, 1, 1, 1, 1}
Semaphore numAllowedToEat(4); // 최소한 한명은 Idle. DeadLock 피함.

void Philosopher(int id)
{
	for (int i=0; i < 3; ++i) 
	{
		Think();
		SemaphoreWait( numAllowedToEat );
		SemaphoreWait( forks[ id ] );
		SemaphoreWait( forks[ (i+1)%5 ] );
		Eat();
		SemaphoreSignal( forks[ id ] );
		SemaphoreSignal( forks[ (id+1)%5 ] );
		SemaphoreSignal( numAllowedToEat );
	}
}

학부때 OS 시간에는 뭔가 엄청 복잡하고 어려웠는데... 왜이렇게 간단하지...? ;;;
:

Reader / Writer 동기화

CS/Common 2010. 1. 8. 05:45
원문 : Stanford iTunesU Programming Paradigm 16강

버퍼에서 Read 전에 Write 금지.
Write 되지 않은 버퍼 Read 하지 않기.
char buffer[8];
Semaphore emptyBuffers(8);
Semaphore fullBuffers(0);

int main()
{
	ThreadNew("Writer", Writer, 0);
	ThreadNew("Reader", Reader, 0);
	RunAllThread();
}

void Writer()
{
	for (int i=0; i < 40; ++i)
	{
		char c = PrepareRandomChar();
		SemaphoreWait(emptyBuffers);
		buffer[ i%f ] = c;
		SemaphoreSignal(fullBuffers);
	}
}

void Reader()
{
	for (int i=0; i < 40; ++i)
	{
		SemaphoreWait(fullBuffers);
		char c = buffer[ i%f ];
		ProcessChar(c);
		SemaphoreSignal(emptyBuffers);
	}
}
:

WebKit Smart Pointer (RefPtr, PassRefPtr)

CS/C/C++ 2009. 12. 11. 05:52
참조 :
1. http://webkit.org/coding/RefPtr.html
2. WebKit Source Code

RefPtr
Simple smart pointer.

생성자 및 소멸자
template <typename T>
RefPtr<T>::RefPtr() : m_ptr(0)
{ }

template <typename T>
RefPtr<T>::RefPtr(T* ptr) : m_ptr(ptr)
{
    if (ptr) ptr->ref();
}

template <typename T>
RefPtr<T>::~RefPtr()
{
    if (T* ptr = m_ptr) ptr->deref();
}

복사 생성자
template <typename T>
RefPtr<T>::RefPtr(const RefPtr& o) : m_ptr(o.m_ptr)
{
    if (T* ptr = m_ptr) ptr->ref();
}

대입 연산자
template <typename T> inline
RefPtr<T>& RefPtr<T>::operator=(T* optr)
{
    if (optr)
        optr->ref();
    T* ptr = m_ptr;
    m_ptr = optr;
    if (ptr)
        ptr->deref();
    return *this;
}

template <typename T> inline
RefPtr<T>& RefPtr<T>::operator=(const RefPtr<T>& o)
{
    T* optr = o.get();
    if (optr)
        optr->ref();
    T* ptr = m_ptr;
    m_ptr = optr;
    if (ptr)
        ptr->deref();
    return *this;
}

template <typename T> inline
RefPtr<T>& RefPtr<T>::operator=(const PassRefPtr<T>& o)
{
    T* ptr = m_ptr;
    m_ptr = o.releaseRef();
    if (ptr)
        ptr->deref();
    return *this;
}

사용 예
// example, not preferred style
class Document
{
    // ...
    RefPtr<Title> m_title;
}

void Document::setTitle(Title* title)
{
    m_title = title;
}

// example, not preferred style
RefPtr<Node> createSpecialNode()
{
    RefPtr<Node> a = new Node;
    a->setSpecial(true);
    return a;
}

RefPtr<Node> b = createSpecialNode();



PassRefPtr
전달시 Ownership을 포기한다.
Recommended only for function argument and result types, copying arguments into RefPtr local variables.

void derefIfNotNull(T* ptr)
{
    if (UNLIKELY(ptr != 0))
        ptr->deref();
}

template <typename T>
T* PassRefPtr<T>::releaseRef() const
{
    T* tmp = m_ptr;
    m_ptr = 0;
    return tmp;
}

생성자 및 소멸자
template <typename T>
PassRefPtr<T>::PassRefPtr() : m_ptr(0)
{ }


template <typename T>
PassRefPtr<T>::PassRefPtr(T* ptr) : m_ptr(ptr)
{
    if (ptr) ptr->ref();
}


template <typename T>
PassRefPtr<T>::~PassRefPtr()
{
    derefIfNotNull<T>(m_ptr);
}


복사 생성자
template <typename T>
PassRefPtr<T>::PassRefPtr(const PassRefPtr& o) : m_ptr(o.releaseRef())
{}


대입 연산자
template <typename T> inline
PassRefPtr<T>& PassRefPtr<T>::operator=(T* optr)
{
    if (optr)
        optr->ref();
    T* ptr = m_ptr;
    m_ptr = optr;
    if (ptr)
        ptr->deref();
    return *this;
}

template <typename T> inline
PassRefPtr<T>& PassRefPtr<T>::operator=(const PassRefPtr<T>& ref)
{
    T* ptr = m_ptr;
    m_ptr = ref.releaseRef();
    if (ptr)
        ptr->deref();
    return *this;
}


사용 예
// example, not preferred style
PassRefPtr<Node> createSpecialNode()
{
    PassRefPtr<Node> a = new Node;
    a->setSpecial(true);
    return a;
}

RefPtr<Node> b = createSpecialNode();

WebKit에서는 모든 경우에 RefPtr을 사용하기를 권장한다. 따라서 위의 경우처럼 ownership을 전달하고자 하는 경우
// example, assuming new Node starts with reference count 0
PassRefPtr<Node> createSpecialNode()
{
    RefPtr<Node> a = new Node;
    a->setSpecial(true);
    return a.release();
}

RefPtr<Node> b = createSpecialNode();




adoptRef
Reference count의 조작 없이 생성된 객체를 전달할 수 있게 한다. PassRefPtr의 friend로 되어있다.

template <typename T>
PassRefPtr<T>::PassRefPtr(T* ptr, bool) : m_ptr(ptr)
{ }

template <typename T> inline PassRefPtr<T> adoptRef(T* p)
{
    return PassRefPtr<T>(p, true);
}

사용 예
// preferred style
PassRefPtr<Node> Node::create()
{
    return adoptRef(new Node);
}
RefPtr<Node> e = Node::create();

// preferred style
PassRefPtr<Node> createSpecialNode()
{
    RefPtr<Node> a = Node::create();
    a->setCreated(true);
    return a.release();
}
RefPtr<Node> b = createSpecialNode();



OwnPtr, PassOwnPtr
RefPtr, PassRefPtr은 RefCounted에서 상속받은 클래스에만 적용할 수 있는 반면, OwnPtr, PassOwnPtr은 pointer type이나 pointed-to type을 취할 수 있다.
복사 생성자를 보면 인자로 std::auto_ptr을 받는데... 그렇다면 결국 패싱할때 소유권을 넘긴다는 말인데... 흠... 음... 흠... 좀더 살펴 봐야 겠다.

template <typename T>
struct RemovePointer {
    typedef T Type;
};

template <typename T>
struct RemovePointer<T*> {
    typedef T Type;
};

template <typename T> class OwnPtr : public Noncopyable
{
public:
    typedef typename RemovePointer<T>::Type ValueType;
    typedef ValueType* PtrType;   
    // ...

private:
    PtrType m_ptr;
};

생성자 및 소멸자
template typename<T> explicit
OwnPtr<T>::OwnPtr(PtrType ptr = 0) : m_ptr(ptr)
{ }

template typename<T>
OwnPtr<T>::~OwnPtr()
{
    deleteOwnedPtr(m_ptr);
}

복사 생성자
template typename<T>
OwnPtr<T>::OwnPtr(std::auto_ptr<ValueType> autoPtr) : m_ptr(autoPtr.release())
{ }

대입 연산자
template <typename T> inline
OwnPtr<T>& OwnPtr<T>::operator=(const PassOwnPtr<T>& o)

{
    T* ptr = m_ptr;
    m_ptr = o.release();
    if (ptr)
        deleteOwnedPtr(ptr);
    return *this;
}

:

Ubuntu Packages

TIPs 2009. 11. 30. 09:53
Manual Pages about using GNU/Linux for development
- manpages-dev

GUI Editor for SQLitedatabase
- sqlitebrowser

:

[C++] Virtual Function에 Access

CS/C/C++ 2009. 11. 6. 21:13
WebKit Source에 보면
void* vptr() { return * reinterpret_cast<void**>(this); }
요런 함수가 정의되어 있다. 그림으로 나타내 보면,



결국 vptr()을 통해서 해당 virtual function에 직접 access 가능 하다.

실제 사용은,
// ...
if (value.isCell() && (value.asCell()->vptr() == globaData.jsFunctionVPtr)
// ...
struct VPtrSet {
    VPtrSet();
    
    void* jsArrayVPtr;
    void* jsByteArrayVPtr;
    void* jsStringVPtr;
    void* jsFunctionVPtr;
};
요렇게 쓰인다.
:

Windows7 System 예약 파티션 없이 설치

TIPs 2009. 11. 2. 13:59
원문 : http://snoopy.textcube.com/902

윈7 파티션 선택화면에서
SHIFT + F10 (콘솔 모드로 전환)

> diskpart
> sel disk 0
> create partition primary
> exit
> exit

[새로고침]
:

Keycode remapping

TIPs 2009. 11. 1. 19:39
원문 : 키보드 리매핑하기(재설정)

[HKLM \ SYSTEM \ CurrentControlSet \ Control \ Keyboard Layout] Scancode Map

00 00 00 00     00 00 00 00 : 헤더부분. 00 8번
XX 00 00 00     .. .. .. .. : (XX : 바꿀 키값 + 1), 00 00 00
.. .. .. ..     .. .. .. .. :
.. .. .. ..     .. .. .. .. :
00 00 00 00                 : 마지막엔 항상 00 을 4번


바꿀 값은 다음과 같은 형식으로 이루어짐
01 23 ab cd : 01 23은 새로 설정할 키값.
ab cd는 고유 키값.

예) 49 E0 51 E0 : 51 E0(고유키) 자리에 PageUP(49 E0) 키 설정
예) 51 E0 4D E0 : 4D E0(고유키) 자리에 PageDown(51 E0) 키 설정

[참고]
한영 키값 : 72 00
한자 키값 : 71 00
:

Trac + SVN 설치

TIPs 2009. 10. 31. 21:16
참고 : http://kldp.org/node/84957

필요한 패키지 설치
# aptitude install trac subversion libapache2-svn libapache2-mod-python

Trac, SVN root directory 생성
# mkdir /var/svn
# mkdir /var/trac
# chown -R www-data.www-data /var/svn
# chown -R www-data.www-data /var/trac

SVN repository 생성
# svnadmin create /var/svn/<project>
# svn mkdir file://localhost/var/svn/<project>/branches -m "initial structure1"
# svn mkdir file://localhost/var/svn/<project>/tags -m "initial structure2"
# svn mkdir file://localhost/var/svn/<project>/trunk -m "initial structure3"

Track 환경 생성 및 초기화
# trac-admin /var/trac/<project> initenv

사용자 계정 생성
# htpasswd -cm /var/trac/<project>/passwd admin
# htpasswd -m  /var/trac/<project>/passwd user

아파치에 읽기, 쓰기 권한 주기
# chown -R www-data.www-data /var/trac
# chown -R www-data.www-data /var/svn

SVN, TRAC apache 설정
/etc/apache2/mods-available/dav_svn.conf
<location /svn/<project>>
	  DAV svn
	  SVNPath /var/svn/<project>
	  #SVNParentPath /var/svn
	  AuthType Basic
	  AuthName "Subversion Repository"
	  AuthUserFile /var/trac/<project>/passwd

	  <limitexcept get="" propfind="" options="" report="">
	  	       Require valid-user
	  </limitexcept>
</location>
# a2enmod dav_svn

/etc/apache2/sites-available/trac
<Location /trac/<project>>
	SetHandler mod_python
	PythonHandler trac.web.modpython_frontend
	PythonOption TracEnvParentDir /var/trac/<project>
	
	PythonOption TracEnv /var/trac/<project>
	PythonOption TracUriRoot /trac/<project>

	AuthType Basic
	AuthName "Repository"
	AuthUserFile /var/trac/<project>/passwd
	Require valid-user
</Location>

#<Location /trac/*/login>
<Location /trac/<project>/login>
	AuthType Basic
	AuthName "Repository"
	AuthUserFile /var/trac/<project>/passwd
	Require valid-user
</Location>
# a2ensite trac

/etc/init.d/apache2 restart
:

[Linux] ps STATE CODES

TIPs 2009. 10. 28. 03:57
원문 : man page

Here are the different values that the s, stat and state output specifiers (header "STAT" or "S") will display to describe the state of a process.
D    Uninterruptible sleep (usually IO)
R    Running or runnable (on run queue)
S    Interruptible sleep (waiting for an event to complete)
T    Stopped, either by a job control signal or because it is being traced.
W    paging (not valid since the 2.6.xx kernel)
X    dead (should never be seen)
Z    Defunct ("zombie") process, terminated but not reaped by its parent.

For BSD formats and when the stat keyword is used, additional characters may be displayed:
<    high-priority (not nice to other users)
N    low-priority (nice to other users)
L    has pages locked into memory (for real-time and custom IO)
s    is a session leader
l    is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
+    is in the foreground process group


:

[C/C++] 컴파일 타임에 ASSERT 시키기

CS/C/C++ 2009. 10. 14. 01:26
원문 : WebKit JavaScriptCore

어떤 클래스의 크기를 제한 할 경우, 컴파일 타임에 클래스 크기를 확인하는 코드.
// tunable parameters
template<size_t bytesPerWord> struct CellSize;

// cell size needs to be a power of two for certain optimizations in collector.cpp
template<> struct CellSize<sizeof(uint32_t)> { static const size_t m_value = 64; };
template<> struct CellSize<sizeof(uint64_t)> { static const size_t m_value = 64; };

const size_t MINIMUM_CELL_SIZE = CellSize<sizeof(void*)>::m_value;
const size_t CELL_ARRAY_LENGTH = (MINIMUM_CELL_SIZE / sizeof(double)) + \
	(MINIMUM_CELL_SIZE % sizeof(double) != 0 ? sizeof(double) : 0);
const size_t CELL_SIZE = CELL_ARRAY_LENGTH * sizeof(double);

#define COMPILE_ASSERT(exp, name) typedef int dummy##name [(exp) ? 1 : -1]
#define ASSERT_CLASS_FITS_IN_CELL(class) \
	COMPILE_ASSERT(sizeof(class) <= CELL_SIZE, class_fits_in_cell)

만약 클래스 크기가 CELL_SIZE보다큰 경우, Compile time error가 발생하게 된다.

error : size of array 'dummyclass_fits_in_cell' is negative.

아, 핵심은

#define COMPILE_ASSERT(exp, name) typedef int dummy##name [(exp) ? 1 : -1]

라는 거죠...
:

[C/C++] Hamming weight

CS/C/C++ 2009. 9. 30. 16:14
원문 : Xen source code
참고 : http://en.wikipedia.org/wiki/Hamming_weight

  
static inline unsigned int generic_hweight32(unsigned int w)
{
    unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
    res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
    res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
    res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
    return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
}

static inline unsigned int generic_hweight16(unsigned int w)
{
    unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555);
    res = (res & 0x3333) + ((res >> 2) & 0x3333);
    res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F);
    return (res & 0x00FF) + ((res >> 8) & 0x00FF);
}

static inline unsigned int generic_hweight8(unsigned int w)
{
    unsigned int res = (w & 0x55) + ((w >> 1) & 0x55);
    res = (res & 0x33) + ((res >> 2) & 0x33);
    return (res & 0x0F) + ((res >> 4) & 0x0F);
}

static inline unsigned long generic_hweight64(__u64 w)
{
#if BITS_PER_LONG < 64
    return generic_hweight32((unsigned int)(w >> 32)) +
        generic_hweight32((unsigned int)w);
#else
    u64 res;
    res = (w & 0x5555555555555555ul) + ((w >> 1) & 0x5555555555555555ul);
    res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul);
    res = (res & 0x0F0F0F0F0F0F0F0Ful) + ((res >> 4) & 0x0F0F0F0F0F0F0F0Ful);
    res = (res & 0x00FF00FF00FF00FFul) + ((res >> 8) & 0x00FF00FF00FF00FFul);
    res = (res & 0x0000FFFF0000FFFFul) + ((res >> 16) & 0x0000FFFF0000FFFFul);
    return (res & 0x00000000FFFFFFFFul) + ((res >> 32) & 0x00000000FFFFFFFFul);
#endif
}
:

[C/C++] enum 내부에서의 macro 사용

CS/C/C++ 2009. 9. 17. 19:38
# 소스 : WebKit JavascriptCore

#define FOR_EACH_OPCODE_ID(macro) \
    macro(op_enter, 1) \
    macro(op_enter_with_activation, 2)	\
    macro(op_init_arguments, 1) \
    macro(op_create_arguments, 1) \
    macro(op_convert_this, 2) \
    \
    macro(op_new_object, 2) \
    macro(op_new_array, 4) \
    macro(op_new_regexp, 3) \
    macro(op_mov, 3) \
    \
    macro(op_end, 2)

#define OPCODE_ID_ENUM(opcode, length) opcode,
typedef enum { FOR_EACH_OPCODE_ID(OPCODE_ID_ENUM) } OpcodeID;
#undef OPCODE_ID_ENUM

const int numOpcodeIDs = op_end + 1;

#define OPCODE_ID_LENGTHS(id, length) const int id##_length = length;
FOR_EACH_OPCODE_ID(OPCODE_ID_LENGTHS);
#undef OPCODE_ID_LENGTHS
    
#define OPCODE_LENGTH(opcode) opcode##_length

#define OPCODE_ID_LENGTH_MAP(opcode, length) length,
const int opcodeLengths[numOpcodeIDs] = {FOR_EACH_OPCODE_ID(OPCODE_ID_LENGTH_MAP)};
#undef OPCODE_ID_LENGTH_MAP

이를 전처리 작업하면
typedef enum {
    op_enter,
    op_enter_with_activation,
    op_init_arguments,
    op_create_arguments,
    op_convert_this,
    op_new_object,
    op_new_array,
    op_new_regexp,
    op_mov,
    op_end,
} OpcodeID;


const int numOpcodeIDs = op_end + 1;


const int op_enter_length = 1;
const int op_enter_with_activation_length = 2;
const int op_init_arguments_length = 1;
const int op_create_arguments_length = 1;
const int op_convert_this_length = 2;
const int op_new_object_length = 2;
const int op_new_array_length = 4;
const int op_new_regexp_length = 3;
const int op_mov_length = 3;
const int op_end_length = 2;


const int opcodeLengths[numOpcodeIDs] = { 1, 2, 1, 1, 2, 2, 4, 3, 3, 2, };


이렇게 된다.
깔끔하지 아니한가?
:

Firefox 다운로드 후 바이러스 검사 비활성화

TIPs 2009. 9. 11. 18:26
원문 : http://kb.mozillazine.org/Browser.download.manager.scanWhenDone

Firefox에서 다운로드 후 기본설정으로 바으러스 검사를 하게 되어 있는데,

about:config 로 고급 설정 모드로 들어간 후

browser.download.manager.scanWhenDone

값을 false 로 설정 해 주면 검사를 하지 않는다.
:

Google 친구들의 goto 피하기

CS/Common 2009. 9. 11. 15:53
Google 친구 아저씨들이 짠 코드를 보면 가끔 이런 형식이 보인다.
do
{
	result = false;

	...

	if ( result = foo() )
		break;
	...

	if ( result = bar() )
		break;
	
	...
} while (0);

if (false == result)
{
	...
}

foo()나 bar()에서 실패시 이후의 코드를 처리하지 않기 위함인데,

결국은 리눅스 커널의 네트워크 관련 코드의 다음과 같은 일을 한다.
if ( result = foo() )
	goto FAILED;

...

if ( result = basr() )	
	goto FAILED;

...

FAILED :
	...

결국 goto를 사용하지 않고, do-while(0) 을 이용하여 break를 사용해서 분기를 제어한 것인데,
나는 커널 코드에 익숙해져 있어서 인지, goto가 더 명시적이고 좋아 보인다.
또한 do-while(0)과 break를 이용한 방법은 그 안에 loop가 없는 경우만 사용할 수 있는 단점도 있다.

하지만,
if (  )
{
	if (  )
	{
		if (  )
		{
			if (  )
			{
				...
			}
		}
	}
}

요렇게 된 코드를
do {
	if (!  )
	{
		break;
	}

	if (!  )
	{
		break;
	}

	if (!  )
	{
		break;
	}

	if (!  )
	{
		break;
	}
} while(0);

요렇게 쓸 수 있다는 점에서는 참 매력적인 방법이다.

첨에 이 코드를 봤을때는 그냥 그렇구나 하고 지나갔었다.
그런데 우연히 미팅 시간에 팀원들과 이 코드에 대해서 얘기를 하게 되었는데, 사람들이 좋은 방법이다... 라고 대부분 얘기 하길래 포스팅 까지... 역시 셀로판귀... 팔락팔락... orz
:

ASCII CODE 표

CS/Common 2009. 9. 11. 13:08
은근히 필요할 때가 많네...

:

[C/C++] Copy constructor, Copy assignment

CS/C/C++ 2009. 9. 10. 11:07
참조 : The C++ Programming Language 3rd Ed.

class X
{
	// ...
	X(Sometype);	// constructor : create objects
	X(const X&);	// copy constructor
	X& operator=(const X&) // copy assignment : cleanup and copy
	~X()	// destructor : cleanup
};


여기서 객체가 대입이 되는데, 객체의 생성 시점에서 대입이 이루어 질 때는, copy constructor가 사용된다.
하지만, 이미 생성되어 있는 객체에 대입이 이루어 질 경우는 copy assignment가 사용된다.
따라서, copy assignment에서는 이미 생성되어 있는 객체를 cleanup 해주고 copy 해야 한다.

즉,
Sample X(10);
Sample Y(20);
Sample Z = X; // copy constructor
Z = Y;        // copy assignment

세 가지 이상의 객체가 복사되는 경우가 있다.
1. 함수의 인자로 전달
2. 함수의 리턴 값
3. 예외 전달

  
#include <iostream>
using namespace std;

class Sample
{
public:
	Sample(int e);
	Sample(const Sample&);
	Sample& operator=(const Sample&);
	~Sample();

private:
	int _elem;
};

Sample::Sample(int e) : _elem(e)
{
	cout << "Constructor : " << this << endl;
}

Sample::Sample(const Sample& s)
{
	cout << "Copy constructor : " << this << endl;

	_elem = s._elem;
}

Sample& Sample::operator=(const Sample& s)
{
	cout << "Copy assignment : " << this << endl;

	_elem = s._elem;
	return *this;
}

Sample::~Sample()
{
	cout << "Destructor : " << this << endl;
}

Sample g(Sample s)
{
	return s;
}

int main(void)
{
	Sample s(1);
	s = g(s);
	return 0;
}


결과는 다음과 같다.

Constructor      : 0x22cc50
Copy constructor : 0x22cc30
Copy constructor : 0x22cc40
Copy assignment  : 0x22cc50
Destructor       : 0x22cc40
Destructor       : 0x22cc30
Destructor       : 0x22cc50



:

같은 종류의 프로그램을 하나의 단추로 표시

TIPs 2009. 9. 10. 10:51
원문 : http://helpwithwindows.com/WindowsXP/tune-02.html

작업 표시줄에 같은 프로그램이 2개 이상 되었을 경우 무조건 그룹화 하게 하는 방법임.

1. Start the Registry Editor
2. Go to HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\
3. Right-click an empty space in the right pane and select New > DWORD Value
4. Name the new value TaskbarGroupSize
5. Double-click this new value, and enter 2 as it's Value data
6. Close the registry editor
7. Log off, or restart Windows for the changes to take effect
:

[C/C++] const

CS/C/C++ 2009. 9. 10. 09:15
원문 : Effective C++

char greeting[] = "Hello";

char *p = greeting;

const char * p = greeting;        // 상수 데이터 (char const * p = greeting;)
char * const p = greeting;        // 상수 포인터      
const char * const p = greeting;  // 상수 데이터, 상수 포인터



class Sample
{
public:
    Sample(char e) : _elem(e) {}
    const char* Get() const { return &_elem; }
    // 앞의 const는 return type이 const라는 것이고, 뒤의 const는 상수 멤버임을 의미한다.
    // 상수 멤버란, 어떤 멤버 함수가 그 객체의 어떤 데이터 멤버도 건드리지 않아야 함(static 멤버 제외).

private:
    char _elem;
};

만약,
char* Get() const { return &_elem; }
같이 한다면, 상수 객체에 대한 포인터를 리턴받아 값을 수정하는 것이 가능해 지므로 compile error.



const 키워드가 있고 없고의 차이만 있는 멤버 함수는 오버로딩이 가능하다.
class TextBlock
{
public:
    ...
   
// 상수 객체에 대한 operator[]
    const char& operator[](std::size_t position) const { return text[position]; }
    // 비 상수 객체에 대한 operation[]
    char& operator[](std::size_t position) { return text[poistion]; }
private:
    std::string text;
};


TextBlock tb("Hello");       
tb[0] = 'x';    // 비 상수 멤버를 호출


const TextBlock ctb("World");
cout << ctb[0]; // 상수 멤버를 호출

:

[C/C++] Shift 연산자

CS/C/C++ 2009. 9. 6. 01:06
2개의 shift 연산자

a << b : a를 b반큰 왼쪽으로 Shift 시킨다.
a >> b : a를 b만큼 오른쪽으로 Shift 시킨다.

왼쪽으로 이동시킬 때, 오른쪽에는 0이 채워진다.
오른쪽으로 이동 이동시킬 때, MSB에는 a의 부호 비트가 채워진다.

-6이 표현되는 비트는
1111 1111 1111 1111 1111 1111 1111 1010
이 된다.

-6 << 1 한다면, 이는
1111 1111 1111 1111 1111 1111 1111 0100
이 되고, 이는 -12 이다.
왼쪽으로 Shift 시에는 오른쪽에 무조건 0이 채워지기 때문에, 중간에 부호가 바뀌는 경우가 생길 수 있다.


-6 >> 1 한다면, 이는
1111 1111 1111 1111 1111 1111 1111 1101
이 되고, 이는 -3 이다.
음수의 표현을 2의 보수법으로 나타내기 때문에, MSB에 부호비트를 유지 함으로써, Shift시에도 올바른 값이 표현된다.


:

[C++] Class Member Function 의 저장과 호출

CS/C/C++ 2009. 9. 3. 11:10

참조 : Gof Design Pattern

Command 패턴에 나온 예이다

  
#include <iostream>
using namespace std;

class Command
{
public:
	virtual void Execute() = 0;
};

template <class Receiver>
class SimpleCommand : public Command
{
public:
	typedef void (Receiver::*Action) ();

	SimpleCommand(Receiver* r, Action a) : _receiver(r), _action(a) {}
	virtual void Execute();

private:
	Action _action;
	Receiver* _receiver;
};

template<class Receiver>
void SimpleCommand<Receiver>::Execute()
{
	(_receiver->*_action)();
}


class MyClass
{
public:
	MyClass() {}
	MyClass(const MyClass &) {}
	MyClass(const MyClass *) {}
	void MyAction() { cout << "MyClass Action\n"; }
};

int main(void)
{
	MyClass* receiver = new MyClass;
	Command* aCommand = new SimpleCommand<MyClass>(receiver, &MyClass::MyAction);
	aCommand->Execute();
}



형정의
typedef void (Receiver::*Action) ();

전달
Action _action =  &MyClass::MyAction;

호출
(_receiver->*_action)();



후아...


:

[Win32] WM_COMMAND

CS/C/C++ 2009. 9. 1. 23:08
The WM_COMMAND message is sent when the user selects a command item from a menu, when a control sends a notification message to its parent window, or when an accelerator keystroke is translated.

WM_COMMAND가 받는 경우는
1. 사용자가 메뉴에서 command item을 선택했을 때 (메뉴)
2. 컨트롤이 부모 윈도우로 통지 메세지를 보낼 때 (컨트롤)
3. 엑셀레이터키가 해석될 때 이다. (Accelerator)

즉, 메뉴, 컨트롤, 엑셀러레이터 의 3가지의 경우이다.
일단 각각을 살펴보기 전에 MSDN에 있는 WM_COMMAND의 파라미터가 어떻게 해석되는가 하면

Message Source wParam(high word) wParam(low word) lParam
Menu 0 Menu identifier (IDM_*) 0
Accelerator 1 Accelerator identifier (IDM_*) 0
Control Control-defined
notification code
Control identifier Handle to the
control window
  
요렇다.


일단 윈도우 메세지가 처리되는 과정을 보기 위해 Win Main을 보면

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
	// ...
	MSG msg;
	// ...
	hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TESTWINDOW));
	// ...
	while (GetMessage(&msg, NULL, 0, 0))	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	return (int) msg.wParam;
}

요렇게 되어있다.그럼 다시 GetMessage()는 어디서 msg를 가져오는 것일까...

MSDN에 보면This function retrieves a message from the calling thread's message queue and places it in the specified structure. 라고 되어있다.
즉,쓰레드의 메세지 큐에서 가져오는 것이다.

그런데, 하나의 UI 쓰레드(메세지큐를 가질 수 있는 쓰레드)는 여러 개의 윈도우 프로시저를 가질 수 있는데, 어떤 윈도우 프로시저에 이 메세지를 전달 해야 할까...

GetMessag()는에 MSG구조체를 채워 주는데, 이 구조체가
typedef struct {
    HWND hwnd;   
    UINT message;   
    WPARAM wParam;   
    LPARAM lParam;   
    DWORD time;   
POINT pt;
} MSG, *PMSG;
요렇게 생겨 먹었다.

MSDN에 보면 hwnd는 Handle to the window whose window procedure receives the message. hwnd is NULL when the message is a thread message. 라고 되어 있다.

즉, 이 메세지를 처리할 윈도우 프로시저를 가지고 있는 윈도우의 핸들을 GetMessage()에서 알게 되고, 핸들을 알게 된다면 그 핸들 클래스의 윈도우 프로시저를 알 수 있다. 따라서 DispatchMessage()에서 해당 윈도우를 처리할 등록된 윈도우 프로시저로 디스패치 해 줄수 있게 된다.



1. Control

일단 컨트롤의 경우는, (컨트롤 이라는 의미를 미리 등록된, 즉, RegisterClass에 등록된 클래스 라고 생각 했다) 자신을 생성한 윈도우(부모 윈도우)에 어떤 이벤트가 발생했음을
PostMessage(hParentWindow, WM_COMMAND, MAKEWORD(ID, NOTIFICATION_CODE), handle);
로 알리는 것일까?

그런데!!!
button클래스를 생각해 보면, 모든 버튼은 이 button 클래스로부터 만들어 지게 되는데, 그렇다면 윈도우즈에 있는 모든 button은 button클래스에 등록된 하나의 윈도우 프로시저에서 처리된다는 것일까?
클래스를 구조체를 보면,

typedef struct {
    UINT cbSize;
    UINT style;
    WNDPROC lpfnWndProc;
    int cbClsExtra;
    int cbWndExtra;
    HINSTANCE hInstance;
    HICON hIcon;
    HCURSOR hCursor;
    HBRUSH hbrBackground;
    LPCTSTR lpszMenuName;
    LPCTSTR lpszClassName;
    HICON hIconSm;
} WNDCLASSEX, *PWNDCLASSEX;

즉, 인스턴스와 프로시저가 같이 등록되게 되어있다. 하지만, 인스턴스마다 다른 윈도우 프로시저를 사용한다는 것은 말이 안된다. 같은 일을 하는 윈도우인데 프로시저가 다름 이상하니깐... 그렇다면?

spy로 button클래스로 생성한 버튼의 윈도우 프로시저와 인스턴스핸들 값을 보면... 어떤 인스턴스이던지 프로시저의 값은 같고, 인스턴스 핸들의 값은 항상 0 이다. ... 쏙았다.... 역시 spy가 짱... -_-;

인스턴스 핸들의 값이 0이라는 것은 어떤 전역적인 인스턴스, 혹은 인스턴스와 상관이 없다는 것일 것이고(이것이 운영체제에서 관리되는어떤 것이라고 생각한다.) 이것은 컨트롤이 받는 메시지 자체가 해당 인스턴스의 메세지 큐와는 관련이 없다는 것을 의미하는 것일것이다. 이렇게 커널에서 관리되는 메세지큐와 프로시저라면, 굳이 Notification을 보내기 위해 PostMessage()api를 사용할 필요는 없을 것이다. 해당 UI 쓰레드의 메세지큐에 집어 넣어 놓으면 펌핑 해 갈테니...(api로 집어 넣었을 수도 있지만, 어차피 운영체제에서 관리 된다면 api가 아닌 좀더 빠른 무언가로 큐에 집어 넣어 놓지 않을까...)

결론을 얘기하면.
1. 버튼이 눌린다.
2. 이 눌림 메세지 자체는 인스턴스와 상관없이 커널단의 메세지 큐에서 관리될 것이다.
3. 해당 메세지 큐에서 메세지가 등록된 윈도우에 해당하는 윈도우 프로시저에 의해 처리된다.
4. 그 컨트롤의 부모 윈도우(hwndParent)가 속한 UI 쓰레드의 메세지 큐에 WM_COMMAND 메세지를 넣어 놓는다.
5. 이제 hwndParent의 UI 쓰레드에서 메세지를 펌핑한다.
6. DispatchMessage()에서 hwndParent가 등록되어 있는 WNDPROC로 이 메세지를 Dispatch한다.
7. 해당 WNDPROC에서 WM_COMMAND를 받는다.

아마도. -_-;

그렇다면, 사용자가 컨트롤을 흉내내는 경우라면,
윈도우 클래스를 등록하고, 이 클래스로 윈도우를 만들고, 클래스에 등록된 윈도우 프로시저에서 2-4의 과정에 해당하는 과정을 해 주면 될 것이다.
만약 버튼의 클릭 되었음을 알린다면, 해당 윈도우 프로시저의 WM_LBUTTONUP 메세지에서
PostMessage(hParentWindow, WM_COMMAND, MAKEWORD(ID, NOTIFICATION_CODE), handle);
해 주면 될 것이다.



2. Menu, Accelerator

Menu는 WM_COMMAND가 전달 되는 것은, 마우스로 메뉴의 아이템을 클릭 했을 때 이고,
Aeccelerator는 WinMain에서 TranslateAccelerator(msg.hwnd, hAccelTable, &msg) 된 정보 이다.

일반적으로 ALT+F(Nmemonic)로 메뉴 자체가 선택되는 것은 이와는 다른 메커니즘인 듯 하다. 나중에 시간 나면 알아봐야지...


:

[C/C++] _strdup

CS/C/C++ 2009. 8. 14. 00:27
참조 : MSDN

char *_strdup(const char *strSource);
wchar_t *_wcsdup(const wchar_t *strSource);
unsigned char *_mbsdup(const unsigned char *strSource);

Return Value
Each of these functions returns a pointer to the storage location for the copied string or NULL if storage cannot be allocated.

Remarks
The _strdup function calls malloc to allocate storage space for a copy of strSource and then copies strSource to the allocated space.
Because _strdup calls malloc to allocate storage space for the copy of strSource, it is good practice always to release this memory by calling the free routine on the pointer returned by the call to _strdup.
:

OS 관련 Site

Develop/Operating System 2009. 8. 13. 13:06
Tthe largest online community of operating system developers.
http://www.osdev.org/

:

Cygwin 한글 설정

TIPs 2009. 8. 12. 22:06
.inputrc 에서
# Allow 8-bit input/output 부분에서
set meta-flag on
set convert-meta off
set input-meta on
set output-meta on
등 주석 해제. 필요한것 있으면 그 밑에도 해제

.bashrc에서
ls aliasing부분에 --show-control-char 추가

:

[COM/C++] offsetofclass 매크로

CS/COM 2009. 8. 9. 22:41

ATL 소스 분석중 나온 매크로로 COM_INTERFACE_ENTRY에 사용된다.
#define offsetofclass(base, derived) \
((DWORD_PTR)(static_cast<base*>((derived*)_ATL_PACKING))  -  _ATL_PACKING))
베이스 클래스의 오프셋을 구하는 매크로다...

별거 아닌데.. DWORD_PTR을 unsigned long* 로 해석해서 완전 해맸다... 히밤




:

[MFC/C++] GetSafeHwnd()

CS/C/C++ 2009. 8. 3. 15:25
참조 : MFC source code

_AFXWIN_INLINE HWND CWnd::GetSafeHwnd() const
	{ return this == NULL ? NULL : m_hWnd; }

별 생각없이 GetSafeHwnd()를 사용하곤 했는데, 소스보니 저리 되있다.
부모 윈도우를 추적하는등의 순환문에서 사용할 경우 따로 NULL인지 판별 해 주지 않아도 되고,
Runtime error를 방지(?) 할 수 있다.
NULL이 아닌것이 확실한 경우 굳이 GetSafeHwnd()를 쓸 이유는 없을듯...
:

[C++] 내부 클래스에서 외부 클래스의 Function에 접근

CS/C/C++ 2009. 7. 30. 11:22
내부 클래스를 포함하고 있는 외부 클래스에서 정의된 함수가 가상 함수인 경우,

내부 클래스의 함수에서 외부 클래스의 주소를 정확히 계산 하지 않으면 가상 함수 테이블을 찾을 수 없기 때문에 해당 함수를 호출 할 수 없게 되어 Runtime error가 발생한다

(가상 함수가 아닌 경우는 VTBL을 찾을 필요가 없기 때문에 굳이 시작 주소를 찾지 않고 캐스팅 만으로 충분)

참고 : MFC source code
#define offset(s, m) \
(size_t)&reinterpret_cast<const volatile char&>((((s *)0)->m));

class A
{
public:
	class X
	{
	public:
		void callAVtFunc();
	} m_x;

	virtual void VtFunc() { std::cout << "OK\n"; }
};

void A::X::callAVtFunc()
{
	A* a = ((A*)((char*)this - offsetof(A, m_x)));
	a->VtFunc();
}

int main(void)
{
	A a;
	a.m_x.callAVtFunc();

	return 0;
}
:

Emacs에서 ^M 제거

TIPs 2009. 7. 1. 13:03
M-x replace-string C-q C-m RET
: