저는 초보자 (및 중급) 프로그래머가 C, C ++ 및 플랫폼에서 정당하지 않은 가정을 인식하고 이의를 제기하는 데 도움이되는 SO를위한 작은 교육 도구를 준비하고 싶습니다.
예 :
- "정수를 둘러싼 다"
- "모든 사람이 ASCII를 가지고 있습니다."
- "함수 포인터를 void *에 저장할 수 있습니다."
저는 소규모 테스트 프로그램이 다양한 플랫폼에서 실행될 수 있다고 생각했습니다.이 가정은 일반적으로 경험이 부족한 / 반 경험이없는 많은 주류 개발자가 만든 "그럴듯한"가정을 실행하고 다양한 시스템에서 중단되는 방식을 기록합니다.
이것의 목표는 무언가를하는 것이 "안전"하다는 것을 증명하는 것이 아니라 (불가능할 것이고, 테스트가 깨질 경우에만 어떤 것을 증명 함), 대신 가장 눈에 띄지 않는 표현을 가장 이해하기 어려운 개인에게 보여주기위한 것입니다. 정의되지 않았거나 구현 정의 된 동작이있는 경우 다른 시스템에서 중단됩니다. .
이를 달성하기 위해 다음과 같이 질문하고 싶습니다.
- 이 아이디어를 어떻게 개선 할 수 있습니까?
- 어떤 테스트가 좋으며 어떻게 표시되어야합니까?
- 손을 잡고 결과를 게시 할 수있는 플랫폼에서 테스트를 실행하여 결과를 게시하여 플랫폼 데이터베이스로 끝낼 수 있으며, 서로 어떻게 다른지, 왜이 차이가 허용되는지?
테스트 장난감의 현재 버전은 다음과 같습니다.
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <stddef.h>
int count=0;
int total=0;
void expect(const char *info, const char *expr)
{
printf("..%s\n but '%s' is false.\n",info,expr);
fflush(stdout);
count++;
}
#define EXPECT(INFO,EXPR) if (total++,!(EXPR)) expect(INFO,#EXPR)
/* stack check..How can I do this better? */
ptrdiff_t check_grow(int k, int *p)
{
if (p==0) p=&k;
if (k==0) return &k-p;
else return check_grow(k-1,p);
}
#define BITS_PER_INT (sizeof(int)*CHAR_BIT)
int bits_per_int=BITS_PER_INT;
int int_max=INT_MAX;
int int_min=INT_MIN;
/* for 21 - left to right */
int ltr_result=0;
unsigned ltr_fun(int k)
{
ltr_result=ltr_result*10+k;
return 1;
}
int main()
{
printf("We like to think that:\n");
/* characters */
EXPECT("00 we have ASCII",('A'==65));
EXPECT("01 A-Z is in a block",('Z'-'A')+1==26);
EXPECT("02 big letters come before small letters",('A'<'a'));
EXPECT("03 a char is 8 bits",CHAR_BIT==8);
EXPECT("04 a char is signed",CHAR_MIN==SCHAR_MIN);
/* integers */
EXPECT("05 int has the size of pointers",sizeof(int)==sizeof(void*));
/* not true for Windows-64 */
EXPECT("05a long has at least the size of pointers",sizeof(long)>=sizeof(void*));
EXPECT("06 integers are 2-complement and wrap around",(int_max+1)==(int_min));
EXPECT("07 integers are 2-complement and *always* wrap around",(INT_MAX+1)==(INT_MIN));
EXPECT("08 overshifting is okay",(1<<bits_per_int)==0);
EXPECT("09 overshifting is *always* okay",(1<<BITS_PER_INT)==0);
{
int t;
EXPECT("09a minus shifts backwards",(t=-1,(15<<t)==7));
}
/* pointers */
/* Suggested by jalf */
EXPECT("10 void* can store function pointers",sizeof(void*)>=sizeof(void(*)()));
/* execution */
EXPECT("11 Detecting how the stack grows is easy",check_grow(5,0)!=0);
EXPECT("12 the stack grows downwards",check_grow(5,0)<0);
{
int t;
/* suggested by jk */
EXPECT("13 The smallest bits always come first",(t=0x1234,0x34==*(char*)&t));
}
{
/* Suggested by S.Lott */
int a[2]={0,0};
int i=0;
EXPECT("14 i++ is strictly left to right",(i=0,a[i++]=i,a[0]==1));
}
{
struct {
char c;
int i;
} char_int;
EXPECT("15 structs are packed",sizeof(char_int)==(sizeof(char)+sizeof(int)));
}
{
EXPECT("16 malloc()=NULL means out of memory",(malloc(0)!=NULL));
}
/* suggested by David Thornley */
EXPECT("17 size_t is unsigned int",sizeof(size_t)==sizeof(unsigned int));
/* this is true for C99, but not for C90. */
EXPECT("18 a%b has the same sign as a",((-10%3)==-1) && ((10%-3)==1));
/* suggested by nos */
EXPECT("19-1 char<short",sizeof(char)<sizeof(short));
EXPECT("19-2 short<int",sizeof(short)<sizeof(int));
EXPECT("19-3 int<long",sizeof(int)<sizeof(long));
EXPECT("20 ptrdiff_t and size_t have the same size",(sizeof(ptrdiff_t)==sizeof(size_t)));
#if 0
{
/* suggested by R. */
/* this crashed on TC 3.0++, compact. */
char buf[10];
EXPECT("21 You can use snprintf to append a string",
(snprintf(buf,10,"OK"),snprintf(buf,10,"%s!!",buf),strcmp(buf,"OK!!")==0));
}
#endif
EXPECT("21 Evaluation is left to right",
(ltr_fun(1)*ltr_fun(2)*ltr_fun(3)*ltr_fun(4),ltr_result==1234));
{
#ifdef __STDC_IEC_559__
int STDC_IEC_559_is_defined=1;
#else
/* This either means, there is no FP support
*or* the compiler is not C99 enough to define __STDC_IEC_559__
*or* the FP support is not IEEE compliant. */
int STDC_IEC_559_is_defined=0;
#endif
EXPECT("22 floating point is always IEEE",STDC_IEC_559_is_defined);
}
printf("From what I can say with my puny test cases, you are %d%% mainstream\n",100-(100*count)/total);
return 0;
}
아, 그리고 나는 사람들이 이것을 읽을 때 내 blabber를 편집하고 싶어한다고 생각했기 때문에 처음부터이 커뮤니티 위키를 만들었습니다.
업데이트 귀하의 의견에 감사드립니다. 귀하의 답변에서 몇 가지 사례를 추가했으며 Greg가 제안한 것처럼 github를 설정할 수 있는지 확인할 것입니다.
업데이트 : 나는 이것을 위해 github repo를 만들었습니다. 파일은 "gotcha.c"입니다.
여기에서 패치 또는 새로운 아이디어로 답변 해주세요. 여기에서 논의하거나 명확히 할 수 있습니다. 그런 다음 gotcha.c로 병합합니다.
dlsym()
void * 를 반환하지만 데이터 포인터와 함수 포인터 모두를위한 것입니다. 따라서 이것에 의존하는 것이 그렇게 나쁘지 않을 수 있습니다.