何时使用unsigned char指针

时间:2013-02-08 09:57:12

标签: c++ pointers

unsigned char指针有什么用?我在很多地方都看到过,指针被指定为unsinged 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
}

4 个答案:

答案 0 :(得分:7)

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

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

答案 1 :(得分:6)

您实际上在寻找pointer arithmetic

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等于'\0'(终止字符)。如果您的字符缓冲区始终以'\0'终止,则您不需要知道它的长度,因为终止字符会准确指定数据的结尾。

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

答案 2 :(得分:2)

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

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

我不是100%确定c++标准对unsigned char的大小的准确说明是什么,是否固定为8位。 通常。我会尝试找到并发布它。

看到您的代码后

当您使用void* input之类的函数作为函数的参数时,您会故意删除有关输入原始类型的信息。这是一个非常强烈的建议,即输入将以非常一般的方式处理。即作为任意字节串。另一方面,int* input表明它将被视为烧结整数的“字符串”。

void*主要用于输入被编码或由于任何原因而被视为bit / byte明智的情况,因为您无法得出有关其内容的结论。

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

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

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

答案 3 :(得分:0)

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

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 ++中标记字符串的结尾。