Распечатать тип void на чистом C
-
20-08-2019 - |
Вопрос
у меня есть функция типа
void printMe (void *i)
{
printf("%d", i);
}
где я хочу передать указатель void и распечатать его на экране.Приведенный выше пример подходит, если i является целым числом, числом с плавающей запятой или двойным числом, но происходит сбой, если i является символом.В C нет перегрузки, которую я обычно использую в C++.Итак, вопрос в том, можем ли мы создать функцию на C, которая будет печатать элемент, который является ее параметром, и если да, то как это возможно, потому что в данный момент это полностью ускользает от меня.
Решение
Вопрос 1: Итак, вопрос в том, можем ли мы создать на C функцию, которая будет печатать элемент, являющийся ее параметром.
А:Не так, как вы хотите.Вам нужно будет передать информацию функции, сообщив ей тип передаваемых данных.
Вопрос 2: и если да, то как это возможно, ведь в данный момент это совершенно ускользает от меня.
А:Это ускользает от вас, потому что это невозможно сделать.С void* не связаны никакие метаданные, которые компилятор или среда выполнения могли бы использовать, чтобы определить тип, на который он указывает.Вам нужно либо
- передать структуру, содержащую
указатель и информация о том, что
указатель указывает на (например.enum). - Передайте дополнительный параметр с информацией о том, что указывает на указатель
В соответствии с кодом единственное, что вы можете здесь напечатать, — это адрес, на который я указываю.
Указатель void указывает на необработанные данные, printf предполагает, что вы знаете, какой тип данных вы печатаете, он не обладает интеллектом и не может «вычислить» это за вас.
Это так просто.
Что вы можете сделать, так это передать информацию о типе функции, но тогда вы получите что-то очень похожее на printf it's self, где вы передаете строку форматирования, содержащую информацию о типе данных в следующих аргументах.
Надеюсь это поможет.
Также ..."В C нет перегрузки, которую я обычно использую в C++."
Даже в C++ перегрузка происходит во время компиляции, и здесь компилятор не может узнать, какие данные будут переданы в эту функцию, поэтому, даже если вы привыкли к перегрузке, это никогда не будет работать так (например,попробуйте то же самое, используя printf, но скомпилировав его компилятором C++, вы получите точно такие же результаты).Вообще-то попробуй
cout << i;
в приведенной выше функции, и она даст вам адрес, на который я указывает, а не «значение» i.Вам нужно будет привести i и отклонить его, прежде чем вы сможете получить его значение
cout << *(int*)i;
Итак, чтобы все вышеперечисленное работало на C++, вам понадобится множество перегруженных функций (или функция шаблона, что на самом деле одно и то же, за исключением того, что компилятор выполняет функции за вас), напримерперегруженные функции
printMe(int i){...}
printMe(double d){...}
printMe(char c){...}
printMe(char* string){...}
В c вам просто нужно дать этим функциям конкретные имена.
printInt(int i){...}
printDouble(double d){...}
printChar(char c){...}
printString(char* string){...}
Другие советы
Для начала вы печатаете указатель, а не то, на что он указывает.Чтобы распечатать фактическое содержимое, вам необходимо передать *i
к printf
, нет i
.
Если вы действительно хотите это сделать, одно из решений:
void printMe (void *p, int typ) {
switch(typ) {
case TYP_INT: printf("%d", *((int*)p)); break;
case TYP_CHR: printf("%c", *((char*)p)); break;
/* and so on ... */
}
}
Итак, вопрос в том, можем ли мы создать на C функцию, которая будет печатать элемент, являющийся ее параметром.
Да мы можем.Такая функция уже есть в стандартной библиотеке — она называется printf
;)
Поскольку в C нет перегрузки функций во время компиляции, вам каким-то образом приходится указывать тип аргументов во время выполнения.А printf
Для этого можно использовать строку формата, поэтому нет смысла создавать собственную функцию-оболочку, если уже есть работающее решение.
Если вы пытаетесь распечатать значение указателя, правильное использование: printf("%p", i);
.Спецификатор «d» предназначен для целых чисел, а «p» — для указателей.Вы несете ответственность за их правильность, и если вы их перепутаете, могут случиться плохие вещи.
Я не знаю, почему это не работает для char *, а не для int *, и возможно, у вас есть другие проблемы, вызывающие это.Если с %p по-прежнему не получается, значит, что-то еще испорчено.Посмотрите, можете ли вы установить какое-нибудь программное обеспечение для мониторинга памяти, чтобы проверять наличие висящих указателей или двойных функций free(), потому что в этот момент умнее всего будет понять, что вы где-то повредили память.