【问题标题】:error: cannot convert 'unsigned char*' to 'const int*' [closed]错误:无法将 'unsigned char*' 转换为 'const int*' [关闭]
【发布时间】:2014-12-02 08:23:03
【问题描述】:

我正在编写一个函数来接受 unsigned char* 和 int*:

int foo(const int * a)

但是,当我将 unsigned char * a 传递给 foo() 时,它会出现此编译错误。我认为 unsigned char 会自动转换为 int 吗? (较小的范围变量将被转换为较大的变量)。它也适用于数组指针吗?

示例代码:

#include <iostream>
using namespace std;

int average(const int * array, int size)
{
    int sum = 0;
    for (int i = 0; i <size; i++)
    sum+=*(array+i);
    return sum/size;
}

int main() {
    unsigned char array[5] = {0,1,2,3,4};
    std::cout << average(array, 5);
    return 0;
}

编写一个同时接受 unsigned char* 和 int* 的函数的最佳方法是什么?

【问题讨论】:

  • MCVE 有空吗?!!
  • 你的函数不接受 int 它接受 int* 这是一个不同的类型。 char 可能会转换为 int,但 char*int* 并非如此。
  • 不,没有从unsigned char*int* 的隐式转换(不是“强制转换”;强制转换是指定转换的显式运算符)。
  • 您说的是积分促销。但是指针不属于整数类型,并且对指针进行这些转换也会带来一些令人讨厌的安全问题。
  • 您有什么理由选择*(array+i) 而不是array[i]?对我来说似乎没有必要。

标签: c++


【解决方案1】:

我认为 unsigned char 会自动转换为 int 吗?

unsigned char 将自动转换为 int,但 unsigned char* 不会自动转换为 int*

 unsigned char c = 'a';
 unsigned char* cp = &a;

 int i = c;      // This is allowed  
 int* ip = cp;   // This is not allowed

如果允许,你可以这样做:

 *ip = INT_MAX;

&amp;c 没有足够的空间来保存该号码。您最终将访问未经授权的内存,这将立即导致未定义的行为。

【讨论】:

    【解决方案2】:

    tl;博士

    欢迎使用某种类型安全。 const intunsigned char 是完全不同的类型。两者之间的隐式转换将是类型系统中的一个巨大缺陷。

    允许的指针转换

    只有 3 种类型的有效指针转换,在标准的 §4.10 中描述:

    空指针

    从空指针纯右值到指针类型。例如:

    const int* ptr = nullptr;
    

    特别是:

    空指针常量是一个整数文字 (2.14.2),其值为 0 或 std::nullptr_t 类型的纯右值。空指针常量可以转换为指针类型;结果是该类型的空指针值,并且可以与对象指针或函数指针类型的所有其他值区分开来。这种转换称为空指针转换。相同类型的两个空指针值应比较相等。将空指针常量转换为指向 cv 限定类型的指针是一次转换,而不是指针转换后跟限定转换 (4.4) 的顺序。整数类型的空指针常量可以转换为 std::nullptr_t 类型的纯右值。 [ 注意:生成的纯右值不是空指针值。 ——尾注]

    void* 的特例

    我说“某种类型系统”的原因正是这个。 [const] void* [const] 可以表示任何指针类型,只要它与常量限定符一样:

    const int* x = ...;
    const void* vx = x; // OK
    
    const int* y = ...;
    void* vy = y; // Nope
    

    这具体描述为:

    “指向 cv T 的指针”类型的纯右值,其中 T 是对象类型,可以转换为“指向 cv void 的指针”类型的纯右值。将指向对象类型的指针的非空指针值转换为“指向 cv void 的指针”的结果表示与原始指针值相同的字节在内存中的地址。将空指针值转换为目标类型的空指针值。

    多态指针

    最后,我们有了多态指针:指向基类的指针:

    class B { ... };
    class C : public B { ... };
    class D : public B { ... };
    
    ...
    
    C* c = new C();
    D* d = new D();
    
    B* b1 = c; // Yup
    B* b2 = d; // Yup
    
    D* dw = b1; // Nope. If you really want this UB you need to use `dynamic_cast`
    

    具体来说:

    “指向 cv D 的指针”类型的纯右值,其中 D 是类类型,可以转换为“指向 cv B 的指针”类型的纯右值,其中 B 是 D 的基类(第 10 条)。如果B 是 D 的不可访问的(第 11 条)或模棱两可的(10.2)基类,需要这种转换的程序是格式错误的。转换的结果是指向派生类对象的基类子对象的指针。将空指针值转换为目标类型的空指针值。

    【讨论】:

      【解决方案3】:

      指针的范围相同,因为它们都是指针。问题是它们都可以被 [] 索引,但是 int 和 char 的字节步长是不同的,它们是 4 和 1。

      如果您要传递一个数组,则必须将字符复制到一个 int 数组中,以便它们像内存中的 int 一样间隔开。

      void char_array_to_int_array(int *ints, char *chars, int length){
           for(int i=0; i<length; i++){
             ints[i]=chars[i]; //Here the cast will happen
           }
       }
      

      或者,您可以再次为 char* 定义函数作为参数,以便可以正确计算索引。

      其实我刚刚意识到你的问题是多态性你想要一个这样的模板函数:

       template <class T>
       int average(T *array, int size){
           int sum = 0;
           for (int i = 0; i <size; i++)
           sum+=*(array+i);
           return sum/size;
       }
      

      在这里,编译器将为程序中调用它的每种类型编译此函数。我应该早点意识到实际问题,而不是参与讨论类型和强制转换。

      这可以正常调用。

      char a[4] = {1,2,3,4};
      int i[4] = {1,2,3,4};
      cout << "The ints: " << average(i,4) << endl;
      cout << "The chars: " << average(a,4) << endl;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-16
        • 2018-10-14
        • 1970-01-01
        • 2012-10-19
        • 2020-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多