C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 팁&트릭
C++Builder Programming Tip&Tricks
[973] [퀴즈] 다음코드의 문제점은?
장성호 [nasilso] 8347 읽음    2010-03-25 03:36
어디서 퍼온 문제입니다.   출처는 나중에..
#include "stdio.h"

int main(int argc, char **argv)
{
    char *buff= "Hello!\n";
    buff[0] = 'K';
    buff[5] = 'g';
    printf("%s\n", buff);

    return 0;
}



-----------------------------------------------------------------------------
[풀이]

이 문제에서 제가 말하고자 한것은?
당연히 에러나야할것 같은데 C++Builder 에서는 위 코드가 에러가 나지 않는다는데 있습니다.

void __fastcall ShowHello(int tag)
{
    char *buff= "Hello!\n";
    if(tag==1)buff[0] = 'K';
    ShowMessage(buff);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    ShowHello(1);//에러없이  "Kello!" 가 보여질 것입니다.
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
    ShowHello(0); //그런데 여기선 "Kello!" 나올까요? "Hello!"가 나타날가요?
}


ShowHello(1);을 한번이라도 호출했다면 그 이후로 모든 ShowHello(0);에 결과는 "Kello!"가 됩니다.

[컴파일 옵션]
그리고 또 컴파일 옵션에 따라 더황당한 경우도 있을수 있습니다.

다음은 bcb6 컴파일 옵션입니다.


위 그림에 보면 "Merge duplicate strings"라는게 있는데요
default는 false인데요 만약 저 옵션이 켜져있으면  다음과 같은 문제도 발생합니다.

void __fastcall ShowHello1()
{
    char *buff= "Hello!\n";
    buff[0] = 'K';
    ShowMessage(buff);
}
//---------------------------------------------------------------------------
void __fastcall ShowHello2()
{
    ShowMessage("Hello!\n");
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    ShowHello1();//"Kello!"
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
    ShowHello2(); //여기서 무엇이 출력될까요?
}
//---------------------------------------------------------------------------


위 코드에서는 서로 다른 함수이지만...
"Merge duplicate strings"옵션이 켜져 있으면
Button1을 한번 이라도 click 했으면 그다음 부터 Button2를 click하면 항상 "Kello!"가 출력됩니다.

위 코드는 단순화 시켰기 때문에 문제점을 쉽게 발견할수도 있겠지만..
실 프로젝트에서는 저런 실수가 전혀 엉뚱한곳 에서 문제가 발생할수도 있고..
이경우 그 원인을 찾기가 쉽지 않을것입니다.

문자열을 받아서 수정해야할경우엔?

문자열을 받아 수정해야할경우엔..

1) 이경문님 얘기처럼 char [] 받던지
2) 아니면 그냥  String으로 받으면 됩니다.

그러면 문자열을 조작하더라도 문제가 발생하지 않죠~!

그럼..
candalgo, 광양 [kongbw]   2010-03-25 08:10 X
예! 주석이 없습니다!!!

쿨럭.... ㄴ(^-^;)ㄱ@@@
Lyn [tohnokanna]   2010-03-25 09:08 X
상수를 수정중
장성호 [nasilso]   2010-03-25 10:44 X
Lyn님 C++Builder에서 혹시 돌려보셨나요?
이경문 [gilgil]   2010-03-26 01:09 X
char *buff= "Hello!\n";
"Hello!\n" read only영역이고(아마두 code 영역에 들어갈 듯) 본 코드는 "mov"라는 어셈블리로 대체된다.
즉 아래 코드(buff[0] = 'K'; buff[5] = 'g';) 에서는 수정할 수 없는 영역을 수정하려 하기 때문에 에러가 난다.

참고로 본 코드 가지고 학교 다닐 때 개고생을 해 봐서 아는데 DOS에서는 제대로 작동합니다. ^^
이경문 [gilgil]   2010-03-26 01:10 X
버퍼의 내용을 수정할 수 있도록 하기 위해서는
char buff[] = "Hello!\n";
로 하면 됨. 참고로 본 코드는 스트링의 복사가 이루어 짐.
이경문 [gilgil]   2010-03-26 01:13 X
어디에선가 본 것 같은데 본 문제점은 C언어의 ambiguity의 영역으로 간주를 하더군요(포인터와 배열을 사용하는데 있어서 차이점을 코드만을 봐서는 (경험해 보지 않은 사람은) 대번에 알 수가 없다는 것입니다. 즉 컴퓨터 언어는 직관적인 인터페이스(코드만 보면 작동 방식을 가늠할 수 있어야 함)에 위배된다는 얘기.
송신영 [palindrome]   2010-03-26 09:11 X
요즘 팁 게시판이 퀴즈 게시판으로 된것 같은 느낌이... ㅎㅎ
꼭 학교에서 수학 숙제를 받은 것같은 미묘한 부담감이... ㅡㅡㅋ
이정구 [appleii]   2010-03-26 09:40 X
C++Builder 에서는 다음과 같이 나오네요.

buff[0] = 'K';
mov eax,[ebp-$04]
mov byte ptr [eax],$4b

buff[5] = 'g';
mov edx,[ebp-$04]
mov byte ptr [edx+$05],$67

에러없이 Kellog 를 출력합니다. 
김태선 [cppbuilder]   2010-03-26 09:58 X
희안하군요.
상수 수정? 수정할 수 없는 read only 영역?
Oh~ No~.

위 코드의 문제는 단지 gossip 이라는 점.
장성호 [nasilso]   2010-03-26 10:40 X
gossip아닌데..

이정구님말씀처럼.. C++Builder에서 에러가 나지 않는데요

그로인해 여러가지 문제가 발생할수 있다는것 입니다.

그걸 얘기하려구 낸 문제입니다.
------------------------------------------------------------
SongShinYoung님 !

알고리즘 퀴즈 2문제를 제외하고는

모두 vcl또는 C++Builder의  특징에 대해 잘 모르는 부분을
단지  퀴즈 형식을 빌어서 얘기하고자 한것입니다.

문제를 푸는데 목적이 있는게 아니라
문제속에 있는 어떤 원리를 얘기하고자 하는것에 목적이 있습니다.
김태선 [cppbuilder]   2010-03-26 11:42 X
이건 C/C++에서 예로부터 다뤄온 문제인데

char *str = "hallo";
때, hallo는 코드영역 뒤의 데이타 영역에 놓입니다.
물론 수정 가능하고요.
그렇기 때문에 그 영역을 한번 수정해 놓으면
다음번
char *str = "hallo";
시에도 수정된 값을 가지게 되어 있으며
이건 C/C++의 기본 세팅입니다.

단지 컴파일러에서 스트링 영역 사용을 효율성을 위해 컴파일러 옵션에 Merge Duplicate Strings
옵션을 둘 뿐인데, 이 옵션은 켜는 것은 좋지 못한 결과만을 초래하기 때문에 켜지 않는게 좋죠.
이건 그냥 과거의 메모리 부족할때 메모리 몇 바이트 아껴보자고 만든 옵션이닌까요.

이건 위에 문제를 낸 코드의 문제가 아니고
C/C++에서 다루고 있는 정적 데이타 영역에 대한 이해에 관한 것이 본질이겠군요.
코드는 전혀 하자가 없습니다.
프로그래밍 할때 전혀 신경 쓰지 않아도 됩니다.
단지 Merge Duplicate Strings의 의미만 안다면.

이정구 [appleii]   2010-03-26 18:17 X
저는 정적 데이터 영역에 있는 값은 바꿀 수 없는 것으로 알고 있는데 틀린건가요?

char *str = "hallo";

후에 str = "Hi"; 로 바꾸면 str 이 가르키는 주소가 바뀝니다.

hallo , Hi 가 이미 각각 공간이 확보되어 있고 str 은 이 주소만 바꾸어서 접근하는 것으로 알고 있습니다.

즉, hallo 가 위치한 주소에 접근해서 값을 바꾸는 것이 아니라 아예 Hi 가 위치한 주소에 접근합니다.

이경문 [gilgil]   2010-03-26 18:45 X
C++Builder 에서 테스트해 보지 않고 답글을 달아서 의미의 혼돈을 가져 온 점 죄송합니다.

static 영역의 데이터를 바꾸면 골치 아픈 일이 많아 지기 때문에
80386 이상에서부터는 특정 메모리 영역의 read/write access 권한을 줄 수가 있다는 것을 이용할 줄 알았는데
컴파일러에 따라서 이런 권한 설정이 조금씩 다른 것 같습니다.

테스트를 해 보았는데
CBuilder에서는 static data 영역의 write가 가능하고
MSVC에서는 방지해 놓은 것 같습니다.

테스트 코드는 다음에서...

http://www.gilgil.net/3643
이정구 [appleii]   2010-03-26 21:37 X
이경문님 소스를 보고나니 알 것 같습니다. 제가 내용을 착각했네요. 아주 재미있는 퀴즈였습니다.
김태선 [cppbuilder]   2010-03-27 11:29 X
원래는 char *str = "hallo"; 의 hallo 영역을 수정할 수 있는 것이
C/C++의 기본세팅이고, 볼랜드에서는 이 규칙을 지금까지 지켜왔습니다.

반면 VC쪽은 윈도 프로그래밍으로 넘어 오면서 char *str의 포인트와
char str[] 배열에 대한 구분을 시작했으며
볼랜드와 달리 데이타를 놓는 위치도 틀립니다.

볼랜드는 원래대로 데이타 영역를 놓고, 수정할 수 있으며
VC쪽은 리소스와 문자열을 마찬가지로 수정할 수 없는 영역에 놓고
이를 배열의 경우는 복사해서 동적데이타 영역에 쓰는 방식을 취하고 있습니다.

재미있는 것은 VC쪽은 char *str = "hallo";의 hallo에 대한
데이타 수정을 막고 있지만, 릴리즈 버전에서는 전혀 에러를 내지 않는
어정쩡한 입장을 취하고 있습니다.

오랫동안 잊고 있다가 말이 나와서 한번 체크해봤습니다.
원래는 어셈블리 컴파일 되었을때의 각각의 데이타 섹션도 알았는데... 기억이 다소 희미해져서...
이경문 [gilgil]   2010-03-27 13:40 X
@김태선 VS 컴파일러 Release Mode에서는 코드를 최적화때문에 결과가 다르게 나오는 것입니다. 코드 최적화가 되지 않도록 컴파일 옵션을 바꾸거나 최적화가 되지 않는 코딩을 하게 되면 결과는 똑같습니다.
이경문 [gilgil]   2010-03-27 13:51 X
>> 반면 VC쪽은 윈도 프로그래밍으로 넘어 오면서 char *str의 포인트와 char str[] 배열에 대한 구분을 시작했으며 볼랜드와 달리 데이타를 놓는 위치도 틀립니다.
제가 이 문제를 가지고 고생을 한 것이 Quick C 라는 컴파일러를 사용할 때였습니다. 당연히 Windows 환경의 컴파일러는 아니었습니다. 본 이슈는 OS와 관련된 문제가 아니고 C 언어 문법 자체의 성격입니다.
송신영 [palindrome]   2010-03-29 10:29 X
오... 항상 많이 배웁니다. ^^
좋은글 감사감사합니다.~~
저도 언제쯤 이런 수준의 토론을 할수 있을 지...
월요병이라 그런지 일이 손에 잘 안잡히네요.
그래서 볼포에서 놀고 있다는...

+ -

관련 글 리스트
973 [퀴즈] 다음코드의 문제점은? 장성호 8347 2010/03/25
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.