C언어의 프로그래밍언어론적 측면에 관해서
글쓴이: canuyes / 작성시간: 일, 2015/03/22 - 3:18오후
과제를 하다가 궁금점이 생겨 질문올립니다.
#include <stdio.h> void main() { char ch = 'a'; printf("%d", ch); }
위 프로그램은 wrong program 이지만, 컴파일도 되고 실행도 됩니다.
이렇게 C를 설계한 이유를 프로그래밍 언어론 적 측면에서 기술하려합니다.
생각해 본 바로는
1. C는 효율성을 위해 type check를 수행하지 않는다.
2. C는 문자도 내부적으로는 정수로 취급하여 다루게 된다.
등이 있습니다.
하지만 저 둘이 과연 프로그래밍 언어론 적 측면에서의 접근이 맞는 것인지,
만약에 맞다면 어떻게 풀어내야할지가 궁금합니다.
책도 찾아보고 여러 웹사이트도 돌아다녀 봤지만 질문이 모호한지라 만족할 만한 답을 얻지 못해 질문드립니다.
Forums:
printf 는 내부가 가변인자로 받아오게끔
printf 는 내부가 가변인자로 받아오게끔 구현되었기 때문에
타입체크를 하지 않습니다.
할 수 없다는게 맞는 표현이려나요?
그저 맨 첫 인자를 가지고 이것이 무슨 타입인지를 결정하는것이죠.
printf의 케이스를 가지고 프로그래밍 언어론적 측면으로 고려하는게 맞는걸까요?
접근해보자면 template가 지원되지 않는다는점?
> 위 프로그램은 wrong program 이지만,
> 위 프로그램은 wrong program 이지만, 컴파일도 되고 실행도 됩니다.
틀리지 않은 프로그램이고, 잘 정의된 작동이 보장된 코드입니다.
> 1. C는 효율성을 위해 type check를 수행하지 않는다.
컴파일 오류(경고)를 내뿜는 타입 체크는 컴파일타임에 하기 때문에 효율성과는 관계가 없습니다.
> 2. C는 문자도 내부적으로는 정수로 취급하여 다루게 된다.
char는 원래 정수입니다.
printf의 구현을 보지 않고 이걸로 C언어의 '프로그래밍 언어론'이라는 걸 논하기엔 무리가 있습니다.
가변 인자 함수가 어떻게 구현되는지 부터 찾아보시는게 좋을 듯합니다.
위 프로그램은 문자의 아스키 코드를 알아 보기 위한
위 프로그램은 문자의 아스키 코드를 알아 보기 위한 정상적인 프로그램입니다.
1. 위 프로그램에서도 type check는 수행된 것이며, 문자에서 정수로의 변환은 안전한 타입 변환임.
2. C 뿐만 아니라 문자를 내부적으로 숫자 아닌 다른 무엇으로 표현하는 것은 불가능함.
예제 코드가 틀리지 않았다구요?
printf의 argument로 1byte 짜리 하나가 넘어갔고
printf의 내부에서는 4byte를 읽으려고 할 텐데 어찌 정상적인 프로그램이 될 수 있나요?
byte align 같은 문제로 인해 1byte이후 나머지 3byte는 0으로 채워진다 라는 보장이 없으면
이상한 쓰레기 값을 출력하는 코드일텐데요.
추측하지 마시고 가변 인자 함수가 어떻게 동작하는지
추측하지 마시고 가변 인자 함수가 어떻게 동작하는지 부터 찾아보세요.
?
뭔가 착각하시는거 같은데 char타입을 넘겼다고 해서 정말로 1바이트가 넘어갈 것 같은가요?
또는 char 변수 하나를 정의했다고 정말 스택영역을 1바이트만 더 늘려서 잡을까요?
프로그램은 기본적으로 word 단위로 처리를 하기 때문에, x86 기준으로 push/pop 명령은
항상 word 단위로 처리됩니다. 그러니 윗 분이 말씀하신 것 같은 상황은 전혀 벌어지지 않습니다.
(char a = 0x22; 이고 &a = 0x80000000 이라고 할 때 0x80000001 부터는 무슨 쓰레기값이
들어있는 게 아닙니다. 0x22 는 결국 4바이트 정수 0x00000022 로 내부적으로 취급됩니다.)
그리고 저건 C의 설계가 문제가 아니라, printf 함수의 구현 문제이며 가변인자의 문제입니다.
가변 인자에서는 원래 type check 를 하지 못하고, 어떤 타입이 넘어왔는지 알 수 있는 방법은 없습니다.
또한 문자에서 정수 변환 된 것이 아닙니다. printf 뒤에 그 어떤 타입을 넘긴다고 해도 컴파일 오류는 나지 않습니다.
%d 나 %c 등의 포맷 스트링은 내부적으로 printf 에서 핸들링하는 것이지 이걸 컴파일 타임에
타입을 체크하기 위한 용도로 쓰는 게 아니고, 또한 이건 타입을 알기 위한 목적으로 쓰는 것이 아니라
넘어온 인자에 대한 출력 타입을 정하는 목적으로 사용하는 것입니다.
그럴까요?
많은 CPU 아키텍처가 4byte / 8byte 단위를 기본으로 하기 때문에
char 타입을 선언해 사용하더라도 4byte 이상의 메모리를 쓰는 경우가 많지요.
하지만 그건 현재 사용하고 있는 CPU 아키텍처에 따른 부수적인 효과지
C언어의 스펙에 "char변수의 argument를 넘길시 stack은 4byte 늘려서 잡아야 한다"라고 명시되어 있을까요?
대부분의 경우에 잘 동작한다고 해서 그게 100%를 보장하는 진리가 되지는 않습니다.
이게 적법한건 플랫폼에 의존하는 것이 아니라 표준에
이게 적법한건 플랫폼에 의존하는 것이 아니라 표준에 의해서 보장된 것입니다.
void main 빼고는 표준에 의해 문제없는 코드가
void main 빼고는 표준에 의해 문제없는 코드가 맞습니다.
가변 인자 진급default argument promotion이라고 찾아보세요.
C언어는 이론적으로나 언어적으로 아름다운 모습은 아닌데.
이는 효율성, 전통, 호환성, 이식성, 기타 이유들이
이런 저런 역사적 과정을 거쳐 타협해간 결과입니다.
가변인자 함수는 원래는 매크로적인 트릭이었다가
표준화 과정에서 정식 문법으로 흡수된 특징입니다.
원래는 윗분이 예상한 대로 플랫폼 의존적인 테크닉 이었겠지만
지금은 아닙니다.
가변 인자 진급이 아니라 기본 인자
가변 인자 진급이 아니라 기본 인자 진급입니다.
영어로는 똑바로 썼는데 한국어로는 그만 실수했군요.
댓글 달기