将不一致类型的`void *`函数参数转换为类型的方法

问题描述 投票:0回答:1

注:我看过thisthis。他们讨论类似的概念,但不回答这些问题。

我的环境是Windows 10,为了进行测试,我使用了两个编译器CLANG和GCC。

我正在通过void *函数参数传递变量,并且需要正确转换它们。我想获得有关不同类型的方法之间不一致的反馈。

以下是使用void *参数和枚举值参数来指示要传入的类型的测试函数的简化描述,该测试函数可容纳多种输入类型:

void func(void *a, int type)
{
    switch(type) {
        case 0://char
            char cVar1    = (char)a;      //compiles with no warnings/errors, seems to work
            char cVar2    = *(char *)a;   //compiles with no warnings/errors, seems to work
            break;
        case 1://int
            int iVar1     = (int)a;       //compiles with no warnings/errors, seems to work
            int iVar2     = *(int *)a;    //compiles with no warnings/errors, seems to work
            break;
        case 2://float
            float fVar1   = (float)a;      //compile error:  (a1)(b1)
            float fVar2   = *(float *)a;   //requires this method
         case 2://double
            double dVar1  = (double)a;     //compile error: (a1)(b1)(b2)
            double dVar2  = *(double *)a;//this appears to be correct approach
            break;
    };
}  

调用方法:

int main(void)
{

    char   c = 'P';
    int    d = 1024;
    float  e = 14.5;
    double f = 0.0000012341;
    double g = 0.0001234567;

    void *pG = &g;

    func4(&c, CHAR);//CHAR defined in enumeration, typical
    func4(&d, INT);
    func4(&e, FLT);
    func4(&f, DBL);
    func4(pG, DBL);

    return 0;
}

与以上注释中的标志有关的确切错误文本如下:

CLANG-3.3版本

  • ((a1)-...错误:无法将指针强制转换为'float'类型”

gcc-(tdm-1)5.1.0

  • ((b1)-...错误:在预期浮点值的地方使用了指针值
  • ((b2)-...错误:无法将指针强制转换为'double'类型]

供以下讨论参考

  • 方法1 == type var = (type)val;
  • 方法2 == type var = *(type *)val;

我的结果表明,转换floatdouble需要方法2。但是对于charint,方法2似乎是可选的,即方法1可以很好地编译,并且似乎可以连续工作。

问题:

  • 似乎是从void *函数中恢复值参数应始终要求使用方法2,为什么要使用方法1(似乎来使用charint类型?这是未定义的行为吗?

  • 如果方法1适用于charint,为什么至少在float类型上它也不能使用?不是因为它们的大小不同,即:sizeof(float) == sizeof(int) == sizeof(int *) == sizeof(float *)。是否因为严格的别名冲突?

c undefined-behavior void-pointers strict-aliasing
1个回答
3
投票

C standard明确允许在指针和整数类型之间进行转换。有关指针转换的详细说明,请参见第6.3.2.3节:

5整数可以转换为任何指针类型。除非先前指定,否则结果是实现定义的,可能不是正确对齐,可能未指向所引用的实体类型,并且可能是陷阱表示。

6任何指针类型都可以转换为整数类型。除非先前指定,否则结果是实现定义的。如果结果不能以整数类型表示,其行为是未定义。结果不必在任何值的范围内整数类型。

假设您在将整数类型传递给函数时将其转换为void *,然后将其转换为适当的整数类型,则可以这样做[[提供实现允许。尤其是在GCC允许这种情况下,假设所讨论的整数类型至少与void *一样大。

这就是为什么该转换适用于charint情况的原因,但是您需要传递值(广播到void *)而不是地址。 6.3.2.3

not

没说过关于在指针和浮点类型之间进行转换的任何事情,这就是为什么不允许这样做的原因。当然,通过void *传递值的最安全的方法是将值存储在适当类型的变量中,传递其地址,然后将函数中的void *强制转换回正确的指针类型。这样可以保证工作。
© www.soinside.com 2019 - 2024. All rights reserved.