검색결과 리스트
개발관련에 해당되는 글 24건
- 2013.10.30 (signed) char와 unsigned char의 차이로 인한 구분의 필요성에 대해
- 2013.10.28 vim에서 make를 이용해 컴파일 후 디버깅 하기
- 2013.10.25 Yacc, Bison으로 인한 문제
- 2013.10.25 lex 간단한 예제2
- 2013.10.24 lex 시작하기
글
숙제 : unsigned char랑 char의 차이점. 꼭 구분해서 써야하는 예를 알려주세요.
위의 숙제를 받고 혼자 생각해본 바는...
이미 알고 있던 사전지식으로는 자료형은 맨 앞에 부호 비트가 있다. 이것이 signed 자료형이고 unsigned로 선언이 되면 부호비트를 일반 데이터비트로 사용하게 되어 데이터를 저장하게 된다.
대부분의 인터넷 검색 자료에서는 이로 인해 데이터 표현범위가 2배로 늘어나게 된다고 하는데...
실상 생각해보면 같은게 아닐까 한다. 양의 정수쪽으로는 표현범위가 2배 늘어나겠지만 음의 정수로 표현하는 범위를 상실했으니 표현 범위의 넓이는 결과적으로 같은게 아닐까?
signed char는 8비트이다. 첫 1비트를 부호비트로 쓰기 때문에 표현 범위는 -2^7~+2^7-1이 될 것이다. 고로 -128~+127이 되니 256개의 표현이 된다.
unsigned char 또한 8비트이지만 첫 1비트 또한 데이터비트이기 때문에 표현 범위는 2^8-1이 될 것이다. 고로 0~255가 된다.
이걸 구분해야 하는 이유가 있을 때는 어떤 때일까?
몇몇 블로그를 방문해 내요을 본 결과 대부분의 사람들은 1bit씩 나누어 통신을 하거나 무언가 비트 단위 작업을 할때 문제를 야기할 수 있다고 한다.
1bit씩 나누어 통신을 하는 경우에 발생하는 오류는 일반 환경에서는 발생하지 않지만 임베디드 환경에서는 발생 할 수 있다고 하는데 컴파일러 문제인지 잘 모르겠다;
char buf; 를 선언하고 RS-232 등의 통신을 위해 한 바이트식 전송을 하려고 할때 buf에 들어가는 값이 0xA0 부터 즉, sign bit 가 1이 되는 시점부터 그 값을 잘못 읽어 sizeof(char) = 1 임에도 불구하고 0xFFFFFFA0 가 되어 실제로 전송되는 값은 FF가 되는 문제가 발생을 할 수 도 있다.
[출처] 데이터는 unsigned char 로!|작성자 구차니
또, 비트단위 작업의 경우 비트단위 연산자를 쓰면 오류가 발생한다는데 예제를 찾지 못했다. 대충 예상을 해보면 10진수로 표현했을 때 정수값이 같더라도 비트값은 틀리다는 것을 말하는 걸까 싶다.
뒤늦게 찾은 예제?
1.
void main() { unsigned char c=0x80; printf("%u\n",c); printf("%d\n",c); }
실행 결과
128
128
unsigned char는 1바이트로 0~255를 표현이 가능합니다.
%u는 인자를 unsigned int 값으로 표현하는 포멧입니다.
인자 c는 unsigned char이고 출력 포멧은 unsinged int여서 묵시적 형변환이 진행됩니다.
둘 다 부호가 없는 표현이므로 묵시적 형변환이 진행될 때 늘어나는 메모리의 값은 0으로 채워집니다.
따라서 0000 0000 0000 0000 0000 0000 1000 0000 로 형변환됩니다.
여전히 10진수로 128이므로 실행 결과는 128이 출력됩니다.
%d는 인자를 int 값으로 표현하는 포멧입니다.
unsigned char는 부호를 표현하지 않으므로 묵시적 형변환이 진행될 때 늘어나는 메모리의 값으 0으로 채워집니다. 마찬가지로 0000 0000 0000 0000 0000 0000 1000 0000 로 형변환됩니다.
여전히 10진수로 128이므로 실행 결과는 128이 출력됩니다.
2.
void main() { char c=0x80; printf("%u\n",c); printf("%d\n",c); }
실행 결과
4294967168
-128
char는 1바이트로 -128~127 을 표현이 가능합니다. 물론, ASCII 코드가 0~127까지 약속되어 있어서 문자를 표현할 때 많이 사용되어 형식 명을 char라 부르게 된 것이죠.
%u는 인자를 unsigned int 값으로 표현하는 포멧입니다.
인자 c는 char이고 출력 포멧은 unsinged int여서 묵시적 형변환이 진행됩니다.
char는 부호가 있는 표현인데 최상위 비트가 1이면 음수입니다. 0x80은 1000 0000 으로 음수입니다. 묵시적 형변환이 진행될 때 늘어나는 메모리의 값은 부호비트로 채워집니다.
따라서 1111 1111 1111 1111 1111 1111 1000 0000 로 형변환됩니다.
부호없는 10진수로 4294967168 이므로 실행 결과는 4294967168를 출력합니다.
%d는 인자를 int 값으로 표현하는 포멧입니다.
인자 c는 char이고 출력 포멧은 int여서 묵시적 형변환이 진행됩니다.
char는 부호가 있는 표현인데 최상위 비트가 1이면 음수입니다. 0x80은 1000 0000 으로 음수입니다. 묵시적 형변환이 진행될 때 늘어나는 메모리의 값은 부호비트로 채워집니다.
따라서 1111 1111 1111 1111 1111 1111 1000 0000 로 형변환됩니다.
부호있는 10진수로 -128 이므로 실행 결과는 -128을 출력합니다.
찾아본 마지막으로 오류 처리를 위한 결과 값을 if 문에 사용할 때이다.
보통 아래와 같이 작성을 하는데...이 때 unsigned char의 경우 조건문을 의도한대로 탈 수 없다는 것입니다.
if([함수 이름이나 함수 리턴값이 담긴 변수 이름] < 0) bla~ bla~
머...이건 별로 유념하지 않아도 될 것 같긴 합니다만...
'개발관련 > 기타' 카테고리의 다른 글
표준출력과 표준오류출력 그리고 컴파일러 옵티마이저 레벨 (0) | 2013.11.05 |
---|---|
개발 시 성능을 고려함에 있어... (0) | 2013.10.31 |
명령 인자 처리에 대한 고민... (0) | 2013.10.31 |
라이브러리(오브젝트) 내용 보기 (0) | 2013.10.30 |
설정
트랙백
댓글
글
제목은 거창하지만 별건 아니지만 익숙해지면 꽤나 유용할 것 같은데 잘 안써서 금새 잊어버리고 막상 쓰려면 기억이 안난다.
블로깅 해두고 기억이 안나면 찾아보는 용도로 해야겠다.
이 기능을 이용하기 전에 나는 vim에서 소스를 편집하다가 테스트를 위해 저장하고 나온 후 make(컴파일)를 수행하거나 별도의 창을 띄워 make를 수행한다.
이 일련의 과정은 무척이나 번거롭다.
이 경우 vim에서 편집을 하다가 저장을 한 후 명령라인(:입력)에서 make를 입력하자.
해당 환경이 정상적인 Makefile을 찾았다면 익히 컴파일 하던데로 수순을 따를 것이다. 만약 Makefile을 의도한데로 찾지 못한다면 ':make -f Makefile' 명령을 이용해 의도한 결과를 볼 수 있을 것이다.
위와 같이 make를 수행하면 화면 하단에 make 메시지가 출력된다. 에러 메시지가 많을 때는 기억하기 힘드니 이럴땐 ':copen'을 입력해보자. 그렇게 하면 화면 하단이 분할되면서 make 메시지가 출력되어있다.
발생한 에러메시지에서 엔터를 입력하면 기존 vim창에서 해당 라인으로 이동한다.
'개발관련 > 환경관련' 카테고리의 다른 글
디버그 메시지 심기 (0) | 2013.10.11 |
---|
설정
트랙백
댓글
글
이전 포스트에서 lex, flex만은 Makefile을 작성하기 무척 쉬웠다. 꽤나 만족스럽다.
하지만 yacc, bison을 함께 하면서 모든게 어긋나기 시작했다.
문제의 발단은 lex도 .c파일을 만들어내고 yacc 또한 .c파일을 만들어내는데서 있다.
이게 왜 문제냐하면 두 소스를 같은 이름으로 못 한다는 것이다.
예로 계산기 소스를 작성하는데 calc.l파일과 calc.y파일을 만들었다고 치자.
bison을 먼저 돌려야 하지만(사실 아직 왜 먼저 돌리는지 모른다...) lex를 먼저 공부했기에 lex의 결과물을 보자.
'flex calc.l' 을 수행한다면 결과물은 lex.yy.c가 된다. 하지만 난 이게 싫어 -o 옵션으로 calc.c로 지정을 했다.
머...이유는 단순히 '.'문자가 두번 있는게 보기 싫어서이다.
이런 상황에서 bison을 돌려야 한다면...'bison -d calc.y' 명령을 사용하겠지만 이 또한 calc.tab.c와 calc.tab.h 파일을 만들어 낼테니 -o 옵션을 사용하려 한다. 하지만 calc.c파일은 이미 flex가 만들어낸 결과물이 있기 때문에 같은 이름을 사용할 수 없다.
젠장...결국 두 소스의 이름을 달리 가거나 두 소스의 컴파일 결과물의 파일이름을 다르게 지정해야한다.
결과적으로 현재는 두 소스의 이름을 별도로 가져갔다. 머가 옳은지 머가 일반적인지 모르겠다.
그래서 만들어진 Makefile
calc : calc.c parser.c $(CC) -o $@ $^ -l$(LIBS) calc.c : calc.l parser.h $(LEX) -o $@ $< parser.c : parser.y $(YACC) -o $*.c $< parser.h : parser.y $(YACC) -o $*.c $<
'개발관련 > (Fast)Lex' 카테고리의 다른 글
lex 간단한 예제2 (0) | 2013.10.25 |
---|---|
lex 시작하기 (0) | 2013.10.24 |
시작하기에 앞서... (0) | 2013.10.24 |
확장자 규칙의 사용 (0) | 2013.10.24 |
lex를 위한 간단한 Makefile (0) | 2013.10.24 |
설정
트랙백
댓글
글
이번에는 enum을 이용한 심볼 테이블을 이용한 예제
%{ enum { NONE = 0, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN }; int number; void action(); %} %% oneone { number = SEVEN; action(); } one | ONE { number = ONE; action(); } two | TWO { number = TWO; action(); } three | THREE { number = THREE; action(); } four | FOUR { number = FOUR; action(); } five | FIVE { number = FIVE; action(); } six | SIX { number = SIX; action(); } [a-zA-Z]+ { number = NONE; action(); } %% void action() { if (number != NONE) printf("%s is %d\n", yytext, number); else printf("%s?? I don't learn it.\n", yytext); } main() { yylex(); }
문자로 one이나 혹은 six까지 입력을 했을때 enum에서 정의한 숫자와 매치해서 미리 정해둔 문장을 출력한다.
'개발관련 > (Fast)Lex' 카테고리의 다른 글
Yacc, Bison으로 인한 문제 (0) | 2013.10.25 |
---|---|
lex 시작하기 (0) | 2013.10.24 |
시작하기에 앞서... (0) | 2013.10.24 |
확장자 규칙의 사용 (0) | 2013.10.24 |
lex를 위한 간단한 Makefile (0) | 2013.10.24 |
설정
트랙백
댓글
글
블로깅의 목적이 타인에게 지식을 공유하기 보다는 내 스스로의 지식 저장소로 쓰기 위한 목적이 더 크므로 방문자를 위한 배려가 고려되지 않았다.
그래서 lex가 어떻게 생겨났고 어떻게 쓰이며 어떻게 설치하고 그런 부분은 과감히 생략한다.
아마도 대부분의 linux라면 설치가 되어있으리라 생각한다. 여튼...내가 사용하는 회사 서버에는 설치가 되어있다.
인터넷에서 검색해서 나온대로 컴파일 방법은 아래와 같다
lex [OPTIONS] [FILE]...
머...옵션은 무쟈게 많다. 기껏 버전은 2.5.35인데 머가 이리 많은지...
그리고 버전과 해당 옵션 설명을 대충이라도 보기위해 매뉴얼을 펼쳐본 순간...내 시스템에서 lex는 flex라는 걸 알게되었다;;;
lrwxrwxrwx. 1 root root 4 2012-03-27 05:33 /usr/bin/lex -> flex*
이게 머야...그럼 지금 난 lex를 하고 있는건가 flex를 하고 있는건가...처음부터 혼돈의 카오스가 밀려오는구나...
각설하고 이전 포스팅에서 사용했던 간단한 예제를 컴파일 해보자.
%% .|\n ECHO; %% main() { yylex(); }
위 예제는 입력을 그대로 화면에 출력해 주는 예제이다. 기본적으로 입력받은 그대로 echo 해주는 것 같음.
그리고 글을 쓰고 있는 지금도 yylex();가 무엇을 의미하는지 모르겠다.
모르겠다고 해놓고 지나가려다 보니 궁금해서 한번 뒤져봤더니 아래와 같단다.
// Call yylex with new input/output sources. int yylex( FLEX_STD istream* new_in, FLEX_STD ostream* new_out = 0 ) { switch_streams( new_in, new_out ); return yylex(); } // Switch to new input/output streams. A nil stream pointer // indicates "keep the current one". virtual void switch_streams( FLEX_STD istream* new_in = 0, FLEX_STD ostream* new_out = 0 ) = 0;
이번에는 간단한 파싱이 들어간 예제이다
%{ /* * My favorite... */ %} %% [\t ]+ ; rain | rose { printf("%s!! That is my favorite.\n", yytext); } love | story { printf("%s!! I like a love story. ^_~\n", yytext); } "potato chip" | potato | chip { printf("%s...!! now and then, I have a potato chip.\n", yytext); } [A-Za-z]+ { printf("%s..., what is that?\n", yytext); } .|\n { ECHO; } %% main() { yylex(); }
rain, rose, love, story, ptato chip, potato, chip에 대한 패턴 처리가 들어있다. lex에서도 | 문자는 or와 같은 의미로 쓰이나보다.
7번 라인의 구문은 먼지 모르겠다;;
[\t ]+ ;
'개발관련 > (Fast)Lex' 카테고리의 다른 글
Yacc, Bison으로 인한 문제 (0) | 2013.10.25 |
---|---|
lex 간단한 예제2 (0) | 2013.10.25 |
시작하기에 앞서... (0) | 2013.10.24 |
확장자 규칙의 사용 (0) | 2013.10.24 |
lex를 위한 간단한 Makefile (0) | 2013.10.24 |
RECENT COMMENT