Un code valide en C et C ++ peut-il produire un comportement différent lorsqu'il est compilé dans chaque langage?

664

C et C ++ ont de nombreuses différences, et tous les codes C valides ne sont pas des codes C ++ valides.
(Par "valide", je veux dire du code standard avec un comportement défini, c'est-à-dire non spécifique à l'implémentation / non défini / etc.)

Existe-t-il un scénario dans lequel un morceau de code valide à la fois en C et C ++ produirait un comportement différent lorsqu'il est compilé avec un compilateur standard dans chaque langue?

Pour en faire une comparaison raisonnable / utile (j'essaie d'apprendre quelque chose d'utile, pas d'essayer de trouver des failles évidentes dans la question), supposons:

  • Rien lié au préprocesseur (ce qui signifie pas de hacks avec #ifdef __cplusplus, pragmas, etc.)
  • Tout ce qui est défini par l'implémentation est le même dans les deux langues (par exemple, limites numériques, etc.)
  • Nous comparons des versions raisonnablement récentes de chaque norme (par exemple, C ++ 98 et C90 ou version ultérieure).
    Si les versions sont importantes, veuillez indiquer quelles versions de chacune produisent un comportement différent.
user541686
la source
11
Soit dit en passant, il peut être utile de programmer dans un dialecte qui est C et C ++ en même temps. Je l'ai fait dans le passé et un projet en cours: le langage TXR. Fait intéressant, les développeurs de la langue Lua ont fait la même chose, et ils appellent ce dialecte "Clean C". Vous bénéficiez d'une meilleure vérification du temps de compilation et éventuellement de diagnostics utiles supplémentaires des compilateurs C ++, tout en conservant la portabilité C.
Kaz
9
J'ai fusionné la question plus ancienne dans cette question car cela a plus de vues et de réponses votées. C'est toujours un exemple de question non constructive, mais c'est assez limite car oui, cela enseigne quelque chose aux utilisateurs SO. Je conclus que ce n'est pas constructif uniquement pour refléter l'état de la question avant la fusion. N'hésitez pas à être en désaccord et à rouvrir.
George Stocker
13
Voter pour rouvrir car je pense qu'il peut être objectivement répondu par un "oui" suivi d'un exemple (comme prouvé ci-dessous). Je pense que c'est constructif dans la mesure où les gens peuvent en tirer des comportements pertinents.
Anders Abel
6
@AndersAbel Le nombre pur de réponses, qui sont toutes correctes, démontre sans ambiguïté que cela reste une question à faire une liste. Il n'y avait aucun moyen que vous auriez pu poser cette question sans obtenir une liste.
dmckee --- chaton ex-modérateur
2
@dmckee Pour ce que ça vaut, je suis d'accord avec vous. Cependant, les gens du tag C ++ sont ... Dites-nous ... fougueux .
George Stocker

Réponses:

397

Les éléments suivants, valides en C et C ++, entraîneront (très probablement) des valeurs différentes ien C et C ++:

int i = sizeof('a');

Voir Taille du caractère ('a') en C / C ++ pour une explication de la différence.

Un autre de cet article :

#include <stdio.h>

int  sz = 80;

int main(void)
{
    struct sz { char c; };

    int val = sizeof(sz);      // sizeof(int) in C,
                               // sizeof(struct sz) in C++
    printf("%d\n", val);
    return 0;
}
Alexey Frunze
la source
8
Je n'attendais certainement pas celui-ci! J'espérais quelque chose d'un peu plus dramatique mais c'est toujours utile, merci. :) +1
user541686
17
+1 le deuxième exemple est un bon pour le fait que C ++ ne nécessite pas de structnoms de structure avant.
Seth Carnegie
1
@Andrey J'ai pensé la même chose il y a quelque temps et l'ai testé et cela a fonctionné sur GCC 4.7.1 sans std, contrairement à mes attentes. Est-ce un bug dans GCC?
Seth Carnegie
3
@SethCarnegie: Un programme non conforme ne doit pas manquer de fonctionner, mais il n'est pas garanti de fonctionner non plus.
Andrey Vihrov
3
struct sz { int i[2];};signifierait que C et C ++ doivent produire des valeurs différentes. (Alors qu'un DSP avec sizeof (int) == 1, pourrait produire la même valeur).
Martin Bonner soutient Monica le
464

Voici un exemple qui tire parti de la différence entre les appels de fonction et les déclarations d'objet en C et C ++, ainsi que du fait que C90 autorise l'appel de fonctions non déclarées:

#include <stdio.h>

struct f { int x; };

int main() {
    f();
}

int f() {
    return printf("hello");
}

En C ++, cela n'imprimera rien car un temporaire fest créé et détruit, mais en C90, il s'imprimera hellocar les fonctions peuvent être appelées sans avoir été déclarées.

Au cas où vous vous poseriez des questions sur le nom futilisé deux fois, les normes C et C ++ le permettent explicitement, et pour faire un objet que vous devez dire struct fpour lever l'ambiguïté si vous voulez la structure, ou laisser de côté structsi vous voulez la fonction.

Seth Carnegie
la source
7
Strictement parlant sous C, cela ne se compilera pas, car la déclaration de "int f ()" est après la définition de "int main ()" :)
Sogartar
15
@Sogartar, vraiment? codepad.org/STSQlUhh Les compilateurs C99 vous donneront un avertissement, mais ils vous laisseront quand même le compiler.
jrajav
22
Les fonctions @Sogartar en C peuvent être déclarées implicitement.
Alex B
11
@AlexB Pas en C99 et C11.
6
@jrajav Ce ne sont donc pas des compilateurs C99. Un compilateur C99 détecte les identificateurs non déclarés comme une erreur de syntaxe. Un compilateur qui ne fait pas cela est soit un compilateur C89, soit un pré-standard ou un autre type de compilateur non conforme.
430

Pour C ++ et C90, il existe au moins un moyen d'obtenir un comportement différent qui n'est pas défini par l'implémentation. C90 n'a pas de commentaires sur une seule ligne. Avec un peu de soin, nous pouvons l'utiliser pour créer une expression avec des résultats entièrement différents en C90 et en C ++.

int a = 10 //* comment */ 2 
        + 3;

En C ++, tout depuis la //fin de la ligne est un commentaire, donc cela fonctionne comme:

int a = 10 + 3;

Étant donné que C90 n'a pas de commentaires sur une seule ligne, seul le /* comment */est un commentaire. Le premier /et le 2sont les deux parties de l'initialisation, il en résulte donc:

int a = 10 / 2 + 3;

Ainsi, un compilateur C ++ correct donnera 13, mais un compilateur C90 strictement correct 8. Bien sûr, je viens de choisir des nombres arbitraires ici - vous pouvez utiliser d'autres nombres comme bon vous semble.

Jerry Coffin
la source
34
WHOA c'est époustouflant !! De toutes les choses possibles, je n'aurais jamais pensé que les commentaires pourraient être utilisés pour changer le comportement haha. +1
user541686
89
même sans le 2, il se lirait comme 10 / + 3valide (unaire +).
Benoit
12
Maintenant, pour le plaisir, modifiez-le de sorte que C et C ++ calculent tous les deux des expressions arithmétiques différentes et évaluent le même résultat.
Ryan C. Thompson,
21
@RyanThompson Trivial. s /
2/1
4
@Mehrdad Je me trompe ou les commentaires sont liés au préprocesseur? Ils doivent donc être exclus comme réponse possible à votre question! ;-)
Ale
179

C90 contre C ++ 11 ( intcontre double):

#include <stdio.h>

int main()
{
  auto j = 1.5;
  printf("%d", (int)sizeof(j));
  return 0;
}

En C autosignifie variable locale. En C90, il est possible d'omettre le type de variable ou de fonction. Il est par défaut int. En C ++ 11 autosignifie quelque chose de complètement différent, il indique au compilateur de déduire le type de la variable à partir de la valeur utilisée pour l'initialiser.

désaccordé
la source
10
C90 a auto?
Seth Carnegie
22
@SethCarnegie: Oui, c'est une classe de stockage; c'est ce qui se passe par défaut lorsque vous l'omettez, donc personne ne l'a utilisé, et ils ont changé sa signification. Je pense que c'est intpar défaut. C'est intelligent! +1
user541686
5
C11 n'a pas implicite- int.
R .. GitHub STOP HELPING ICE
23
@KeithThompson Ah, je suppose que vous voulez dire l'inféré int. Pourtant, dans le monde réel, où il y a des tonnes de code hérité et où le leader du marché n'a toujours pas implémenté C99 et n'a aucune intention de le faire, parler d'une "version obsolète de C" est absurde.
Jim Balter
11
"Chaque variable DOIT avoir une classe de stockage explicite. Cordialement, la haute direction."
btown
120

Un autre exemple que je n'ai pas encore vu mentionné, celui-ci mettant en évidence une différence de préprocesseur:

#include <stdio.h>
int main()
{
#if true
    printf("true!\n");
#else
    printf("false!\n");
#endif
    return 0;
}

Cela affiche "false" en C et "true" en C ++ - En C, toute macro non définie est évaluée à 0. En C ++, il y a 1 exception: "true" est évalué à 1.

godlygeek
la source
2
Intéressant. Quelqu'un connaît-il la justification de ce changement?
entrée le
3
parce que "vrai" est un mot clé / une valeur valide, il est donc évalué comme vrai comme toute "vraie valeur" (donc comme tout entier positif). Vous pouvez toujours faire #define true false pour afficher "false" en C ++ aussi;)
CoffeDeveloper
22
#define true false ಠ_ಠ
Bryan Boettcher
2
@DarioOO ne donnera pas une telle redéfinition dans UB?
Ruslan
3
@DarioOO: Oui, vous vous trompez. La redéfinition des mots-clés n'est pas autorisée, punition laissée au destin (UB). Le préprocesseur étant une phase distincte de compilation nonobstant.
Déduplicateur
108

Selon la norme C ++ 11:

une. L'opérateur virgule effectue une conversion de lvalue en rvalue en C mais pas en C ++:

   char arr[100];
   int s = sizeof(0, arr);       // The comma operator is used.

En C ++, la valeur de cette expression sera 100 et en C, ce sera sizeof(char*).

b. En C ++, le type d'énumérateur est son énumération. En C, le type d'énumérateur est int.

   enum E { a, b, c };
   sizeof(a) == sizeof(int);     // In C
   sizeof(a) == sizeof(E);       // In C++

Cela signifie que sizeof(int)peut ne pas être égal à sizeof(E).

c. En C ++, une fonction déclarée avec une liste de paramètres vide ne prend aucun argument. En C, une liste de paramètres vide signifie que le nombre et le type de paramètres de fonction sont inconnus.

   int f();           // int f(void) in C++
                      // int f(*unknown*) in C
Kirill Kobelev
la source
Le premier est également défini par l'implémentation comme celui d'Alexey. Mais +1.
Seth Carnegie du
1
@Seth, Tout le matériel ci-dessus provient directement de l'annexe C.1 de la norme C ++ 11.
Kirill Kobelev
Oui, mais il est toujours défini par l'implémentation. sizeof(char*)pourrait être 100, auquel cas le premier exemple produirait le même comportement observable en C et C ++ (c.-à-d. bien que la méthode d'obtention ssoit différente, sfinirait par être 100). Le PO a mentionné que ce type de comportement défini par la mise en œuvre était bien car il voulait simplement éviter les réponses des juristes linguistiques, donc le premier est bien par son exception. Mais le second est bon en tout cas.
Seth Carnegie
5
Il existe une solution simple - changez simplement l'exemple en:char arr[sizeof(char*)+1]; int s = sizeof(0, arr);
Mankarse
5
Pour éviter les différences définies par l'implémentation, vous pouvez également utiliser void *arr[100]. Dans ce cas, un élément a la même taille qu'un pointeur vers le même élément, donc tant qu'il y a 2 éléments ou plus, le tableau doit être plus grand que l'adresse de son premier élément.
finnw
53

Ce programme imprime 1en C ++ et 0en C:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int d = (int)(abs(0.6) + 0.5);
    printf("%d", d);
    return 0;
}

Cela se produit car il y a double abs(double)surcharge en C ++, donc abs(0.6)retourne 0.6alors qu'en C il retourne à 0cause de la conversion implicite double en entier avant l'appel int abs(int). En C, vous devez utiliser fabspour travailler avec double.

Pavel Chikulaev
la source
5
a dû déboguer le code de quelqu'un d'autre avec ce problème. Oh comme j'ai adoré ça. Quoi qu'il en soit, votre programme imprime également 0 en C ++. C ++ doit utiliser l'en-tête "cmath" voir comparaison premier retour dans 0 ideone.com/0tQB2G 2ème retour 1 ideone.com/SLeANo
CoffeDeveloper
Heureux / désolé d'apprendre que je ne suis pas le seul à trouver cette différence via le débogage. Juste testé dans VS2013, un fichier vide avec uniquement ce contenu affichera 1 si l'extension est .cpp et 0 si l'extension est .c. Il semble que <math.h> soit inclus indirectement dans VS.
Pavel Chikulaev,
Et ressemble à VS C ++, <math.h> inclut des trucs C ++ dans l'espace de noms global, alors que pour GCC ce n'est pas le cas. Je ne sais pas quel est le comportement standard cependant.
Pavel Chikulaev
2
Cet exemple de code particulier dépend de l'implémentation: stdlib.hdéfinit uniquement abs(int)et abs(long); la version abs(double)est déclarée par math.h. Donc, ce programme peut toujours appeler la abs(int)version. Il s'agit d'un détail de mise en œuvre qui doit stdlib.hégalement math.hêtre inclus. (Je pense que ce serait un bug s'il abs(double)était appelé, mais d'autres aspecs math.hn'étaient pas inclus).
MM
1
Un problème secondaire est que, bien que la norme C ++ semble dire que l'inclusion <math.h>inclut également les surcharges supplémentaires; en pratique, il s'avère que tous les principaux compilateurs n'incluent pas ces surcharges à moins que le formulaire ne <cmath>soit utilisé.
MM
38
#include <stdio.h>

int main(void)
{
    printf("%d\n", (int)sizeof('a'));
    return 0;
}

En C, cela imprime quelle que soit la valeur de sizeof(int)est sur le système actuel, qui est généralement4 dans la plupart des systèmes couramment utilisés aujourd'hui.

En C ++, cela doit afficher 1.

Adam Rosenfield
la source
3
Oui, je connaissais vraiment cette astuce, étant que «c» est un entier en C et un caractère en C ++, mais il est toujours bon de l'avoir répertorié ici.
Sean
9
Cela ferait une question d'entrevue intéressante - en particulier pour les personnes qui mettent un expert c / c ++ sur leurs CV
Martin Beckett
2
Un peu sournois cependant. Le but de sizeof est que vous n'avez pas besoin de savoir exactement la taille d'un type.
Dana the Sane
13
En C, la valeur est définie par l'implémentation et 1 est une possibilité. (En C ++, il doit imprimer 1 comme indiqué.)
Programmeur Windows
3
En fait, il a un comportement indéfini dans les deux cas. %dn'est pas le bon spécificateur de format pour size_t.
R .. GitHub STOP HELPING ICE
37

Autre sizeofpiège: les expressions booléennes.

#include <stdio.h>
int main() {
    printf("%d\n", (int)sizeof !0);
}

Il est égal à sizeof(int)C, car l'expression est de type int, mais est généralement 1 en C ++ (bien qu'il ne soit pas obligatoire de l'être). En pratique, ils sont presque toujours différents.

Alex B
la source
6
Un !devrait suffire pour un bool.
Alexey Frunze du
4
!! est l'opérateur de conversion int en booléen :)
EvilTeach
1
sizeof(0)est 4à la fois en C et C ++ car 0est une valeur entière. sizeof(!0)est 4en C et 1en C ++. Logical NOT fonctionne sur des opérandes de type bool. Si la valeur int est 0elle est implicitement convertie en false(une valeur booléenne), alors elle est inversée, résultant en true. Les deux trueet falsesont des valeurs booléennes en C ++ et sizeof(bool)is 1. Cependant en C est !0évalué à 1, qui est une valeur r de type int. Le langage de programmation C n'a pas de type de données bool par défaut.
Galaxy
26

Le langage de programmation C ++ (3e édition) donne trois exemples:

  1. sizeof ('a'), comme @Adam Rosenfield l'a mentionné;

  2. // commentaires utilisés pour créer du code caché:

    int f(int a, int b)
    {
        return a //* blah */ b
            ;
    }
  3. Structures, etc. masquant des éléments dans des portées, comme dans votre exemple.

derobert
la source
25

Un vieux châtaignier qui dépend du compilateur C, ne reconnaissant pas les commentaires de fin de ligne C ++ ...

...
int a = 4 //* */ 2
        +2;
printf("%i\n",a);
...
dmckee --- chaton ex-modérateur
la source
21

Un autre répertorié par la norme C ++:

#include <stdio.h>

int x[1];
int main(void) {
    struct x { int a[2]; };
    /* size of the array in C */
    /* size of the struct in C++ */
    printf("%d\n", (int)sizeof(x)); 
}
Johannes Schaub - litb
la source
vous obtenez donc des différences de rembourrage?
v.oddou
ah désolé je l'ai eu, il y en a un autre xen haut. je pensais que vous avez dit "le tableau a".
v.oddou
20

Les fonctions en ligne en C ont par défaut une portée externe, contrairement à celles de C ++.

La compilation des deux fichiers suivants afficherait le "Je suis en ligne" dans le cas de GNU C mais rien pour C ++.

Fichier 1

#include <stdio.h>

struct fun{};

int main()
{
    fun();  // In C, this calls the inline function from file 2 where as in C++
            // this would create a variable of struct fun
    return 0;
}

Fichier 2

#include <stdio.h>
inline void fun(void)
{
    printf("I am inline\n");
} 

En outre, C ++ traite implicitement tout constglobal comme statics'il n'est pas déclaré explicitement extern, contrairement à C dans lequel externest la valeur par défaut.

fkl
la source
Je ne pense vraiment pas. Vous avez probablement raté le point. Il ne s'agit pas de définir la structure st qui est simplement utilisée pour rendre le code valide c ++. Le fait est qu'il met en évidence un comportement différent des fonctions en ligne en c vs c ++. Il en va de même pour les externes. Aucun de ceux-ci n'est discuté dans aucune des solutions.
fkl
2
Quel est le comportement différent des fonctions en ligne et externcela est démontré ici?
Seth Carnegie du
C'est écrit assez clairement. "Les fonctions en ligne dans c par défaut à la portée externe alors que celles de c ++ ne le sont pas (le code le montre). De plus, C ++ traite implicitement tout const global comme la portée du fichier sauf s'il est explicitement déclaré extern, contrairement à C dans lequel extern est la valeur par défaut. exemple peut être créé pour cela ". Je suis perplexe - n'est-ce pas compréhensible?
fkl
12
@fayyazkl Le comportement affiché n'est dû qu'à la différence de recherche ( struct funvs fn) et n'a rien à voir si la fonction est en ligne. Le résultat est identique si vous supprimez le inlinequalificatif.
Alex B
3
En ISO C, ce programme est mal formé: inlinen'a pas été ajouté avant C99, mais en C99, fun()il ne peut pas être appelé sans un prototype de portée. Je suppose donc que cette réponse ne s'applique qu'à GNU C.
MM
16
struct abort
{
    int x;
};

int main()
{
    abort();
    return 0;
}

Renvoie avec un code de sortie de 0 en C ++ ou 3 en C.

Cette astuce pourrait probablement être utilisée pour faire quelque chose de plus intéressant, mais je ne pouvais pas penser à un bon moyen de créer un constructeur qui serait acceptable pour C. J'ai essayé de faire un exemple similaire ennuyeux avec le constructeur de copie, qui laisserait un argument être adopté, bien que d'une manière plutôt non portable:

struct exit
{
    int x;
};

int main()
{
    struct exit code;
    code.x=1;

    exit(code);

    return 0;
}

VC ++ 2005 a refusé de compiler cela en mode C ++, cependant, se plaignant de la façon dont le "code de sortie" a été redéfini. (Je pense que c'est un bogue du compilateur, sauf si j'ai soudainement oublié comment programmer.) Il s'est terminé avec un code de sortie de processus de 1 quand il est compilé en C.


la source
Votre deuxième exemple utilisant exit, ne se compile pas sur gcc ou g ++, malheureusement. C'est une bonne idée, cependant.
Sean
1
exit(code)est une déclaration valide d'une variable codede type exit, apparemment. (Voir "analyse la plus vexante", qui est un problème différent mais similaire).
user253751
16
#include <stdio.h>

struct A {
    double a[32];
};

int main() {
    struct B {
        struct A {
            short a, b;
        } a;
    };
    printf("%d\n", sizeof(struct A));
    return 0;
}

Ce programme affiche 128( 32 * sizeof(double)) lorsqu'il est compilé à l'aide d'un compilateur C ++ et 4lorsqu'il est compilé à l'aide d'un compilateur C.

C'est parce que C n'a pas la notion de résolution de portée. En C, les structures contenues dans d'autres structures sont mises dans le cadre de la structure externe.

wefwefa3
la source
Celui-ci est intéressant! (Je pense que vous voulez dire 32*sizeof(double)plutôt que 32 cependant :))
user1354557
3
notez que vous obtenez UB en imprimant size_tavec%d
phuclv
7

N'oubliez pas la distinction entre les espaces de noms globaux C et C ++. Supposons que vous ayez un foo.cpp

#include <cstdio>

void foo(int r)
{
  printf("I am C++\n");
}

et un foo2.c

#include <stdio.h>

void foo(int r)
{
  printf("I am C\n");
}

Supposons maintenant que vous ayez un main.c et un main.cpp qui ressemblent tous les deux à ceci:

extern void foo(int);

int main(void)
{
  foo(1);
  return 0;
}

Une fois compilé en C ++, il utilisera le symbole dans l'espace de noms global C ++; en C il utilisera le C:

$ diff main.cpp main.c
$ gcc -o test main.cpp foo.cpp foo2.c
$ ./test 
I am C++
$ gcc -o test main.c foo.cpp foo2.c
$ ./test 
I am C
user23614
la source
Vous voulez dire la spécification de liaison?
user541686
nom mangling. Les noms C ++ ont des préfixes et des suffixes alors que C n'est pas
CoffeDeveloper
Le changement de nom ne fait pas partie de la spécification C ++. Est-ce interdit en C?
skyking
5
Il s'agit d'un comportement non défini (définition multiple de foo). Il n'y a pas d '"espaces de noms globaux" séparés.
MM
4
int main(void) {
    const int dim = 5; 
    int array[dim];
}

C'est assez particulier en ce sens qu'il est valide en C ++ et en C99, C11 et C17 (bien que facultatif en C11, C17); mais non valide en C89.

En C99 +, il crée un tableau de longueur variable, qui a ses propres particularités par rapport aux tableaux normaux, car il a un type d'exécution au lieu du type au moment de la compilation, et sizeof arrayn'est pas une expression constante entière en C. En C ++, le type est entièrement statique.


Si vous essayez d'ajouter un initialiseur ici:

int main(void) {
    const int dim = 5; 
    int array[dim] = {0};
}

est C ++ valide mais pas C, car les tableaux de longueur variable ne peuvent pas avoir d'initialiseur.

Antti Haapala
la source
0

Cela concerne les lvalues ​​et les rvalues ​​en C et C ++.

Dans le langage de programmation C, les opérateurs de pré-incrémentation et de post-incrémentation renvoient rvalues, pas lvalues. Cela signifie qu'ils ne peuvent pas être sur le côté gauche de l' =opérateur d'affectation. Ces deux instructions donneront une erreur de compilation en C:

int a = 5;
a++ = 2;  /* error: lvalue required as left operand of assignment */
++a = 2;  /* error: lvalue required as left operand of assignment */

En C ++ cependant, l'opérateur de pré-incrémentation renvoie une valeur l , tandis que l'opérateur de post-incrémentation renvoie une valeur r. Cela signifie qu'une expression avec l'opérateur de pré-incrémentation peut être placée sur le côté gauche de l' =opérateur d'affectation!

int a = 5;
a++ = 2;  // error: lvalue required as left operand of assignment
++a = 2;  // No error: a gets assigned to 2!

Maintenant, pourquoi en est-il ainsi? Le post-incrément incrémente la variable, et il renvoie la variable telle qu'elle était avant l'incrémentation ne se produise. C'est en fait juste une valeur r. L'ancienne valeur de la variable a est copiée dans un registre comme temporaire, puis a est incrémentée. Mais l'ancienne valeur de a est renvoyée par l'expression, c'est une valeur r. Il ne représente plus le contenu actuel de la variable.

La pré-incrémentation incrémente d'abord la variable, puis elle renvoie la variable telle qu'elle est devenue après l'incrémentation. Dans ce cas, nous n'avons pas besoin de stocker l'ancienne valeur de la variable dans un registre temporaire. Nous récupérons simplement la nouvelle valeur de la variable après son incrémentation. Ainsi, le pré-incrément renvoie une valeur l, il renvoie la variable a elle-même. Nous pouvons utiliser assigner cette valeur à quelque chose d'autre, c'est comme l'instruction suivante. Il s'agit d'une conversion implicite de lvalue en rvalue.

int x = a;
int x = ++a;

Puisque le pré-incrément renvoie une valeur l, nous pouvons également lui attribuer quelque chose. Les deux déclarations suivantes sont identiques. Dans la deuxième affectation, d'abord a est incrémenté, puis sa nouvelle valeur est remplacée par 2.

int a;
a = 2;
++a = 2;  // Valid in C++.
Galaxie
la source
3
Il n'y a pas de "valide en C" ici.
o11c
0

Les structures vides ont une taille 0 en C et 1 en C ++:

#include <stdio.h>

typedef struct {} Foo;

int main()
{
    printf("%zd\n", sizeof(Foo));
    return 0;
}
Daniel Frużyński
la source
1
Non, la différence est que C n'a pas de structures vides, sauf en tant qu'extension de compilateur, c'est-à-dire que ce code ne correspond pas "est valide à la fois en C et C ++"
Antti Haapala