2013-02-08 77 views
7

Việc sử dụng con trỏ unsigned char là gì? Tôi đã nhìn thấy nó ở nhiều nơi mà con trỏ là loại đúc để con trỏ đến unsinged char Tại sao chúng ta làm như vậy?Khi nào cần sử dụng con trỏ char chưa ký

Chúng tôi nhận được con trỏ đến int và sau đó nhập truyền tới unsigned char*. Nhưng nếu chúng ta cố gắng in phần tử trong mảng đó bằng cách sử dụng cout nó không in bất cứ thứ gì. tại sao? Tôi không hiểu. Tôi mới dùng C++.

EDIT Mẫu Mã Dưới

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 
} 
+0

khi chuyển đổi thành con trỏ ký tự, byte đầu tiên có thể là số không giống với ký tự kết thúc chuỗi và do đó sẽ không có nội dung nào được in. Nó sẽ giúp ích nhiều hơn nếu bạn có thể hiển thị những gì bạn thực sự làm, tức là đăng một số mã. Vui lòng tạo [SSCCE] (http://sscce.org/) và thêm vào câu hỏi. –

+0

Nhưng tôi nghĩ rằng sẽ mất thông tin nếu byte đầu tiên là số không và thực sự tôi đang cố gắng để in tất cả bốn byte nhưng nó không in bất cứ điều gì. –

+2

Câu hỏi của bạn có vẻ nhiều hơn về "tại sao" thay vì "khi". Rất thường xuyên, 'unsigned char *' được sử dụng như một phương thức truy cập mức byte để tiếp cận vào một biến hoặc địa chỉ bộ nhớ của một kiểu không chính thức hơn. Nó có nhiều niceties, trong số đó, miễn dịch với các quy tắc bí mật nghiêm ngặt và sự liên kết được đảm bảo tiêu chuẩn với bất kỳ địa chỉ nào bạn ném vào nó. Mới với C + + không nên làm cho điều này khó khăn nếu bạn đang hợp lý quen thuộc với C. Mới để * lập trình *, tôi thấy điều này như là một thách thức để hiểu. Có lẽ bạn có một số mã và ý tưởng đằng sau nó bạn có câu hỏi về? – WhozCraig

Trả lời

5

Bạn đang thực sự tìm kiếm pointer arithmetic:

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

Trong ví dụ này, bytes[i] bằng *(bytes + i) và nó được sử dụng để truy cập vào bộ nhớ trên địa chỉ: bytes + (i* sizeof(*bytes)). Nói cách khác: Nếu bạn có int* intPtr và bạn cố gắng truy cập vào intPtr[1], bạn đang thực sự truy cập vào các số nguyên được lưu trữ tại byte: 4-7:

0 1 2 3 
4 5 6 7 <-- 

Kích thước của gõ điểm con trỏ của bạn để ảnh hưởng đến nơi nó trỏ sau khi nó được tăng/giảm. Vì vậy, nếu bạn muốn iterate byte dữ liệu của bạn bằng byte, bạn cần phải có một con trỏ để loại kích thước 1 byte (đó là lý do tại sao unsigned char*).


unsigned char thường được sử dụng để giữ dữ liệu nhị phân nơi 0 là giá trị hợp lệ và vẫn là một phần của dữ liệu. Khi làm việc với "naked" unsigned char*, bạn có thể phải giữ độ dài của bộ đệm.

char thường được sử dụng để giữ các ký tự đại diện cho chuỗi và 0 bằng '\0' (ký tự kết thúc). Nếu bộ đệm ký tự của bạn luôn bị chấm dứt với '\0', bạn không cần biết độ dài của nó vì ký tự chấm dứt chỉ định chính xác phần cuối của dữ liệu của bạn. Lưu ý rằng trong cả hai trường hợp này, tốt hơn nên sử dụng một số đối tượng ẩn dữ liệu nội bộ của bạn và sẽ quản lý bộ nhớ cho bạn (xem RAII idiom). Vì vậy, bạn nên sử dụng std::vector<unsigned char> (đối với dữ liệu nhị phân) hoặc std::string (đối với chuỗi).

2

Loại unsinged char thường được sử dụng làm đại diện cho một dữ liệu nhị phân đơn lẻ byte. Vì vậy, và mảng thường được sử dụng như một bộ đệm dữ liệu nhị phân, trong đó mỗi phần tử là một byte đơn.

Cấu trúc unsigned char* sẽ là con trỏ tới bộ đệm dữ liệu nhị phân (hoặc phần tử thứ nhất của nó).

Tôi không chắc chắn 100% những gì hiện c++ tiêu chuẩn chính xác nói về kích thước của unsigned char, cho dù đó là cố định là 8 bit hay không. Thường là. Tôi sẽ cố gắng tìm và đăng nó.

Sau khi nhìn thấy mã của bạn

Khi bạn sử dụng một cái gì đó giống như void* input như một tham số của một hàm, bạn cố tình dải xuống thông tin về nguyên liệu đầu vào loại gốc. Đây là gợi ý rất mạnh mẽ rằng đầu vào sẽ được xử lý theo cách rất chung chung. I E. như một chuỗi byte tùy ý. Mặt khác, int* input sẽ gợi ý rằng nó sẽ được coi là "chuỗi" của các số nguyên được chọn.

void* chủ yếu được sử dụng trong trường hợp khi đầu vào được mã hóa, hoặc xử lý bit/byte khôn ngoan vì lý do gì, vì bạn không thể rút ra kết luận về nội dung của nó.

Sau đó, trong chức năng của bạn, bạn dường như muốn coi đầu vào là một chuỗi các byte. Nhưng để hoạt động trên các đối tượng, ví dụ: thực hiện operator= (bài tập) trình biên dịch cần phải biết phải làm gì. Vì bạn khai báo đầu vào là việc gán void* chẳng hạn như *input = something sẽ không có ý nghĩa vì *input là loại void. Để làm cho trình biên dịch xử lý các phần tử input là "các mẩu bộ nhớ thô nhỏ nhất", bạn hãy đưa nó vào loại thích hợp là unsigned int.

cout có thể không hoạt động do chuyển đổi loại sai hoặc không mong muốn. char* được coi là một chuỗi chấm dứt null và rất dễ nhầm lẫn mã số phiên bản singedunsigned. Nếu bạn vượt qua unsinged char* đến ostream::operator<< dưới dạng char*, nó sẽ xử lý và mong đợi đầu vào byte làm ký tự ASCII bình thường, trong đó 0 có nghĩa là kết thúc chuỗi không phải là giá trị số nguyên 0. Khi bạn muốn in nội dung của bộ nhớ, tốt nhất là nên sử dụng con trỏ một cách rõ ràng.

Cũng lưu ý rằng để in nội dung bộ nhớ của bộ đệm, bạn sẽ cần phải sử dụng vòng lặp, vì chức năng in ấn khôn ngoan khác sẽ không biết khi nào nên dừng.

+1

C và C++ xác định các kiểu ký tự ('char',' unsigned char' và 'signed char') để có kích thước một byte và yêu cầu chúng phải có ít nhất 8 bit. Có, hoặc ít nhất cho đến gần đây là một máy tính với 9 bit 'char', và có một số với 32 bit char. (Trong lịch sử, tất nhiên, có rất nhiều máy có byte nhỏ hơn 8 bit, nhưng C không cho phép điều này.) –

+0

@ James, cảm ơn bạn. Tôi đã đề cập đến nó, bởi vì tôi nhớ điều gì đó về việc không được đảm bảo rằng nó luôn luôn là 8bits. Tôi muốn ở lại rõ ràng trong trường hợp một trong những sẽ được thực hiện một số giao thức mạng cấp thấp hoặc di chuyển các tập tin nhị phân từ một hệ thống vào hệ thống, họ có thể gặp phải như vậy caveats. – luk32

+1

Rất nhiều phụ thuộc vào cách di động bạn có được. Đối với hầu hết mọi người, các ràng buộc về tính di động sẽ đủ lỏng để cho phép giả định rằng 'char' là 8 bit, nhưng có các máy _are_ mà nó không ở đâu. –

7

Trong C, unsigned char là loại duy nhất được đảm bảo không có giá trị bẫy và đảm bảo việc sao chép sẽ dẫn đến hình ảnh bitwise chính xác. (C++ mở rộng bảo lãnh này thành char.) Vì lý do này, nó được sử dụng theo truyền thống cho "bộ nhớ nguyên" (ví dụ: ngữ nghĩa của memcpy được xác định theo điều khoản của unsigned char).

Ngoài ra, các loại tích phân không dấu nói chung được sử dụng khi hoạt động bitwise (&, |, >> v.v.) sẽ được sử dụng. unsigned char là loại tích phân không dấu nhỏ nhất và có thể được sử dụng khi thao tác các mảng có giá trị nhỏ mà các hoạt động bitwise được sử dụng. Đôi khi, nó cũng được sử dụng bởi vì người ta cần hành vi modulo trong trường hợp tràn, mặc dù điều này thường xuyên hơn với các loại lớn hơn (ví dụ: khi tính toán giá trị băm). Cả hai lý do này áp dụng cho các loại chưa ký nói chung; unsigned char thường sẽ chỉ được sử dụng cho họ khi có nhu cầu giảm sử dụng bộ nhớ.

+1

"C++ cũng mở rộng bảo đảm này thành' char'. " - Chúng ta có thể có nguồn cho việc này không? – emlai

0

Con trỏ char chưa được ký hiệu hữu ích khi bạn muốn truy cập byte dữ liệu theo byte. Ví dụ: một hàm sao chép dữ liệu từ khu vực này sang khu vực khác có thể cần đến điều này:

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

Nó cũng phải làm với thực tế là byte là bộ nhớ địa chỉ nhỏ nhất.Nếu bạn muốn đọc bất cứ thứ gì nhỏ hơn một byte từ bộ nhớ, bạn cần lấy byte chứa thông tin đó, và sau đó chọn thông tin bằng cách sử dụng các phép toán bit.

Bạn có thể sao chép dữ liệu ở hàm trên bằng cách sử dụng con trỏ int, nhưng điều đó sẽ sao chép các khối 4 byte, có thể không phải là hành vi chính xác trong một số trường hợp.

Tại sao không có gì xuất hiện trên màn hình khi bạn cố gắng sử dụng cout, giải thích rất có thể là dữ liệu bắt đầu bằng ký tự 0, trong C++ đánh dấu kết thúc chuỗi ký tự.

+0

Nếu nó bắt đầu bằng 0 ký tự thì nó sẽ in giá trị của 3 ký tự còn lại. Và nếu trong vòng lặp for trong mã cho (int i = 0; i

+0

"Bạn có thể sao chép dữ liệu trong hàm trên bằng cách sử dụng con trỏ' int' "Không, bạn rất có thể _not_! Các loại trừ 'unsigned char' (& I think _especially_ signed types), không được bảo đảm (A) bao gồm tất cả các bit của bộ nhớ bên dưới hoặc (B) cho phép các giá trị bẫy/không hợp lệ có thể phát sinh từ việc cố gắng diễn giải lại các byte tùy ý. int 's. Sử dụng bất kỳ con trỏ nào khác ngoài 'unsigned char *' ở đây vốn dĩ, & rất, không di động. Việc triển khai có thể sử dụng nó như một chi tiết dựa trên nền tảng, nhưng người dùng không nên. –

Các vấn đề liên quan