Standar C99 mengatakan dalam 6.5.16: 2:
Operator penugasan harus memiliki nilai yang dapat dimodifikasi sebagai operan kirinya.
dan di 6.3.2.1:1:
Lvalue yang dapat dimodifikasi adalah lvalue yang tidak memiliki tipe array, tidak memiliki tipe tidak lengkap, tidak memiliki tipe const-kualifikasi, dan jika itu adalah struktur atau gabungan, tidak memiliki anggota (termasuk, secara rekursif, setiap anggota atau elemen dari semua agregat atau serikat yang terkandung) dengan tipe const-kualifikasi.
Sekarang, mari kita pertimbangkan non- const
struct
dengan const
bidang.
typedef struct S_s {
const int _a;
} S_t;
Secara standar, kode berikut adalah perilaku tidak terdefinisi (UB):
S_t s1;
S_t s2 = { ._a = 2 };
s1 = s2;
Masalah semantik dengan hal ini adalah bahwa entitas terlampir ( struct
) harus dianggap dapat ditulis (non-read-only), dilihat dari tipe entitas yang dinyatakan ( S_t s1
), tetapi tidak boleh dianggap dapat ditulis oleh kata-kata standar (2 klausa di atas) karena const
bidang _a
. Standar membuatnya tidak jelas bagi seorang programmer yang membaca kode bahwa tugas itu sebenarnya adalah UB, karena tidak mungkin untuk mengatakan bahwa tanpa definisi struct S_s ... S_t
tipe.
Selain itu, akses baca-saja ke bidang ini hanya ditegakkan secara sintaksis pula. Tidak mungkin beberapa const
bidang non const
struct
-benar-benar ditempatkan untuk penyimpanan read-only. Tetapi kata-kata standar seperti itu melarang kode yang dengan sengaja membuang const
kualifikasi bidang dalam prosedur aksesor bidang ini, seperti itu ( Apakah itu ide yang baik untuk menyamakan kualifikasi bidang struktur di C? ):
(*)
#include <stdlib.h>
#include <stdio.h>
typedef struct S_s {
const int _a;
} S_t;
S_t *
create_S(void) {
return calloc(sizeof(S_t), 1);
}
void
destroy_S(S_t *s) {
free(s);
}
const int
get_S_a(const S_t *s) {
return s->_a;
}
void
set_S_a(S_t *s, const int a) {
int *a_p = (int *)&s->_a;
*a_p = a;
}
int
main(void) {
S_t s1;
// s1._a = 5; // Error
set_S_a(&s1, 5); // OK
S_t *s2 = create_S();
// s2->_a = 8; // Error
set_S_a(s2, 8); // OK
printf("s1.a == %d\n", get_S_a(&s1));
printf("s2->a == %d\n", get_S_a(s2));
destroy_S(s2);
}
Jadi, untuk beberapa alasan, agar keseluruhan struct
dapat dibaca - hanya cukup untuk menyatakannyaconst
const S_t s3;
Tetapi untuk keseluruhan struct
menjadi non-read-only saja tidak cukup untuk menyatakannya tanpa const
.
Apa yang saya pikir akan lebih baik, adalah:
- Untuk membatasi penciptaan non-
const
struktur denganconst
bidang, dan mengeluarkan diagnostik dalam kasus seperti itu. Itu akan memperjelas bahwastruct
bidang yang hanya baca hanya baca itu sendiri. - Untuk mendefinisikan perilaku dalam kasus menulis ke
const
bidang milik non-const
struct untuk membuat kode di atas (*) sesuai dengan Standar.
Kalau tidak, tingkah lakunya tidak konsisten dan sulit dipahami.
Jadi, apa alasan C Standard mempertimbangkan const
-ness secara rekursif, seperti yang dikatakannya?
Jawaban:
Dari perspektif tipe saja, tidak melakukan hal itu akan tidak sehat (dengan kata lain: sangat rusak dan sengaja tidak dapat diandalkan).
Dan itu karena apa yang berarti "=" pada struct: itu adalah tugas rekursif. Oleh karena itu, pada akhirnya Anda mengalami
s1._a = <value>
"di dalam aturan mengetik". Jika standar memungkinkan ini untukconst
bidang "bersarang" , itu menambah inkonsistensi serius dalam definisi sistem tipenya sebagai kontradiksi eksplisit (mungkin juga membuangconst
fitur, karena hanya menjadi tidak berguna dan tidak dapat diandalkan dengan definisi yang sangat).Solusi Anda (1), sejauh yang saya mengerti, tidak perlu memaksa seluruh struktur untuk menjadi
const
setiap kali salah satu bidangnyaconst
. Dengan cara ini,s1._b = b
akan ilegal untuk bidang non-const._b
pada non-const yangs1
mengandung aconst a
.sumber
C
nyaris tidak memiliki sistem jenis suara (lebih seperti sekelompok kasus sudut diikat satu sama lain selama bertahun-tahun). Selain itu, cara lain untuk menempatkan tugas kestruct
adalahmemcpy(s_dest, s_src, sizeof(S_t))
. Dan saya cukup yakin itulah cara sebenarnya penerapannya. Dan dalam kasus seperti itu bahkan "sistem tipe" yang ada tidak melarang Anda melakukan itu.Alasannya adalah bahwa bidang hanya baca adalah hanya baca. Tidak ada kejutan besar di sana.
Anda keliru dengan asumsi bahwa satu-satunya efek adalah pada penempatan di ROM, yang memang tidak mungkin ketika ada bidang non-const yang berdekatan. Pada kenyataannya, pengoptimal mungkin menganggap
const
ekspresi tidak ditulis untuk, dan mengoptimalkan berdasarkan itu. Tentu saja asumsi itu tidak berlaku ketika alias non-const ada.Solusi Anda (1) melanggar kode hukum dan akal yang ada. Itu tidak akan terjadi. Solusi Anda (2) cukup banyak menghilangkan makna
const
pada anggota. Meskipun ini tidak akan merusak kode yang ada, tampaknya tidak memiliki alasan.sumber
const
bidang tidak ditulis untuk, karena Anda selalu dapat menggunakanmemset
ataumemcpy
, dan itu bahkan akan sesuai dengan Standar. (1) dapat diimplementasikan sebagai, setidaknya, peringatan tambahan, diaktifkan oleh sebuah bendera. (2) 's alasan adalah bahwa, baik, persis - tidak ada cara komponenstruct
dapat dianggap non-ditulis ketika seluruh struktur adalah ditulis.operator=
dalam hal anggota, dan karena itu tidak menentukanoperator=
kapan satu anggotaconst
. C dan C ++ masih kompatibel di sini.memcpy
? Adapun alasan lain - ok, itu warisan, tetapi mengapa itu dilakukan sedemikian rupa di tempat pertama?memcpy
itu benar. AFACIT Kutipan John Bode dalam pertanyaan Anda yang lain benar: kode Anda menulis ke objek yang memenuhi syarat dan karenanya BUKAN keluhan standar, akhir diskusi.