Inisialisasi / reset struct ke nol / null

92
struct x {
    char a[10];
    char b[20];
    int i;
    char *c;
    char *d[10];
};

Saya mengisi struct ini dan kemudian menggunakan nilainya. Pada iterasi berikutnya, saya ingin mengatur ulang semua bidang ke 0atau nullsebelum saya mulai menggunakannya kembali.

Bagaimana saya bisa melakukan itu? Dapatkah saya menggunakan memsetatau saya harus melalui semua anggota dan kemudian melakukannya secara individu?

hari
sumber

Jawaban:

109

Tentukan instance statis const dari struct dengan nilai awal dan kemudian cukup tetapkan nilai ini ke variabel Anda kapan pun Anda ingin menyetel ulang.

Sebagai contoh:

static const struct x EmptyStruct;

Di sini saya mengandalkan inisialisasi statis untuk menetapkan nilai awal saya, tetapi Anda dapat menggunakan penginisialisasi struct jika Anda menginginkan nilai awal yang berbeda.

Kemudian, setiap kali putaran Anda dapat menulis:

myStructVariable = EmptyStruct;
David Heffernan
sumber
1
@David Heffernan: apakah ini lebih baik daripada menggunakan memsetjika saya hanya ingin mengatur ulang semuanya ke 0??
hari
9
@ari Saya lebih suka persetujuan ini sendiri. Menggunakan memsetmembuat saya merasa kotor. Saya lebih suka membiarkan kompiler khawatir tentang tata letak memori jika memungkinkan. Sebenarnya penggunaan semacam memsetitu tidak portabel tetapi dalam praktiknya saya akan terkejut jika Anda pernah menyusun kode Anda di mana saja yang penting. Jadi, Anda mungkin dapat menggunakan memset dengan aman jika Anda menginginkannya.
David Heffernan
2
@hari, secara konseptual lebih baik, karena Anda memberikan nilai inisialisasi default (sesuatu seperti pola pabrik objek.)
Diego Sevilla
1
@cnicutar Saya tahu ini. Perhatikan bahwa jawaban saya merekomendasikan untuk tidak menggunakan memset. Perhatikan juga komentar tentang di mana saya menunjukkan non-portabilitas menggunakan memset sebagai sarana untuk menetapkan nilai null. Komentar saya sebelumnya hanya menunjukkan kenyataan bahwa 0 bit selalu sesuai dengan angka nol floating point.
David Heffernan
1
@ kp11 kutipan please
David Heffernan
85

Cara untuk melakukan hal seperti itu bila Anda memiliki C modern (C99) adalah dengan menggunakan literal majemuk .

a = (const struct x){ 0 };

Ini agak mirip dengan solusi David, hanya saja Anda tidak perlu khawatir untuk mendeklarasikan struktur kosong atau apakah akan mendeklarasikannya static. Jika Anda menggunakan constseperti yang saya lakukan, kompilator bebas mengalokasikan literal gabungan secara statis dalam penyimpanan hanya-baca jika sesuai.

Jens Gustedt
sumber
Apakah itu membuat instance x pada tumpukan untuk kemudian menyalinnya ke a? Untuk struktur besar / tumpukan kecil itu bisa jadi masalah.
Étienne
1
Seperti semua pengoptimalan, ini sepenuhnya bergantung pada compiler, jadi Anda harus memeriksa apa yang dihasilkan oleh compiler Anda. "Biasanya" pada kompiler modern tidak, ini dapat melacak inisialisasi dengan sangat baik dan hanya melakukan apa yang diperlukan, tidak lebih. (Dan jangan berpikir bahwa hal-hal seperti itu adalah masalah sebelum Anda mengukur perlambatan yang sebenarnya. Biasanya tidak.)
Jens Gustedt
3
Peringatan "penginisialisasi hilang" benar-benar palsu. Standar C mengatur dengan tepat apa yang harus terjadi daripada, dan menganggap { 0 }sebagai penginisialisasi default. Matikan peringatan itu, itu adalah alarm palsu.
Jens Gustedt
1
@JensGustedt Apakah typecasting ini benar-benar diperlukan? Tidak bisakah saya menulisnya seperti ini? struct xa = (const) {0};
Patrick
1
@Patrick, meskipun sintaksnya serupa, ini bukan pemeran tetapi "literal gabungan". Dan Anda mencampur inisialisasi dan tugas.
J Gustedt
58

Lebih baik dari semua di atas adalah menggunakan spesifikasi Standar C untuk inisialisasi struct:

struct StructType structVar = {0};

Ini semua bit nol (pernah).

pengguna411313
sumber
13
Saya tidak berpikir Anda dapat melakukannya setiap kali dalam satu lingkaran
David Heffernan
2
Ini memang seharusnya berhasil. Namun sayangnya, gcc & g ++ mengeluhkannya. gcc menghasilkan peringatan, sedangkan g ++ menghasilkan kesalahan. Saya tahu bahwa gcc & g ++ salah dalam hal ini (mereka seharusnya mengikuti spesifikasi Standar C), tetapi meskipun demikian, untuk portabilitas yang baik, batasan tersebut wajib dipertimbangkan.
Cyan
3
@Cyan Anda dapat menggunakan {}C ++. Gcc devs tampaknya tidak yakin apakah C ++ seharusnya mendukung{0} dan saya sendiri tidak terbiasa dengan bagian standar itu.
Matius Baca
@Matthew: Ya, sebenarnya, saya akhirnya menggunakan memset (), karena ada terlalu banyak masalah portabilitas dengan {0}atau {}. Tidak yakin apakah standar C & C ++ jelas dan sinkron tentang masalah ini, tetapi tampaknya, kompiler tidak.
Cyan
apakah ini akan berhasil dalam kasus seperti itu? struct StructType structVar = malloc (sizeof(StructType)); structVar ={0}
Sam Thomas
35

Di C, itu adalah idiom umum untuk menghilangkan memori untuk structpenggunaan memset:

struct x myStruct;
memset(&myStruct, 0, sizeof(myStruct));

Secara teknis, saya tidak percaya bahwa ini portabel karena mengasumsikan bahwa NULLpenunjuk pada mesin diwakili oleh nilai bilangan bulat 0, tetapi ini digunakan secara luas karena pada sebagian besar mesin demikian.

Jika Anda berpindah dari C ke C ++, berhati-hatilah untuk tidak menggunakan teknik ini pada setiap objek. C ++ hanya membuat ini legal pada objek tanpa fungsi anggota dan tidak ada warisan.

templatetypedef
sumber
2
Standar C menyatakan bahwa NULL selalu 0. Jika mesin dirancang sedemikian rupa sehingga alamat tidak valid yang telah ditentukan sebelumnya tidak secara harfiah 0, kompilator untuk arsitektur itu harus menyesuaikan selama kompilasi.
Kevin M
9
@KevinM Ya, simbol "0" selalu sesuai dengan penunjuk NULL meskipun semuanya nol; tetapi tidak ada yang dapat dilakukan kompilator jika Anda menyetel bit ke nol menggunakan memset.
Adrian Ratnapala
"C ++ hanya membuat ini legal pada objek tanpa fungsi anggota dan tidak ada warisan." Ini tentang apakah jenisnya dianggap 'data lama biasa'. Kriteria bergantung pada versi bahasa C ++.
Max Barraclough
19

Jika Anda memiliki kompilator yang mendukung C99, Anda dapat menggunakan

mystruct = (struct x){0};

jika tidak, Anda harus melakukan apa yang ditulis David Heffernan, yaitu menyatakan:

struct x empty = {0};

Dan di loop:

mystruct = empty;
Rudy Velthuis
sumber
6

Anda dapat menggunakan memsetdengan ukuran struct:

struct x x_instance;
memset (&x_instance, 0, sizeof(x_instance));
Diego Sevilla
sumber
1
Saya rasa pemeran tidak diperlukan di sini. Apakah itu?
templatetypedef
Yah, saya sangat terbiasa dengan C ++ sehingga ... yah, ini akan berfungsi juga di C ++, jadi saya tidak melihatnya sebagai beban.
Diego Sevilla
Ya, saya tidak cukup spesifik. Itu semua pointer ke cv berkualifikasi T dapat diubah ke cv kualifikasi void *. Setiap penunjuk data, penunjuk fungsi adalah masalah yang berbeda sama sekali. Kudos
@Kevin
memsetadalah sebuah opsi, tetapi saat menggunakannya, Anda harus memastikan bahwa memori yang ditulis sama ukurannya dengan parameter ketiga, oleh karena itu lebih baik merujuk ke ukuran objek sebenarnya, bukan ukuran jenis yang Anda gunakan. tahu itu saat ini. IOW memset (&x_instance, 0, sizeof(x_instance));adalah pilihan yang jauh lebih baik. BTW: (void*)pemerannya juga berlebihan di C ++.
Serigala
(maaf saya melewatkan untuk mengurus pertanyaan, lebih baik sekarang)
Wolf
4

Saya yakin Anda bisa menetapkan set kosong ( {}) ke variabel Anda.

struct x instance;

for(i = 0; i < n; i++) {
    instance = {};
    /* Do Calculations */
}
Archmede
sumber
Ini bukan C yang valid, bahkan C99 pun tidak. Ini harus berupa literal majemuk seperti dalam jawaban JensGustedt di atas.
Anders
0
 struct x myX;
 ...
 memset(&x, 0, sizeof(myX));
Josh Matthews
sumber
5
Saya pikir OP tahu bagaimana memanggil memset, tetapi masalahnya adalah apakah melakukannya bijaksana atau tidak
David Heffernan
-1

masukkan deskripsi gambar di sini Kejutan dari gnu11!

typedef struct {
    uint8_t messType;
    uint8_t ax;  //axis
    uint32_t position;
    uint32_t velocity;
}TgotoData;

TgotoData tmpData = { 0 };

tidak ada yang nol.

Андрей Тернити
sumber
1
Ini tidak mencoba menjawab pertanyaan "Bagaimana saya dapat mengatur ulang semua bidang ke 0"
MM