在 C 中,有没有办法将 void 指针转换为定义的大小类型?

In C, is there a way to cast a void pointer to a defined size type?

我需要一个“通用”scanf 函数来验证输入,同时还为指令和错误打印一条消息。扫描是一个接受空指针的函数,它是将存储输入值、类型说明符和消息的变量的方向。代码如下所示:

void scan(char specifier, void *dest, string instruction, string error) {
bool success = true;
do {
    if(!success) {
        while (getchar()!='\n');
        perror(error);
    }
    puts(instruction);
    switch (specifier)
    {
    case 'd':
        success = scanf(" %d", (int *)dest);
        break;
        
    case 's’:
        // In this particular program I need the strings to be 30 bytes with spaces.
        success = scanf(“ %29[^\n]s", (char *)dest);
        break;

    case 'h':
        success = scanf(" %hd", (short *)dest);
        break;

    case 'f':
        success = scanf(" %f", (float *)dest);
        break;
    }
} while (!success ); }

但是是否可以将 void 指针转换为给定大小类型的指针而不是 switch?像这样:

double myVar;
size_t varSize = sizeof(double); void * dest = &myVar;
// specifierForDest is a string
scanf(specifierForDest, (varSize *)dest);

因此 dest 成为指向大小为 varSize 的变量的指针。

或者比在 C 中为每个类型编写 case 更好的任何其他已知方法?

C 标准不提供将指针动态转换为 scanf 所需指针类型的方法。这意味着,一旦您的函数接收到 void * 参数,将其转换为指定接收的 scanf 类型的唯一方法是将它们作为个别情况处理。

另一种方法是不以 void * 形式接收参数,而是在可变参数列表中接收它并将其转发给专为此类操作设计的 vscanf。为此,您必须将目标参数移动到参数列表的末尾。下面是示例代码。可变参数列表处理在最后几行。

#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>


typedef char *string;


void scan(char specifier, string instruction, string error,...)
{
    bool success = true;
    do
    {
        if (!success)
        {
            int c;
            do
                c = getchar();
            while (c != EOF && c != '\n');
            perror(error);
        }
        puts(instruction);
        char *specifierForDest;
        switch (specifier)
        {
            case 'd': specifierForDest = " %d";       break;
            case 's': specifierForDest = " %30[^\n]"; break;
            case 'h': specifierForDest = " %hd";      break;
            case 'f': specifierForDest = " %f";       break;
            default:
                ;   // Do something here; do not neglect error cases.
        }
        va_list ap;           // Create argument list pointer.
        va_start(ap, error);  // Initialize argument list handling.
        success = 1 == vscanf(specifierForDest, ap);
                              // Forward argument to vscanf.
        va_end(ap);           // Clean up argument list handling.
    } while (!success);
}

谢谢。根据您的所有建议,我想出了这个:

#include <stdarg.h>
#include <stdlib.h>

typedef char string[30];
void scan(string specifier, string instruction, string error, ...) {
bool success = true;
va_list ap; va_start(ap, error);
do {
    if(!success) {
        int c;
        do
            c = getchar();
        while (c != EOF && c != '\n');
        puts(error);
    }
    puts(instruction);
    success = vscanf(specifier, ap);
} while (!success );
va_end(ap); }

效果很好。