Явное приведение при назначении указателей в C - PullRequest
2 голосов
/ 27 сентября 2019

В C, если я напишу следующий код:

#include <stdio.h>

int main() {
        char c;    
        int* ip;
        char* cp;

        cp = &c;
        ip = cp;

        printf("%p %p %p %p\n", cp, ip, cp+1, ip+1);

        return 0;
}

, я получу предупреждение о не явном приведении cp к ip.Однако сам код, кажется, работает просто отлично.Если c имел адрес 1000, я получаю 1000 1000 1001 1004 в качестве вывода.

Мой вопрос заключается в том, зачем нужен явный приведение.Это просто потому, что в стандарте C ничего не говорится о неявном преобразовании указателей (кроме void*) или что-то еще происходит в явном приведении?

Ответы [ 3 ]

4 голосов
/ 27 сентября 2019

Я получаю предупреждение об отсутствии явного приведения cp к ip.

Вы не компилируете с достаточно строгими настройками компилятора.Если вы хотите получить ошибку при нарушениях языка C, вам понадобится что-то вроде gcc -std=c11 -pedantic-errors или эквивалентного.

Однако сам код, похоже, работает просто отлично.

char* и int* не являются совместимыми типами указателей.Ваш код не подходит для языка Си - ip = cp; является нарушением правила "простого присваивания".И поэтому ваш код опирается на неопределенное поведение и нестандартные расширения компилятора.

Мой вопрос заключается в том, зачем нужен явный приведение.Это просто потому, что в стандарте C ничего не говорится о неявном преобразовании указателей (кроме void *) или что-то еще происходит в явном приведении?

В частности, из-за правило том, как использовать оператор присваивания, указанный в C17 6.5.16.1 Простое присваивание, выделено мое:

Должно быть выполнено одно из следующих действий:
/ - /
- левый операнд имеет атомарный, квалифицированный или неквалифицированный тип указателя и (учитывая тип, который левый операнд будет иметь после преобразования в lvalue) оба операнда являются указателями на квалифицированный или неквалифицированныйверсии совместимых типов , а тип, на который указывает слева, содержит все квалификаторы типа, на который указывает справа;

То же правило имеет исключения для void*и константы нулевого указателя.

3 голосов
/ 27 сентября 2019

предупреждение о не явном приведении cp к ip
почему требуется явное приведение (?)

Указатели на int могут иметь более строгие требования выравнивания, чем char *.Например, все int должны начинаться с четного адреса, тогда как char * может быть нечетным.Также применимы и другие проблемы.

Приведение говорит: «Глупый компилятор, я знаю лучше, и просто делаю преобразование - не волнует, вызывает ли оно ошибку шины».

Совет: не делайтене делай этого.

1 голос
/ 27 сентября 2019

В сущности, он просто говорит компилятору: «Поверь мне. Я знаю, что делаю».Чаще всего программист ошибается.Если вы используете только приведение только для подавления предупреждений, то вы делаете что-то серьезно неправильно.А * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} * * * * * * * * *} * * * * * * * * *} * * * * * * * * * * 1006 * * * * * * * * * * * * * * * * * * * * * * * * * * * *} * * * * * * * * * *} * * * * * * * * 100} * 1006должно.И это здесь.

Вот пример того, как это может пойти не так:

#include <stdio.h>

struct myStruct {
        char a, b, c, d;
};

int main(void)
{
        struct myStruct s = { 'a', 'b', 'c', 'd' };
        int* p = &s.b;
        printf("%c %c %c %c\n", s.a, s.b, s.c, s.d);
        *p=42;
        printf("%c %c %c %c\n", s.a, s.b, s.c, s.d);
}

Вывод:

$ ./a.out 
a b c d
a *   

То, что произошло здесь, это потому, чтоint - это четыре байта, он перезапишет три других байта при записи в s.b.Это s.c, s.d и еще один байт, о котором мы ничего не знаем.Нетрудно понять, что это может вызвать нежелательные эффекты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...