пустые указатели: разница между C и C ++ - PullRequest
17 голосов
/ 15 ноября 2009

Я пытаюсь понять разницу между C и C ++ относительно пустых указателей. следующие компиляции в C, но не в C ++ (все компиляции выполняются с помощью gcc / g ++ -ansi -pedantic -Wall):

int* p = malloc(sizeof(int));

Потому что malloc возвращает void*, который C ++ не позволяет присвоить int*, в то время как C разрешает это.

Однако, здесь:

void foo(void* vptr)
{
}

int main()
{
    int* p = (int*) malloc(sizeof(int));
    foo(p);
    return 0;
}

И C ++, и C компилируют его без жалоб. Почему?

K & R2 говорят:

Любой указатель на объект может быть преобразован в тип void * без потерь информации. Если результат преобразован обратно в исходный указатель тип, оригинальный указатель выздоровел.

И это довольно суммирует все, что есть о void* преобразованиях в C. Что диктует стандарт C ++?

Ответы [ 3 ]

32 голосов
/ 15 ноября 2009

В C преобразования указателей в void* и обратно всегда были неявными.

В C ++ преобразования из T* в void* неявны, но void* во что-либо еще требует приведения.

6 голосов
/ 15 ноября 2009

C ++ более строго типизирован, чем C. Многие преобразования, особенно те, которые подразумевают различную интерпретацию значения, требуют явного преобразования. Оператор new в C ++ является безопасным для типов способом выделения памяти в куче без явного преобразования.

0 голосов
/ 15 ноября 2009

Полезно понимать, что преобразования типов указателей на самом деле не требуют выполнения дополнительных инструкций процессора. Они анализируются во время компиляции, чтобы понять намерения разработчика. void * - непрозрачный указатель. Все это говорит о том, что тип заостренного предмета неизвестен. С слабо типизирован. Это позволяет прямое преобразование между (void *) и любым (T*) неявно. C ++ строго типизирован. Преобразование из (void *) в (T*) не очень хорошо подойдет для строго типизированного языка. Но C ++ должен был оставаться обратно совместимым с C, следовательно, он должен был разрешать такие преобразования. Тогда руководящий принцип: явное лучше, чем неявное. Следовательно, если вы хотите преобразовать (void*) в какой-то определенный (T*) указатель, вам нужно явно записать это в коде. Преобразование из (T*) в (void*) не требует явного преобразования, поскольку ничего нельзя сделать с указателем (void *) напрямую (хотя можно вызвать free ()). Следовательно, преобразование (T*) в (void*) в значительной степени безопасно.

...