[C] array 선언과 관련된 질문입니다.

strongspirit의 이미지

안녕하세요.

C를 공부하고 있는데 array 사용중 이해가 되지 않는 부분이
있어서 질문글을 올립니다.

코드는 다음과 같습니다.

#include <stdio.h>
#include <stdlib.h>

typedef struct
{
    char *name;
    char *id;
} student;

int main(int argc, char*argv[])
{
    int length;
    FILE *fp;

    fp=fopen("db.txt","r");
    // db.txt파일 첫부분에 int가 있다고 가정.
    fscanf(fp, "%d", &length);
    fclose(fp);

    student array[length];

    return 0;
}

위와 같이 사용할때 에러가 발생하는데 왜 에러가 발생하는지
이해가 잘되지 않습니다. 컴파일러가 알려주는 메세지도 너무
짧아서 정보도 부족하구요.

그런데 array선언을 FILE 핸들링 하기 전에 선언해주면
올바로 컴파일이 되더군요. 물론 이때 array size는 미리 정했습니다.

위와 같은 경우에 컴파일이 불가능 하다면

만약 어떤 파일의 첫부분에 array의 사이즈를 나타내는 수가 있고
그 이후부터는 struct의 member에 알맞는 자료들이 있다고
가정할때 어떤식으로 접근해야 할까요?

그럼 즐거운 하루 되세요.

Necromancer의 이미지

C는 중간에 변수선언 못해서 그럴겁니다.
C++은 이게 가능하지만

scope 시작부분에 써야만 되더군요. array 변수를 앞쪽의
fp나 length 변수 있는데 놓아야 할겁니다.

Written By the Black Knight of Destruction

wafe의 이미지

선언은 항상 스코프 제일 앞에서 해야하구요, 배열의 개수를 지정하는 값은 상수가 아니면 안될겁니다.

Heejoon Lee

rapzzard의 이미지

Quote:

선언은 항상 스코프 제일 앞에서 해야하구요, 배열의 개수를 지정하는 값은 상수가 아니면 안될겁니다.

현재 C99에서는 두가지 경우 다가 가능합니다..
gcc를 쓰는경우에는 -std=c99옵션을 붙이시고 해보세요..:D
wafe의 이미지

rapzzard wrote:
Quote:

선언은 항상 스코프 제일 앞에서 해야하구요, 배열의 개수를 지정하는 값은 상수가 아니면 안될겁니다.

현재 C99에서는 두가지 경우 다가 가능합니다..
gcc를 쓰는경우에는 -std=c99옵션을 붙이시고 해보세요..:D

스코프 제일 앞이 아니라도 변수 선언이 되고, 배열 개수를 상수가 아닌 값으로 지정할 수 있다는 건가요? :shock:

Heejoon Lee

버려진의 이미지

wafe wrote:
rapzzard wrote:
Quote:

선언은 항상 스코프 제일 앞에서 해야하구요, 배열의 개수를 지정하는 값은 상수가 아니면 안될겁니다.

현재 C99에서는 두가지 경우 다가 가능합니다..
gcc를 쓰는경우에는 -std=c99옵션을 붙이시고 해보세요..:D

스코프 제일 앞이 아니라도 변수 선언이 되고, 배열 개수를 상수가 아닌 값으로 지정할 수 있다는 건가요? :shock:

그게 C99표준입니다.

여기서도 여러차례 이야기가 나왔었기 때문에 자세한건 생략.. =3=3

kslee80의 이미지

strongspirit wrote:
만약 어떤 파일의 첫부분에 array의 사이즈를 나타내는 수가 있고
그 이후부터는 struct의 member에 알맞는 자료들이 있다고
가정할때 어떤식으로 접근해야 할까요?

그런 경우를 위해서 malloc() 이라는 함수가 존재하는 것이죠.
익명 사용자의 이미지

kslee80 wrote:
strongspirit wrote:
만약 어떤 파일의 첫부분에 array의 사이즈를 나타내는 수가 있고
그 이후부터는 struct의 member에 알맞는 자료들이 있다고
가정할때 어떤식으로 접근해야 할까요?

그런 경우를 위해서 malloc() 이라는 함수가 존재하는 것이죠.

그래서 저도 malloc()으로 구현해 봤습니다만 잘 안되던데요^^;;
위의 코드에 추가시킨다면 아래와 같은 코드가 되지 않을까요?
student *a;
a=malloc( sizeof(student)*length);
근데 void* type과 student* type은 전환이 안된다고 하네요...
이럴땐 어떻게 해결하죠?
Visual C++에서 void* a; 라고 선언하니까 다른 에러가 나왔습니다.

doldori의 이미지

C++로 컴파일하신 겁니다. 확장자를 c로 바꾸고 다시 해보세요.

d3m3vilurr의 이미지

Anonymous wrote:
kslee80 wrote:
strongspirit wrote:
만약 어떤 파일의 첫부분에 array의 사이즈를 나타내는 수가 있고
그 이후부터는 struct의 member에 알맞는 자료들이 있다고
가정할때 어떤식으로 접근해야 할까요?

그런 경우를 위해서 malloc() 이라는 함수가 존재하는 것이죠.

그래서 저도 malloc()으로 구현해 봤습니다만 잘 안되던데요^^;;
위의 코드에 추가시킨다면 아래와 같은 코드가 되지 않을까요?
student *a;
a=malloc( sizeof(student)*length);
근데 void* type과 student* type은 전환이 안된다고 하네요...
이럴땐 어떻게 해결하죠?
Visual C++에서 void* a; 라고 선언하니까 다른 에러가 나왔습니다.

student *a;
a=(student*)malloc(sizeof(sutdent)*length);

이렇게 해주어야 하지 않나요?
doldori의 이미지

d3m3vilurr wrote:
student *a;
a=(student*)malloc(sizeof(sutdent)*length);

이렇게 해주어야 하지 않나요?

C에서는 void*로부터 대상체 포인터로 암시적인 형변환이 됩니다. (C++에서는
명시적인 캐스팅이 필요합니다.) malloc()의 반환값을 캐스팅하는 것은 불필요하며
더 나아가 바람직하지 않는 스타일입니다. 권장되는 방법은
studen* a = malloc(sizeof *a * length);

입니다. 불필요한 캐스팅은 컴파일러를 입다물게 해서 혹시 있을지도 모르는 에러를
감출 수 있기 때문입니다. 그리고 위에서 보듯이 student라는 형명을 여러 번 쓰게
만들어 중복성을 높이고 코드의 유지보수를 힘들게 만듭니다.
익명 사용자의 이미지

doldori wrote:
d3m3vilurr wrote:
student *a;
a=(student*)malloc(sizeof(sutdent)*length);

이렇게 해주어야 하지 않나요?

C에서는 void*로부터 대상체 포인터로 암시적인 형변환이 됩니다. (C++에서는
명시적인 캐스팅이 필요합니다.) malloc()의 반환값을 캐스팅하는 것은 불필요하며
더 나아가 바람직하지 않는 스타일입니다. 권장되는 방법은
studen* a = malloc(sizeof *a * length);

입니다. 불필요한 캐스팅은 컴파일러를 입다물게 해서 혹시 있을지도 모르는 에러를
감출 수 있기 때문입니다. 그리고 위에서 보듯이 student라는 형명을 여러 번 쓰게
만들어 중복성을 높이고 코드의 유지보수를 힘들게 만듭니다.

그게 정말 그럴까요? 오히려 그 부분은 C++의 Strong typing 기능으로 C에서 모호하게 넘어가는 부분을 강력하게 체크해서 에러를 최대한 줄여보고자 했던걸로 아는데요? 뭐든지 의도에 맞지 않게 사용하면 위험한 법인데, 권장사항을 의도에 맞지 않게 엉뚱하게 사용할것까지 예상하여 "위험하다"고 말하는건 넌센스라고 봅니다. C++에서 Strong 하게 타입 캐스팅까지 철저히 체크하는 이유가 분명히 있습니다.

제가 볼때 답변하신 분은 캐스팅을 잘못사용할 경우까지 포함하면 "너무 위험하기 때문에" 사용하지 않는것이 좋겠다고 말씀하신것 같은데 이것은 자동차가 "어떤 경우에는" 위험하기 때문에 자동차 타는것을 거부해야 한다는 얘기랑 비슷한것 같습니다. 그렇게 따지면 이 세상에 아무것도 할 수 있는것이 없을겁니다.

shji의 이미지

student *a;
a=(student*)malloc(sizeof(sutdent)*length);

이게 정확한 사용법이라고 생각되는데요..
(가변배열이나 new를 쓰지 않고 malloc을 사용한다면요..)

타입 캐스팅을 권장하지 않는다고 하지만 void*를 리턴하는
이와 같은 경우에는 바람직하지 않다고 할 수는 없지 않을지요..

student라는 이름을 여러번 사용하는 것이 번거로울지는
몰라도 이렇게 해 주지 않으면 컴파일 시에 타입체크 에러가
발생하므로 잘 못 사용하여 다른 타입으로 지정하여 런타임
에러가 발생하는 불상사는 없으니, 이와 같은 사용에 거부감을
가질 필요는 없습니다..

doldori의 이미지

길동 wrote:
그게 정말 그럴까요? 오히려 그 부분은 C++의 Strong typing 기능으로 C에서 모호하게 넘어가는 부분을 강력하게 체크해서 에러를 최대한 줄여보고자 했던걸로 아는데요? 뭐든지 의도에 맞지 않게 사용하면 위험한 법인데, 권장사항을 의도에 맞지 않게 엉뚱하게 사용할것까지 예상하여 "위험하다"고 말하는건 넌센스라고 봅니다. C++에서 Strong 하게 타입 캐스팅까지 철저히 체크하는 이유가 분명히 있습니다.

cdpark님 말씀대로 C인지 C++인지 분명하게 할 필요가 있겠습니다.
일단 C++에서 malloc은 쓸모가 없다는 점에 대해서는 동의하시리라 믿습니다.
(적어도 새로 작성하는 코드에서는.) 따라서 이 논의에서 C++은 제외하겠습니다.
그럼 "C에서 malloc의 반환형을 캐스팅하는 것이 바람직한가"가 초점이 되는데,
이 점에 대해서는 많은 분들이 "바람직하지 않다"고 말하고 있습니다. 다음에 몇 가지를
소개합니다. 모두 C에 관한 한 매우 정확한 지식을 갖고 있는 분들입니다.

http://groups.google.co.kr/groups?selm=kbjo9.147%24t56.4603%40news.hananet.net
http://groups.google.co.kr/groups?selm=3ADD0E1D.FB9609C%40bawi.org
http://pcrc.hongik.ac.kr/~cinsk/cfaqs/html/node9.html#7.7

길동 wrote:
제가 볼때 답변하신 분은 캐스팅을 잘못사용할 경우까지 포함하면 "너무 위험하기 때문에" 사용하지 않는것이 좋겠다고 말씀하신것 같은데 이것은 자동차가 "어떤 경우에는" 위험하기 때문에 자동차 타는것을 거부해야 한다는 얘기랑 비슷한것 같습니다. 그렇게 따지면 이 세상에 아무것도 할 수 있는것이 없을겁니다.

적절하지 않은 비유입니다. 그 말씀은 "C를 쓰면 잘못된 코드를 작성할 수 있기 때문에
C를 쓰면 안된다"고 하는 거나 마찬가집니다. 그보다는 "자동차에 불필요한 장식은
위험하므로 하지 않는 것이 좋다"는 비유가 더 적당하다고 봅니다.
GunSmoke의 이미지

아~
또다시 반복되는 토론이군요.
doldori님께서 링크하신 뉴스그룹에서의 토론 내용이 비생산적인 쳇바퀴 굴리기를 막아줄 것이라고 생각합니다. 'C에서 malloc()의 반환형에 대한 강제 casting은 바람직하지 않습니다.'

大逆戰

doldori의 이미지

shji wrote:
student라는 이름을 여러번 사용하는 것이 번거로울지는
몰라도 이렇게 해 주지 않으면 컴파일 시에 타입체크 에러가
발생하므로 잘 못 사용하여 다른 타입으로 지정하여 런타임
에러가 발생하는 불상사는 없으니, 이와 같은 사용에 거부감을
가질 필요는 없습니다..

student* a = (teacher*)malloc(sizeof(teacher));
student* b = malloc(sizeof(*b));

shji님은 a에서 경고 메시지라도 기대하시는 것 같은데, 그보다는 차라리 b처럼
해서 불필요한 캐스팅도 없애고 타입에도 안전한 쪽으로 하는 것이 바람직합니다.
shji의 이미지

>...
>char *a = malloc(10);
>은 다음과 같은 implicit declaration 을 만들게 되고,
>int malloc();
>반환형과 a 의 데이터형이 다르기 때문에 진단 메시지가 출력되도록 요구되
>는 상황이 전개됩니다 - malloc() 가 제대로 선언되지 않았다는 사실을 알 게 되겠죠.
>...

음.. 선언이 되지 않은 경우의 부작용이 있군요..
공부가 되었습니다..

익명 사용자의 이미지

doldori wrote:
cdpark님 말씀대로 C인지 C++인지 분명하게 할 필요가 있겠습니다.
일단 C++에서 malloc은 쓸모가 없다는 점에 대해서는 동의하시리라 믿습니다.
(적어도 새로 작성하는 코드에서는.) 따라서 이 논의에서 C++은 제외하겠습니다..

C++을 제외하고 생각한다면 애초에 제가 그런글을 쓰지도 않았을겁니다. (물론 이 쓰레드 주제안에 C++이 포함되느냐/아니냐의 문제는 별도의 논의가 필요할것입니다.-다시 말해 별도의 제한이 없다면 현재의 논의는 C++까지 포함하는것이 맞다고 봅니다-)

인용하신 글에서도 답변하시는 분들께서 심각하게 다른 측면을 무시하고 계신듯한 느낌이었습니다. 제가 말씀드리는 "다른 측면"이란 코드의 가독성 or 명료성입니다. C++이 보다 강력한 타입체킹을 했던것도 첫째가 컴파일러 입장에서 코드가 여러가지로 해석될 수 있는 모호함을 제거하고자 위함이었고, 둘째가 프로그래머 입장에서도 코드 읽기에 불편함이 없도록 타입을 명시화하는것을 강제하여 가독성을 높이려는 의도였던걸로 압니다. 이것이 무슨뜻인지는 이해하고 계실것 같으니 자세한 설명은 생략하겠습니다.

"컴파일러가 입다물어서" 뿌려주어야 할 에러조차 주지 않는 경우는 분명히 피해야 합니다. 하지만, 이것은 위에 설명한 경우를 배제하기 위해 코드를 보다 명료화시키는데서 발생할 수 있는 장점에서 오는 단점입니다.

1. 억지로 캐스팅을 행해서 코드를 명료하게 만들어 놓았는데 그것으로 인해 런타임시 죽어버리는 현상이 발생했다.
2. malloc에 명확한 캐스팅을 써놓지 않아서 매번 코드를 읽을때마다 변수 선언부를 뒤져보아야 했다.(코멘트로 해결하는것도 생각해 볼 수 있겠으나, 오히려 그렇게 하면 컴파일러가 해석하는것과 코멘트의 내용이 불일치하는 경우가 발생할 수 있음)

1, 2의 문제를 동시에 해결하는것은 불가능해 보입니다. 어떤 가치(혹은 어떤 실수를 줄이는데)에 더 높은점수를 두느냐에 따라 캐스팅을 할것인지 말것인지가 결정될것입니다.

그런데 doldori 님과 인용해주신 뉴스그룹에서의 글은 2의 측면을 거의 무시하고 말씀하시고 계시다는 느낌이 들었습니다. 제 경우 현실적으로 2사항이 훨씬 저를 괴롭혔고, 그래서 저는 명시적으로 캐스팅을 사용합니다. 설령 1의 실수가 나오더라도 그것이 2의 경우로 인해 발생하는 시간낭비, 실수를 넘어서지 않는다면 저는 명시적 캐스팅으로 인해 얻어지는 장점을 취할것입니다.

익명 사용자의 이미지

사족을 달면, 비단 이것은 malloc 사용에 한정된 얘기가 아닙니다. 또 그저 언어의 문법이나 코딩 스타일을 얘기하는것도 아닙니다. 제 글의 요지는 프로그램의 semantics가 "자기 완결적"이어야 한다는 뜻입니다. 컴파일러에 의존하여 프로그램의 의미구조 변경을 허용한다면 그런 프로그램은 지양해야 한다는거죠. 프로그래밍 언어를 연구하는 분야에서는 (특히 functional 언어에서) 그래서 type checking 라는 주제가 매우 중요하게 여겨지는걸로 압니다. 물론 그 분야에서는 C/C++조차도 거의 Ad-hoc으로 취급하는이유로 필드에서 발생하는 현실적인 측면이 무시되는 부분이 있다는것은 인정합니다. 하지만, 저는 프로그래밍 언어가 그런 방향으로 진화하게 될것을 예상하고 있고, 또 그렇게 가야 한다고 믿고 있기 때문에 프로그램의 의미구조를 흩어놓을 수 있는 doldori 님의 "충고"가 그렇게 올바르게 보이지 않는것이 사실이군요.

doldori의 이미지

길동 wrote:
C++을 제외하고 생각한다면 애초에 제가 그런글을 쓰지도 않았을겁니다. (물론 이 쓰레드 주제안에 C++이 포함되느냐/아니냐의 문제는 별도의 논의가 필요할것입니다.-다시 말해 별도의 제한이 없다면 현재의 논의는 C++까지 포함하는것이 맞다고 봅니다-)

C++에 대해 논의하면서 malloc 얘기를 하는 것은 별로 어울리지 않아서 그랬던
것입니다. 앞으로도 C만을 대상으로 얘기하겠습니다.

길동 wrote:
"컴파일러가 입다물어서" 뿌려주어야 할 에러조차 주지 않는 경우는 분명히 피해야 합니다. 하지만, 이것은 위에 설명한 경우를 배제하기 위해 코드를 보다 명료화시키는데서 발생할 수 있는 장점에서 오는 단점입니다.

1. 억지로 캐스팅을 행해서 코드를 명료하게 만들어 놓았는데 그것으로 인해 런타임시 죽어버리는 현상이 발생했다.
2. malloc에 명확한 캐스팅을 써놓지 않아서 매번 코드를 읽을때마다 변수 선언부를 뒤져보아야 했다.(코멘트로 해결하는것도 생각해 볼 수 있겠으나, 오히려 그렇게 하면 컴파일러가 해석하는것과 코멘트의 내용이 불일치하는 경우가 발생할 수 있음)

1, 2의 문제를 동시에 해결하는것은 불가능해 보입니다. 어떤 가치(혹은 어떤 실수를 줄이는데)에 더 높은점수를 두느냐에 따라 캐스팅을 할것인지 말것인지가 결정될것입니다.


제 생각에는 동시에 해결하는 것이 가능합니다. 명시적 캐스팅을 쓰는 이유로 (2)를
말씀하시는 분들이 있습니다만, 이것은 C99에서 문장과 선언을 섞어쓸 수 있게
함으로써 자연스럽게 해결이 되었습니다. 이와 관련하여 바람직한 스타일은

1. 초기치가 확실히 정해질 때까지는 변수 선언을 최대한 미룬다.
2. 따라서 변수 선언은 초기치 지정까지 함께 한다.

입니다. 예를 들면

int get_size(void);

void f(void)
{
    int size;
    int* p;
    /* ... */
    size = get_size();
    p = malloc(size * sizeof *p);
    /* ... */
}

void g(void)
{
    /* ... */
    int size = get_size();
    int* p = malloc(size * sizeof *p);
    /* ... */
}

f()보다는 g()가 바람직한 스타일이라는 뜻입니다. C++을 알고 계신다면 이것이
가독성뿐만 아니라 효율과도 관련이 있다는 점도 이해하실 것입니다.

길동 wrote:
그런데 doldori 님과 인용해주신 뉴스그룹에서의 글은 2의 측면을 거의 무시하고 말씀하시고 계시다는 느낌이 들었습니다. 제 경우 현실적으로 2사항이 훨씬 저를 괴롭혔고, 그래서 저는 명시적으로 캐스팅을 사용합니다. 설령 1의 실수가 나오더라도 그것이 2의 경우로 인해 발생하는 시간낭비, 실수를 넘어서지 않는다면 저는 명시적 캐스팅으로 인해 얻어지는 장점을 취할것입니다.

좋습니다. 이것은 어디까지나 스타일의 문제이고 언어의 강제 사항은 아닙니다.
그렇지만 바람직한 스타일이라는 것은 코딩 실수를 줄일 수 있도록 오랜 경험에
의해 축적된 지혜라고도 볼 수 있고 이것을 가볍게 무시하는 것은 득이 되지 않는다는
점은 말씀드리고 싶습니다.
doldori의 이미지

길동 wrote:
사족을 달면, 비단 이것은 malloc 사용에 한정된 얘기가 아닙니다. 또 그저 언어의 문법이나 코딩 스타일을 얘기하는것도 아닙니다. 제 글의 요지는 프로그램의 semantics가 "자기 완결적"이어야 한다는 뜻입니다. 컴파일러에 의존하여 프로그램의 의미구조 변경을 허용한다면 그런 프로그램은 지양해야 한다는거죠.

"자기 완결적"이라는 말이 구체적으로 어떤 뜻인지는 잘 모르겠습니다. 캐스팅을
하지 않으면 컴파일러에 의해 코드의 의미가 변경될 수 있다는 뜻인가요? 그렇다면
그것은 캐스팅을 쓰지 않았기 때문이 아니라, 프로그래머의 의도를 제대로 코드로
표현하지 않았기 때문이고, 컴파일러가 이해하는(언어 표준에서 정해진) 의미와
프로그래머가 기대한 의미가 다르다는 것은 잘못된 코드라는 뜻이 됩니다.

길동 wrote:
프로그래밍 언어를 연구하는 분야에서는 (특히 functional 언어에서) 그래서 type checking 라는 주제가 매우 중요하게 여겨지는걸로 압니다. 물론 그 분야에서는 C/C++조차도 거의 Ad-hoc으로 취급하는이유로 필드에서 발생하는 현실적인 측면이 무시되는 부분이 있다는것은 인정합니다. 하지만, 저는 프로그래밍 언어가 그런 방향으로 진화하게 될것을 예상하고 있고, 또 그렇게 가야 한다고 믿고 있기 때문에 프로그램의 의미구조를 흩어놓을 수 있는 doldori 님의 "충고"가 그렇게 올바르게 보이지 않는것이 사실이군요.

타입 체킹을 그렇게도 중요하게 생각하신다면 명시적인 캐스팅을 옹호하는 것은
모순이 아닙니까? 명시적인 캐스팅은 오히려 타입 체킹을 무시하겠다는 뜻으로
이해하고 있습니다만.
그리고 제가 제시한 코드가 어떤 점에서 의미 구조를 흩어놓는다고 보십니까?
제가 보기에는 전혀 오해의 소지가 없는 명확한 코드인데요.
익명 사용자의 이미지

doldori wrote:
C++에 대해 논의하면서 malloc 얘기를 하는 것은 별로 어울리지 않아서 그랬던
것입니다. 앞으로도 C만을 대상으로 얘기하겠습니다.

밝혔듯이 저는 malloc함수만을 대상으로 하지 않았습니다. 때문에 doldori님이 C++을 제외시키고 싶으시다면 그렇게 하셔도 되겠습니다만, 제 글은 C++까지 포함하는것으로 가정하여 생각해주십시오.
doldori wrote:
제 생각에는 동시에 해결하는 것이 가능합니다. ...
f()보다는 g()가 바람직한 스타일이라는 뜻입니다. C++을 알고 계신다면 이것이
가독성뿐만 아니라 효율과도 관련이 있다는 점도 이해하실 것입니다.

코딩스타일을 선언과 초기치 지정을 함께하는것으로 바꾸어서 2의 문제를 해결하도록 하였는데 이제는 1의 문제가 발생하게 된것 같은데요? 이 경우 캐스팅 여부와 상관없이 포인터 형과 메모리 형에 대해 프로그래머가 잘못된 가정을 하고 프로그래밍하여 에러가 발생할 여지가 충분히 있다는겁니다. 1의 문제를 제대로 해결하려면 어떠한 가정도 하지 말았어야죠. 즉, doldori님의 의견대로면 여러 형의 포인터 변수들을 마련해두고 컴파일러가 알아서 에러를 뱉어내도록 일일이 컴파일과정을 거쳐가면서 체크하는 시행착오를 통해서만이 알맞은 형식의 코딩이 가능하다는 얘깁니다. 아시겠지만, 위의 예는 변수선언과 함께 메모리 할당이 되게끔 하여 이런 시행착오의 여지를 없애버렸습니다. 결국 캐스팅을 쓰진 않았지만, 의미적으로는 쓴것과 마찬가지가 되어버린 셈입니다.
doldori wrote:

좋습니다. 이것은 어디까지나 스타일의 문제이고 언어의 강제 사항은 아닙니다.
그렇지만 바람직한 스타일이라는 것은 코딩 실수를 줄일 수 있도록 오랜 경험에
의해 축적된 지혜라고도 볼 수 있고 이것을 가볍게 무시하는 것은 득이 되지 않는다는
점은 말씀드리고 싶습니다.

이 의견에는 동감하지만, "바람직한 스타일"이란것이 정말 그렇게 한가지 밖에 없는것인지는 모르겠습니다. 저도 바람직한 스타일을 사용하고 있다고 생각하는데 말이죠.
익명 사용자의 이미지

doldori wrote:

"자기 완결적"이라는 말이 구체적으로 어떤 뜻인지는 잘 모르겠습니다. 캐스팅을
하지 않으면 컴파일러에 의해 코드의 의미가 변경될 수 있다는 뜻인가요? 그렇다면
그것은 캐스팅을 쓰지 않았기 때문이 아니라, 프로그래머의 의도를 제대로 코드로
표현하지 않았기 때문이고, 컴파일러가 이해하는(언어 표준에서 정해진) 의미와
프로그래머가 기대한 의미가 다르다는 것은 잘못된 코드라는 뜻이 됩니다.

컴파일러의 구현사항에 의해 프로그램이 번역되는 방식이 2가지 이상이 발생하도록 해서는 안된다는겁니다. 즉, 어떤 컴파일러를 사용하든 그와는 독립적으로 자신의 프로그램이 한가지 방식으로만 번역될것을 확신할 수 있어야 합니다. 아마 C standard Spec 을 중시하는 사람이라면 표준을 지키는것으로 충분하다고 생각하실지 모르지만, 제가 얘기하는것은 "표준 그 이상"까지를 포함한것입니다. 표준을 지키지 않는 이상한 컴파일러를 사용하더라도 표준을 지켜가면서 최대한 방어적으로 프로그래밍 하면, 컴파일러에 의해 잘못번역될 여지가 그만큼 적습니다.(물론 아주 이상한 컴파일러라면 그렇게 해도 잘못 번역되는 경우를 막을 수 없을겁니다.) 그리고 타입 캐스팅은 프로그래머의 의도를 제대로(명시적으로) 표현해주는 중요한 수단중에 하나라고 생각합니다. 컴파일러가 이해하는 의미 == 프로그래머가 기대하는 의미가 될 수 있도록 하자는것이 strong typing의 핵심 골자입니다.
doldori wrote:
타입 체킹을 그렇게도 중요하게 생각하신다면 명시적인 캐스팅을 옹호하는 것은
모순이 아닙니까? 명시적인 캐스팅은 오히려 타입 체킹을 무시하겠다는 뜻으로
이해하고 있습니다만.

전혀 모순이 아닙니다. 캐스팅이 없을때 모호해질 수 있는 부분을 캐스팅을 통해 프로그램의 의미가 하나로 결정되도록 제한하자는것이 왜 type check 의도와 모순이 됩니까? 위에서도 말씀드렸지만, doldori님은 타입 캐스팅이 잘못 적용되는 경우를 지나치게 부각시켜 그것이 정상적으로 사용되었을때 얻을 수 있는 장점을 덮어버리시는것 같습니다.
doldori wrote:

그리고 제가 제시한 코드가 어떤 점에서 의미 구조를 흩어놓는다고 보십니까?
제가 보기에는 전혀 오해의 소지가 없는 명확한 코드인데요.

확실히 doldori 님이 예로 드신 코드는 선언과 할당을 한줄에 같이 해 놓아서 명확해보입니다. 여기서 제가 문제 삼는것은 그 밑에 달린 설명입니다. 타입 캐스팅을 하지 않는것이 일반적으로 권장된다고 하신 부분이 문제가 된다는겁니다.

결론적으로 형변환을 컴파일러에게 맡긴다는것은 분명히 편하고 또 어떤 경우는 상당한 실수를 줄일 수 있는 방법이 된다고 생각합니다. 하지만, 이런 개발방식은 모든 논리구조가 formal 하게 define되어야 한다는 제 입장과는 차이가 있는것입니다. 다시 말해 결국 프로그램을 작성하면서 현재 코딩되고 있는 부분에 대해 프로그래머가 명시적인 캐스팅을 쓰지 않고 그것을 컴파일러에게 맡겨버린다는것은 그렇게 가정하여 프로그램 하는것이 힘들만큼 프로그램의 논리자체가 명료하지 못하다는 뜻 이상이 되지 않는다는겁니다.

blitzerg의 이미지

strong type 하에서는 명시적인 캐스팅이 프로그래밍 기법상 맞는 방법입니다.

C++보다 높은 수준의 typed 언어는 대부분 strong type과 명시적 캐스팅을 지원합니다.

또한 strong type이 아닌 언어라고 하더라도 대부분의 경우에 명시적인 캐스팅을 권장합니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.