과거 C90버젼의 C로 작성된 소스는 현재의 VS2010 같은 컴파일러로 컴파일이 불가능한가요?
글쓴이: bshi02 / 작성시간: 월, 2015/07/20 - 3:20오후
아래의 두소스는 아주 오래전에 유행했던 터보씨정복의 예제인데요 근데 보면 둘다 터보씨 전용함수를 전혀 사용하지 않았지만 컴파일하면
#include <stdio.h> #define SMAX 11 #define NMAX 10 void arraycopy(void *dest,void *source,int size,int n); void main() { char s1[SMAX]="Good copy!"; char s2[SMAX]; int n1[NMAX]={000,100,200,300,400,500,600,700,800,900}; int n2[NMAX]; int i; arraycopy(s2,s1,sizeof(*s1),SMAX); arraycopy(n2,n1,sizeof(*n1),NMAX); printf("s1: %s\n",s1); printf("s2: %s\nn1",s2); for(i=0;i<NMAX;i++) printf("%03d ",n1[i]); printf("\nn2:"); for(i=0;i<NMAX;i++) printf("%03d",n2[i]); printf("\n"); } void arraycopy(void *dest,void *source,int size,int n) { int register max; max=n*size; while(max-->0) *((char*)dest)++=*((char *)source)++; } //에러메세지 //32줄 IntelliSense: 식이 수정할 수 있는 lvalue여야 합니다. //32줄 error C2105: '++'에 l-value가 필요합니다.
#include <stdio.h> #include <conio.h> #include <stdlib.h> #define printexprc(expr) printf("%16s==%c\n",#expr,expr) #define printexprs(expr) printf("%16s==\"%s\"\n",#expr,expr) #define printexpri(expr) printf("%16s==%d\n",#expr,expr) void main(void) { void *pv; char *ps,s[]="ABCDEFG"; int *px,x[]={1234,2345,3456}; ps=s; px=x; pv=ps; printexprs(ps); printexprs((char*) pv); printexprc(*ps); printexprc(*(char*)pv); ((char*)pv)++; ps=pv; printexprs((char*)pv); printexprs(ps); pv=px; printexpri(*px); printexpri(*(int*)pv); printexpri(*(px+1)); printexpri(*((int*)pv+1)); printexpri(px[2]); printexpri(((int*)pv)[2]); } //에러메세지 //22줄 error C2105: '++'에 l-value가 필요합니다. //23줄 error C2440: '=' : 'void *'에서 'char *'(으)로 변환할 수 없습니다. //22줄 IntelliSense: 식이 수정할 수 있는 lvalue여야 합니다. //23줄 IntelliSense: "void *" 형식의 값을 "char *" 형식의 엔터티에 할당할 수 없습니다.
에러가 나오는 데요. 근데 분명히 지금까지 터보씨정복 교재에 있는 소스를 컴파일 하면서 터보씨 전용 함수가 아니라면 vs2010에서 전부 문제없이 컴파일이 되었었는데 void포인터를 설명하고 있는 이 두 예제가 컴파일이 되지 않는데, 터보시 2.0은 C90으로 알고 있는데, 구체적으로 현재 표준과 어떤게 달라져서 위의 C90버젼의 예제들이 컴파일이 않되는 건지 알고 싶네요.
수정:몇번째줄에 에러가 있는지 쓰질 않아서 에러의 위치를 알수 없는 것 같아서 고쳤습니다.그리고 비쥬얼 스튜디오 2010 에서 컴파일 했습니다.
Forums:
답변
1. Visual Studio 2013 community 에디션에서 문제 없이 실행됩니다.
그런데 codepad.org와 ideone.com 온라인 컴파일러에서는 같은 오류가 발생하네요.
2. 이 코드에서는 다음과 같은 수식을 사용하지요.
case 2와 같이 연산을 진행하면, 소괄호에 의해 pv에 캐스트 연산이 먼저 적용됩니다.
case 1의 경우 캐스트 연산보다 후위 연산자의 우선순위가 높아서,
++ 연산자가 먼저 계산된 후 캐스트 연산이 적용되는 것이구요.
TCPL에서는 부록 A7.5절에서, 캐스트가 있는 수식이 좌변값이 아니라고 설명하고 있습니다.
좌변값이란 할당 연산자(=, +=, ...)의 좌변에 올 수 있는 식을 말합니다.
예를 들어 int num;과 같이 변수가 정의되었다면 num = 10;에서 "num"은 좌변값이지만,
(int)num = 20;에서 "(int)num"은 좌변값이 될 수 없습니다.
이 오류는, 캐스트 연산이 먼저 적용되어 ((char *)pv) 수식이 좌변값이 아니게 된 상태에서
증감 연산을 사용하려고 했기 때문에 발생한 것으로 보입니다.
VS2013에서는 특수하게 처리하는지 컴파일이 되었습니다만.
현재 표준과의 차이는 잘 모르겠네요. 다른 분의 답변을 기다려봅니다.
3.
오류 메시지를 보여주실 때 몇 번째 행에서 오류가 났는지도 적어주시는 게 좋을 것 같습니다.
4.
(답변은 아니고, 다른 분들은 표준 문서에 이런 내용이 있어서 여기에 위반된다고 답변을 주시던데
그런 분들을 볼 때마다 뭔가 멋지다는 생각이 듭니다.)
저는 이렇게 생각했습니다.
짐작이지만 결국 C90버젼이후부터 캐스트 연산이
답변 감사합니다. 결국 결국 캐스트 연산이 적용된 변수는 현재의 표준에서는 좌변값으로 허용하지 않은 것 같군요.
그리고 23번째 줄에서 "'void *'에서 'char *'(으)로 변환할 수 없습니다." 라고 에러가 나옵니다만
저 예제는 터보씨정복의 p639에 나오는데 본래는 char*,int*형의 포인터 변수를 void*형의 변수에 대입하거나 혹은 그 역으로 void*형의 포인터 변수를 char*,int*형의 변수에 대입하는 것이 가능하므로 void* 포인터변수는 양방향으로 대입하거나 대입받는 피연산자로 사용할 수 있다는 것을 보여주는 것으로 생각합니다만
그 이유는 모르겠습니다만 현재의 C 표준에서는 오로지 char*,int*형의 포인터 변수를 void*형의 변수에 대입하는 한방향만 가능 한 것 같네요.
댓글 달기