มาตรฐาน C99 ระบุไว้ใน 6.5.16: 2:
ผู้ประกอบการที่ได้รับมอบหมายจะต้องมีค่า lvalue ที่สามารถแก้ไขได้เป็นตัวถูกดำเนินการด้านซ้าย
และใน 6.3.2.1:1:
lvalue ที่แก้ไขได้คือ lvalue ที่ไม่มีประเภทอาร์เรย์, ไม่มีประเภทที่ไม่สมบูรณ์, ไม่มีประเภทที่ผ่านการรับรองและถ้าเป็นโครงสร้างหรือสหภาพไม่มีสมาชิกใด ๆ (รวมถึงสมาชิกแบบเรียกซ้ำสมาชิกใด ๆ ) หรือองค์ประกอบของมวลรวมหรือสหภาพที่มีอยู่ทั้งหมด) ที่มีประเภทที่ผ่านการรับรอง
ตอนนี้ขอพิจารณาไม่ใช่const
struct
มีconst
ข้อมูล
typedef struct S_s {
const int _a;
} S_t;
ตามมาตรฐานรหัสต่อไปนี้คือพฤติกรรมที่ไม่ได้กำหนด (UB):
S_t s1;
S_t s2 = { ._a = 2 };
s1 = s2;
ปัญหาทางความหมายของเรื่องนี้คือสิ่งที่แนบมาเอนทิตี้ของ ( struct
) ควรพิจารณาเขียนได้ (ไม่ใช่อ่านอย่างเดียว), ตัดสินตามประเภทของกิจการที่ประกาศ ( S_t s1
), แต่ไม่ควรพิจารณาเขียนโดยถ้อยคำของมาตรฐาน (2 ข้อ ด้านบน) เพราะฟิลด์const
_a
มาตรฐานทำให้ไม่ชัดเจนสำหรับโปรแกรมเมอร์ที่อ่านรหัสว่าการมอบหมายนั้นเป็น UB จริง ๆ เพราะมันเป็นไปไม่ได้ที่จะบอกว่าไม่มีนิยามของstruct S_s ... S_t
ประเภท
ยิ่งกว่านั้นการเข้าถึงฟิลด์แบบอ่านอย่างเดียวจะถูกบังคับใช้ทางไวยากรณ์เท่านั้น ไม่มีทางที่บางconst
ฟิลด์ที่ไม่ใช่const
struct
จะถูกนำไปไว้ในที่เก็บข้อมูลแบบอ่านอย่างเดียว แต่การใช้ถ้อยคำมาตรฐานเช่นรหัสที่จงใจโยนconst
คุณสมบัติของเขตข้อมูลในขั้นตอนการเข้าถึงของเขตข้อมูลเหล่านี้เช่น ( มันเป็นความคิดที่ดีที่จะ const - ปรับสาขาของโครงสร้างใน 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);
}
ดังนั้นด้วยเหตุผลบางอย่างการstruct
ที่จะอ่านอย่างเดียวทั้งหมดก็เพียงพอที่จะประกาศได้const
const S_t s3;
แต่สำหรับคนstruct
ที่ไม่ใช่ผู้อ่านอย่างเดียวมันไม่เพียงพอที่จะประกาศว่าconst
ไม่มี
สิ่งที่ฉันคิดว่าน่าจะดีกว่าก็คือ:
- เพื่อ จำกัด การสร้าง
const
โครงสร้างที่ไม่มีconst
ฟิลด์และออกการวินิจฉัยในกรณีเช่นนี้ นั่นจะทำให้ชัดเจนว่าstruct
เขตข้อมูลแบบอ่านอย่างเดียวที่มีนั้นเป็นแบบอ่านอย่างเดียว - เพื่อกำหนดพฤติกรรมในกรณีที่เขียนไปยัง
const
เขตข้อมูลที่เป็นของ non-const
struct ว่าจะทำให้รหัสข้างต้น(*) เป็นไปตามมาตรฐาน
มิฉะนั้นพฤติกรรมจะไม่สอดคล้องและเข้าใจยาก
ดังนั้นอะไรคือเหตุผลที่ C Standard ต้องคำนึงถึงการใช้ความconst
รู้สึกแบบเรียกซ้ำ