何时使用无符号字符指针

When to use unsigned char pointer

本文关键字:指针 字符 无符号 何时使      更新时间:2023-10-16

unsigned char指针的用途是什么?我在很多地方看到指针是类型转换为指向unsigned char的指针。我们为什么这么做?

我们收到一个指向int的指针,然后键入并将其强制转换为unsigned char*。但如果我们尝试使用cout打印该数组中的元素,它不会打印任何内容。为什么?我不明白。我是C++新手。

编辑下方的示例代码

int Stash::add(void* element)
{
    if(next >= quantity)
    // Enough space left?
        inflate(increment);
    
    // Copy element into storage, starting at next empty space:
    int startBytes = next * size; 
    unsigned char* e = (unsigned char*)element;
    for(int i = 0; i < size; i++)
        storage[startBytes + i] = e[i];
    next++;
    return(next - 1); // Index number
}

您实际上正在寻找指针算术:

unsigned char* bytes = (unsigned char*)ptr;
for(int i = 0; i < size; i++)
    // work with bytes[i]

在本例中,bytes[i]等于*(bytes + i),用于访问地址为bytes + (i* sizeof(*bytes))的存储器。换句话说:如果你有int* intPtr,并且你试图访问intPtr[1],你实际上是在访问存储在字节4到7:中的整数

0  1  2  3
4  5  6  7 <-- 

指针指向的类型大小会影响指针在递增/递减后指向的位置。所以,如果您想逐字节迭代数据,您需要有一个指向大小为1字节的类型的指针(这就是unsigned char*的原因)。


unsigned char通常用于保存二进制数据,其中0是有效值,仍然是数据的一部分。在使用"裸"unsigned char*时,您可能需要保持缓冲区的长度。

char通常用于保存表示字符串的字符,0等于''(终止字符)。如果您的字符缓冲区总是以''结尾,那么您不需要知道它的长度,因为终止字符正好指定数据的末尾。

请注意,在这两种情况下,最好使用一些对象来隐藏数据的内部表示,并为您负责内存管理(请参阅RAII习惯用法)。因此,最好使用std::vector<unsigned char>(用于二进制数据)或std::string(用于字符串)。

在C中,unsigned char是唯一保证没有陷阱值的类型,它保证复制将产生精确的逐位图像。(C++也将这种保证扩展到了char。)因此,它传统上被用于"原始内存"(例如,memcpy的语义是根据unsigned char定义的)。

此外,当要使用逐位运算(&|>>等)时,通常使用无符号积分类型。unsigned char是最小的无符号积分类型,可以在操作使用逐位运算的小值数组时使用。偶尔,它也会被使用,因为在溢出的情况下需要模行为,尽管这种情况在较大的类型中更常见(例如,在计算哈希值时)。这两个原因通常都适用于无符号类型;CCD_ 29通常仅在需要减少内存使用时用于它们。

unsinged char类型通常用作二进制数据的单个byte的表示。因此,和数组经常被用作二进制数据缓冲区,其中每个元素都是一个单字节。

unsigned char*构造将是指向二进制数据缓冲区(或其第一个元素)的指针。

对于unsigned char的大小,无论它是否固定为8位,我都不能100%确定c++标准到底说了什么通常是。我会设法找到并发布它。

看到您的代码后

当您使用类似void* input的东西作为函数的参数时,您会故意去掉输入原始类型的信息。这是一个非常强烈的建议,即将以非常一般的方式处理输入。即作为任意的字节串。另一方面,int* input建议将其视为有符号整数的"字符串"。

void*主要用于对输入进行编码或出于任何原因对bit/byte进行处理的情况,因为您无法对其内容得出结论。

然后,在您的函数中,您似乎希望将输入视为一个字节字符串但是要对对象进行操作,例如执行operator=(赋值),编译器需要知道该做什么。由于将输入声明为void*赋值(如*input = something),因此*input属于void类型,因此没有任何意义。为了使编译器将input元素视为"最小的原始内存块",您将其转换为适当的类型unsigned int

cout可能由于错误或意外的类型转换而无法工作。char*被认为是一个以null结尾的字符串,在代码中很容易混淆singedunsigned版本。如果将unsinged char*作为char*传递给ostream::operator<<,则会将byte输入视为普通ASCII字符,其中0是字符串的末尾,而不是0的整数值。当您想要打印内存的内容时,最好显式地投射指针。

还要注意,要打印缓冲区的内存内容,您需要使用循环,因为其他方面的打印功能不知道何时停止。

当您想要逐字节访问数据时,无符号字符指针非常有用。例如,将数据从一个区域复制到另一个区域的功能可能需要以下内容:

void memcpy (unsigned char* dest, unsigned char* source, unsigned count)
{
    for (unsigned i = 0; i < count; i++)
        dest[i] = source[i];
}

它还与字节是内存中最小的可寻址单元这一事实有关。如果您想从内存中读取小于一个字节的内容,则需要获取包含该信息的字节,然后使用位操作选择该信息。

您可以很好地使用int指针复制上面函数中的数据,但这将复制4字节的块,在某些情况下这可能不是正确的行为。

当您尝试使用cout时,为什么屏幕上没有显示任何内容,最可能的解释是数据以零字符开头,在C++中,零字符标记字符串的结束。