C11 : la normalisation est achevée
Après douze ans de travaux, multithreading et Unicode au menu
Le 2011-12-29 15:46:41, par Gordon Fowler, Expert éminent sénior
Voilà qui est fait. Après douze ans de travaux, la normalisation du C1.x vient d’être bouclée par l’International Organization for Standardization.
C11 succède donc à C99, réalisé en 1999, et propose la prise en charge du multithreading (autrement dit l’utilisation des différents cœurs d’un processeur pour accélérer les traitements et les processus) et de l’Unicode.
Dennis Ritchie, créateur du C
Pour rappel, le C est un langage de programmation impératif conçu en 1972 au sein des Bell Labs pour la programmation système. Inventé avec UNIX, C est devenu en quelques années un des langages les plus utilisés. De nombreux autres comme C++, C#, Objective-C mais aussi Java ou PHP en reprennent bien des aspects.
Son créateur, Dennis Ritchie, est décédé en novembre dernier, suscitant une très vive émotion et une reconnaissance unanime au sein du monde IT.
Cette certification lui aurait certainement fait plaisir.
Le nouveau standard ISO/IEC 9899:2011 est disponible depuis cette page
C11 succède donc à C99, réalisé en 1999, et propose la prise en charge du multithreading (autrement dit l’utilisation des différents cœurs d’un processeur pour accélérer les traitements et les processus) et de l’Unicode.
Dennis Ritchie, créateur du C
Pour rappel, le C est un langage de programmation impératif conçu en 1972 au sein des Bell Labs pour la programmation système. Inventé avec UNIX, C est devenu en quelques années un des langages les plus utilisés. De nombreux autres comme C++, C#, Objective-C mais aussi Java ou PHP en reprennent bien des aspects.
Son créateur, Dennis Ritchie, est décédé en novembre dernier, suscitant une très vive émotion et une reconnaissance unanime au sein du monde IT.
Cette certification lui aurait certainement fait plaisir.
-
rt15Membre éclairéLe but de restrict n'est pas du tout d'empêcher le développeur ou le compilateur de faire des bêtises.
Le but est de préciser au compilo qu'il n'y a pas d'overlap.
Cette information permet au compilo de générer un code plus rapide dans certains cas.
Et le compilo ne peut généralement pas deviner cette information que l'on utilise -O3 ou pas. Pour le déterminer, il faut qu'il vérifie dans le source que lors des appels (Ou de l'appel, si la fonction est inliné) qu'il ne peut pas y avoir d'overlap car les paramètres sont "différents". Jolie casse tête. Et dans certains cas, c'est même tout à fait impossible car il ne peut pas connaître tous les appels d'avance (Cas d'une fonction exportée par une librairie).
Considérons une fonction plus proche de ce qui peut exister, c'est à dire une fonction updatePoints qui prend en paramètre :
1/ Un tableau de points(Coordonnées x et y).
2/ Le nombre d'élément du tableau.
3/ Un pointeur vers un point delta.
Le but de la fonction est d'ajouter à tous les points du tableau le delta contenu dans le paramètre trois.
Code : 1
2
3
4pour i de 0 à n - 1 points[i].x += delta.x; points[i].y += delta.y; fait;
Code C : 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56#include <stdio.h> #define POINT_COUNT 4 typedef struct { int x; int y; } MY_POINT; void updatePoints1(MY_POINT *lpPoints, int nPointCount, MY_POINT *lpDelta) { int i; for (i = 0; i < nPointCount; i++) { lpPoints[i].x += lpDelta->x; lpPoints[i].y += lpDelta->y; } } void updatePoints2(MY_POINT *restrict lpPoints, int nPointCount, MY_POINT *restrict lpDelta) { int i; for (i = 0; i < nPointCount; i++) { lpPoints[i].x += lpDelta->x; lpPoints[i].y += lpDelta->y; } } int main() { int i; MY_POINT lpPoints[4]; MY_POINT delta; for (i = 0; i < POINT_COUNT; i++) { lpPoints[i].x = i; lpPoints[i].y = 100 + i; } delta.x = 1; delta.y = 1; updatePoints1(lpPoints, POINT_COUNT, &delta); updatePoints2(lpPoints, POINT_COUNT, &delta); for (i = 0; i < POINT_COUNT; i++) { printf("%d %d\n", lpPoints[i].x, lpPoints[i].y); } return 0; }
La différence entre updatePoints1 et updatePoints2 est simplement l'ajout du mot clé restrict. La différence se fait dans le code généré. En effet, comme restrict indique que delta n'est pas modifié quand lpPoints est modifié, la valeur de delta n'a pas à être lue à chaque tour de boucle.
Code sans restrict :
Code : 1
2
3
4
5
6
7
8loop: mov ecx,[esi] # ecx = delta.x mov eax,[esi+0x4] # eax = delta.y add [ebx+edx*8],ecx # points[i].x += ecx add [ebx+edx*8+0x4],eax # points[i].y += eax inc edx # i++ cmp edx,0x4 # si i < 4 alors ... jl loop # ... saute à loop
Code : 1
2
3
4
5
6
7
8mov ecx,[esi] mov eax,[esi+0x4] loop: add [ebx+edx*8],ecx add [ebx+edx*8+0x4],eax inc edx cmp edx,0x4 jl loop
Bref, restrict, c'est une information qui en théorie peut bien aider le compilo à générer du code plus rapide. Il semble donc intéressant de l'avoir dans la norme.
[ ************** edit ************** ]
A noter que dans les faits, avec les flags de compilation :
gcc -O3 test.c -o test.exe -std=c99 -fstrict-aliasing
gcc 3.4.5 (Version ancienne... Il semble qu'il y ait eu des amélioration de restrict en 4.5) ne réalise pas l'optimisation permise par restrict ci-dessus.
Par contre, on peut forcer gcc 3.4.5 à réaliser l'optimisation en faisant une copie du contenu de lpDelta dans une variable locale. Le code C paraît alors moins optimisé, mais le code machine généré est comme celui ci-dessus "avec restrict".Code c : 1
2
3
4
5
6
7
8
9
10
11
12
13void updatePoints1(MY_POINT *lpPoints, int nPointCount, MY_POINT *lpDelta) { int i; MY_POINT delta; delta = *lpDelta; for (i = 0; i < nPointCount; i++) { lpPoints[i].x += delta.x; lpPoints[i].y += delta.y; } }
[ ************** edit 2 ************** ]
gcc 4.6.1 réalise correctement l'optimisation avec le mot clé restrict.
(Et il fait aussi l'optimisation en cas de copie locale de delta comme ci-dessus)le 17/01/2012 à 11:57 -
BkteroModérateurJ'ai du mal à comprendre pourquoi certains ne "veulent" pas que ça soit un mot-clé du langage, car je ne vois pas comment le compilateur pourrait deviner le non chevauchement des entités... Si on souhaite avoir un tel mécanisme, il doit obligatoirement passer par un mot clé du langage, non ?
Après, j'entends parfaitement les arguments disant que ce n'est pas le rôle du langage de faire des optimisations mais au compilateur de se débrouiller. En même temps, il existe bien des directives #pragma pour influencer le compilateur (je ne m'en suis jamais servi perso). On a aussi la possibilité de mettre un mot clé const à l'un des paramètres d'une fonction pour bloquer à la compilation quelque chose comme : Code : 1
2
3
4void maFonction(int const *a) { (*a)++; }
Ce genre de petits bonus dans le code me fait penser aux hints qu'on peut mettre dans le code SQL. Normalement, c'est le SGBD qui décide des plans d'exécutions mais il est parfois très utile de forcer un comportement quand on sait qu'il sera bénéfique.
Je trouve dommage de se priver d'"outils" pour faciliter la programmation ou améliorer la performance sous couvert d'une envie d'excellence, voire d'élitisme :
Envoyé par souviron34 le 18/01/2012 à 17:54 -
MédinocExpert éminent séniorDonc il n'y a plus qu'à attendre 2030 pour le voir dans Visual Studio?le 11/10/2018 à 21:12
-
BkteroModérateurComment être indifférent à C18 ?le 12/10/2018 à 8:49
-
DavidbrczRédacteurY'a d'autres évolutions, dont un travail sur l'alignement, unions et structure anonymes ainsi que de rendre optionnel les VLA et les complex.
Le reste ICIle 29/12/2011 à 16:39 -
rt15Membre éclairéLes développeurs C++ bavaient devant C++11
. Ils trépignent en attendant que les compilos se mettent à jour.
Les développeurs C en sont encore à critiquer C99. Certains se demandent même si une quelconque évolution est nécessaire voire bénéfique.
Perso, je ne sais pas ce que j'aurai aimé voire dans C11.le 18/01/2012 à 20:41 -
souviron34Expert éminent séniorPas compliqué :
Primo = compatibilité
Secondo = accessoire
Franchement, ce n'est en aucune manière de "grandes avancées", et ont plus été introduites pour faire le lien avec C++ et les notions utilisées que pour le C...
Si tu avais, comme les révisions de Fortran, quelque chose qui passe d'opérations "normales" aux mêmes sur des matrices (par exemple addition ou multiplication ou division) , là tu fais un bond en avant et ça vaut vraiment le coup. Si par contre tu "ajoutes" quelques "trucs" ici et là, franchement, entre le coût des modifs, de la maintenance, et les avantages, y'a en général pas photo (d'autant plus qu'un certain inombre de softs sont "certifiés", et repasser des certifications est payant - et cher).
Donc les "babioles" relativement peu évidentes à implanter et à assurer une compatibilité, et qui ne sont pas considérées comme de grosses différences de fond, ben....le 06/07/2012 à 15:02 -
gangsoleilModérateurVC++ implemente le C89, et le C++11.
Si tu veux du C autre que 89, ils disent que c'est probablement inclus dans C++11.
Si vraiment tu veux faire du C89, alors tu te tournes vers un compilateur C, car eux s'en foutent.
Le probleme qu'ils ne prennent pas en compte, c'est que C++ n'est pas un sur-ensemble du C !
La fonction suivante est par exemple valide en C (pre-89, 89, 99, et meme 11), mais incompilable en l'etat en C++ :Code : 1
2
3
4
5void fonction (int new) { /* du code ici si on a envie, ou pas, on s'en fout */ return; }
le 06/07/2012 à 15:23 -
grim7reaperMembre éclairéLe C18 est sorti cette année, en juin, dans l’indifférence la plus absolue.
Bon en même temps, après 7 ans il y a 0 nouvelle fonctionnalités, seulement du bugfix et un bump de version pour __STDC_VERSION__.
Décevant…le 11/10/2018 à 19:20 -
grim7reaperMembre éclairéEn revanche, le C2X semble beaucoup plus riche: https://gustedt.wordpress.com/2018/11/12/c2x/
On dirait qu'en plus d'ajouter de nouvelles fonctionnalités, y'a une passe de ménage (les déclarations K&R, le complément à un et le signe-magnitude ne seront plus supporté).
Y’aura peut-être du bignum aussi.
Ça aussi c’est peut-être intéressant, à voir (pas trop de détail pour le moment): "Add a new calling conventions with error return for library functions that avoids the use of errno"le 12/11/2018 à 16:21