Tập tin định nghĩa lại C ++ (wonock2.h)


142

Làm cách nào để ngăn chặn bao gồm các tệp tiêu đề hai lần? Vấn đề là tôi bao gồmtrong MyClass.h và sau đó tôi bao gồm MyClass.h trong nhiều tệp, do đó, nó bao gồm nhiều lần và xảy ra lỗi xác định lại. Làm thế nào để ngăn chặn?

Tôi đang sử dụng #pragma một lần thay vì bao gồm các vệ sĩ và tôi đoán điều đó tốt.

MyClass.h:

// MyClass.h
#pragma once

#include <winsock2.h>

class MyClass
{

// methods
public:
 MyClass(unsigned short port);
 virtual ~MyClass(void);
};

EDIT: Một vài lỗi tôi đang mắc phải

c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(91) : warning C4005: 'AF_IPX' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(460) : see previous definition of 'AF_IPX'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(124) : warning C4005: 'AF_MAX' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(479) : see previous definition of 'AF_MAX'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(163) : warning C4005: 'SO_DONTLINGER' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(402) : see previous definition of 'SO_DONTLINGER'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(206) : error C2011: 'sockaddr' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(485) : see declaration of 'sockaddr'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(384) : error C2143: syntax error : missing '}' before 'constant'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(384) : error C2143: syntax error : missing ';' before 'constant'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(384) : error C2059: syntax error : 'constant'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(437) : error C2143: syntax error : missing ';' before '}'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(437) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(437) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(518) : warning C4005: 'IN_CLASSA' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(287) : see previous definition of 'IN_CLASSA'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(524) : warning C4005: 'IN_CLASSB' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(293) : see previous definition of 'IN_CLASSB'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(530) : warning C4005: 'IN_CLASSC' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(299) : see previous definition of 'IN_CLASSC'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(541) : warning C4005: 'INADDR_ANY' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(304) : see previous definition of 'INADDR_ANY'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(543) : warning C4005: 'INADDR_BROADCAST' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(306) : see previous definition of 'INADDR_BROADCAST'
c:\program files\microsoft sdks\windows\v6.0a\include\ws2def.h(577) : error C2011: 'sockaddr_in' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(312) : see declaration of 'sockaddr_in'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(132) : error C2011: 'fd_set' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(68) : see declaration of 'fd_set'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(167) : warning C4005: 'FD_SET' : macro redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(102) : see previous definition of 'FD_SET'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(176) : error C2011: 'timeval' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(111) : see declaration of 'timeval'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(232) : error C2011: 'hostent' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(167) : see declaration of 'hostent'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(245) : error C2011: 'netent' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(180) : see declaration of 'netent'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(252) : error C2011: 'servent' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(187) : see declaration of 'servent'
c:\program files\microsoft sdks\windows\v6.0a\include\winsock2.h(264) : error C2011: 'protoent' : 'struct' type redefinition
        c:\program files\microsoft sdks\windows\v6.0a\include\winsock.h(199) : see declaration of 'protoent'

4
Bạn đã sử dụng #pragma một lần, vì vậy chỉ nên đưa vào một lần.
Naveen

1
Trình biên dịch của bạn không hỗ trợ pragma một lần?
Svetlozar Angelov

Tôi đang sử dụng Visual Studio 2008, tại sao sau đó <wonock2.h> được bao gồm hai lần?
akif

1
Nó có thể được bao gồm hai lần từ một số tiêu đề được bao gồm từ MyClass.h
Svetlozar Angelov

5
winock2 và winock có cấu trúc chung. Bạn phải bao gồm chỉ một trong số họ, không phải cả hai
Svetlozar Angelov

Câu trả lời:


233

Vấn đề này được gây ra khi bao gồm cả <windows.h>trước đây <winsock2.h>. Hãy thử sắp xếp danh sách bao gồm của bạn <windows.h>được bao gồm sau <winsock2.h>hoặc xác định _WINSOCKAPI_trước:

#define _WINSOCKAPI_    // stops windows.h including winsock.h
#include <windows.h>
// ...
#include "MyClass.h"    // Which includes <winsock2.h>

Xem thêm này .


Tôi hoàn toàn không bao gồm <windows.h>, tôi biết <wonock2.h> làm điều đó cho tôi.
akif

2
Đối với tôi mã của bạn biên dịch ok chỉ với <winsock2.h>MSVC2008. <windows.h>bao gồm làm cho nó tạo ra các lỗi biên dịch giống hệt như bạn cung cấp.
pingw33n

<Windows.h> có được bao gồm trong stdafx.h không?
Colin Desmond

1
Giải pháp này đã khắc phục sự cố cho tôi trên VS 2010 với SDK 7.1. Cảm ơn pingw33n!
adamfisk

Tôi đã có #include <winsock2.h> #include <ws2tcpip.h> #include <windows.h>thứ tự và đã nhận được winock2, không tìm thấy tập tin h. Bao gồm #define _WINSOCKAPI_ trên cả 3 vẫn bao gồm cùng một lỗi
Ava

75

Như những người khác đề xuất, vấn đề là khi windows.hđược đưa vào trước WinSock2.h. Bởi vì windows.hbao gồm winsock.h. Bạn không thể sử dụng cả hai WinSock2.hwinsock.h.

Các giải pháp:

  • Bao gồm WinSock2.htrước windows.h. Trong trường hợp các tiêu đề được biên dịch trước, bạn nên giải quyết nó ở đó. Trong trường hợp của dự án đơn giản, nó là dễ dàng. Tuy nhiên, trong các dự án lớn (đặc biệt là khi viết mã di động, không có tiêu đề được biên dịch trước) có thể rất khó, bởi vì khi tiêu đề của bạn WinSock2.hđược bao gồm, windows.hcó thể đã được bao gồm từ một số tệp tiêu đề / thực hiện khác.

  • Xác định WIN32_LEAN_AND_MEANtrước windows.hhoặc dự án rộng. Nhưng nó sẽ loại trừ nhiều thứ khác mà bạn có thể cần và bạn nên tự đưa nó vào.

  • Xác định _WINSOCKAPI_trước windows.hhoặc dự án rộng. Nhưng khi bạn bao gồm WinSock2.hbạn nhận được cảnh báo xác định lại vĩ mô.

  • Sử dụng windows.hthay vì WinSock2.hkhi nào winsock.hlà đủ cho dự án của bạn (trong hầu hết các trường hợp là như vậy). Điều này có thể sẽ dẫn đến thời gian biên dịch dài hơn nhưng giải quyết bất kỳ lỗi / cảnh báo.


14
WIN32_LEAN_AND_MEANlà giải pháp cho tôi rất nhiều xe tăng
Jonatan Cloutier

Về _WINSOCK_giải pháp: Bạn không nên cảnh báo xác định lại macro nếu cả hai định nghĩa giống hệt nhau. Lỗi phổ biến là mọi người thêm định nghĩa vào dự án mà không đặt bất kỳ giá trị nào và mong đợi định nghĩa trống. Tuy nhiên, nếu bạn thêm -D_WINSOCK_vào dòng cmd, nó sẽ được đặt _WINSOCK_thành 1. Để tạo định nghĩa trống, -D_WINSOCK_=phải được thông qua.
Paweł Stankowski

Nếu bạn sử dụng #define _WINSOCKAPI_, bạn cũng có thể cần #define _WINSOCK_DEPRECATED_NO_WARNINGS, tùy thuộc vào hoàn cảnh của bạn.
Lorien Brunei

16

Ôi - sự xấu xí của Windows ... Thứ tự bao gồm rất quan trọng ở đây. Bạn cần bao gồm winock2.h trước windows.h. Vì windows.h có thể được bao gồm từ tiêu đề được biên dịch trước của bạn (stdafx.h), nên bạn sẽ cần phải bao gồm winock2.h từ đó:

#include <winsock2.h>
#include <windows.h>

14

Bằng cách sử dụng "tiêu đề bảo vệ":

#ifndef MYCLASS_H
#define MYCLASS_H

// This is unnecessary, see comments.
//#pragma once

// MyClass.h

#include <winsock2.h>

class MyClass
{

// methods
public:
    MyClass(unsigned short port);
    virtual ~MyClass(void);
};

#endif

2
Tôi đoán rằng tôi đã sai (4 upvote cho đến bây giờ), nhưng tôi nghĩ rằng sử dụng bao gồm các vệ sĩ cũng giống như pragma một lần, bạn đặt cả hai?
Svetlozar Angelov

1
Chà, tôi đã có #pragma một lần mà afaik là những người bảo vệ tiêu đề tương tự
akif

2
@Angelov: Vâng, đó là những gì tôi đang nói họ là những thứ giống nhau. Vấn đề không nằm ở các tệp tiêu đề của tôi, nhưng tôi nghĩ bản thân <wonock2.h> không có bộ bảo vệ tiêu đề hoặc có thể là một cái gì đó khác.
akif

1
Theo định nghĩa #pragma là phụ thuộc vào trình biên dịch (không chuẩn). Nó có thể không hoạt động trên tất cả các trình biên dịch. Tôi biết rằng studio hình ảnh chấp nhận #pargma một lần. Tôi không chắc chắn nếu gcc làm. Tôi biết rằng bao gồm các vệ sĩ LUÔN LUÔN làm việc. Tôi sử dụng cả #pragma một lần và bao gồm các vệ sĩ để có khả năng chống đỡ tối đa. Có vẻ như MSVC đã tối ưu hóa việc xử lý #pragma một lần và gcc đã tối ưu hóa việc xử lý bao gồm các vệ sĩ. Sự khác biệt duy nhất với tiêu đề tiêu chuẩn của tôi là #praga một lần nằm ngoài các vệ sĩ bao gồm.
KitsuneYMG

1
Lệnh '#pragma' được chỉ định trong tiêu chuẩn ANSI để có hiệu ứng được xác định do triển khai tùy ý. Trong bộ tiền xử lý GNU C, '#pragma' lần đầu tiên thử chạy trò chơi 'lừa đảo'; nếu thất bại, nó cố chạy trò chơi 'hack'; nếu thất bại, nó cố chạy GNU Emacs hiển thị Tháp Hà Nội; nếu thất bại, nó báo lỗi nghiêm trọng Trong mọi trường hợp, tiền xử lý không tiếp tục. - Richard M. Stallman, Bộ tiền xử lý GNU C, phiên bản 1.34
DevSolar

6

Tôi gặp phải vấn đề này khi cố gắng kéo gói bên thứ ba rõ ràng bao gồm cả windows. Ở đâu đó trong mớ hỗn độn của tiêu đề. Xác định _WINSOCKAPI_ở cấp độ dự án dễ dàng hơn nhiều (chưa kể có thể bảo trì nhiều hơn) so với lội qua súp của họ và khắc phục vấn đề bao gồm.


1
Trên Qt, trong tệp .pro, nó trông như thế này: DEFINES += _WINSOCKAPI_
phyatt

@phyatt: bạn nên biến câu trả lời thành câu trả lời, nếu không tôi sẽ làm thế!
Leif Gruenwoldt

@LeifGruenwoldt đi cho nó! Rất vui vì tôi có thể giúp.
phyatt 5/2/2015

6

Trong VS 2015, những điều sau đây sẽ hoạt động:

#define _WINSOCKAPI_

Trong khi sau đây sẽ không:

#define WIN32_LEAN_AND_MEAN

6

Tôi đã kiểm tra đệ quy bao gồm, tôi phát hiện các tập tin tiêu đề bao gồm (đệ quy) một số #include "windows.h"#include "Winsock.h"và viết #include "Winsock2.h". trong tập tin này, tôi đã thêm vào #include "Winsock2.h"như là bao gồm đầu tiên.

Chỉ là vấn đề kiên nhẫn, nhìn vào bao gồm từng cái một và thiết lập trật tự này, trước tiên #include "Winsock2.h"sau đó#include "windows.h"


5

Tôi đã tìm thấy liên kết này windows.h và wonock2.h có một sự thay thế phù hợp với tôi:

#define _WINSOCKAPI_    // stops windows.h including winsock.h
#include <windows.h>
#include <winsock2.h>

Tôi đã gặp khó khăn khi tìm kiếm sự cố xảy ra ở đâu nhưng bằng cách thêm #define đó, tôi đã có thể xây dựng mà không tìm ra vấn đề.


4

Tôi sẽ không sử dụng chỉ FILENAME_H nhưng

#ifndef FILENAME_H_AF06570D_B36E_4B82_8F97_C456AF4A38FD
#define FILENAME_H_AF06570D_B36E_4B82_8F97_C456AF4A38FD

//code stuff
#endif // FILENAME_H_AF06570D_B36E_4B82_8F97_C456AF4A38FD

Tôi đã luôn luôn sử dụng một hướng dẫn postfix. Tôi đã bắt gặp một cơ sở mã rất kém cách đây vài năm có các tệp tiêu đề khác nhau có cùng tên tệp và bao gồm bảo vệ. Các tập tin trong câu hỏi đã định nghĩa một lớp có cùng tên. Nếu chỉ có không gian tên được sử dụng. Một số dự án biên dịch một số không. Sử dụng các vệ sĩ độc đáo là một phần của giải pháp trong việc phân biệt các tiêu đề và nội dung của chúng.

Trên Windows với Visual Studio, hãy sử dụng guidegen.exe, trên Linux uuidgen -t.


4

Tôi đã gặp vấn đề tương tự và đây là những gì tôi đã phát hiện ra cho đến nay:

Từ đoạn đầu ra này -

c: \ chương trình tập tin \ microsoft sdks \ windows \ v6.0a \ include \ ws2def.h (91): cảnh báo C4005: 'AF_IPX': xác định lại macro
c: \ tệp chương trình \ microsoft sdks \ windows \ v6.0a \ include \ wonock.h (460): xem định nghĩa trước của 'AF_IPX'

-Có vẻ như cả ws2def.h và wonock.h đã được đưa vào giải pháp của bạn.

Nếu bạn nhìn vào tệp ws2def.h, nó bắt đầu bằng nhận xét sau -

/*++

Copyright (c) Microsoft Corporation. All rights reserved.

Module Name:

    ws2def.h

Abstract:

    This file contains the core definitions for the Winsock2
    specification that can be used by both user-mode and 
    kernel mode modules.

    This file is included in WINSOCK2.H. User mode applications
    should include WINSOCK2.H rather than including this file
    directly. This file can not be included by a module that also
    includes WINSOCK.H.

Environment:

    user mode or kernel mode

--*/

Hãy chú ý đến dòng cuối cùng - "Không thể bao gồm tệp này bởi một mô-đun cũng bao gồm WINSOCK.H"

Vẫn đang cố gắng khắc phục vấn đề mà không thực hiện thay đổi mã.

Hãy cho tôi biết nếu điều này có ý nghĩa.


2

Bạn nên sử dụng bảo vệ tiêu đề.

đặt những dòng đó ở đầu tập tin tiêu đề

#ifndef PATH_FILENAME_H
#define PATH_FILENAME_H

và ở phía dưới

#endif

1
#pragma một lần và bao gồm các vệ sĩ là những thứ giống nhau phải không?
akif

Chúng không hoàn toàn giống nhau - các bộ bảo vệ tiêu đề sẽ ngăn việc đưa lại tệp vào cấp độ tiền xử lý, cộng với việc chúng rõ ràng là dễ mang theo hơn so với #pragma một lần.
Timo Geusch

1
Tôi có nghĩa là chúng được xây dựng cho cùng một mục đích :)
akif

2
#pragma một lần là không chuẩn, afaik
ntcong

2

#pragma onceđược dựa trên đường dẫn đầy đủ của tên tệp. Vì vậy, những gì bạn có thể có là có hai bản sao giống nhau của MyClass.h hoặc Winsock2.h trong các thư mục khác nhau.


một liên kết tượng trưng hoặc ngã ba NTFS cũng sẽ khiến hệ thống bị hỏng.
Thomi

1

#pragma oncelà hoàn hảo, ngay cả trên trình biên dịch MS và không được hỗ trợ bởi nhiều trình biên dịch khác. Như nhiều người khác đã đề cập, sử dụng bao gồm các vệ sĩ là cách để đi. Đừng sử dụng #pragma oncetất cả - nó sẽ làm cho cuộc sống của bạn dễ dàng hơn nhiều.


3
Thật không may, tôi đã thấy nhiều hơn 0 bị lừa bao gồm các bộ bảo vệ, trong đó một lỗi chính tả có nghĩa là bộ bảo vệ không thực sự hoạt động hoặc khi các tệp cùng tên trong các thư mục khác nhau sử dụng cùng một mã thông báo hoặc khi mã thông báo được sử dụng bắt đầu bằng một đôi gạch dưới hoặc gạch dưới sau đó viết hoa (và do đó không thể mang theo giống như #pragma một lần). Vì vậy, đối với mã vốn không có khả năng di động, giống như bất kỳ thứ gì sử dụng winock.h, tôi đã vô cùng bối rối bởi #pragma một lần cho đến khi bạn nói rằng nó không ổn định. Khi nào nó thất bại, ngoài việc không được hỗ trợ?
Steve Jessop

3
Khi sử dụng #pragma once, trình biên dịch sẽ lấy tên nút tệp tiêu đề làm Id duy nhất. Điều này có thể thất bại nếu bạn có các liên kết tượng trưng hoặc các mối nối NTFS trong cây nguồn của bạn (phổ biến hơn bạn nghĩ) hoặc ngay cả khi bạn có một tệp cùng tên trong một hệ thống khác bao gồm thư mục (điều này đã xảy ra với tôi trước đây khi tôi có phiên bản 1 và phiên bản 2 của cùng một thư viện được cài đặt cho hai hệ thống khác nhau bao gồm các đường dẫn). Điểm mấu chốt: đối với tôi, tôi thích có nhiều quyền kiểm soát hơn và sống với lỗi thỉnh thoảng đi đường hơn là tin tưởng vào một trình biên dịch để làm điều đó cho tôi.
Thomi


1

Trong dự án của tôi (tôi sử dụng VS 2008 SP1) hoạt động giải pháp tiếp theo:

Tập tin tiêu đề:

//myclass.h
#pragma once
#define _WINSOCKAPI_
#include <windows.h>

Lớp Cpp:

//myclass.cpp
#include "Util.h"
#include "winsock2class.h"
#pragma comment(lib, "Ws2_32.lib")

trong đó #include "wonock2group.h" có nghĩa là lớp đã triển khai wonock2.h:

//winsock2class.h
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib, "Ws2_32.lib")

0

Tôi thực sự gặp phải một vấn đề trong đó tôi phải xác định winock2.h là bao gồm đầu tiên, có vẻ như nó có các vấn đề khác với bao gồm từ các gói khác. Hy vọng điều này hữu ích cho ai đó gặp phải vấn đề tương tự, không chỉ windows.h mà tất cả bao gồm.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.