it-swarm-id.com

Apa yang dimaksud dengan {0} saat menginisialisasi objek?

Kapan {0} digunakan untuk menginisialisasi objek, apa artinya? Saya tidak dapat menemukan referensi ke {0} di mana saja, dan karena kurung kurawal pencarian Google tidak membantu.

Kode contoh:

SHELLEXECUTEINFO sexi = {0}; // what does this do?
sexi.cbSize = sizeof(SHELLEXECUTEINFO);
sexi.hwnd = NULL;
sexi.fMask = SEE_MASK_NOCLOSEPROCESS;
sexi.lpFile = lpFile.c_str();
sexi.lpParameters = args;
sexi.nShow = nShow;

if(ShellExecuteEx(&sexi))
{
    DWORD wait = WaitForSingleObject(sexi.hProcess, INFINITE);
    if(wait == WAIT_OBJECT_0)
        GetExitCodeProcess(sexi.hProcess, &returnCode);
}

Tanpa itu, kode di atas akan macet saat runtime.

249
Mahmoud Al-Qudsi

Apa yang terjadi di sini disebut inisialisasi agregat . Berikut adalah definisi (disingkat) agregat dari bagian 8.5.1 dari spesifikasi ISO:

Agregat adalah array atau kelas tanpa konstruktor yang dideklarasikan oleh pengguna, tidak ada anggota data non-statis pribadi atau yang dilindungi, tanpa kelas dasar, dan tanpa fungsi virtual.

Sekarang, menggunakan {0} Untuk menginisialisasi agregat seperti ini pada dasarnya adalah trik untuk 0 Semuanya. Ini karena ketika menggunakan inisialisasi agregat Anda tidak harus menentukan semua anggota dan spek mensyaratkan bahwa semua anggota yang tidak ditentukan secara default diinisialisasi, yang berarti menyetel ke 0 untuk tipe sederhana.

Berikut adalah kutipan yang relevan dari spec:

Jika ada lebih sedikit inisialisasi dalam daftar daripada ada anggota dalam agregat, maka setiap anggota yang tidak diinisialisasi secara eksplisit harus diinisialisasi-default. Contoh:

struct S { int a; char* b; int c; };
S ss = { 1, "asdf" };

menginisialisasi ss.a dengan 1, ss.b dengan "asdf", dan ss.c dengan nilai ekspresi dari bentuk int(), yaitu, 0.

Anda dapat menemukan spesifikasi lengkap tentang topik ini di sini

298
Don Neufeld

Satu hal yang perlu diperhatikan adalah bahwa teknik ini tidak akan mengatur padding byte ke nol. Sebagai contoh:

struct foo
{
    char c;
    int  i;
};

foo a = {0};

Tidak sama dengan:

foo a;
memset(&a,0,sizeof(a));

Dalam kasus pertama, pad byte antara c dan i tidak diinisialisasi. Kenapa kamu peduli? Nah, jika Anda menyimpan data ini ke disk atau mengirimnya melalui jaringan atau apa pun, Anda bisa memiliki masalah keamanan.

89
Harold Ekstrom

Perhatikan bahwa penginisialisasi agregat kosong juga berfungsi:

SHELLEXECUTEINFO sexi = {};
char mytext[100] = {};
20
dalle

Sebagai jawaban mengapa ShellExecuteEx() sedang crash: Anda SHELLEXECUTEINFO "sexi" struct memiliki banyak anggota dan Anda hanya menginisialisasi beberapa dari mereka.

Misalnya, anggota sexi.lpDirectory Dapat menunjuk ke mana saja, tetapi ShellExecuteEx() masih akan mencoba menggunakannya, maka Anda akan mendapatkan pelanggaran akses memori.

Ketika Anda memasukkan baris:

SHELLEXECUTEINFO sexi = {0};

sebelum sisa pengaturan struktur Anda, Anda memberi tahu kompiler untuk menghapus --- semua anggota struktur sebelum Anda menginisialisasi yang spesifik yang Anda minati. ShellExecuteEx() tahu bahwa jika sexi.lpDirectory Adalah nol, harus diabaikan.

11
snowcrash09

Saya juga menggunakannya untuk menginisialisasi string misalnya.

char mytext[100] = {0};
7
Adam Pierce

{0} adalah penginisialisasi yang valid untuk semua jenis (objek lengkap), dalam C dan C++. Ini adalah idiom umum yang digunakan untuk menginisialisasi objek ke nol (baca terus untuk melihat apa artinya).

Untuk tipe skalar (tipe aritmatika dan pointer), kurung tidak diperlukan, tetapi mereka diizinkan secara eksplisit. Mengutip draft N157 dari standar ISO C, bagian 6.7.9:

Inisialisasi untuk skalar harus berupa ekspresi tunggal, secara opsional tertutup dalam kurung kurawal.

Ini menginisialisasi objek ke nol (0 untuk bilangan bulat, 0.0 untuk floating-point, pointer nol untuk pointer).

Untuk jenis non-skalar (struktur, array, serikat pekerja), {0} menetapkan bahwa elemen pertama dari objek diinisialisasi ke nol. Untuk struktur yang mengandung struktur, susunan struktur, dan sebagainya, ini diterapkan secara rekursif, sehingga elemen skalar pertama diatur ke nol, sesuai jenisnya. Seperti pada penginisialisasi apa pun, elemen apa pun yang tidak ditentukan ditetapkan ke nol.

Kawat gigi menengah ({, }) dapat dihilangkan; misalnya keduanya valid dan setara:

int arr[2][2] = { { 1, 2 }, {3, 4} };

int arr[2][2] = { 1, 2, 3, 4 };

itulah sebabnya Anda tidak perlu menulis, misalnya, { { 0 } } untuk jenis yang elemen pertamanya adalah non-skalar.

Jadi ini:

some_type obj = { 0 };

adalah cara singkat menginisialisasi obj ke nol, yang berarti bahwa setiap sub-objek skalar dari obj diatur ke 0 jika bilangan bulat, 0.0 jika itu floating-point, atau null pointer jika itu pointer.

Aturannya mirip untuk C++.

Dalam kasus khusus Anda, karena Anda memberikan nilai ke sexi.cbSize dan sebagainya, jelas bahwa SHELLEXECUTEINFO adalah tipe struct atau kelas (atau mungkin gabungan, tetapi mungkin tidak), jadi tidak semua ini berlaku, tetapi seperti yang saya katakan { 0 } adalah idiom umum yang dapat digunakan dalam situasi yang lebih umum.

Ini bukan (tentu saja) setara dengan menggunakan memset untuk mengatur representasi objek ke semua-bit-nol. Tidak ada titik apung 0.0 atau sebuah pointer nol harus direpresentasikan sebagai semua-bit-nol, dan { 0 } initializer tidak selalu mengatur byte padding ke nilai tertentu. Pada sebagian besar sistem, kemungkinan besar memiliki efek yang sama.

7
Keith Thompson

Sudah beberapa saat sejak saya bekerja di c/c ++ tetapi IIRC, cara pintas yang sama dapat digunakan untuk array juga.

3
µBio

Saya selalu bertanya-tanya, mengapa Anda harus menggunakan sesuatu seperti

struct foo bar = { 0 };

Berikut ini adalah contoh kasus untuk dijelaskan:

check.c

struct f {
    int x;
    char a;
} my_zero_struct;

int main(void)
{
    return my_zero_struct.x;
}

Saya kompilasi dengan gcc -O2 -o check check.c dan kemudian menampilkan tabel simbol dengan readelf -s check | sort -k 2 (ini dengan gcc 4.6.3 di ubuntu 12.04.2 pada sistem x64). Kutipan:

59: 0000000000601018     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
48: 0000000000601018     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
25: 0000000000601018     0 SECTION LOCAL  DEFAULT   25 
33: 0000000000601018     1 OBJECT  LOCAL  DEFAULT   25 completed.6531
34: 0000000000601020     8 OBJECT  LOCAL  DEFAULT   25 dtor_idx.6533
62: 0000000000601028     8 OBJECT  GLOBAL DEFAULT   25 my_zero_struct
57: 0000000000601030     0 NOTYPE  GLOBAL DEFAULT  ABS _end

Bagian penting di sini adalah, bahwa my_zero_struct setelah __bss_start. Bagian ".bss" dalam program C adalah bagian dari memori yang disetel ke nol sebelum main disebut see - wikipedia pada .bss .

Jika Anda mengubah kode di atas menjadi:

} my_zero_struct = { 0 };

Kemudian "centang" yang dihasilkan terlihat dapat dijalankan persis sama setidaknya dengan kompiler gcc 4.6.3 di ubuntu 12.04.2; my_zero_struct masih dalam .bss bagian dan karenanya akan secara otomatis diinisialisasi ke nol, sebelum main dipanggil.

Petunjuk dalam komentar, bahwa memset mungkin menginisialisasi struktur "penuh" juga bukan perbaikan, karena .bss bagian dihapus sepenuhnya yang juga berarti struktur "penuh" disetel ke nol.

Ini mungkin adalah bahwa standar bahasa C tidak menyebutkan semua ini, tetapi dalam dunia nyata kompiler C saya belum pernah melihat perilaku yang berbeda.

2
Ingo Blackman