Необходимость спецификатора const в приведении - PullRequest
3 голосов
/ 31 мая 2019

Предположим, у меня есть такой код:

void foo (void *ptr) {
    const struct some *azaza = (const struct some *)ptr;
    azaza->some_field = 123; // inadvertently assignment => error
    // ...

Действительно ли спецификатор const нужен для приведения?


EDIT: foo - это функция обратного вызова с конкретным прототипом , который я не могу изменить (это не в моем коде).

Ответы [ 4 ]

6 голосов
/ 31 мая 2019

В вашем конкретном случае вам даже не нужен актерский состав. В случае void * приведение требуется только при разыменовании . Так что достаточно сделать:

const struct some *azaza = ptr;

Но ради интереса,

#gcc test.c:

// 1)
const struct some *azaza = ptr;
azaza->some_field = 123; // error: assignment in read-only object

// 2)
struct some *azaza = (const struct some *)ptr; // (!)warning: initialization discards ‘const’ qualifier

azaza->some_field = 123;

#gcc test.c -pedantic-errors

// 1)
const struct some *azaza = ptr;
azaza->some_field = 123; // error: assignment in read-only object

// 2)
struct some *azaza = (const struct some *)ptr; // error: initialization
                                               // discards ‘const’ qualifier

azaza->some_field = 123;

Подводя итог:

  1. Вам не нужно const в ролях.
  2. Если вы используете const только в приведении (по какой-то нечетной причине ._.) И без -pedantic-errors - случайное назначение не приведет к ошибке, что чревато последствиями.
0 голосов
/ 31 мая 2019

Если я понимаю ваш вопрос, вы хотите, чтобы экземпляр был защищен const, и вы спрашиваете, достаточно ли написать:

  const struct some *azaza = (struct some *)ptr;

Вместо

const struct some *azaza = (const struct some *)ptr;

Я бы сказал, что это так, поскольку атрибут const может автоматически применяться компилятором, но его нельзя убрать. Если бы это был C ++, это был бы минимально достаточный код, но, как уже упоминали другие, в C достаточно написать:

const struct some *azaza = ptr;

Поскольку C позволяет приводить пустой указатель к любому другому типу указателя, то константность может быть выведена. Тем не менее, я думаю, что мандат C ++ делает для более понятного кода.

Обратите внимание, что если у вас уже есть указатель const, вы не можете присвоить его неконстантному указателю без "отбрасывания" const. Чтобы соответствовать спецификации C ++, я бы предпочел поставить 2 приведения, хотя C мог бы принять одно из них:

void foo (const void *ptr) {
  struct some *azaza = (struct some *)(void*)ptr;
  azaza->some_field = 123; // intentional overwrite!
  // ...
0 голосов
/ 31 мая 2019

Это зависит от того, что вы пытаетесь сделать.Ваш фрагмент кода сбивает с толку по следующим причинам:

Функция принимает неконстантный указатель, что означает, что функция может захотеть изменить содержимое, на которое указывает ptr.

Тогдапосле входа в функцию вы приводите ptr к константному указателю.Поэтому теперь компилятор считает, что функция не намерена изменять содержимое, на которое указывает ptr.Поэтому обычно возникает ошибка, когда программа вызывает:

azaza->some_field = 123; // not allowed !

В зависимости от ваших намерений, вы можете написать функцию в одной из двух форм:

Опция № 1:функция не намеревается изменять то, на что указывает указатель: ptr:

void foo( const void * ptr ) {
    const struct some * azaza = (const struct some *) ptr ;
    // ... do something other than writing to 'azaza', for example:
    printf("Some field: %d\n", azaza->some_field ) ;

}

Опция # 2: функция намерена изменить то, на что указывает указатель ptr:

void foo(void * ptr ) {
    struct some * azaza = (struct some *) ptr ;
    // ... write to 'azaza', for example:
    azaza->some_field = 123 ;
}
0 голосов
/ 31 мая 2019
  1. если значение, указанное ptr, было объявлено как const, то вы пытаетесь сделать неопределенное поведение. Вы не должны изменять значения констант. вы можете удалить const с помощью приведения и изменить значение, только если оно не было объявлено с помощью const изначально.

    int modify(void *ptr) {
        some_t *value = ptr;
        value->member = 0; // here where UB could happen
    }
    
    int main(void)
    {
       some_t obj0 = {0};
       const some_t obj1 = {0};
       modify(&obj0); // OK
       modify(&obj1); // leads to undefined behaviour
       return 0;
    }
    
  2. в противном случае, если это не объявлено с помощью const, почему бы просто не: struct some *azaza = ptr;

...