Il codice valido sia in C che in C ++ può produrre comportamenti diversi se compilato in ogni lingua?


664

C e C ++ hanno molte differenze e non tutto il codice C valido è codice C ++ valido.
(Per "valido" intendo codice standard con comportamento definito, cioè non specifico dell'implementazione / non definito / ecc.)

Esiste uno scenario in cui un pezzo di codice valido sia in C che in C ++ produrrebbe comportamenti diversi se compilato con un compilatore standard in ogni lingua?

Per renderlo un confronto ragionevole / utile (sto cercando di imparare qualcosa di praticamente utile, non di cercare ovvie lacune nella domanda), supponiamo che:

  • Niente relativo al preprocessore (il che significa che non esistono hack con #ifdef __cplusplus, pragmi, ecc.)
  • Qualunque cosa definita dall'implementazione è la stessa in entrambe le lingue (ad es. Limiti numerici, ecc.)
  • Stiamo confrontando versioni ragionevolmente recenti di ogni standard (ad esempio diciamo, C ++ 98 e C90 o successive)
    Se le versioni contano, si prega di indicare quali versioni di ciascuna producono comportamenti diversi.

11
A proposito, può essere utile programmare in un dialetto che è C e C ++ contemporaneamente. L'ho fatto in passato e un solo progetto attuale: il linguaggio TXR. È interessante notare che gli sviluppatori del linguaggio Lua hanno fatto la stessa cosa e hanno chiamato questo dialetto "Clean C". Ottieni il vantaggio di una migliore verifica dei tempi di compilazione e, eventualmente, di ulteriori utili diagnosi dai compilatori C ++, mantenendo tuttavia la portabilità C.
Kaz,

9
Ho unito la domanda più vecchia a questa domanda poiché ha più punti di vista e risposte votate. Questo è ancora un esempio di una domanda non costruttiva, ma è piuttosto borderline poiché sì, insegna agli utenti SO qualcosa. Lo sto chiudendo come non costruttivo solo per riflettere lo stato della domanda prima della fusione. Sentiti libero di non essere d'accordo e riaprire.
George Stocker,

13
Votando per riaprire come penso possa essere obiettivamente risposto con un "sì" seguito da un esempio (come dimostrato di seguito). Penso che sia costruttivo in quanto le persone possono imparare da esso comportamenti pertinenti.
Anders Abel,

6
@AndersAbel Il numero puro di risposte, tutte corrette, dimostra inequivocabilmente che rimane una domanda da fare. Non sarebbe stato possibile porre questa domanda senza ottenere un elenco.
dmckee --- ex gattino moderatore,

2
@dmckee Per quello che vale, sono d'accordo con te. Tuttavia, il tag C ++ è ... Diciamo ... esuberante .
George Stocker,

Risposte:


397

Quanto segue, valido in C e C ++, determinerà (molto probabilmente) valori diversi iin C e C ++:

int i = sizeof('a');

Vedi Dimensione del carattere ('a') in C / C ++ per una spiegazione della differenza.

Un altro da questo articolo :

#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;
}

8
Sicuramente non mi aspettavo questo! Speravo in qualcosa di un po 'più drammatico, ma questo è ancora utile, grazie. :) +1
user541686

17
+1 il secondo esempio è buono per il fatto che C ++ non richiede structprima dei nomi di struttura.
Seth Carnegie,

1
@Andrey Ho pensato lo stesso qualche tempo fa e l'ho provato e ha funzionato su GCC 4.7.1 senza lo standard, contrariamente alle mie aspettative. È un bug in GCC?
Seth Carnegie,

3
@SethCarnegie: un programma non conforme non deve necessariamente fallire, ma non è garantito che funzioni neanche.
Andrey Vihrov,

3
struct sz { int i[2];};significherebbe che C e C ++ devono produrre valori diversi. (Considerando che un DSP con sizeof (int) == 1, potrebbe produrre lo stesso valore).
Martin Bonner supporta Monica il

464

Ecco un esempio che sfrutta la differenza tra chiamate di funzioni e dichiarazioni di oggetti in C e C ++, nonché il fatto che C90 consente la chiamata di funzioni non dichiarate:

#include <stdio.h>

struct f { int x; };

int main() {
    f();
}

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

In C ++ questo non stampa nulla perché un temporaneo fviene creato e distrutto, ma in C90 verrà stampato helloperché le funzioni possono essere chiamate senza essere state dichiarate.

Nel caso in cui ti stavi chiedendo il nome fusato due volte, gli standard C e C ++ lo consentono esplicitamente e per creare un oggetto devi dire struct fper chiarire se vuoi la struttura o lasciar perdere structse vuoi la funzione.


7
A rigor di termini in C questo non verrà compilato, perché la dichiarazione di "int f ()" è dopo la definizione di "int main ()" :)
Sogartar,

15
@Sogartar, davvero? codepad.org/STSQlUhh I compilatori C99 ti daranno un avvertimento, ma ti permetteranno comunque di compilarlo.
jrajav,

22
@Sogartar nelle funzioni C può essere implicitamente dichiarato.
Alex B,

11
@AlexB Non in C99 e C11.

6
@jrajav Quelli non sono compilatori C99, quindi. Un compilatore C99 rileva identificatori non dichiarati come un errore di sintassi. Un compilatore che non lo fa è un compilatore C89 o un pre-standard o un altro tipo di compilatore non conforme.

430

Per C ++ vs. C90, esiste almeno un modo per ottenere comportamenti diversi che non sono definiti dall'implementazione. C90 non ha commenti a riga singola. Con un po 'di attenzione, possiamo usarlo per creare un'espressione con risultati completamente diversi in C90 e in C ++.

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

In C ++, tutto dalla //fine alla riga è un commento, quindi questo funziona come:

int a = 10 + 3;

Poiché C90 non ha commenti a riga singola, è solo /* comment */un commento. Il primo /e il 2sono entrambi parti dell'inizializzazione, quindi viene fuori:

int a = 10 / 2 + 3;

Quindi, un compilatore C ++ corretto fornirà 13, ma un compilatore C90 rigorosamente corretto 8. Naturalmente, ho appena selezionato numeri arbitrari qui: puoi usare altri numeri come ritieni opportuno.


34
WHOA questo è strabiliante !! Di tutte le cose possibili non avrei mai pensato che i commenti potessero essere usati per cambiare il comportamento ahah. +1
user541686,

89
anche senza il 2, leggerebbe come 10 / + 3valido (unario +).
Benoit,

12
Ora per divertimento, modificalo in modo che C e C ++ calcolino entrambe espressioni aritmetiche diverse per valutare lo stesso risultato.
Ryan C. Thompson,

21
@RyanThompson Trivial. s /
2/1

4
@Mehrdad Sbaglio o i commenti sono relativi al preprocessore? Dovrebbero quindi essere esclusi come possibile risposta alla tua domanda! ;-)
Ale

179

C90 vs. C ++ 11 ( intvs. double):

#include <stdio.h>

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

In C autosignifica variabile locale. In C90 è ok omettere la variabile o il tipo di funzione. L'impostazione predefinita è int. In C ++ 11 autosignifica qualcosa di completamente diverso, dice al compilatore di inferire il tipo di variabile dal valore usato per inizializzarlo.


10
C90 ha auto?
Seth Carnegie,

22
@SethCarnegie: Sì, è una classe di archiviazione; è ciò che accade di default quando lo ometti, quindi nessuno lo ha usato e ne hanno cambiato il significato. Penso che sia di intdefault. Questo è intelligente! +1
user541686,

5
C11 non ha implicito- int.
R .. GitHub smette di aiutare ICE il

23
@KeithThompson Ah, immagino tu intenda l'inferito int. Tuttavia, nel mondo reale, dove ci sono tonnellate di codice legacy e il leader di mercato non ha ancora implementato C99 e non ha intenzione di farlo, parlare di "una versione obsoleta di C" è assurdo.
Jim Balter,

11
"Ogni variabile DEVE avere una classe di archiviazione esplicita. Cordiali saluti, alta direzione."
btown,

120

Un altro esempio che non ho ancora visto menzionato, questo evidenzia una differenza del preprocessore:

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

Questo stampa "false" in C e "true" in C ++ - In C, qualsiasi macro non definita restituisce 0. In C ++, esiste 1 eccezione: "true" restituisce 1.


2
Interessante. Qualcuno conosce la logica alla base di questo cambiamento?
antred

3
perché "vero" è una parola chiave / valore valido, quindi viene valutato come vero come qualsiasi "valore vero" (quindi come qualsiasi numero intero positivo). Puoi ancora fare #define true false per stampare "false" anche in C ++;)
CoffeDeveloper

22
#define true false ಠ_ಠ
Bryan Boettcher il

2
@DarioOO non porterà a tale ridefinizione in UB?
Ruslan,

3
@DarioOO: Sì, ti sbagli. La ridefinizione delle parole chiave non è consentita, la punizione lasciata al destino (UB). Il preprocessore essendo una fase separata della compilazione non resiste.
Deduplicatore,

108

Secondo lo standard C ++ 11:

un. L'operatore virgola esegue la conversione da lvalue a rvalue in C ma non in C ++:

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

In C ++ il valore di questa espressione sarà 100 e in C questo sarà sizeof(char*).

b. In C ++ il tipo di enumeratore è il suo enum. In C il tipo di enumeratore è int.

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

Ciò significa che sizeof(int)potrebbe non essere uguale a sizeof(E).

c. In C ++ una funzione dichiarata con un elenco di parametri vuoto non accetta argomenti. Nella lista dei parametri vuota C significa che il numero e il tipo di parametri della funzione sono sconosciuti.

   int f();           // int f(void) in C++
                      // int f(*unknown*) in C

Il primo è anche definito dall'implementazione come quello di Alexey. Ma +1.
Seth Carnegie,

1
@Seth, tutto il materiale sopra è preso direttamente dall'allegato C.1 della norma C ++ 11.
Kirill Kobelev,

Sì, ma è ancora definito dall'implementazione. sizeof(char*)potrebbe essere 100, nel qual caso il primo esempio produrrebbe lo stesso comportamento osservabile in C e C ++ (cioè, sebbene il metodo di ottenimento ssarebbe diverso, sfinirebbe per essere 100). L'OP ha menzionato che questo tipo di comportamento definito dall'implementazione andava bene poiché voleva solo evitare le risposte dell'avvocato linguista, quindi il primo va bene per la sua eccezione. Ma il secondo è buono in ogni caso.
Seth Carnegie,

5
C'è una soluzione semplice: cambia l'esempio in:char arr[sizeof(char*)+1]; int s = sizeof(0, arr);
Mankarse,

5
Per evitare differenze definite dall'implementazione, è inoltre possibile utilizzare void *arr[100]. In questo caso un elemento ha le stesse dimensioni di un puntatore allo stesso elemento, quindi finché ci sono 2 o più elementi, l'array deve essere più grande dell'indirizzo del suo primo elemento.
Finnw,

53

Questo programma stampa 1in C ++ e 0in C:

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

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

Ciò accade perché c'è un double abs(double)sovraccarico in C ++, quindi abs(0.6)ritorna 0.6mentre in C ritorna a 0causa della conversione implicita da doppio a int prima di invocare int abs(int). In C, devi usare fabsper lavorare double.


5
ha dovuto eseguire il debug del codice di qualcun altro con quel problema. Oh, come l'ho adorato. Ad ogni modo il tuo programma stampa anche 0 in C ++. Il C ++ deve usare l'intestazione "cmath" vedi il confronto primo ritorno in 0 ideone.com/0tQB2G secondo ritorno 1 ideone.com/SLeANo
CoffeDeveloper

Sono contento / mi dispiace sapere che non sono l'unico a trovare questa differenza tramite il debug. Appena testato in VS2013, un file vuoto con solo file con questo contenuto produrrà 1 se l'estensione è .cpp e 0 se l'estensione è .c. Sembra che <math.h> sia incluso indirettamente in VS.
Pavel Chikulaev,

E sembra che in VS C ++, <math.h> includa materiale C ++ nello spazio dei nomi globale, dove non lo è per GCC. Non sono sicuro quale sia il comportamento standard comunque.
Pavel Chikulaev il

2
Questo particolare esempio di codice dipende dall'implementazione: stdlib.hdefinisce solo abs(int)e abs(long); la versione abs(double)è dichiarata da math.h. Quindi questo programma potrebbe ancora chiamare la abs(int)versione. È un dettaglio dell'implementazione se stdlib.hanche le cause math.hdevono essere incluse. (Penso che sarebbe un bug se abs(double)fossero chiamati, ma altri aspetti math.hnon erano inclusi).
MM

1
Un problema secondario è che sebbene lo standard C ++ sembri dire che includere <math.h>include anche i sovraccarichi aggiuntivi; in pratica si scopre che tutti i principali compilatori non includono tali sovraccarichi a meno che non <cmath>venga utilizzato il modulo .
MM

38
#include <stdio.h>

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

In C, questo stampa qualunque sia il valore di sizeof(int)sul sistema attuale, che è in genere 4nella maggior parte dei sistemi comunemente in uso oggi.

In C ++, questo deve stampare 1.


3
Sì, in realtà conoscevo questo trucco, dato che 'c' è un int in C e un carattere in C ++, ma è comunque bello averlo elencato qui.
Sean,

9
Ciò farebbe un'interessante domanda per l'intervista, specialmente per le persone che hanno inserito esperti c / c ++ nei loro CV
Martin Beckett,

2
Un po 'subdolo però. L'intero scopo di sizeof è quindi non è necessario sapere esattamente quanto è grande un tipo.
Dana the Sane,

13
In C il valore è definito dall'implementazione e 1 è una possibilità. (In C ++ deve stampare 1 come indicato.)
Programmatore di Windows

3
In realtà ha un comportamento indefinito in entrambi i casi. %dnon è l'identificatore di formato corretto per size_t.
R .. GitHub smette di aiutare ICE il

37

Un'altra sizeoftrappola: espressioni booleane.

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

È uguale a sizeof(int)in C, perché l'espressione è di tipo int, ma in genere è 1 in C ++ (anche se non è necessario che sia). In pratica sono quasi sempre diversi.


6
Uno !dovrebbe essere abbastanza per a bool.
Alexey Frunze,

4
!! è l'int operatore di conversione booleana :)
EvilTeach

1
sizeof(0)è 4sia in C che in C ++ perché 0è un valore intero. sizeof(!0)è 4in C e 1in C ++. Logical NOT funziona su operandi di tipo bool. Se il valore int è 0convertito implicitamente in false(un valore bool), viene invertito, risultando in true. Entrambi truee falsesono valori booleari in C ++ e sizeof(bool)is 1. Tuttavia in C !0valuta 1, che è un valore di tipo int. Il linguaggio di programmazione C non ha alcun tipo di dati bool di default.
Galaxy,

26

Il linguaggio di programmazione C ++ (3a edizione) fornisce tre esempi:

  1. sizeof ('a'), come menzionato da @Adam Rosenfield;

  2. // commenti utilizzati per creare codice nascosto:

    int f(int a, int b)
    {
        return a //* blah */ b
            ;
    }
  3. Strutture ecc. Nascondono oggetti all'interno di ambiti, come nel tuo esempio.


25

Una vecchia castagna che dipende dal compilatore C, non riconoscendo i commenti di fine riga C ++ ...

...
int a = 4 //* */ 2
        +2;
printf("%i\n",a);
...

21

Un altro elencato dallo standard 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)); 
}

quindi ottieni differenze di riempimento?
v. Il

ah scusa l'ho preso, ce n'è un altro xin alto. pensavo avessi detto "l'array a".
v. Il

20

Le funzioni incorporate in C sono predefinite nell'ambito esterno, mentre quelle in C ++ no.

Compilando insieme i seguenti due file, si stampa "I am inline" in caso di GNU C ma niente per C ++.

File 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;
}

File 2

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

Inoltre, C ++ tratta implicitamente qualsiasi constglobale come staticse non sia esplicitamente dichiarato extern, a differenza di C in cui externè l'impostazione predefinita.


Davvero non la penso così. Probabilmente hai perso il punto. Non si tratta della definizione di struct st che viene semplicemente utilizzata per rendere il codice valido c ++. Il punto è che mette in evidenza il diverso comportamento delle funzioni inline in c vs c ++. Lo stesso vale per l'esterno. Nessuna di queste è discussa in nessuna delle soluzioni.
fkl,

2
Qual è il diverso comportamento delle funzioni in linea e externche è dimostrato qui?
Seth Carnegie,

È scritto abbastanza chiaramente. "Le funzioni incorporate in c sono predefinite nell'ambito esterno dove non lo sono quelle in c ++ (il codice mostra che). Inoltre C ++ tratta implicitamente qualsiasi const globale come ambito di file a meno che non sia esplicitamente dichiarato extern, a differenza di C in cui extern è l'impostazione predefinita. Un simile esempio può essere creato per questo ". Sono perplesso - Non è comprensibile?
fkl,

12
@fayyazkl Il comportamento mostrato è solo a causa della differenza di ricerca ( struct funvs fn) e non ha nulla a che fare se la funzione è in linea. Il risultato è identico se si rimuove il inlinequalificatore.
Alex B,

3
In ISO C questo programma è mal formato: inlinenon è stato aggiunto fino a C99, ma in C99 fun()non può essere chiamato senza un prototipo in ambito. Quindi suppongo che questa risposta si applichi solo a GNU C.
MM

16
struct abort
{
    int x;
};

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

Restituisce con il codice di uscita 0 in C ++ o 3 in C.

Questo trucco potrebbe probabilmente essere usato per fare qualcosa di più interessante, ma non riuscivo a pensare a un buon modo per creare un costruttore che fosse appetibile per C. Ho provato a fare un esempio altrettanto noioso con il costruttore di copie, che avrebbe lasciato un argomento essere superato, anche se in modo piuttosto non portatile:

struct exit
{
    int x;
};

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

    exit(code);

    return 0;
}

VC ++ 2005 ha rifiutato di compilarlo in modalità C ++, lamentandosi di come il "codice di uscita" è stato ridefinito. (Penso che questo sia un bug del compilatore, a meno che non mi sia improvvisamente dimenticato come programmare.) È uscito con un codice di uscita del processo 1 quando è stato compilato come C.


Il tuo secondo esempio usando exit, purtroppo non si compila su gcc o g ++. È una buona idea, comunque.
Sean,

1
exit(code)è una dichiarazione valida di una variabile codedi tipo exit, apparentemente. (Vedi "analisi più irritante", che è un problema diverso ma simile).
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;
}

Questo programma stampa 128( 32 * sizeof(double)) quando compilato usando un compilatore C ++ e4 quando compilato usando un compilatore C.

Questo perché C non ha il concetto di risoluzione dell'ambito. In C le strutture contenute in altre strutture vengono inserite nell'ambito della struttura esterna.


Questo è interessante! (Penso che intendi 32*sizeof(double)piuttosto che 32 però :))
user1354557

3
nota che stai ottenendo UB stampando size_tcon%d
phuclv

7

Non dimenticare la distinzione tra gli spazi dei nomi globali C e C ++. Supponiamo di avere un foo.cpp

#include <cstdio>

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

e un foo2.c

#include <stdio.h>

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

Supponiamo ora di avere un main.c e main.cpp che entrambi assomigliano a questo:

extern void foo(int);

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

Se compilato come C ++, utilizzerà il simbolo nello spazio dei nomi globale C ++; in C utilizzerà quello 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

Intendi le specifiche del collegamento?
user541686,

nome mangling. I nomi C ++ hanno prefissi e suffissi mentre C no
CoffeDeveloper

La modifica del nome non fa parte della specifica C ++. È vietato in C?
stelle

5
Questo è un comportamento indefinito (definizione multipla di foo). Non esistono "spazi dei nomi globali" separati.
MM

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

Ciò è piuttosto peculiare in quanto è valido in C ++ e in C99, C11 e C17 (sebbene facoltativo in C11, C17); ma non valido in C89.

In C99 + crea un array di lunghezza variabile, che ha le sue peculiarità rispetto agli array normali, poiché ha un tipo di runtime invece del tipo di tempo di compilazione e sizeof arraynon è un'espressione costante intera in C. In C ++ il tipo è completamente statico.


Se provi ad aggiungere un inizializzatore qui:

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

è C ++ valido ma non C, poiché le matrici a lunghezza variabile non possono avere un inizializzatore.


0

Ciò riguarda i valori e i valori in C e C ++.

Nel linguaggio di programmazione C, sia l'operatore pre-incremento che quello post-incremento restituiscono valori, non valori. Ciò significa che non possono trovarsi sul lato sinistro =dell'operatore di assegnazione. Entrambe queste istruzioni daranno un errore del compilatore in C:

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

In C ++, tuttavia, l'operatore pre-incremento restituisce un valore , mentre l'operatore post-incremento restituisce un valore. Significa che un'espressione con l'operatore di pre-incremento può essere posizionata sul lato sinistro =dell'operatore di assegnazione!

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

Ora, perché è così? Il post-incremento incrementa la variabile e restituisce la variabile com'era prima dell'incremento. Questo è in realtà solo un valore. Il valore precedente della variabile a viene copiato in un registro come temporaneo, quindi viene incrementato. Ma il valore precedente di a viene restituito dall'espressione, è un valore. Non rappresenta più il contenuto corrente della variabile.

Il pre-incremento incrementa prima la variabile, quindi restituisce la variabile come è diventata dopo l'incremento. In questo caso, non è necessario archiviare il vecchio valore della variabile in un registro temporaneo. Recuperiamo semplicemente il nuovo valore della variabile dopo che è stata incrementata. Quindi il pre-incremento restituisce un valore, restituisce la variabile a se stessa. Possiamo usare assegnare questo valore a qualcos'altro, è come la seguente affermazione. Questa è una conversione implicita di lvalue in rvalue.

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

Poiché il pre-incremento restituisce un valore, possiamo anche assegnargli qualcosa. Le seguenti due affermazioni sono identiche. Nella seconda assegnazione, prima a viene incrementato, quindi il suo nuovo valore viene sovrascritto con 2.

int a;
a = 2;
++a = 2;  // Valid in C++.

3
Non c'è "valido in C" qui.
o11c,

0

Le strutture vuote hanno dimensione 0 in C e 1 in C ++:

#include <stdio.h>

typedef struct {} Foo;

int main()
{
    printf("%zd\n", sizeof(Foo));
    return 0;
}

1
No, la differenza è che C non ha strutture vuote, tranne che come estensione del compilatore, vale a dire che questo codice non corrisponde "è valido sia in C che in C ++"
Antti Haapala,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.