Ich möchte ein kleines Lernwerkzeug für SO vorbereiten, das Anfängern (und fortgeschrittenen Programmierern) helfen soll, ihre ungerechtfertigten Annahmen in C, C ++ und ihren Plattformen zu erkennen und in Frage zu stellen.
Beispiele:
- "ganze Zahlen wickeln sich um"
- "Jeder hat ASCII"
- "Ich kann einen Funktionszeiger in einer Leere speichern *"
Ich dachte mir, dass ein kleines Testprogramm auf verschiedenen Plattformen ausgeführt werden könnte, das die "plausiblen" Annahmen ausführt, die nach unserer Erfahrung in SO normalerweise von vielen unerfahrenen / halb erfahrenen Mainstream-Entwicklern getroffen werden, und die Art und Weise aufzeichnet, wie sie auf verschiedenen Maschinen brechen.
Ziel ist es nicht, zu beweisen, dass es "sicher" ist, etwas zu tun (was unmöglich wäre, die Tests beweisen nur etwas, wenn sie brechen), sondern selbst dem verständnislosesten Individuum zu demonstrieren, wie unauffällig der Ausdruck ist brechen Sie auf einem anderen Computer ab, wenn dieser ein undefiniertes oder implementierungsdefiniertes Verhalten aufweist. .
Um dies zu erreichen, möchte ich Sie fragen:
- Wie kann diese Idee verbessert werden?
- Welche Tests wären gut und wie sollten sie aussehen?
- Würden Sie die Tests auf den Plattformen ausführen, die Sie in die Hände bekommen und die Ergebnisse veröffentlichen können, damit wir eine Datenbank mit Plattformen erhalten, wie sie sich unterscheiden und warum dieser Unterschied zulässig ist?
Hier ist die aktuelle Version für das Testspielzeug:
#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, und ich habe dieses Community-Wiki von Anfang an erstellt, weil ich dachte, dass die Leute mein Geschwätz bearbeiten wollen, wenn sie dies lesen.
UPDATE Vielen Dank für Ihre Eingabe. Ich habe einige Fälle aus Ihren Antworten hinzugefügt und werde sehen, ob ich einen Github dafür einrichten kann, wie Greg vorgeschlagen hat.
UPDATE : Ich habe dafür ein Github-Repo erstellt, die Datei lautet "gotcha.c":
Bitte antworten Sie hier mit Patches oder neuen Ideen, damit diese hier diskutiert oder geklärt werden können. Ich werde sie dann in gotcha.c zusammenführen.
dlsym()
ein void * zurückgegeben wird, aber sowohl für Daten- als auch für Funktionszeiger vorgesehen ist. Daher kann es nicht so schlimm sein, sich darauf zu verlassen.