2016-02-22 17 views
6

Trình biên dịch tạo ra cảnh báo này khi tôi đang làm việc với một số mã trông giống như -cast từ sockaddr * để sockaddr_in * tăng đòi hỏi sự liên kết

.... 

for(p = res; p != NULL; p = p->ai_next) { 
    void *addr; 
    std::string ipVer = "IPv0"; 

    if(p->ai_family == AF_INET) { 
     ipVer     = "IPv4"; 
     struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr; 
     addr      = &(ipv4->sin_addr); 
    } 

    else { 
     ipVer      = "IPv6"; 
     struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr; 
     addr      = &(ipv6->sin6_addr); 
    } 
.... 
} 

nơi p = res là loại struct addrinfo và các loại cảnh báo sản xuất là sockaddr_in và . Cảnh báo xuất phát từ báo cáo:

  • struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
  • struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;

Tất cả tôi muốn biết là những gì là gây cảnh báo này và những gì tôi có thể làm để sửa chữa nó nếu đây không phải là cách thích hợp để làm việc. Tôi có thể sử dụng bất kỳ số nào trong số static_cast/dynamic_cast/reinterpret_cast tại đây không?

Cảnh báo chính xác là - cast from 'struct sockaddr *' to 'struct sockaddr_in *' increases required alignment from 2 to 4.

+0

??? 'p' và' res' trông giống kiểu 'struct addrinfo', phải không? Dù sao, các diễn viên sản xuất không có cảnh báo trên nền tảng của tôi (OSX, clang 700.1.81). Xin vui lòng chính xác vấn đề của bạn. –

+0

Oh ok bạn đang sử dụng '-Wcast-align', phải không? –

+0

Để tránh nó, bạn nên sử dụng 'memcpy' ví dụ, phá vỡ quy tắc bí danh là UB. –

Trả lời

7

TLDR: Cảnh báo này không cho biết lỗi trong mã của bạn, nhưng bạn có thể tránh cảnh báo bằng cách sử dụng trình phát C++ reinterpret_cast (nhờ @Kurt Stutsman).


Giải thích:

Lý do cảnh báo:

  • sockaddr bao gồm một đoạn ngắn (thường là 16 bit) unsigned và một mảng char, vì vậy đòi hỏi sự liên kết của nó là 2 .
  • sockaddr_in chứa (trong số những thứ khác) một số struct in_addr có căn chỉnh yêu cầu tư duy của 4 lần lượt có nghĩa là sockaddr_in cũng phải được căn chỉnh với một ranh giới 4 Byte.

Vì lý do đó, đúc một tùy sockaddr* một sockaddr_in* thay đổi các yêu cầu liên kết, và việc tiếp cận các đối tượng thông qua con trỏ mới thậm chí sẽ vi phạm quy tắc răng cưa và dẫn đến hành vi không xác định.

Tại sao bạn có thể bỏ qua nó:

Trong trường hợp của bạn, đối tượng, p->ai_addr được trỏ đến, rất có thể là một sockaddr_in hoặc đối tượng nào (được xác định bằng cách kiểm tra ai_family) và do đó hoạt động là an toàn . Tuy nhiên bạn trình biên dịch không biết điều đó và tạo ra một cảnh báo. Về cơ bản, nó giống như việc sử dụng một số static_cast để đưa con trỏ đến lớp cơ sở đến con trỏ đến lớp được thừa kế - nó không an toàn trong trường hợp chung, nhưng nếu bạn biết đúng loại động bên ngoài, nó là được xác định rõ.

Giải pháp:
Tôi không biết một cách sạch sẽ xung quanh này (trừ ngăn chặn cảnh báo), mà không phải là bất thường với các cảnh báo được kích hoạt bởi -Weverything. Bạn có thể sao chép đối tượng được trỏ tới bởi p->ai_addr byte theo byte tới đối tượng thuộc loại thích hợp, nhưng sau đó bạn có thể (không nhất thiết) không còn sử dụng addr giống như trước đây, vì nó bây giờ sẽ trỏ đến một khác (ví dụ: cục bộ) biến.
-Weverything không phải là điều mà tôi sẽ sử dụng cho xây dựng thông thường của tôi dù sao, bởi vì nó cho biết thêm quá nhiều tiếng ồn, nhưng nếu bạn muốn giữ nó, @Kurt Stutsman đề cập đến một giải pháp tốt trong các ý kiến:

kêu vang ++ (g ++ không phát ra cảnh báo trong bất kỳ trường hợp nào) không phát ra cảnh báo, nếu bạn sử dụng reinterpret_cast thay vì dàn diễn viên kiểu c (mà bạn không nên sử dụng), mặc dù cả hai đều có (trong trường hợp này) giống hệt nhau chức năng. Có lẽ vì reinterpret_cast nói rõ ràng với trình biên dịch: "Tin tôi đi, tôi biết, những gì tôi đang làm".


Một mặt Lưu ý: Trong mã C++ bạn không cần struct từ khóa.

6

Vâng -Weverything cho phép khá nhiều cảnh báo một số người trong số họ được biết là ném cảnh báo không mong muốn.

Ở đây mã của bạn bắn các cast-align cảnh báo, nói rằng explicitely

đúc từ ... đến ... tăng đòi hỏi sự liên kết từ ... đến ...

Và nó là trường hợp ở đây bởi vì sự sắp xếp cho struct addr chỉ là 2 trong khi đó là 4 cho struct addr_in.

Nhưng bạn (và các lập trình viên cho getaddrinfo ...) biết rằng con trỏ p->ai_addr đã chỉ ra một thực tế struct addr_in, vì vậy các diễn viên là hợp lệ.

Bạn có thể:

  • để cho lửa cảnh báo và bỏ qua nó - sau khi tất cả nó chỉ là một cảnh báo ...
  • im lặng nó với -Wno-cast-align sau -Weverything

Tôi phải thừa nhận tôi hiếm khi sử dụng -Weverything vì lý do đó và chỉ sử dụng -Wall


.210

Ngoài ra, nếu bạn biết rằng bạn chỉ sử dụng Clang, bạn có thể sử dụng pragmas để explicetely biến cảnh báo chỉ vào những dòng:

for(p = res; p != NULL; p = p->ai_next) { 
    void *addr; 
    std::string ipVer = "IPv0"; 

#pragma clang diagnostic push 
#pragma clang diagnostic ignored "-Wcast-align" 

    if(p->ai_family == AF_INET) { 
     ipVer     = "IPv4"; 
     struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr; 
     addr      = &(ipv4->sin_addr); 
    } 

    else { 
     ipVer      = "IPv6"; 
     struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr; 
     addr      = &(ipv6->sin6_addr); 
    } 
#pragma clang diagnostic pop 

.... 
} 
1

Để xây dựng trên phiên bản memcpy. Tôi thnk này là cần thiết cho ARM mà không thể có dữ liệu misalligned.

Tôi tạo ra một cấu trúc có chứa chỉ là hai lĩnh vực đầu tiên (tôi chỉ cổng cần thiết)

struct sockaddr_in_header { 
    sa_family_t sin_family; /* address family: AF_INET */ 
    in_port_t  sin_port; /* port in network byte order */ 
}; 

Sau đó, để có được những cổng ra, tôi đã sử dụng memcpy để di chuyển dữ liệu vào ngăn xếp

struct sockaddr_in_header sinh; 
unsigned short    sin_port; 

memcpy(&sinh, conn->local_sockaddr, sizeof(struct sockaddr_in_header)); 

Và trả lại cảng

sin_port = ntohs(sinh.sin_port); 

Câu trả lời này là thực sự liên quan đến việc các cổng trên Arm

How do I cast sockaddr pointer to sockaddr_in on Arm

Những kẻ cầm quyền được nghĩ là cùng một câu hỏi như thế này, tuy nhiên tôi không muốn bỏ qua cảnh báo. Kinh nghiệm đã dạy tôi rằng đó là một ý tưởng tồi.

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