2013-06-18 55 views
14

Tôi đã nhìn thấy mã này trong dự án.Truyền hai lần trong cùng một dòng

b 's loại là void*:

void *b = ...; 
int a = (int) (unsigned long) b; 

là dòng này vô nghĩa? Ý tôi là, nó giống như a = (int) b trong mọi trường hợp?

Trả lời

22

Điều này có thể tránh cảnh báo trình biên dịch trên hệ thống UNIX 64 bit trong đó unsigned long là số lượng 64 bit và đủ lớn để giữ con trỏ, nhưng int là số lượng 32 bit không đủ lớn để giữ con trỏ . Các diễn viên để (unsigned long) bảo tồn tất cả các bit của địa chỉ; lần truyền tiếp theo tới số int sẽ loại bỏ các địa chỉ 32 bit cao cấp của địa chỉ, nhưng thực hiện như vậy mà không nhận được cảnh báo theo mặc định.

Để chứng minh:

int main(void) 
{ 
    void *b = (void *)0x12345678; 
    int a = (int)(unsigned long)b; 
    int c = (int)b; 
    return a + c; 
} 

$ gcc -O3 -g -std=c99 -Wall -Wextra -c ar.c 
ar.c: In function ‘main’: 
ar.c:5:15: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] 
$ 

Sử dụng GCC 4.7.1 trên Mac OS X 10.8.4, mặc định cho 64-bit biên dịch.

Thật thú vị khi suy đoán những gì sẽ được thực hiện với giá trị 'một phần của địa chỉ'.

+2

Hãy nhớ bạn, những người sáng tạo ẩn thông tin số (hoặc boolean) trong 'void *' s :) – hroptatyr

+0

Điều đó có làm tôi sáng tạo không - với mã ví dụ mà tôi đang viết trong khi bạn đang nhận xét? –

+0

Hehe, quả thật vậy, do đó +1 :) Trên một lưu ý quan trọng, rất nhiều API sử dụng 'void *' trong đó 'intptr_t' sẽ là thích hợp – hroptatyr

0

Tôi cũng thấy điều này trong dự án của mình.

Đối với trường hợp của tôi, nội dung của 'b' được phổ biến bởi các nguồn/phần mềm trung gian khác được sử dụng để liên lạc giữa các quá trình.

Khi 'b' được điền, chương trình sẽ lấy nội dung của 'b' bằng cách truyền tới trường 'a' chính xác. ứng dụng sau đó sử dụng 'a' để xử lý.

Dự án của tôi sử dụng char * thay vì void *.

1

Chèn trực tiếp vào con trỏ đến kiểu nhỏ hơn nói int có thể dẫn đến lỗi biên dịch trên một số trình biên dịch (như Clang) trong môi trường bit x64.

Ví dụ:

void *p = GetSomeAddress; 
int i = (int)p; //error on compilers like Clang. 

Giải pháp là:

int i = (int)(unsigned long)p; 

hoặc

int i = (int)(long)p; 

này là bởi vì, trên Unix, theo mô hình LP64, dài là 64-bit.

Trường hợp như vậy, bạn cần phải xem xét kỹ lưỡng lý do tại sao bạn cần typecast từ con trỏ đến int hoặc loại nhỏ hơn khác có thể dẫn đến mất dữ liệu.

Câu hỏi này cũng có thể giúp bạn. How should I handle "cast from ‘void*’ to ‘int’ loses precision" when compiling 32-bit code on 64-bit machine?

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