Я пишу функцию, где я хотел бы принять 2 type
с параметров.
- A
string
(символ *) - А
structure
где будет n элементов.
И чтобы достичь этого, я думаю об использовании простого void *
типа параметра. Но я не знаю, как проверить, является ли параметр того или иного типа, безопасно.
void*
указывает.func_str
иfunc_struct
и получить проверки типов во время компиляции._Generic
макрос. Вы также можете создавать самоидентифицируемые типы, например, с помеченными объединениями , что будет означать, что вы не можете передать необработаннуюchar *
строку. Все это, вероятно, больше проблем, чем оно того стоит.Ответы:
Перевод
void*
является«Дорогой компилятор, это указатель, нет никакой дополнительной информации для вас на этом.».
Обычно компилятор знает лучше, чем вы (программист), из-за информации, которую он получил ранее и до сих пор помнит, а вы, возможно, забыли.
Но в этом особом случае вы знаете лучше или должны знать лучше. Во всех случаях
void*
информация доступна иначе, но только для программиста, который «случайно узнает». Для этого программист должен предоставить информацию компилятору или, что лучше, работающей программе, потому что одно преимуществоvoid*
заключается в том, что информация может меняться во время выполнения.Обычно это делается путем передачи информации через дополнительные параметры функциям, иногда через контекст, т.е. программа «случайно узнает» (например, для каждого возможного типа существует отдельная функция, в зависимости от того, какая функция вызывается, подразумевает тип).
Таким образом, в конце концов
void*
, не содержит информацию о типе.Многие программисты неправильно понимают это как «мне не нужно знать информацию о типе».
Но верно и обратное: использование
void*
повышает ответственность программиста за отслеживание информации о типе и предоставление ее соответствующим образом программе / компилятору.источник
void*
функции, приведете к неправильному типу, а затем отмените ссылку на данные ... тогда будет вызван любой способ неопределенного поведения.void*
в некотором роде устарели для общего программирования, сейчас не так много ситуаций, в которых вы должны их использовать. Они опасны, потому что приводят к несуществующей безопасности типа. И, как вы заметили, вы также теряете информацию о типе, а это значит, что вам придется перетаскивать некоторые громоздкиеenum
вместе сvoid*
.Вместо этого вы должны использовать C11,
_Generic
который может проверять типы во время компиляции и добавлять безопасность типов. Пример:Не забудьте предоставить квалифицированные (
const
) версии всех типов, которые вы хотите поддерживать.Если вы хотите, чтобы ошибки компилятора были лучше, когда вызывающий передает неверный тип, вы можете добавить статическое утверждение:
Если вы попробуете что-то подобное,
int x; func(x);
вы получите сообщение компилятора"x: incorrect type"
.источник