Bisakah kode yang valid di C dan C ++ menghasilkan perilaku yang berbeda ketika dikompilasi dalam setiap bahasa?

664

C dan C ++ memiliki banyak perbedaan, dan tidak semua kode C yang valid adalah kode C ++ yang valid.
(Dengan "valid" maksud saya kode standar dengan perilaku yang ditentukan, yaitu tidak spesifik implementasi / tidak terdefinisi / dll.)

Apakah ada skenario di mana sepotong kode valid dalam C dan C ++ akan menghasilkan perilaku yang berbeda ketika dikompilasi dengan kompiler standar di setiap bahasa?

Untuk menjadikannya perbandingan yang masuk akal / berguna (saya mencoba mempelajari sesuatu yang praktis berguna, bukan mencoba menemukan celah yang jelas dalam pertanyaan), mari kita asumsikan:

  • Tidak ada yang terkait dengan preprosesor (yang berarti tidak ada peretasan #ifdef __cplusplus, pragma, dll.)
  • Implementasi apa pun yang didefinisikan adalah sama di kedua bahasa (misalnya batas numerik, dll.)
  • Kami membandingkan versi terbaru dari setiap standar (mis. Katakan, C ++ 98 dan C90 atau lebih baru).
    Jika versi penting, maka tolong sebutkan versi masing-masing yang menghasilkan perilaku yang berbeda.
pengguna541686
sumber
11
Ngomong-ngomong, dapat berguna untuk memprogram dalam dialek yang merupakan C dan C ++ secara bersamaan. Saya telah melakukan ini di masa lalu dan satu proyek saat ini: bahasa TXR. Menariknya, para pengembang bahasa Lua melakukan hal yang sama, dan mereka menyebut dialek ini "Bersihkan C". Anda mendapatkan manfaat dari pemeriksaan waktu kompilasi yang lebih baik dan kemungkinan diagnostik tambahan yang berguna dari kompiler C ++, namun tetap mempertahankan portabilitas C.
Kaz
9
Saya menggabungkan pertanyaan lama ke pertanyaan ini karena ini memiliki lebih banyak pandangan dan jawaban terangkat. Ini masih merupakan contoh dari pertanyaan yang tidak konstruktif, tetapi ini merupakan batasan karena ya, itu mengajarkan sesuatu kepada pengguna SO. Saya menutupnya sebagai tidak konstruktif hanya untuk mencerminkan keadaan pertanyaan sebelum penggabungan. Jangan ragu untuk tidak setuju dan membuka kembali.
George Stocker
13
Voting untuk dibuka kembali karena saya pikir itu dapat secara objektif dijawab dengan "ya" diikuti oleh contoh (seperti yang dibuktikan di bawah). Saya pikir itu konstruktif karena orang bisa belajar perilaku yang relevan darinya.
Anders Abel
6
@AndersAbel Jumlah murni jawaban, semuanya benar, menunjukkan dengan jelas bahwa itu tetap menjadi pertanyaan buat-daftar. Tidak mungkin Anda bisa menanyakan pertanyaan ini tanpa mendapatkan daftar.
dmckee --- ex-moderator kitten
2
@ dmckee Untuk apa nilainya, saya setuju dengan Anda. Namun, orang-orang tag C ++ adalah ... Haruskah kita katakan ... penuh semangat .
George Stocker

Jawaban:

397

Berikut ini, valid dalam C dan C ++, akan (kemungkinan besar) menghasilkan nilai yang berbeda di idalam C dan C ++:

int i = sizeof('a');

Lihat Ukuran karakter ('a') di C / C ++ untuk penjelasan perbedaannya.

Satu lagi dari artikel ini :

#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
sumber
8
Pasti tidak mengharapkan yang satu ini! Saya berharap untuk sesuatu yang sedikit lebih dramatis tetapi ini masih berguna, terima kasih. :) +1
user541686
17
+1 contoh kedua adalah contoh yang bagus karena C ++ tidak diperlukan structsebelum nama struct.
Seth Carnegie
1
@ Andrew saya memikirkan hal yang sama beberapa waktu lalu dan mengujinya dan bekerja pada GCC 4.7.1 tanpa std, bertentangan dengan harapan saya. Apakah itu bug di GCC?
Seth Carnegie
3
@SethCarnegie: Program yang tidak sesuai tidak perlu gagal untuk bekerja, tetapi juga tidak dijamin untuk bekerja.
Andrey Vihrov
3
struct sz { int i[2];};berarti bahwa C dan C ++ harus menghasilkan nilai yang berbeda. (Sedangkan DSP dengan sizeof (int) == 1, dapat menghasilkan nilai yang sama).
Martin Bonner mendukung Monica
464

Berikut adalah contoh yang mengambil keuntungan dari perbedaan antara pemanggilan fungsi dan deklarasi objek dalam C dan C ++, serta fakta bahwa C90 memungkinkan pemanggilan fungsi yang tidak dideklarasikan:

#include <stdio.h>

struct f { int x; };

int main() {
    f();
}

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

Dalam C ++ ini tidak akan mencetak apa-apa karena sementara fdibuat dan dihancurkan, tetapi dalam C90 ini akan mencetak hellokarena fungsi dapat dipanggil tanpa dideklarasikan.

Jika Anda bertanya-tanya tentang nama fyang digunakan dua kali, standar C dan C ++ secara eksplisit memungkinkan ini, dan untuk membuat objek Anda harus mengatakan struct funtuk ambigu jika Anda ingin struktur, atau tinggalkan structjika Anda ingin fungsi.

Seth Carnegie
sumber
7
Sebenarnya di bawah C ini tidak akan dikompilasi, karena deklarasi "int f ()" adalah setelah definisi "int main ()" :)
Sogartar
15
@ Logogar, benarkah? codepad.org/STSQlUhh C99 kompiler akan memberi Anda peringatan, tetapi mereka masih akan membiarkan Anda mengkompilasinya.
jrajav
22
@Sogartar dalam fungsi C diizinkan untuk dideklarasikan secara implisit.
Alex B
11
@AlexB Tidak dalam C99 dan C11.
6
@ jrajav Itu bukan kompiler C99, kalau begitu. Kompiler C99 mendeteksi pengidentifikasi yang tidak dideklarasikan sebagai kesalahan sintaksis. Kompiler yang tidak melakukan itu adalah kompiler C89, atau pra-standar atau jenis kompiler yang tidak sesuai.
430

Untuk C ++ vs. C90, setidaknya ada satu cara untuk mendapatkan perilaku berbeda yang tidak didefinisikan implementasi. C90 tidak memiliki komentar single-line. Dengan sedikit perhatian, kita dapat menggunakannya untuk membuat ekspresi dengan hasil yang sepenuhnya berbeda di C90 dan di C ++.

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

Di C ++, segala sesuatu dari //hingga akhir baris adalah komentar, jadi ini berfungsi sebagai:

int a = 10 + 3;

Karena C90 tidak memiliki komentar satu baris, hanya /* comment */itu yang merupakan komentar. Yang pertama /dan 2yang kedua adalah bagian dari inisialisasi, sehingga keluar ke:

int a = 10 / 2 + 3;

Jadi, kompiler C ++ yang benar akan memberikan 13, tetapi kompiler C90 yang benar-benar benar 8. Tentu saja, saya hanya memilih angka acak di sini - Anda dapat menggunakan angka lain sesuai keinginan Anda.

Jerry Coffin
sumber
34
WHOA ini sangat mengejutkan !! Dari semua hal yang mungkin saya tidak pernah mengira komentar dapat digunakan untuk mengubah perilaku haha. +1
user541686
89
bahkan tanpa 2, itu akan dibaca sebagai 10 / + 3yang valid (unary +).
Benoit
12
Sekarang untuk bersenang-senang, modifikasi sehingga C dan C ++ keduanya menghitung ekspresi aritmatika yang berbeda, evaluasi untuk hasil yang sama.
Ryan C. Thompson
21
@RyanThompson Trivial. s /
2/1
4
@Mehrdad Apakah saya salah atau komentar terkait dengan preprosesor? Dengan demikian mereka harus dikecualikan sebagai jawaban yang mungkin dari pertanyaan Anda! ;-)
Ale
179

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

#include <stdio.h>

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

Dalam C autoberarti variabel lokal. Di C90 tidak masalah untuk menghilangkan variabel atau tipe fungsi. Defaultnya adalah int. Dalam C ++ 11 autoberarti sesuatu yang sama sekali berbeda, ia memberitahu kompiler untuk menyimpulkan jenis variabel dari nilai yang digunakan untuk menginisialisasi itu.

diasingkan
sumber
10
C90 punya auto?
Seth Carnegie
22
@SethCarnegie: Ya, ini kelas penyimpanan; itu yang terjadi secara default ketika Anda menghilangkannya, jadi tidak ada yang menggunakannya, dan mereka mengubah artinya. Saya pikir ini intsecara default. Ini pintar! +1
user541686
5
C11 tidak memiliki implisit- int.
R .. GitHub BERHENTI MEMBANTU ICE
23
@KeithThompson Ah, saya kira maksud Anda yang disimpulkan int. Namun, di dunia nyata, di mana ada banyak kode warisan dan pemimpin pasar masih belum menerapkan C99 dan tidak memiliki niat untuk melakukannya, pembicaraan tentang "versi C yang usang" adalah tidak masuk akal.
Jim Balter
11
"Setiap variabel HARUS memiliki kelas penyimpanan eksplisit. Hormat kami, manajemen atas."
btown
120

Contoh lain yang belum saya lihat disebutkan, yang satu ini menyoroti perbedaan preprosesor:

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

Ini mencetak "false" dalam C dan "true" di C ++ - Di C, setiap makro tak terdefinisi mengevaluasi ke 0. Dalam C ++, ada 1 pengecualian: "true" mengevaluasi ke 1.

godlygeek
sumber
2
Menarik. Adakah yang tahu alasan di balik perubahan ini?
antred
3
karena "true" adalah kata kunci / nilai yang valid, jadi ia dievaluasi menjadi true seperti "true value" apa pun (jadi seperti bilangan bulat positif). Anda masih dapat melakukan #define true false untuk mencetak "false" di C ++ juga;)
CoffeDeveloper
22
#define true false ಠ_ಠ
Bryan Boettcher
2
@DarioOO tidak akan hasil redefinisi seperti itu di UB?
Ruslan
3
@DarioOO: Ya, Anda salah. Definisi ulang kata kunci tidak diperbolehkan, hukuman dibiarkan nasib (UB). Preprosesor menjadi fase kompilasi terpisah yang tidak tahan.
Deduplicator
108

Per standar C ++ 11:

Sebuah. Operator koma melakukan konversi nilai-ke-nilai dalam C tetapi tidak pada C ++:

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

Di C ++ nilai ekspresi ini akan menjadi 100 dan di C ini akan menjadi sizeof(char*).

b. Dalam C ++ jenis enumerator adalah enumnya. Dalam C tipe enumerator adalah int.

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

Ini berarti bahwa sizeof(int)mungkin tidak sama dengan sizeof(E).

c. Dalam C ++ fungsi yang dideklarasikan dengan daftar params kosong tidak membutuhkan argumen. Dalam daftar params C kosong berarti bahwa jumlah dan jenis params fungsi tidak diketahui.

   int f();           // int f(void) in C++
                      // int f(*unknown*) in C
Kirill Kobelev
sumber
Yang pertama juga implementasi-didefinisikan seperti Alexey. Tapi +1.
Seth Carnegie
1
@Seth, Semua materi di atas diambil langsung dari Lampiran C.1 dari standar C ++ 11.
Kirill Kobelev
Ya tapi itu masih implementasi-didefinisikan. sizeof(char*)bisa 100 dalam hal contoh pertama akan menghasilkan perilaku yang dapat diamati yang sama dalam C dan C ++ (yaitu meskipun metode memperoleh sakan berbeda, sakhirnya akan menjadi 100). OP menyebutkan bahwa jenis perilaku yang ditentukan implementasi ini baik-baik saja karena ia hanya ingin menghindari jawaban pengacara bahasa, jadi yang pertama baik-baik saja dengan pengecualiannya. Tapi yang kedua bagus dalam hal apa pun.
Seth Carnegie
5
Ada perbaikan yang mudah - cukup ubah contohnya menjadi:char arr[sizeof(char*)+1]; int s = sizeof(0, arr);
Mankarse
5
Untuk menghindari perbedaan yang ditentukan implementasi, Anda juga bisa menggunakan void *arr[100]. Dalam hal ini elemen berukuran sama dengan pointer ke elemen yang sama, jadi selama ada 2 elemen atau lebih, array harus lebih besar dari alamat elemen pertamanya.
finnw
53

Program ini mencetak 1dalam C ++ dan 0dalam C:

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

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

Ini terjadi karena ada double abs(double)kelebihan dalam C ++, jadi abs(0.6)kembali 0.6sementara di C itu kembali 0karena konversi double-to-int implisit sebelum memohon int abs(int). Di C, Anda harus menggunakannya fabsuntuk bekerja dengannya double.

Pavel Chikulaev
sumber
5
harus men-debug kode orang lain dengan masalah itu. Oh Betapa aku menyukainya. Bagaimanapun program Anda mencetak 0 dalam C ++ juga. C ++ harus menggunakan header "cmath" melihat perbandingan pertama returnin 0 ideone.com/0tQB2G 2 satu kembali 1 ideone.com/SLeANo
CoffeDeveloper
Senang / menyesal mendengar bahwa saya bukan satu-satunya yang menemukan perbedaan ini melalui debugging. Baru saja diuji di VS2013, sebuah file kosong dengan hanya dengan konten ini akan menampilkan 1 jika ekstensi .cpp, dan 0 jika ekstensi .c. Sepertinya <math.h> dimasukkan secara tidak langsung dalam VS.
Pavel Chikulaev
Dan sepertinya di VS C ++, <math.h> menyertakan barang-barang C ++ ke dalam namespace global, sedangkan untuk GCC tidak. Tidak yakin mana yang merupakan perilaku standar.
Pavel Chikulaev
2
Contoh kode khusus ini tergantung pada implementasi: stdlib.hhanya mendefinisikan abs(int)dan abs(long); versi abs(double)ini dinyatakan oleh math.h. Jadi program ini masih dapat memanggil abs(int)versi. Ini adalah detail implementasi apakah stdlib.hjuga menyebabkan math.huntuk dimasukkan. (Saya pikir itu akan menjadi bug jika abs(double)dipanggil, tetapi aspek lain dari math.htidak termasuk).
MM
1
Masalah kedua adalah bahwa meskipun standar C ++ tampaknya mengatakan bahwa memasukkan <math.h>juga termasuk kelebihan beban tambahan; dalam praktek ternyata semua kompiler utama tidak termasuk kelebihan itu kecuali formulir <cmath>digunakan.
MM
38
#include <stdio.h>

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

Dalam C, ini mencetak berapa pun nilainya sizeof(int)pada sistem saat ini, yang biasanya 4di sebagian besar sistem yang umum digunakan saat ini.

Di C ++, ini harus dicetak 1.

Adam Rosenfield
sumber
3
Ya, saya sebenarnya akrab dengan trik ini, karena 'c' adalah int di C, dan char di C ++, tapi masih bagus untuk terdaftar di sini.
Sean
9
Itu akan membuat pertanyaan wawancara yang menarik - terutama untuk orang-orang yang menempatkan c / c ++ ahli di CV mereka
Martin Beckett
2
Agak licik. Seluruh tujuan sizeof adalah agar Anda tidak perlu tahu persis seberapa besar jenisnya.
Dana the Sane
13
Dalam C nilai implementasi didefinisikan dan 1 adalah kemungkinan. (Dalam C ++ itu harus mencetak 1 sebagaimana dinyatakan.)
Pemrogram Windows
3
Sebenarnya itu memiliki perilaku yang tidak terdefinisi dalam kedua kasus. %dbukan specifier format yang tepat untuk size_t.
R .. GitHub BERHENTI MEMBANTU ICE
37

sizeofPerangkap lain : ekspresi boolean.

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

Itu sama dengan sizeof(int)di C, karena ekspresi adalah tipe int, tetapi biasanya 1 di C ++ (meskipun tidak harus). Dalam praktiknya mereka hampir selalu berbeda.

Alex B
sumber
6
Seseorang !harus cukup untuk a bool.
Alexey Frunze
4
!! adalah operator konversi int ke boolean :)
EvilTeach
1
sizeof(0)ada 4di C dan C ++ karena 0merupakan nilai integer. sizeof(!0)ada 4di C dan 1di C ++. Logical NOT beroperasi pada operan tipe bool. Jika nilai int 0secara implisit dikonversi ke false(nilai bool), maka dibalik, menghasilkan true. Keduanya truedan falsemerupakan nilai-nilai bool di C ++ dan sizeof(bool)itu 1. Namun dalam C !0mengevaluasi 1, yang merupakan nilai dari tipe int. Bahasa pemrograman C tidak memiliki tipe data bool secara default.
Galaxy
26

Bahasa Pemrograman C ++ (Edisi ke-3) memberikan tiga contoh:

  1. sizeof ('a'), seperti yang disebutkan @Adam Rosenfield;

  2. // komentar yang digunakan untuk membuat kode tersembunyi:

    int f(int a, int b)
    {
        return a //* blah */ b
            ;
    }
  3. Struktur, dll. Menyembunyikan barang di luar lingkup, seperti pada contoh Anda.

derobert
sumber
25

Berangan tua yang tergantung pada kompiler C, tidak mengenali komentar akhir C ++ ...

...
int a = 4 //* */ 2
        +2;
printf("%i\n",a);
...
dmckee --- mantan kucing moderator
sumber
21

Satu lagi terdaftar oleh Standar 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
sumber
sehingga Anda mendapatkan perbedaan padding?
v.oddou
ah maaf saya mengerti, ada satu lagi xdi atas. Saya pikir Anda mengatakan "array a".
v.oddou
20

Fungsi sebaris di C default ke lingkup eksternal sedangkan yang di C ++ tidak.

Mengkompilasi dua file berikut bersama-sama akan mencetak "I am inline" untuk GNU C tetapi tidak untuk 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");
} 

Juga, C ++ secara implisit memperlakukan constglobal apa pun statickecuali jika dinyatakan secara eksplisit extern, tidak seperti C yang externmerupakan default.

fkl
sumber
Saya benar-benar tidak berpikir begitu. Mungkin Anda telah melewatkan intinya. Ini bukan tentang definisi struct st yang hanya digunakan untuk membuat kode valid c ++. Intinya adalah bahwa ini menyoroti perilaku fungsi inline yang berbeda di c vs c ++. Hal yang sama berlaku untuk extern. Tak satu pun dari ini dibahas dalam salah satu solusi.
fkl
2
Apa perbedaan perilaku fungsi inline dan externyang ditunjukkan di sini?
Seth Carnegie
Itu ditulis dengan cukup jelas. "Fungsi inline dalam c default ke lingkup eksternal di mana seperti yang ada di c ++ tidak (kode menunjukkan bahwa). Juga C ++ secara implisit memperlakukan sembarang global sebagai ruang lingkup file kecuali dinyatakan secara eksplisit sebagai eksternal, tidak seperti C di mana extern adalah default. contoh dapat dibuat untuk itu ". Saya bingung - Apakah tidak bisa dimengerti?
fkl
12
@fayyazkl Perilaku yang ditampilkan hanya karena perbedaan pencarian ( struct funvs fn) dan tidak ada hubungannya apakah fungsi tersebut sebaris. Hasilnya identik jika Anda menghapus inlinekualifikasi.
Alex B
3
Dalam ISO C program ini tidak terbentuk: inlinetidak ditambahkan hingga C99, tetapi dalam C99 fun()tidak dapat dipanggil tanpa prototipe dalam cakupan. Jadi saya menganggap jawaban ini hanya berlaku untuk GNU C.
MM
16
struct abort
{
    int x;
};

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

Kembali dengan kode keluar 0 di C ++, atau 3 di C.

Trik ini mungkin bisa digunakan untuk melakukan sesuatu yang lebih menarik, tetapi saya tidak bisa memikirkan cara yang baik untuk membuat konstruktor yang cocok untuk C. Saya mencoba membuat contoh yang sama membosankannya dengan copy constructor, yang akan membuat argumen dilewati, meskipun dengan cara yang agak tidak portabel:

struct exit
{
    int x;
};

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

    exit(code);

    return 0;
}

VC ++ 2005 menolak untuk mengkompilasi bahwa dalam mode C ++, mengeluh tentang bagaimana "kode keluar" didefinisikan ulang. (Saya pikir ini adalah kompiler bug, kecuali jika saya tiba-tiba lupa bagaimana memprogramnya.) Ia keluar dengan kode keluar proses 1 saat dikompilasi sebagai C sekalipun.


sumber
Contoh kedua Anda menggunakan exit, sayangnya tidak dikompilasi pada gcc atau g ++. Tapi itu ide yang bagus.
Sean
1
exit(code)adalah deklarasi yang valid dari variabel codejenis exit, rupanya. (Lihat "parsing yang paling menjengkelkan", yang merupakan masalah yang berbeda namun serupa).
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;
}

Program ini mencetak 128( 32 * sizeof(double)) ketika dikompilasi menggunakan kompiler C ++ dan 4ketika dikompilasi menggunakan kompiler C.

Ini karena C tidak memiliki gagasan tentang resolusi ruang lingkup. Dalam struktur C yang terkandung dalam struktur lain bisa dimasukkan ke dalam ruang lingkup struktur luar.

wefwefa3
sumber
Yang ini menarik! (Saya pikir maksud Anda 32*sizeof(double)alih - alih 32) :)
user1354557
3
Perhatikan bahwa Anda mendapatkan UB dengan mencetak size_tdengan%d
phuclv
7

Jangan lupa perbedaan antara ruang nama global C dan C ++. Misalkan Anda memiliki foo.cpp

#include <cstdio>

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

dan foo2.c

#include <stdio.h>

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

Sekarang anggaplah Anda memiliki main.c dan main.cpp yang keduanya terlihat seperti ini:

extern void foo(int);

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

Ketika dikompilasi sebagai C ++, ia akan menggunakan simbol dalam namespace global C ++; di C akan menggunakan C satu:

$ 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
pengguna23614
sumber
Maksud Anda spesifikasi tautan?
user541686
nama mangling. Nama C ++ memiliki awalan dan sufiks sedangkan C tidak
CoffeDeveloper
Name mangling bukan bagian dari spesifikasi C ++. Apakah itu dilarang di C?
skyking
5
Ini adalah perilaku yang tidak terdefinisi (definisi ganda foo). Tidak ada "ruang nama global" yang terpisah.
MM
4
int main(void) {
    const int dim = 5; 
    int array[dim];
}

Ini agak aneh karena valid dalam C ++ dan C99, C11, dan C17 (meskipun opsional dalam C11, C17); tapi tidak berlaku di C89.

Dalam C99 + ia menciptakan array panjang variabel, yang memiliki kekhasan tersendiri terhadap array normal, karena memiliki tipe runtime, bukan tipe waktu kompilasi, dan sizeof arraybukan ekspresi konstanta bilangan bulat dalam C. Pada C ++ jenisnya sepenuhnya statis.


Jika Anda mencoba menambahkan inisialisasi di sini:

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

valid C ++ tetapi bukan C, karena array panjang variabel tidak dapat memiliki initializer.

Antti Haapala
sumber
0

Ini menyangkut nilai dan nilai dalam C dan C ++.

Dalam bahasa pemrograman C, operator pre-increment dan post-increment mengembalikan nilai, bukan nilai. Ini berarti bahwa mereka tidak dapat berada di sisi kiri =operator penugasan. Kedua pernyataan ini akan memberikan kesalahan kompilator di C:

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

Namun dalam C ++, operator pra-kenaikan mengembalikan nilai , sedangkan operator pasca kenaikan mengembalikan nilai. Ini berarti bahwa ekspresi dengan operator pra-kenaikan dapat ditempatkan di sisi kiri =operator penugasan!

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

Sekarang mengapa demikian? Post-increment menambah variabel, dan mengembalikan variabel seperti sebelum kenaikan terjadi. Ini sebenarnya hanya nilai. Nilai sebelumnya dari variabel a disalin ke dalam register sebagai sementara, dan kemudian a bertambah. Tetapi nilai sebelumnya dari a dikembalikan oleh ekspresi, itu adalah nilai. Itu tidak lagi mewakili konten variabel saat ini.

Pre-increment pertama-tama akan menambah variabel, dan kemudian mengembalikan variabel sesuai dengan yang terjadi setelah kenaikan terjadi. Dalam hal ini, kita tidak perlu menyimpan nilai lama dari variabel ke register sementara. Kami hanya mengambil nilai baru dari variabel setelah ditambahkan. Jadi pre-increment mengembalikan nilai, ia mengembalikan variabel itu sendiri. Kita dapat menggunakan nilai ini untuk sesuatu yang lain, seperti pernyataan berikut. Ini adalah konversi implisit nilai menjadi nilai.

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

Karena pra-kenaikan mengembalikan nilai, kami juga dapat menetapkan sesuatu untuknya. Dua pernyataan berikut ini identik. Dalam penugasan kedua, pertama a bertambah, kemudian nilai baru ditimpa dengan 2.

int a;
a = 2;
++a = 2;  // Valid in C++.
Galaksi
sumber
3
Tidak ada "valid dalam C" di sini.
o11c
0

Struktur kosong memiliki ukuran 0 dalam C dan 1 dalam C ++:

#include <stdio.h>

typedef struct {} Foo;

int main()
{
    printf("%zd\n", sizeof(Foo));
    return 0;
}
Daniel Frużyński
sumber
1
Tidak, perbedaannya adalah bahwa C tidak memiliki struktur kosong, kecuali sebagai ekstensi kompiler, yaitu kode ini tidak cocok "valid di C dan C ++"
Antti Haapala