C99 existe depuis plus de 10 ans, mais le soutien à celui-ci a été lent, de sorte que la plupart des développeurs ont été bloqués avec C89. Même aujourd'hui, je suis parfois légèrement surpris lorsque je rencontre des fonctionnalités de C99 en Code C.
Maintenant que la plupart des grands compilateurs soutiennent C99 (MSVC étant une exception notable et certains compilateurs intégrés à la traîne en retard), je pense que les développeurs qui travaillent avec C devraient probablement savoir quelles fonctionnalités de C99 sont disponibles. Certaines des caractéristiques ne sont que des caractéristiques communes qui n'ont jamais été normalisées avant (snprintf
, par exemple), ou sont familières de C++ (placement de déclaration variable flexible ou unique //
Commentaires), mais certaines des nouvelles fonctionnalités ont été introduites pour la première fois en C99 et ne sont pas familiarisées à de nombreux programmeurs.
Que trouvez-vous les nouvelles fonctionnalités les plus utiles en C99?
Pour référence, la norme C99 (étiquetée comme un brouillon, mais identique à la norme mise à jour, autant que je sache), le Liste des nouvelles fonctionnalités , et le Statut de la mise en œuvre de la GCC C99 .
Une caractéristique par réponse, s'il vous plaît; N'hésitez pas à laisser plusieurs réponses. Les exemples de code de courte démonstration de nouvelles fonctionnalités sont encouragés.
Je suis tellement habitué à taper
for (int i = 0; i < n; ++i) { ... }
en C++ que c'est une douleur à utiliser un compilateur non-C99 où je suis obligé de dire
int i;
for (i = 0; i < n; ++i ) { ... }
stdint.h
, qui définit int8_t
, uint8_t
, etc. Plus besoin d'avoir à faire des hypothèses non portables sur la taille de vos entiers.
uint32_t truth = 0xDECAFBAD;
Je pense que les nouveaux mécanismes d'initialistes sont extrêmement importants.
struct { int x, y; } a[10] = { [3] = { .y = 12, .x = 1 } };
OK - pas un exemple convaincant, mais la notation est exacte. Vous pouvez initialiser des éléments spécifiques d'une matrice et des membres spécifiques d'une structure.
Peut-être qu'un meilleur exemple serait ceci - si j'avais admettre que ce n'est pas extrêmement convaincant:
enum { Iron = 26, Aluminium = 13, Beryllium = 4, ... };
const char *element_names[] =
{
[Iron] = "Iron",
[Aluminium] = "Aluminium",
[Beryllium] = "Beryllium",
...
};
Tableaux de longueur variable:
int x;
scanf("%d", &x);
int a[x];
for (int i = 0; i < x; ++i)
a[i] = i * i;
for (int i = 0; i < x; ++i)
printf("%d\n", a[i]);
Soutien aux commentaires d'une ligne commençant par //
.
Être capable de déclarer des variables à des endroits autres que le début d'un bloc.
Macros variadiques. Facilite la génération de code de chaudron avec un nombre illimité d'arguments.
snprintf()
- Sérieusement, cela vaut beaucoup de choses à pouvoir faire des chaînes formatées en toute sécurité.
Membres de tableau flexibles.
6.7.2.1 Structure et spécifications syndicales
En tant que cas particulier, le dernier élément d'une structure avec plus d'un membre nommé peut avoir un type de matrice incomplète; Ceci s'appelle un membre de tableau A FL Exibex. À deux exceptions près, l'élément de réseau flexible est ignoré. Premièrement, la taille de la structure doit être égale au décalage du dernier élément d'une structure par ailleurs identique qui remplace l'élément de matrice flexible avec une matrice de longueur non spécifiée) de seconde, quand un
.
(ou->
) l'opérateur a un opérande gauche (un pointeur à) une structure avec un élément de matrice flexible et l'opérande droit que le membre se comporte comme si ce membre était remplacé par le tableau le plus long (avec le même élément type) qui ne rendrait pas la structure plus grande que l'accès à l'objet; Le décalage du tableau doit rester celui de l'élément de matrice flexible, même si cela différerait de celui du tableau de remplacement. Si ce tableau n'aurait aucun élément, il se comporte comme s'il avait un élément, mais le comportement est indéfini si une tentative est faite pour accéder à cet élément ou pour générer un pointeur un autre.
Exemple:
typedef struct {
int len;
char buf[];
} buffer;
int bufsize = 100;
buffer *b = malloc(sizeof(buffer) + sizeof(int[bufsize]));
Littéraux composés. Structures de réglage Membres par membre est de plus en 89;)
Vous pouvez également les utiliser pour obtenir des pointeurs sur des objets avec durée de stockage automatique sans déclarer des variables inutiles, par exemple
foo(&(int){ 4 });
degré de
int tmp = 4;
foo(&tmp);
Le type bool.
Vous pouvez maintenant faire quelque chose comme ça:
bool v = 5;
printf("v=%u\n", v);
imprimera
1
Les littéraux composés, déjà mentionnés, mais voici mon exemple convaincant:
struct A *a = malloc(sizeof(*a));
*a = (struct A){0}; /* full zero-initialization */
/* or */
*a = (struct A){.bufsiz=1024, .fd=2}; /* rest are zero-initialized. */
C'est un moyen clair d'initialiser les données même si c'est sur le tas. Il n'y a aucun moyen d'oublier de zéro-initialiser quelque chose.
Prise en charge des fonctions inline
.
Le mot clé restrict
. Surtout quand vous crachez des numéros ...
Support de séquence d'échappée Unicode:
printf("It's all \u03B5\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC to me.\n");
Ou même des caractères unicode littéraux:
printf("日本語\n");
(Remarque: peut ne pas fonctionner en fonction de votre localisation; la prise en charge portable pour différents codages prendra plus de travail que cela)
Personnellement, j'aime la reconnaissance de CEI 60559: 1989 (arithmétique de point flottant binaire pour les systèmes de microprocesseur) et un meilleur support de point flottant.
Dans une veine similaire, réglage et interrogeant le mode arrondi à virgule flottante, la vérification des numéros de NaN/Infinity/SubNormal, etc., est idéal pour avoir.