2012-04-03 31 views
5

Tôi có cấu trúc nhằm mục đích lưu trữ dữ liệu do người dùng xác định (ví dụ: từ plugin). Nó có một số char[] với kích thước tối đa nhất định để lưu trữ dữ liệu đó.Nhập punning, char [] và dereferencing

struct A 
{ 
    // other members omitted 
    // data meant to be type punned, only contains PODs 
    char data[256]; 
}; 

Sau đó có một cấu trúc sử dụng mẫu mà có một chức năng tĩnh để đúc chính nó từ A.

struct B 
{ 
    int i; 
    double d; 

    static B& FromA_ref(A& a) 
    { 
     // static_assert that sizeof(B) < sizeof(A::data) 
     return * reinterpret_cast<B*>(a.data); 
    } 
}; 

Tôi biên dịch với g++ -O3 -std=c++0x -Wall -o test test.cpp (GCC 4.6.1).

Điều này kích hoạt cảnh báo dereferencing type-punned pointer will break strict-aliasing rules. Tôi nghĩ rằng sẽ là ok kể từ khi tôi đã sử dụng một char[] như lưu trữ mà tôi nghĩ rằng sẽ làm theo các quy tắc tương tự như char*. Tôi thấy nó kỳ lạ là không. Phải không? À, ... Tôi không thể thay đổi nó ngay bây giờ, vì vậy hãy tiếp tục.

Bây giờ chúng ta hãy xem xét các phương pháp sau đây:

struct B 
{ 
    .... 
    static B* FromA_ptr(A& a) 
    { 
     // static_assert that sizeof(B) < sizeof(A::data) 
     return reinterpret_cast<B*>(a.data); 
    } 
} 

Kể từ khi tôi không dereferencing bất cứ điều gì ở đây GCC thường không tạo ra bất kỳ cảnh báo. Cũng không khi tôi sử dụng con trỏ của tôi đến B sau này.

A a; 
auto b = B::FromA_ptr(a); 
b->i = 2; // no warnings. 

Nhưng có an toàn không? Tôi cảm thấy như tôi đã làm việc theo cách của tôi xung quanh vấn đề hơn là giải quyết nó. Đối với tôi -> vẫn là dereferencing biến bằng cách nào đó.

Ngoài ra, có cách nào tốt hơn để đạt được hiệu quả không? I E. có được một tham chiếu có thể sửa đổi (hoặc con trỏ) được đúc từ một bộ nhớ bên trong một cấu trúc khác không? (Liên minh sẽ không hoạt động vì tập hợp các loại được lưu trữ không được biết khi A được xác định và một số có thể được thêm qua plug-in, memcpy sẽ buộc tôi sao chép dữ liệu qua lại mặc dù nó có vẻ là cách an toàn duy nhất đến nay)

+0

Tôi không có chuyên gia, nhưng bạn đang tìm thuộc tính '__may_alias__'? http://blog.worldofcoding.com/2010/02/solving-gcc-44-strict-aliasing-problems.html –

+0

Dù sao, bạn xử lý vấn đề liên kết như thế nào? – curiousguy

+0

@curiousguy: cho đến nay tôi không nhưng tôi nên. Ngày x86 tôi đoán rằng tôi có thể làm suy giảm hiệu suất tồi tệ nhất, mặc dù. Tôi hy vọng '__attribute __ ((liên kết (8)));' sẽ là đủ kể từ khi tôi không cố gắng tự động vector hóa bất cứ điều gì. Có lẽ, 'may_alias' đã nói với GCC phải chú ý đến sự liên kết trước khi làm quá nhiều thứ kì lạ. –

Trả lời

3

Câu trả lời là không, nó không phải là an toàn (xem này SO question)

GCC sẽ cho rằng các con trỏ có thể không bí danh. Ví dụ, nếu bạn gán thông qua một cái rồi đọc từ cái kia, GCC có thể, như một sự tối ưu, sắp xếp lại đọc và viết - tôi đã thấy điều này xảy ra trong mã sản xuất, nó không dễ dàng để gỡ rối.

thuộc tính ((may_alias)) trên các loại sử dụng có lẽ là gần nhất bạn có thể nhận để vô hiệu hóa các giả định cho một phần cụ thể của mã.