Tôi muốn chuẩn bị một công cụ giáo dục nhỏ cho SO sẽ giúp các lập trình viên mới bắt đầu (và trung cấp) nhận ra và thách thức các giả định không chính đáng của họ trong C, C ++ và các nền tảng của họ.
Ví dụ:
- "số nguyên quấn quanh"
- "mọi người đều có ASCII"
- "Tôi có thể lưu trữ một con trỏ hàm trong một khoảng trống *"
Tôi nhận thấy rằng một chương trình thử nghiệm nhỏ có thể được chạy trên nhiều nền tảng khác nhau, chạy các giả định "hợp lý", theo kinh nghiệm của chúng tôi trong SO, thường được thực hiện bởi nhiều nhà phát triển chính thống thiếu kinh nghiệm / bán kinh nghiệm và ghi lại cách chúng phá vỡ trên các máy khác nhau.
Mục tiêu của việc này không phải để chứng minh rằng làm điều gì đó là "an toàn" (điều mà không thể làm được, các bài kiểm tra chỉ chứng minh bất cứ điều gì nếu chúng bị phá vỡ), mà thay vào đó là để chứng minh cho cả những người không hiểu nhất cách diễn đạt kín đáo nhất. phá vỡ trên một máy khác, nếu nó có một hành vi chưa được xác định hoặc triển khai được xác định. .
Để đạt được điều này, tôi muốn hỏi bạn:
- Làm thế nào để ý tưởng này có thể được cải thiện?
- Những bài kiểm tra nào sẽ tốt và chúng trông như thế nào?
- Bạn có chạy thử nghiệm trên các nền tảng mà bạn có thể thực hiện và đăng kết quả, để chúng tôi đưa ra cơ sở dữ liệu về các nền tảng, chúng khác nhau như thế nào và tại sao lại cho phép sự khác biệt này?
Đây là phiên bản hiện tại cho đồ chơi thử nghiệm:
#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;
}
Ồ, và tôi đã lập wiki cộng đồng này ngay từ đầu vì tôi nhận ra rằng mọi người muốn chỉnh sửa lời nói dối của tôi khi họ đọc nó.
CẬP NHẬT Cảm ơn bạn đã đóng góp ý kiến. Tôi đã thêm một số trường hợp từ câu trả lời của bạn và sẽ xem liệu tôi có thể thiết lập github cho việc này như Greg đã đề xuất hay không.
CẬP NHẬT : Tôi đã tạo một repo github cho việc này, tệp là "gotcha.c":
Vui lòng trả lời ở đây với các bản vá lỗi hoặc ý tưởng mới, vì vậy chúng có thể được thảo luận hoặc làm rõ ở đây. Sau đó tôi sẽ hợp nhất chúng thành gotcha.c.
dlsym()
trả về giá trị void * nhưng dành cho cả con trỏ hàm và dữ liệu. Do đó, có thể không quá tệ khi phụ thuộc vào điều này.