File Header Redefinisi C ++ (winsock2.h)

143

Bagaimana saya mencegah memasukkan file header dua kali? Masalahnya adalah saya termasukdi MyClass.h dan kemudian saya termasuk MyClass.h dalam banyak file, jadi itu termasuk beberapa kali dan terjadi redefinisi kesalahan. Bagaimana cara mencegahnya?

Saya menggunakan #pragma sekali alih-alih menyertakan penjaga, dan saya kira itu tidak masalah.

MyClass.h:

// MyClass.h
#pragma once

#include <winsock2.h>

class MyClass
{

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

EDIT: Beberapa kesalahan yang saya dapatkan

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'
akif
sumber
4
Anda sudah menggunakan #pragma sekali, jadi itu harus dimasukkan hanya sekali.
Naveen
1
Kompiler Anda tidak mendukung pragma sekali?
Svetlozar Angelov
Saya menggunakan Visual Studio 2008, mengapa kemudian <winsock2.h> dimasukkan dua kali?
akif
1
Mungkin disertakan dua kali dari beberapa header yang disertakan dari
MyClass.h
5
winsock2 dan winsock memiliki struktur yang sama. Anda harus memasukkan hanya salah satu dari mereka, bukan keduanya
Svetlozar Angelov

Jawaban:

234

Masalah ini disebabkan ketika termasuk <windows.h>sebelumnya <winsock2.h>. Coba atur daftar sertakan Anda yang <windows.h>disertakan setelah <winsock2.h>atau tetapkan _WINSOCKAPI_dulu:

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

Lihat juga ini .

pingw33n
sumber
Saya tidak termasuk <windows.h> sama sekali, saya tahu <winsock2.h> melakukannya untuk saya.
akif
2
Bagi saya kompilasi kode Anda ok dengan hanya <winsock2.h>di MSVC2008. <windows.h>inklusi membuatnya menghasilkan kesalahan kompilasi yang sama seperti yang Anda berikan.
pingw33n
Apakah <windows.h> dimasukkan dalam stdafx.h?
Colin Desmond
1
Solusi ini memperbaiki masalah saya di VS 2010 dengan SDK 7.1. Terima kasih pingw33n!
adamfisk
Saya telah #include <winsock2.h> #include <ws2tcpip.h> #include <windows.h>dalam rangka dan mendapatkan winsock2, file h tidak ditemukan. Termasuk di #define _WINSOCKAPI_ atas semua 3 termasuk masih kesalahan yang sama
Ava
75

Seperti yang disarankan orang lain, masalahnya adalah kapan windows.hdimasukkan sebelumnya WinSock2.h. Karena windows.htermasuk winsock.h. Anda tidak dapat menggunakan keduanya WinSock2.hdan winsock.h.

Solusi:

  • Sertakan WinSock2.hsebelumnya windows.h. Dalam kasus tajuk yang dikompilasi, Anda harus menyelesaikannya di sana. Dalam kasus proyek sederhana, itu mudah. Namun dalam proyek-proyek besar (terutama ketika menulis kode portabel, tanpa header yang dikompilasi) itu bisa sangat sulit, karena ketika header Anda WinSock2.hdisertakan, windows.hdapat sudah disertakan dari beberapa header lain / file implementasi.

  • Tentukan WIN32_LEAN_AND_MEANsebelum windows.hatau luas proyek. Tapi itu akan mengecualikan banyak hal lain yang mungkin Anda butuhkan dan Anda harus memasukkannya sendiri.

  • Tentukan _WINSOCKAPI_sebelum windows.hatau luas proyek. Tetapi ketika Anda termasuk WinSock2.hAnda mendapatkan peringatan redefinisi makro.

  • Gunakan windows.halih-alih WinSock2.hkapan winsock.hcukup untuk proyek Anda (dalam banyak kasus itu). Ini mungkin akan menghasilkan waktu kompilasi yang lebih lama tetapi menyelesaikan kesalahan / peringatan.

Pavel Machyniak
sumber
14
WIN32_LEAN_AND_MEANadalah solusi bagi saya banyak tank
Jonatan Cloutier
Tentang _WINSOCK_solusi: Anda tidak boleh grt peringatan redefinisi makro jika kedua definisi sama. Bug umum adalah bahwa orang menambahkan definisi ke proyek tanpa menetapkan nilai apa pun dan mengharapkan definisi kosong. Namun, jika Anda menambahkan -D_WINSOCK_ke baris cmd, itu akan diatur _WINSOCK_ke 1. Untuk membuat definisi kosong, -D_WINSOCK_=harus diteruskan.
Paweł Stankowski
Jika Anda menggunakan #define _WINSOCKAPI_, Anda mungkin juga perlu #define _WINSOCK_DEPRECATED_NO_WARNINGS, tergantung pada keadaan Anda.
Lorien Brune
16

Oh - keburukan Windows ... Urutan termasuk penting di sini. Anda harus memasukkan winsock2.h sebelum windows.h. Karena windows.h mungkin disertakan dari tajuk yang sudah dikompilasi sebelumnya (stdafx.h), Anda harus menyertakan winsock2.h dari sana:

#include <winsock2.h>
#include <windows.h>
Daniel Paull
sumber
14

Dengan menggunakan "penjaga tajuk":

#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
DevSolar
sumber
2
Saya kira saya salah (4 suara sekarang), tapi saya pikir menggunakan penjaga termasuk sama dengan pragma sekali, Anda menempatkan keduanya?
Svetlozar Angelov
1
Yah, aku punya #pragma sekali yang afaik adalah penjaga tajuk yang sama
akif
2
@Ngelov: Ya, itulah yang saya katakan mereka adalah hal yang sama. Masalahnya bukan pada file header saya, tapi saya pikir <winsock2.h> itu sendiri tidak memiliki penjaga header atau mungkin sesuatu yang lain.
akif
1
Menurut definisi #pragma bergantung pada kompiler (non-standar). Ini mungkin tidak bekerja pada semua kompiler. Saya tahu bahwa studio visual menerima #pargma sekali. Saya tidak yakin apakah gcc melakukannya. Saya tahu itu termasuk penjaga SELALU bekerja. Saya menggunakan #pragma sekaligus dan menyertakan penjaga untuk perlindungan maksimal. Tampaknya MSVC telah mengoptimalkan penanganan #pragma sekali dan gcc telah mengoptimalkan penanganan termasuk penjaga. Satu-satunya perbedaan dengan header standar saya adalah bahwa #praga dulunya berada di luar penjaga sertakan.
KitsuneYMG
1
Perintah '#pragma' ditentukan dalam standar ANSI untuk memiliki efek yang ditentukan oleh implementasi arbitrer. Di preprocessor GNU C, '#pragma' pertama kali mencoba menjalankan game 'nakal'; jika itu gagal, ia mencoba menjalankan permainan 'retas'; jika gagal, ia mencoba menjalankan GNU Emacs yang menampilkan Menara Hanoi; jika gagal, ini melaporkan kesalahan fatal. Bagaimanapun, preprocessing tidak berlanjut. - Richard M. Stallman, The GNU C Preprocessor, versi 1.34
DevSolar
6

Saya mengalami masalah ini ketika mencoba menarik paket pihak ketiga yang ternyata termasuk windows.h di suatu tempat di dalamnya berantakan header. Mendefinisikan _WINSOCKAPI_di tingkat proyek jauh lebih mudah (belum lagi lebih dapat dipelihara) daripada mengarungi sup mereka dan memperbaiki termasuk yang bermasalah.

Yaur
sumber
1
Pada Qt, dalam file .pro, terlihat seperti ini: DEFINES += _WINSOCKAPI_
phyatt
@ phyatt: Anda harus mengubahnya menjadi jawaban, jika tidak, saya akan melakukannya!
Leif Gruenwoldt
@LeifGruenwoldt melakukannya! Senang saya bisa membantu.
phyatt
6

Dalam VS 2015, yang berikut ini akan berfungsi:

#define _WINSOCKAPI_

Sementara yang berikut tidak akan:

#define WIN32_LEAN_AND_MEAN
MariuszW
sumber
6

Aku memeriksa rekursif meliputi, aku melihat file header yang meliputi (rekursif) beberapa #include "windows.h"dan #include "Winsock.h"dan menulis #include "Winsock2.h". dalam file ini, saya menambahkan #include "Winsock2.h"sebagai yang pertama termasuk.

Hanya masalah kesabaran, lihat termasuk satu per satu dan tentukan urutan ini, pertama #include "Winsock2.h"kemudian#include "windows.h"

Kiriloff
sumber
5

Saya menemukan tautan ini windows.h dan winsock2.h yang memiliki alternatif yang bekerja sangat baik bagi saya:

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

Saya mengalami kesulitan menemukan di mana masalah terjadi tetapi dengan menambahkan bahwa #define saya dapat membangun tanpa mencari tahu.

Benjamin Herreid
sumber
4

Saya tidak akan menggunakan FILENAME_H saja tetapi

#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

Saya selalu menggunakan panduan postfix. Saya menemukan basis kode yang sangat buruk beberapa tahun yang lalu yang memiliki file header yang berbeda dengan nama file yang sama dan termasuk penjaga. File-file tersebut telah mendefinisikan kelas dengan nama yang sama. Jika hanya ruang nama yang digunakan. Beberapa proyek yang dikompilasi tidak. Menggunakan penjaga unik adalah bagian dari solusi dalam membedakan header dan isinya.

Pada Windows dengan Visual Studio gunakan guidgen.exe, di Linux uuidgen -t.

Sam
sumber
4

Saya telah mengalami masalah yang sama dan inilah yang saya temukan sejauh ini:

Dari fragmen output ini -

c: \ program file \ microsoft sdks \ windows \ v6.0a \ include \ ws2def.h (91): peringatan C4005: 'AF_IPX': redefinisi makro
c: \ program file \ microsoft sdks \ windows \ v6.0a \ include \ winsock.h (460): lihat definisi sebelumnya tentang 'AF_IPX'

-Tampak bahwa ws2def.h dan winsock.h telah dimasukkan dalam solusi Anda.

Jika Anda melihat file ws2def.h ini dimulai dengan komentar berikut -

/*++

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

--*/

Perhatikan baris terakhir - "File ini tidak bisa dimasukkan oleh modul yang juga termasuk WINSOCK.H"

Masih berusaha memperbaiki masalah tanpa membuat perubahan pada kode.

Beri tahu saya jika ini masuk akal.

Shailesh Tainwala
sumber
2

Anda harus menggunakan pelindung tajuk.

letakkan baris itu di bagian atas file header

#ifndef PATH_FILENAME_H
#define PATH_FILENAME_H

dan di bagian bawah

#endif
ntcong
sumber
1
#pragma sekali dan menyertakan penjaga adalah hal yang sama bukan?
akif
Mereka tidak persis sama - penjaga tajuk akan mencegah penyertaan kembali file pada tingkat preprocessor, ditambah mereka jelas sedikit lebih portabel daripada #pragma sekali.
Timo Geusch
1
Aku berarti mereka dibangun untuk tujuan yang sama :)
akif
2
#pragma once adalah non-standar, afaik
ntcong
2

#pragma oncedidasarkan pada path lengkap dari nama file. Jadi yang mungkin Anda miliki adalah ada dua salinan identik dari MyClass.h atau Winsock2.h di direktori yang berbeda.

soru
sumber
tautan simbolik atau persimpangan NTFS juga akan menyebabkan sistem rusak.
Thomi
1

#pragma onceflakey, bahkan pada kompiler MS, dan tidak didukung oleh banyak kompiler lain. Seperti banyak orang lain telah menyebutkan, menggunakan penjaga termasuk adalah cara untuk pergi. Jangan gunakan #pragma oncesama sekali - itu akan membuat hidup Anda lebih mudah.

Thomi
sumber
3
Sayangnya, saya telah melihat lebih dari nol yang gagal termasuk penjaga, baik di mana kesalahan ketik berarti penjaga tidak benar-benar bekerja, atau di mana file dengan nama yang sama di direktori yang berbeda menggunakan token yang sama, atau di mana token yang digunakan dimulai dengan double. menggarisbawahi atau menggarisbawahi maka huruf kapital (dan karenanya non-portabel seperti #pragma sekali). Jadi untuk kode non-portabel yang inheren, seperti apa pun yang menggunakan winsock.h, saya sangat tidak terganggu oleh #pragma sekali sampai pada titik yang Anda katakan itu flakey. Kapan itu gagal, selain tidak didukung sama sekali?
Steve Jessop
3
Saat menggunakan #pragma once, kompiler mengambil nama simpul file header sebagai Id unik. Ini bisa gagal jika Anda memiliki tautan simbolis atau persimpangan NTFS di pohon sumber Anda (lebih umum daripada yang Anda kira), atau bahkan jika Anda memiliki file dengan nama yang sama di sistem lain termasuk direktori (ini telah terjadi pada saya sebelumnya ketika saya memiliki versi 1 dan versi 2 dari perpustakaan yang sama diinstal ke dua sistem yang berbeda termasuk jalur). Intinya: bagi saya, saya lebih suka memiliki kontrol lebih, dan hidup dengan kesalahan wetware sesekali, daripada percaya kompiler untuk melakukannya untuk saya.
Thomi
1

#sertakan penjaga adalah cara standar untuk melakukan ini. #pragma sekali tidak, artinya tidak semua kompiler mendukungnya.

Dima
sumber
1

Dalam proyek saya (saya menggunakan VS 2008 SP1) bekerja solusi berikut:

File tajuk:

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

Kelas Cpp:

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

di mana #include "winsock2class.h" kelas rata-rata yang menerapkan winsock2.h:

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

Saya benar-benar mengalami masalah di mana saya harus mendefinisikan winsock2.h sebagai termasuk pertama, tampaknya memiliki masalah lain dengan menyertakan dari paket lain. Semoga ini bermanfaat bagi seseorang yang mengalami masalah yang sama, tidak hanya windows.h tetapi semua termasuk.

Jeff
sumber