Intereting Posts
Почему логические операторы в C не оценивают целое выражение, когда это необязательно? Как написать функцию, которая возвращает указатель на стек количество повторяющихся элементов в массиве RDTSCP по сравнению с RDTSC + CPUID Как использовать feof (FILE * f)? Печать массива символов, возвращаемых из функции в C Реализация strcmp Как создать программу на C / C ++, которая генерирует XML и запускает команду DOS? Отделите двойное в знаке, экспоненте и мантиссе Как сделать вкладку многострочного текстового поля в приложении win32api Ограничить применение одного экземпляра на сеанс оболочки в Windows Помогите мне понять эту битрейтную программу «Программирование жемчуга» создать архитектуру библиотеки c в mac Как использовать mmap для размещения памяти в куче? Как рассчитать расстояние между координатами GPS на процессоре с плохой поддержкой с плавающей запятой?

Почему нам нужно указывать указатель void на int или что-то еще, прежде чем печатать значение в памяти, адрес которой находится в указателе?

Интересно, зачем нужно void указатель void на int * или char * перед тем, как печатать содержимое адреса в памяти, хотя мы говорим printf() как интерпретировать данные в памяти?

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

 int main (void) { void* c = malloc(4); printf("%d",*c); return 0; } 

Почему это невозможно?

Поэтому, чтобы быть ясным, мой вопрос заключается в том, почему это невозможно?

EDIT: после всех ответов и исследований я до сих пор не уверен, где именно происходит фатальная ошибка в компиляции. Основная причина, по которой я запутался, заключается в том, что мой компилятор (gcc) дает только ПРЕДУПРЕЖДЕНИЕ, говоря о «разыменовании указателя пустоты». Это фактическая ошибка? Из того, что я знаю, программа должна компилироваться даже с предупреждениями.

EDIT2 Я все еще смущен тем, что у нас есть ОШИБКА и ПРЕДУПРЕЖДЕНИЕ, которые кажутся полностью отдельными, но генерируются одним и тем же fragmentом кода:

 pointer.c:7:13: warning: dereferencing 'void *' pointer printf("%d",*p); ^~ pointer.c:7:13: error: invalid use of void expression printf("%d",*p); 

Некоторые пользователи говорят, что ошибка появляется только тогда, когда мы пытаемся использовать результат дерефенциации и что WARNING – это когда мы фактически выделяем память для указателя VOID.

Это явно не так, поскольку, если мы удалим строку printf, мы действительно получаем только предупреждение, но ПОЛНОСТЬЮ НЕОПРЕДЕЛЕННО.

 pointer.c:6:8: warning: unused variable 'p' [-Wunused-variable] void * p=malloc(4); 

    Проблема заключается не в интерпретации printf() , а в случае разыменования.

    В случае утверждения типа

      printf("%d",*c); 

    вы пытаетесь разыменовать void * . Теперь void является вечно-неполным типом. Вы не можете разыменовать указатель на «что-то неполное» и получить в результате что-то значимое.

    Цитирование C11 , глава §6.2.5, P19

    Тип void содержит пустой набор значений; это неполный тип объекта, который не может быть завершен.

    Другими словами (хотя и немного моей), C является строго типизированным языком и для каждого определенного типа, компилятор знает ( или должен знать ), сколько байтов (размера) из памяти необходимо читать / работать на. Для типа void компилятор не знает.

    По той же причине арифметика указателя также не допускается на void * s. gcc имеет расширение, которое обрабатывает void* же, как char * , но это расширение, а не стандартное.


    РЕДАКТИРОВАТЬ:

    Мой компилятор выдает ошибку для оператора, проверяя его в Интернете .

    *c разыскивает указатель, который имеет тип void (неполный тип). Вы не можете разыменовать void , поскольку компилятор не знает тип (таким образом, его размер). В результате разыменование указателя void вызывает Undefined Behavior.

    Другими словами, нецелесообразно разыменовывать указатель на пустоту. Представьте, что вы являетесь компилятором, как бы вы интерпретировали память, на которую указывают указатели (поскольку это может быть что угодно)? Кастинг void* для правильного типа сделает трюк (предоставит компилятору информацию о nessecairy).

    Почему компилятор дает предупреждение, а не ошибку?

    Он замечает, что он будет генерировать предупреждение и сопроводительную ошибку:

     main.c:8:14: warning: dereferencing 'void *' pointer printf("%d",*c); ^~ main.c:8:14: error: invalid use of void expression printf("%d",*c); ^~~~~~ 

    (gcc) дает предупреждение, говоря о «разыменовании указателя пустоты». Это фактическая ошибка?

    Нет.

    Но попытайтесь использовать результат этой деgradleации, и вам не повезло.

    Я имею в виду, что:

     void* c = malloc(4); *c; 

    не вызывает ошибку (но только предупреждение):

     main.c:6:2: warning: dereferencing 'void *' pointer *c; ^~ 

    Однако, если вы попытаетесь использовать результат *c , будет создана ошибка.

    Подробнее об этом читайте на пути к пониманию указателей void .

    Так как cvoid pointer на void pointer это может быть что угодно. Для разыменования компилятор должен знать тип, включая размер.

    Без malloc и void * рассмотрите, что здесь происходит:

     int main() { int i = 555555; char * c = (char *)&i; printf("%c\n", *c); short * s = (short *)&i; printf("%d\n", *s); } 

    Вы печатаете очень разные вещи. То же самое происходит с void * – что это должно быть?

    Вы сказали printf ожидать число, но это отдельная операция по устранению void * в первую очередь.

    Указатель c был объявлен void* . Прежде чем обращаться к указателю void разыменования / разыменования, вам необходимо ввести cast , чтобы он указывал на соответствующий тип, который вы ожидаете в этом указателе.

    Подводя итог, как указано в предыдущих ответах, void является неполным типом во всех стандартах C, поэтому вы обязательно получите сообщение об ошибке, когда вы попытаетесь разыменовать его. Однако GNU C обрабатывает void с размером 1 (char), поэтому он отображает только предупреждение, но GCC переносит компиляцию в соответствии с расширением GNU.

    Если вы хотите, чтобы GCC строго следовал стандарту, вам нужно добавить -std=c11 (возможно, с -pedantic ).

    printf не принимает указатели на вещи для печати, в основном так, что он может принимать результат выражений:

     printf("%d",4*my_function()); // value has no user-visible address 

    Таким образом, компилятор должен знать тип, чтобы получить значение и передать его printf . (Вам также нужна строка формата, потому что язык предлагает реализацию printf без возможности узнать, какой тип объекта вы ему дали.)