SO için yeni başlayanlar (ve orta seviye) programcıların C, C ++ ve platformlarındaki gereksiz varsayımlarını tanımalarına ve bunlara meydan okumalarına yardımcı olacak küçük bir eğitim aracı hazırlamak istiyorum.
Örnekler:
- "tamsayılar etrafına sarılır"
- "herkesin ASCII'si vardır"
- "Bir işlev işaretçisini boşlukta saklayabilirim *"
Küçük bir test programının çeşitli platformlarda çalıştırılabileceğini düşündüm, SO'daki deneyimlerimize dayanarak, genellikle birçok deneyimsiz / yarı deneyimsiz ana akım geliştirici tarafından yapılan ve çeşitli makinelerde kırılma yollarını kaydeden "makul" varsayımları çalıştıran.
Bunun amacı, bir şeyi yapmanın "güvenli" olduğunu kanıtlamak değil (ki bunu yapmak imkansızdır, testler sadece kırılırsa her şeyi kanıtlar), bunun yerine en anlaşılmaz bireye bile en göze çarpmayan ifadenin nasıl olduğunu göstermektir. tanımlanmamış veya uygulama tanımlı bir davranışa sahipse, farklı bir makinede kırılma. .
Bunu başarmak için size sormak istiyorum:
- Bu fikir nasıl geliştirilebilir?
- Hangi testler iyi olur ve nasıl görünmelidir?
- Testleri elinize alabileceğiniz ve sonuçları gönderebileceğiniz platformlarda çalıştırır mısınız, böylece bir platform veritabanı elde ederiz, bunlar nasıl farklılaşır ve bu farklılığa neden izin verilir?
İşte test oyuncağının güncel versiyonu:
#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;
}
Oh, ve bu topluluk wiki'sini en başından beri yaptım çünkü insanların bunu okuduklarında blabber'ımı düzenlemek istediklerini düşündüm.
GÜNCELLEME Girişiniz için teşekkürler. Cevaplarınızdan birkaç durum ekledim ve Greg'in önerdiği gibi bunun için bir github kurabilir miyim göreceğim.
GÜNCELLEME : Bunun için bir github deposu oluşturdum, dosya "gotcha.c":
Lütfen buraya yamalar veya yeni fikirlerle yanıt verin, böylece burada tartışılabilir veya açıklığa kavuşturulabilir. Onları gotcha.c ile birleştireceğim o zaman.
dlsym()
void * döndürmesidir, ancak hem veri hem de işlev işaretçileri için tasarlanmıştır. Bu nedenle buna güvenmek o kadar da kötü olmayabilir.