Create TOC

2003년 5월 15일

char *과 char []의 차이

아래와 같은 소스가 있을때

void foo()
{
	char *pHello = "Hello, World";
	char aryHello[] = "Hello, World";
}

"Hello, World" 문자열은 data segment에 잡히고 pHello, aryHello 는 stack에 잡힌다.(전역변수라면 BSSThe portion of a program that is to be initialized to zero at the time the program is loaded into memory. The name bss is an abbreviation for "block started by symbol".)

약간의 차이점이 있는데

pHello는 data segment 에 저장된 "Hello, World" 의 메모리 주소를 pointing 하지만 aryHello 경우 "Hello, World"를 pointing 하는 것이 아니라 data segment에 잡힌 "Hello, World"를 복사한 복사본을 가지게 된다(배열을 초기화 하는 것이기 때문).

그런데 여기에 사용된 "Hello, World" 류의 상수처럼 사용되는 문자열은 string literal 라고 불리우며 ISO C 규약에 따르면 동일한 string literal 은 같은 메모리를 공유하도록 정하고 있다(메모리의 내용을 바꿀 수는 있지만 바꾸지 않는 것을 권장한다). 즉 동일 문자열 상수를 여러번 사용한다고 해서 메모리를 많이 사용하지 않는다. VC나 GCC 는 이런 string literal을 rodata(read only data) segment에 별도로 관리해서 메모리의 내용을 변경하려고 할때 에러를 발생시킨다. (gcc 경우 -fwritable-strings 옵션을 사용하면 rodata 에 관리하지 않기 때문에 에러가 발생하지 않는다). VC에서 /ZI 옵션을 주지 않고 빌드한 경우 위 내용이 적용되지 않는다. 보통 /ZI 옵션은 Debug 빌드에서 사용하기 때문에 Release 빌드에서는 /GF 옵션을 줘야 string literal에 대한 read only 처리가 된다.

그렇기 때문에 *(pHello + 1) = 'c' 와 같은 문법을 사용할 수 없다.

Pointers and Constants

StroustrupThe C++ Programming Lanugage Chapter 5 중 일부분

void f1(char *p)
{
	char s[] = "Gorm";

	const char *pc = s;         // pointer to constant
	pc[3] = 'g';                // error:pc points to constant
	pc = p;                     // ok

	char *const cp = s;         // const pointer
	cp[3] = 'a';                // ok
	cp = p;                     // error: cp is constant

	const char *const cpc = s;  // const pointer to const
	cpc[3] = 'a';               // error: cpc points to constant
	cpc = p;                    // error: cpc is constant
}

매크로 선언시 do { ... } while(0)을 사용하면 좋은 이유

원문

  • 매크로 안에서 지역 변수를 선언할 수 있다.
  • 복잡한 매크로를 만들 수 있다. 예를 들어 아래와 같이 매크로를 선언하고:

#define FOO(x) \
	printf("arg is %s\n", x); \
	do_something_useful(x);

아래와 같이 사용하면:

if (blah == 2)
	FOO(blah);

이렇게 해석된다:

if (blah == 2)
	printf("arg is %s\n", blah);
	do_something_useful(blah);;

의도한 바와는 다르게 base == 2 일때 do_something_useful(blash) 는 실행되지 않는다. 이 매크로를 do{...}while(0) 을 사용해서 만들었다면 아래와 같은 코드를 얻을 수 있다:

if (blah == 2)
	do {
		printf("arg is %s\n", blah);
		do_something_useful(blah);
	} while (0);

매크로를 단지 블럭({...}) 으로만 묶을 경우 복잡한 매크로 선언이나 지역 변수 사용은 가능하나 한가지 문제가 생긴다. 아래 예를 들어:

#define exch(x,y) { int tmp; tmp=x; x=y; y=tmp; }

이 매크로를 if 구절에 사용하면:

if(x>y)
	exch(x,y);          // Branch 1
else
	do_something();     // Branch 2

해석하면 아래와 같은 코드가 된다:

if(x>y) {                    // Single-branch if-statement!!!
	int tmp;                 // The one and only branch consists
	tmp = x;                 // of the block.
	x = y;
	y = tmp;
}
;                            // empty statement
else                         // ERROR!!! "parse error before else"
	do_something();

세미콜론(;) 으로 인해서 if 구절이 완료가되고 그 다음 else 구절은 에러구문이 된다.

이런 문제를 해결하기 위해서 매크로를 do{...}while(0) 로 묶는다. 이럴경우 컴파일러는 코드를 아래와 같이 해석한다:

if(x>y)
	do {
		int tmp;
		tmp = x;
		x = y;
		y = tmp;
	} while(0);
else
	do_something();

2003년 5월 8일

Network profile 저장 및 불러오기

Windows XP부터 포함된 netsh 도구를 사용하면 별도 유틸리티 없이 network profile을 저장하고 불러올 수 있다.

저장

C:\> netsh -c interface dump > networksetting.txt

불러오기

C:\> netsh -f networksetting.txt

2003년 3월 8일

wide character (wchar_t)

wchar_t

wide character란 1바이트가 아닌 그 이상의 바이트를 차지하는 정수에 저장되는 문자 코드를 의미한다. 즉 유니코드를 말한다.

C 표준은 wide character를 표현하기 위해 wchar_t 데이터 형을 정의하고 있다. 그러나 표준에서 정확한 형식을 정의하지 않은 이유로 컴파일러 구현마다 정의가 다르다.

MSVC 경우 unsigned short를 사용한다. 즉 UCS-2를 나타낸다.(UTF-16과는 다르다고 한다.). MSVC 경우 Unicode API에서는 WCHAR를 사용하는데 정의 상 wchar_t와 동일하다.(unsigned short)

gcc 경우에는 int를 사용하며 UCS-4를 나타낸다. MSVC와 동일하게 사용하려면 -fshort-wchar 옵션을 주면 된다. 그러나 이렇게 변경했을 경우 C 표준 라이브러리들이 제대로 동작할지는 알 수 없다.

이런 모호한 이유로 wchar_t를 사용할 때는 해당 시스템의 매뉴얼(msdn이던 man page던)을 읽고 사용하는 수밖에는 없다.

wint_t

char을 위한 wchar_t가 있다면 int를 위한 wint_t가 있다.

C 표준 라이브러리를 보면 문자를 다루는 함수들은 char 대신 int를 사용한다(이유를 알고 있었는데 잊었다).

이런 함수들의 unicode 버전은 wint_t를 사용한다.

주의할 점은 ansi 세계에서 문자열 표현을 위해서 int 배열을 쓰지 않는 것처럼 unicode 세계에서도 문자열 표현을 위해서 wint_t를 사용하지 않는다는 점이다(wchar_t를 사용한다).

unicode string literal

C 표준에서 unicode string literal은 아래와 같은 방법으로 표현하도록 정의되어 있다.

wchar_t wtext[] = L"Hello";

그런데 이때 gcc와 MSVC의 동작이 다르다. MSVC는 시스템 기본 로케일을 기준으로 UCS-2로 변환하지만(즉 컴파일하는 시점의 시스템 설정에 따라 다르다), gcc 경우 소스 파일의 각 byte를 하나씩 wchar_t에 복사하고 있다. 즉 소스가 영문 ascii라고 전제하고 UTF-32로 변환한다.

Debian/Zaurus와 Sync

원문

Kernel setup

아래와 같은 순서로 커널을 설청한다.

  1. 커널 버전을 결정한다. (i.e. 2.4.19-k7)
  2. apt 또는 dpkg 를 사용해서 kernel-source- 을 설치한다. (i.e. 2.4.19)
  3. apt-get install kernel-package fakeroot
  4. cd /usr/src; tar jxvf kernel-source-x.y.z.tar.bz2 (i.e. 2.4.19)
  5. cd /usr/src/kernel-source-
  6. cp /boot/config- .config
  7. make menuconfig, CDCEther 사용안함, USBDnet 사용함 으로 설정한다.
  8. dpkg -s kernel-image- - check Version line (i.e. 2.4.19-1)
  9. fakeroot make-kpkg --bzimage --arch-in-name --revision from step 5 kernel_image;
  10. sudo dpkg -i ../kernel-image-*.deb

Network Configuration

/etc/network/interfaces 파일에 아래와 같이 Zaurus 를 위한 dhcp server를 설정한다:

# iface usb0 inet dhcp

고정 IP를 사용한다면 아래와 같이 설정한다:

iface usb0 inet static
    address 192.168.129.1
    pointopoint 192.168.129.201
    netmask 255.255.255.255

Hot Plug

Hotplug 는 Zaurus를 cradle에 꼽는순간 usb0 장치를 자동으로 인식시켜준다.

/etc/network/if-up.d/50zaurus 파일을 생성하여(실행 가능한 형태로) Zaurus가 debian box를 통해서 internet을 쓸 수 있게 설정한다:

#!/bin/sh

case $IFACE in
  usb0)
    echo 1 > /proc/sys/net/ipv4/ip_forward

    iptables -t filter -F FORWARD
    iptables -t filter -P FORWARD DROP
    iptables -t filter -A FORWARD -s $IF_POINTOPOINT/$IF_NETMASK -j ACCEPT
    iptables -t filter -A FORWARD -d $IF_POINTOPOINT/$IF_NETMASK -j ACCEPT

    iptables -t nat -F PREROUTING
    iptables -t nat -P PREROUTING ACCEPT

    iptables -t nat -F POSTROUTING
    iptables -t nat -P POSTROUTING ACCEPT

    iptables -t nat -F OUTPUT
    iptables -t nat -P OUTPUT ACCEPT
    iptables -t nat -A POSTROUTING -s $IF_POINTOPOINT/$IF_NETMASK -o eth0 -j MASQUERADE
    ;;
esac