将 `void *` 函数参数不一致从类型转换为类型的方法 [英] Methods to convert `void *` function parmeter inconsistant from type to type

查看:26
本文介绍了将 `void *` 函数参数不一致从类型转换为类型的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:这个问题试图改进我尝试在此处提出的问题,但没有达到.
另外,我已经看到了这个这个.他们讨论类似的概念,但不回答这些问题.

Note: This question attempts to improve what I attempted to ask here, but fell short.
Also, I have seen this, and this. They discuss similar concepts, but do not answer these questions.

我的环境是 Windows 10,为了测试我使用了两个编译器,CLANGGCC.

My environment is Windows 10, and for testing I used two compilers, CLANG and GCC.

我通过 void * 函数参数传递变量,需要转换它们.我想就我在不同类型的方法之间看到的不一致问题获得一些反馈.

I am passing variables via a void * function argument, and need to convert them. I would like to get some feedback on inconsistencies I am seeing between methods for different types.

以下是一个测试函数的精简描述,该函数使用 void * 参数和枚举值参数来适应多种输入类型,以指示传入的类型.

The following is a stripped-down depiction of a test function that accommodates multiple input types using a void * parameter, and an enumerated value parameter to indicate the type being passed in.:

void func(void *a, int type)
{
    switch(type) {
        case CHAR://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 INT://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 FLT://float
            float fVar1   = (float)a;      //compile error:  (a1)(b1)
            float fVar2   = *(float *)a;   //requires this method
         case DBL://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;

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

    return 0;
}

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

Exact error text relating to flags in comments above follows:

CLANG - 3.3 版

  • (a1) - ...错误:指针不能转换为float"类型

gcc - (tdm-1) 5.1.0

  • (b1) - ...错误:在需要浮点值的地方使用了指针值
  • (b2) - ...错误:指针不能转换为double"类型

供以下讨论参考

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

我的结果表明转换 float &double 需要方法 2.
但是对于 char &int 方法 2 似乎是可选的,即方法 1 编译良好,并且似乎始终如一地工作.

My results indicate that converting float & double require method 2.
But for char & int method 2 seems to be optional, i.e. method 1 compiles fine, and seems to work consistently.

问题:

  • 似乎从 void * 函数中恢复一个值参数应该总是需要方法 2,那么为什么方法 1(似乎) 使用 charint 类型?这是未定义的行为吗?

  • It would seem that recovering a value from a void * function argument should always require method 2, so why does method 1 (seem to) work with char and int types? Is this undefined behavior?

如果方法 1 适用于 charint,为什么它至少不适用于 float 类型?这不是因为它们的大小不同,即:sizeof(float) == sizeof(int) == sizeof(int *) == sizeof(float *).是因为严格的别名违规吗?

If method 1 works for char and int, why does it not also work with at least the float type? It's not because their sizes are different, i.e.: sizeof(float) == sizeof(int) == sizeof(int *) == sizeof(float *). Is it because of a strict aliasing violation?

推荐答案

C 标准 明确允许指针和整数类型之间的转换.这在关于指针转换的第 6.3.2.3 节中有详细说明:

The C standard explicitly allows conversions between pointers and integer types. This is spelled out in section 6.3.2.3 regarding pointer conversions:

5 整数可以转换为任何指针类型.除了前面指定的,结果是实现定义的,可能不是正确对齐,可能不会指向引用的实体类型,并且可能是陷阱表示.

5 An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.

6 任何指针类型都可以转换为整数类型.除了前面指定的,结果是实现定义的.如果结果不能用整数类型表示,行为是不明确的.结果不必在任何值的范围内整数类型.

6 Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type.

假设您在将整数类型传递给函数时将其转换为 void * 然后将其转换回正确的整数类型,则可以这样做 提供 实现允许它.假设所讨论的整数类型至少与 void * 一样大,GCC 尤其会允许这样做.

Assuming you cast an integer type to void * when passing it to the function then cast it back to the proper integer type, this can be done provided the implementation allows it. GCC in particular will allow this assuming the integer type in question is at least as big as a void *.

这就是转换适用于 charint 情况的原因,但是您需要传入值(转换为 void *) 而不是地址.

This is why the conversion will work for the char and int cases, however you would need to pass in the values (casted to void *) instead of the addresses.

例如,如果您像这样调用函数:

So for example if you called the function like this:

func4((void *)123, INT);

然后函数可以这样做:

int val = (int)a;

并且 val 将包含值 123.但是如果你这样调用它:

And val would contain the value 123. But if you called it like this:

int x = 123;
func4(&x, INT);

然后函数中的val将包含转换为整数值的mainx的地址.

Then val in the function would contain the address of x in main converted to an integer value.

根据关于转换运算符的第 6.5.4p4 节,明确禁止在指针类型和浮点类型之间进行转换:

Casting between a pointer type and a floating point type is explicitly disallowed as per section 6.5.4p4 regarding the cast operator:

指针类型不应转换为任何浮点类型.浮动类型不得转换为任何指针类型.

A pointer type shall not be converted to any floating type. A floating type shall not be converted to any pointer type.

当然,通过 void * 传递值的最安全方法是将值存储在适当类型的变量中,传递其地址,然后转换 void *> 在函数中返回正确的指针类型.这保证有效.

Of course the safest way to pass values via a void * is to store the value in a variable of the appropriate type, pass its address, then cast the void * in the function back to the proper pointer type. This is guaranteed to work.

这篇关于将 `void *` 函数参数不一致从类型转换为类型的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆