Je voudrais préparer un petit outil éducatif pour SO qui devrait aider les programmeurs débutants (et intermédiaires) à reconnaître et à contester leurs hypothèses injustifiées en C, C ++ et leurs plates-formes.
Exemples:
- "les entiers s'enroulent"
- "tout le monde a ASCII"
- "Je peux stocker un pointeur de fonction dans un vide *"
J'ai pensé qu'un petit programme de test pourrait être exécuté sur différentes plates-formes, qui exécute les hypothèses «plausibles» qui sont, d'après notre expérience en SO, généralement faites par de nombreux développeurs grand public inexpérimentés / semi-expérimentés et enregistrent les façons dont ils se cassent sur diverses machines.
Le but de ceci n'est pas de prouver qu'il est «sûr» de faire quelque chose (ce qui serait impossible à faire, les tests ne prouvent que quoi que ce soit s'ils cassent), mais plutôt de démontrer à l'individu le plus incompréhensible comment l'expression la plus discrète break sur une machine différente, si elle a un comportement non défini ou défini par l'implémentation. .
Pour y parvenir, je voudrais vous demander:
- Comment cette idée peut-elle être améliorée?
- Quels tests seraient bons et à quoi devraient-ils ressembler?
- Souhaitez-vous exécuter les tests sur les plates-formes sur lesquelles vous pouvez mettre la main et publier les résultats, de sorte que nous nous retrouvions avec une base de données de plates-formes, en quoi elles diffèrent et pourquoi cette différence est autorisée?
Voici la version actuelle du jouet de test:
#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, et j'ai créé ce wiki communautaire dès le début parce que je pensais que les gens voulaient éditer mon discours quand ils liraient ceci.
MISE À JOUR Merci pour votre contribution. J'ai ajouté quelques cas à partir de vos réponses et je vais voir si je peux configurer un github pour cela, comme Greg l'a suggéré.
MISE À JOUR : J'ai créé un dépôt github pour cela, le fichier est "gotcha.c":
Veuillez répondre ici avec des correctifs ou de nouvelles idées, afin qu'elles puissent être discutées ou clarifiées ici. Je vais alors les fusionner dans gotcha.c.
dlsym()
renvoie un void * mais est destiné à la fois aux pointeurs de données et de fonction. Par conséquent, il n'est peut-être pas si grave de dépendre de cela.