ฉันต้องการเตรียมเครื่องมือทางการศึกษาเล็ก ๆ น้อย ๆ สำหรับ SO ซึ่งจะช่วยให้โปรแกรมเมอร์มือใหม่ (และระดับกลาง) รับรู้และท้าทายสมมติฐานที่ไม่ได้รับการรับรองใน C, C ++ และแพลตฟอร์มของพวกเขา
ตัวอย่าง:
- "จำนวนเต็มพันรอบ"
- "ทุกคนมี ASCII"
- "ฉันสามารถจัดเก็บตัวชี้ฟังก์ชันในความว่างเปล่า *"
ฉันคิดว่าโปรแกรมทดสอบขนาดเล็กสามารถทำงานบนแพลตฟอร์มต่างๆได้ซึ่งเรียกใช้สมมติฐานที่ "เป็นไปได้" ซึ่งจากประสบการณ์ของเราใน SO มักสร้างขึ้นโดยนักพัฒนากระแสหลักที่ไม่มีประสบการณ์ / กึ่งมีประสบการณ์จำนวนมากและบันทึกวิธีที่พวกเขาทำลายบนเครื่องต่างๆ
เป้าหมายของสิ่งนี้ไม่ใช่เพื่อพิสูจน์ว่า "ปลอดภัย" ที่จะทำบางสิ่ง (ซึ่งคงเป็นไปไม่ได้ที่จะทำการทดสอบจะพิสูจน์อะไรก็ได้ถ้ามันแตก) แต่แทนที่จะแสดงให้เห็นว่าแม้แต่คนที่ไม่เข้าใจที่สุดว่าการแสดงออกที่ไม่เด่นชัดที่สุด หยุดทำงานบนเครื่องอื่นหากมีพฤติกรรมที่กำหนดไว้โดยไม่ได้กำหนดหรือการนำไปใช้งาน .
เพื่อให้บรรลุสิ่งนี้ฉันอยากจะถามคุณ:
- ความคิดนี้จะปรับปรุงได้อย่างไร?
- แบบทดสอบใดที่จะดีและควรมีลักษณะอย่างไร?
- คุณจะทำการทดสอบบนแพลตฟอร์มที่คุณสามารถทำได้และโพสต์ผลลัพธ์เพื่อที่เราจะได้ฐานข้อมูลของแพลตฟอร์มแตกต่างกันอย่างไรและเหตุใดจึงอนุญาตให้ใช้ความแตกต่างนี้ได้
นี่คือเวอร์ชันปัจจุบันสำหรับของเล่นทดสอบ:
#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;
}
โอ้และฉันสร้างวิกิชุมชนนี้ตั้งแต่เริ่มต้นเพราะฉันคิดว่ามีคนต้องการแก้ไขคนพูดไม่ชัดของฉันเมื่อพวกเขาอ่านสิ่งนี้
อัปเดตขอบคุณสำหรับข้อมูลของคุณ ฉันได้เพิ่มบางกรณีจากคำตอบของคุณและจะดูว่าฉันสามารถตั้งค่า github สำหรับสิ่งนี้ตามที่ Greg แนะนำได้หรือไม่
UPDATE : ฉันได้สร้าง github repo สำหรับสิ่งนี้ไฟล์คือ "gotcha.c":
โปรดตอบที่นี่ด้วยแพตช์หรือแนวคิดใหม่ ๆ เพื่อให้สามารถพูดคุยหรือชี้แจงได้ที่นี่ ฉันจะรวมมันเป็น gotcha.c แล้ว
dlsym()
ส่งคืนโมฆะ * แต่มีไว้สำหรับทั้งข้อมูลและตัวชี้ฟังก์ชัน ดังนั้นจึงอาจไม่เลวร้ายนักที่จะขึ้นอยู่กับสิ่งนี้