cygwin에서 UTF-8 변환을 하려고 합니다.
글쓴이: withtel / 작성시간: 목, 2013/03/28 - 9:38오전
Local에 있는 데이터를 Cygwin에서 Pro*C로 읽어서
UNIX 서버의 Oracle 테이블에 데이터를 넣으려고 하는데
한글 문자열을 UTF-8로 변환하는 부분에서 잘 되지 않고 있습니다.
인터넷에서 찾은 몇개 소스로 테스트를 하려고 하니
컴파일 에러가 나는데 도움을 부탁드립니다.
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iconv.h> char inBuffer[128]; char outBuffer[128]; int ConvHgCode(char *inBuffer, char *outBuffer) { memset(outBuffer, 0x00, sizeof(outBuffer)); iconv_t charset = iconv_open("UTF-8", "EUC-KR"); if ( charset == (iconv_t)-1) { printf("iconv open Error...\n"); return -1; } char* pIn = inBuffer; char* pOut = outBuffer; size_t inByte = strlen(inBuffer); size_t outByte = 9; size_t ret_iconv = iconv(charset, &pIn, &inByte, &pOut, &outByte); if(ret_iconv == -1) printf("iconvert Error...\n"); iconv_close(charset); } void main() { strcpy(inBuffer, "고길동"); printf("inBuffer : %s, Len: %d\n", inBuffer, strlen(inBuffer)); ConvHgCode(inBuffer, outBuffer); printf("outBuffer: %s, Len: %d\n", outBuffer, strlen(outBuffer)); return; } wcom@shins ~/source $ gcc -o t13 t13.c /tmp/ccvNW9a4.o:t13.c:(.text+0x31): undefined reference to `_libiconv_open' /tmp/ccvNW9a4.o:t13.c:(.text+0x95): undefined reference to `_libiconv' /tmp/ccvNW9a4.o:t13.c:(.text+0xb5): undefined reference to `_libiconv_close' collect2: ld returned 1 exit status wcom@shins ~/source $
UTF-8로 컨버전하기 위해서
다른 모듈을 설치해야 하는 건가요??
위 소스가 제대로 된 건 지도...
고수님들의 답변 부탁드립니다.
Forums:
혹시 iconv라이브러리 링크시켰나여?
저 함수이름보니까
libiconv에 있는 함수같은데
한번 링크시켜보세여
즐린
말씀하신 대로 -liconv를 추가하니 컴파일은
말씀하신 대로 -liconv를 추가하니 컴파일은 되는데
실행시키면 ret_iconv에 -1을 리턴합니다.
원래는 Unix AP 서버에서 프로그램을 돌려 DB 서버에 데이터를 넣으면 정상적으로 보이던 한글이
데이터를 PC로 내려서 cygwin에서 실행시켜서 Unix DB에 데이터를 넣으면 깨지는 관계로
UTF-8로 컨버전하려고 테스트를 하는 중인데(Unix는 모두 UTF-8 임)
에러는 나고 있지만 이 테스트 프로그램에서 출력한 것을 보면
컨버전 이전의 한글 길이가 9바이트로 꼭 UTF-8로 변환된 한글처럼 보이는 건 무슨 이유인가요?
PC의 데이터 파일을 메모장으로 열면 한글이 깨지지 않고 보이고
cygwin에서 vi로 열어도 똑같이 정상적으로 보여서
테스트 프로그램에 한글을 상수로 넣고 테스트 한 것인데...
cygwin의 profile은 언어와 관련해서는 별도로 수정한 것이 없고
LANG=ko_KR.UTF-8 으로 표시됩니다.
InBuffer Length가 9바이트로 나온 이유도 모르겠고
iconv error도 어떻게 추적해야 할지 난감합니다.
자답
테스트 하다가 보니 cygwin의 .bash_profile에 언어 관련해서 추가한 것은 없는데
set을 치면 LANG=ko_KR.UTF-8 로 뜨는게 이상해서...
혹시 vi 창에서 텍스트 파일을 꺼내도 한글이 깨지지 않지만
직접 상수로 한글을 입력한게 UTF-8로 변환해서 보여지는게 아닌가 하는 생각이 들었습니다.
그래서, 메모장에 한글을 입력해서 파일로 저장하고
그 파일을 읽어 컨버전하도록 프로그램을 수정해서 실행하니까 정상적으로 수행이 되는군요..
아래는 수정한 내용입니다.
답변을 주신 hys545 님께 감사드립니다..
한가지 문제가 있습니다. 텍스트 파일에 다음과 같이
한가지 문제가 있습니다.
텍스트 파일에 다음과 같이 두 건의 데이터를 넣을 경우
위의 프로그램을 실행시키면 다음과 같이 출력됩니다.
어디에선가 이전 데이터가 초기화되지 않고 남아서 다음 데이터에 겹쳐지고 있습니다.
그래서, iconv를 실행하기 바로 직전에
pIn과 pOut을 출력해본 결과입니다.
iconv를 실행하기 이전에는 분명 input 데이터는 17바이트와 13바이트가 분명한데
함수를 실행한 이후 outBuffer 값은 22바이트로 똑 같습니다.
원인이 무엇일까요?
고수님들 조언 부탁드립니다....
ConvHgCode()에서 outByte가 24로
ConvHgCode()에서 outByte가 24로 고정이네요. 연관이 있으려나요?
outByte는 다른 값을 지정해도
outByte는 다른 값을 지정해도 똑같습니다.
주어지는 문자열 모두가 한글일 수도 일부 몇 글자만 한글일 수도 있는데
UTF-8로 변환되는 길이가 정확히 얼마이다 라고 계산은 불가하고
일반적으로 2바이트가 3바이트로 변환되니
input 값의 1.5배 이상의 값을 주면 될 듯 싶은데요....
iconv를 호출하기 이전까지 변수가 초기화 된 것을
iconv를 호출하기 이전까지 변수가 초기화 된 것을 확인했는데도
이전 데이터가 겹쳐지는 원인을 찾을 수 없어
다른 소스를 찾아 테스트하였습니다.
이 함수에서는 이전 데이터가 더 길 경우에도
다음 데이터에 영향을 주지 않고 메모장에 있는 데이터 그대로 변환을 합니다.
그러나, 이 함수에서는 malloc으로 인해(?)
outStr이 계속 증가하고 있어
수백만건 이상의 데이터를 처리하려면 문제가 될 것도 같아
memory allocate 한 것을 컨버전이 한번 끝날 때마다
deallocate 하여야 할 것 같습니다.
그래서, 다음과 같이 free()를 추가하였습니다. 맞나요?
free()를 추가한 이후 실행 결과입니다.
이번에는 가장 긴 데이터만 다르고 모두 outStr 값이 증가하지 않고 같은데
그런 경우에는 역시 이전 데이터가 겹쳐집니다.
원인이나 잘못된 곳을 지적해 주세요..
iconv를 제대로 처리하는 방법이 너무 급합니다. 계속 삽질만... ㅠㅠ
iconv 내에서 output값으로 내보내는 변수가 clear 되지 않고 계속 사용되는 느낌입니다.
처음 테스트한 소스나 두번째 소스 모두 같은 결과인데
어디가 문제일까요?
문자열 끝에 null 을 주지않아 생기는
문자열 끝에 null 을 주지않아 생기는 문제입니다.
Iconv 함수가 dest str 길이를 return 하면 해당위치에 null 을 써 주어야 합니다
man iconv 만 해도 쉽게 정보를 찾을 수 있을 텐데요
EUC-KR -> CP949 코드가 좀 더 있습니다.
EUC-KR -> CP949
코드가 좀 더 있습니다.
https://xenosi.de/
iconv의 리턴값 뒤의 null
iconv의 리턴값 뒤의 null 관련..
qiiiiiiiip 님이 주신 답변대로 리턴되는 length 위치에 null을 넣으려고 보니까
다음과 같네요..
우선 첫번째 테스트했던 소스코드에 함수를 호출하기 전과 호출한 뒤의 값입니다.
outByte 값이 어떻게 계산된 것인지 추측이 어렵습니다.
첫번째 데이터는 22바이트인데 7바이트 크게 리턴되었고
두번째 데이터는 16바이트인데 역시 7바이트 크게 리턴되었고
세번째는 영문 뿐이므로 5바이트인데 5바이트 많은 10바이트가 리턴되었고
네번째는 33바이트인데 3바이트 많은 36바이트가 리턴되었고
다섯번째 데이터는 17바이트인데 2바이트가 크게 리턴되었네요..
두번째 테스트한 소스코드에도 동일하게 값들을 출력해 보았습니다.
우선 메모리를 free() 하지 않으면 잘 나오지만
free()를 넣으면 대부분의 결과값이 앞부분 부터 깨지는 것도 문제이고
outBufLen 값은 유추해 보건대
영문과 한글, 공백 모두 1바이트로 계산해서
전체 글자 수가 리턴되는 거 같습니다.
제가 잘못 이해한 건가요?
당연합니다. free하면 그순간부터 해당 메모리는
당연합니다. free하면 그순간부터 해당 메모리는 못쓰는겁니다. free(outStr)이라고 하면 그다음부터 outStr에는 접근해서는 안됩니다.
따라서 free(outStr) 다음에 outStr을 리턴해도 그 주소는 이미 쓸수 없는 곳이니 제대로된 결과를 얻을 수 없습니다.
함수밖에서 문자열을 획득하려면 다음 두가지중 하나입니다.
1. 함수안에서 할당한 포인터를 반환하기(예:strdup)
2. 인자로 미리 할당된 버퍼를 받기(예:strcpy)
어떤 경우던 함수 안에서 메모리를 관리하지는 않습니다.
xylosper 님 말씀대로 제가 free()에만
xylosper 님 말씀대로
제가 free()에만 정신이 팔려
이 소스 함수가 char 로 선언된 것을 깜박했었습니다.
함수를 void로 바꾸고 outStr을 outBuffer 라는 변수로 옮긴 뒤
free()를 하도록 수정하였습니다.
그런데 결과는 똑같네요..
저 위에 qiiiiiiiip님의 답변을 참고하세요.
저 위에 qiiiiiiiip님의 답변을 참고하세요.
최종 자답!
위에 테스트에 사용했던 소스코드들이 모두 구글링을 해서 찾은 거였는데
다들 조금씩 문제가 있었네요..
대부분 포인터 문제로 한번은 제대로 되어도
연속적으로 사용하는 테스트에서 문제가 나타난 걸
원 소스를 그대로 어찌하려다가 어렵게 꼬였습니다.
굳이 호출 때마다 malloc(), free()를 할 필요도 없고
그냥 있는 문자열을 가지고 호출하면 되는 거였습니다.
단지, 제가 아래에 올린 테스트용 소스에서는
컨버전할 데이터 스트링을 메모장으로 넣어 놓은 것을 파일로 읽어서 변환하는 관계로
맨 뒤의 crlf를 떼는 문장이 포함되어 있습니다.
아래는 문자열 텍스트 파일 내용과
실행한 결과입니다.
답변을 주신 hys545님, Prentice님을 비롯해서
qiiiiiiiip님, 송효진님, xylosper님 모두 감사드립니다.
사족:
소스코드를 첨부할 때
printf 문에서 %s 앞뒤에 대괄호(bracket:"[]")를 사용할 경우
여기 입력 창에서는 어떻게 입력하나요?
default 인 Filtered HTML도 그렇고
어떤 입력형식을 사용해도 다 깨져 버리던데...
댓글 달기