E 'una buona idea per qualificare i campi della struttura in C?

5

Considera il seguente programma:

#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);
}

Non sono a conoscenza di qualcosa di particolarmente brutto in questo tipo di progettazione, ma potrebbe esserci un impatto quando il compilatore sta ottimizzando strongmente il codice e alcune considerazioni mi mancano.

È una buona idea usare const in C come meccanismo di controllo degli accessi in scrittura in questo modo?

    
posta Michael Pankov 27.12.2013 - 15:45
fonte

2 risposte

9

No, l'utilizzo di const in questo modo è non una buona idea.

Dichiarando i campi della struttura come const , stai dichiarando l'intenzione che quei campi non cambieranno mai il loro valore. Se poi modifichi il valore, stai fuorviando entrambi i lettori umani del tuo codice e del compilatore. Il primo rende il codice più difficile da capire e il secondo può essere la causa di bug sottili nel tuo programma.

Se vuoi evitare l'accesso diretto ai membri della tua struttura, puoi semplicemente usarlo come un tipo opaco:

//in s.h:
typedef struct S_s S_t;

S_t *create_S(void);
void destroy_S(const S_t *s);
int get_S_a(const S_t *s);
void set_S_a(S_t *s, const int a);

//in s.c
#include "s.h"
struct S_s {
    const int _a;
};

S_t *
create_S(void) {
    return calloc(sizeof(S_t), 1);
}

void
destroy_S(const S_t *s) {
    free((S_t *)s);
}

int
get_S_a(const S_t *s) {
    return s->_a;
}

void
set_S_a(S_t *s, const int a) {
    s->_a = a;
}

// In main.c
#include "s.h"
int
main(void) {
    // const S_t s1; // Error: size of S_t unknown here
    S_t *s2 = create_S();
    // s2->_a = 8; // Error: members of S_t unknown here
    set_S_a(s2, 8); // OK

    printf("s2->a == %d\n", get_S_a(s2));

    destroy_S(s2);
}
    
risposta data 27.12.2013 - 16:40
fonte
7

bozza C 2011

6.7.3 Type qualifiers
...
6 If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined. If an attempt is made to refer to an object defined with a volatile-qualified type through use of an lvalue with non-volatile-qualified type, the behavior is undefined.133)

133) This applies to those objects that behave as if they were defined with qualified types, even if they are never actually defined as objects in the program (such as an object at a memory-mapped input/output address).

Enfasi mia.

Quindi no, questa non è una buona idea. Se non vuoi che qualcuno metta direttamente sul contenuto del tuo tipo di struct, rendilo opaco e fornisci un'API per manipolarlo.

    
risposta data 27.12.2013 - 23:59
fonte

Leggi altre domande sui tag