Как установить и изменить значение постоянной переменной / структуры / указателя в C? - PullRequest
1 голос
/ 04 апреля 2019

В .h файле

typedef enum
{A1,A2}struct_A;

typedef struct
{const struct_A G;} struct_B;

typedef struct
{const struct_B * F;} struct_C;

typedef struct
{const struct_C *E;} struct_D;

В .c файле

const struct_D temp;

Как установить / изменить значение:

temp->E[i].F[0].G

Ответы [ 2 ]

2 голосов
/ 04 апреля 2019

Единственный способ установить значение в структуру const - это инициализировать его при объявлении. Итак, решение будет:

struct_B B = {A1}; 
struct_C C = {&B};  
struct_D temp = {&C};

Однако я не сталкивался ни с одним сценарием, в котором потребовались бы такие вложенные const структуры.

0 голосов
/ 04 апреля 2019

Сначала: если мы видим что-то, квалифицированное как const, мы должны относиться к этому серьезно и избегать выбрасывать постоянство. Если вы отбрасываете константный квалификатор глобальных или статических данных, то вы получаете неопределенное поведение, и в Linux вы получите ошибку сегментации.

В общем, правильный путь - тот, который указал Сувен Пандей в другом ответе.

Тем не менее, есть действительные случаи, чтобы отбросить const. Ваш случай может квалифицироваться как одно из исключений в https://wiki.sei.cmu.edu/confluence/display/c/EXP05-C.+Do+not+cast+away+a+const+qualification

EXP05-C-EX3: поскольку const означает «только для чтения», а не «константа», иногда полезно объявить членов структуры как (указатель на) объекты const для получения диагностики, когда пользователь пытается изменить их в каким-то иным способом, кроме как через функции, специально разработанные для поддержки этого типа данных. Однако в рамках этих функций может потребоваться снять квалификацию const для обновления этих членов.

Мы можем отказаться от const, когда ваши данные находятся в изменяемой области памяти, такой как стек или куча. В любом случае, мы должны быть осторожны, так как это может привести к непредвиденному поведению, если код использует эти данные как неизменяемые, и мы изменяем их.

Итак, это то, что вы просили:

typedef enum {A1, A2} enum_A;
typedef struct { const enum_A G; } struct_B;
typedef struct { const struct_B * F; } struct_C;
typedef struct { const struct_C *E; } struct_D;

int main() {
   const struct_B b = {A1};
   const struct_C c = {&b}; 
   const struct_D temp = {&c};
   enum_A *pointer_to_non_const_A = &temp.E[0].F[0].G;
   *pointer_to_non_const_A = A2;
}

Но это зависит от того, где temp определен и будет вызывать предупреждение компиляции. Если temp - глобал, который может потерпеть крах. Вот случаи, когда он работает, но не должен использоваться, и когда он падает:

#include <stdlib.h>

const int global_in_data_segment = 0;

int main() {
    const int in_stack = 0;
    static const int static_in_data_segment = 0;
    const int *in_heap = malloc(sizeof(int));

    int *works;
    works = &in_stack; *works = 1;
    works = in_heap; *works = 2;

    int *crashes;
    crashes = &global_in_data_segment; *crashes = 3;
    crashes = &static_in_data_segment; *crashes = 4;
}

Для полноты, c ++ имеет const_cast: https://en.cppreference.com/w/cpp/language/const_cast

...