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