C ++ Yeniden Tanımlama Başlık Dosyaları (winsock2.h)


143

Başlık dosyalarının iki kez eklenmesini nasıl önleyebilirim? Sorun şu ki ben dahiliçinde MyClass.h ve sonra da dahil ediyorum MyClass.h birden çok kez içermektedir ve yeniden tanımlanması hata oluşur, böylece birçok dosyalarda. Nasıl önlenir?

Ben korumaları yerine #pragma bir kez kullanıyorum ve sanırım bu iyi.

MyClass.h:

// MyClass.h
#pragma once

#include <winsock2.h>

class MyClass
{

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

EDIT: Aldığım hataların birkaçı

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
Zaten #pragma'yı bir kez kullanıyorsunuz, bu yüzden sadece bir kez dahil edilmelidir.
Naveen

1
Derleyiciniz pragmayı bir kez desteklemiyor mu?
Svetlozar Angelov

Visual Studio 2008 kullanıyorum, neden <winsock2.h> iki kez dahil edilir?
akif

1
Bu, MyClass.h
Svetlozar Angelov

5
winsock2 ve winsock ortak yapılara sahiptir.
İkisini

Yanıtlar:


234

Bu sorun, daha <windows.h>önce dahil edildiğinde ortaya çıkar <winsock2.h>. Listenize dahil düzenlemek deneyin <windows.h>sonra dahil edilir <winsock2.h>ya da tanımlamak _WINSOCKAPI_ilk:

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

Ayrıca bkz bu .


Hiç <windows.h> eklemiyorum, biliyorum <winsock2.h> bunu benim için yapıyor.
akif

2
Benim için kod sadece <winsock2.h>MSVC2008 ile tamam derler . <windows.h>içerme, sağladığınız gibi derleme hataları oluşturmasını sağlar.
pingw33n

<Windows.h>, stdafx.h dosyasına dahil ediliyor mu?
Colin Desmond

1
Bu çözüm, SDK 7.1 ile VS 2010'da benim için sorunu düzeltti. Teşekkürler pingw33n!
adamfisk

Ben #include <winsock2.h> #include <ws2tcpip.h> #include <windows.h>sırayla vardı ve winsock2 alıyordum, h dosyası bulunamadı. Her #define _WINSOCKAPI_ şeyden önce 3 hala aynı hatayı içerir
Ava

75

Diğerlerinin önerdiği gibi, sorun daha windows.hönce ne zaman dahil edildiğidir WinSock2.h. Çünkü windows.hiçerir winsock.h. Her iki kullanamazsınız WinSock2.hve winsock.h.

Çözümler:

  • WinSock2.hÖnce ekleyin windows.h. Önceden derlenmiş başlıklar söz konusu olduğunda, bunu orada çözmelisiniz. Basit bir proje söz konusu olduğunda kolaydır. Bununla birlikte, büyük projelerde (özellikle önceden derlenmiş üstbilgiler olmadan taşınabilir kod yazarken) çok zor olabilir, çünkü üstbilginiz WinSock2.hdahil edildiğinde, windows.hbaşka bir üstbilgi / uygulama dosyasından zaten dahil edilebilir.

  • WIN32_LEAN_AND_MEANÖnceden tanımlayın windows.hveya geniş çapta yansıtın. Ancak ihtiyacınız olabilecek diğer birçok şeyi hariç tutacaktır ve bunu kendi başınıza eklemeniz gerekir.

  • _WINSOCKAPI_Önceden tanımlayın windows.hveya geniş çapta yansıtın. Ancak eklediğinizde WinSock2.hmakro yeniden tanımlama uyarısı alırsınız.

  • Projeniz için ne zaman yeterli olduğu windows.hyerine kullanın (çoğu durumda). Bu muhtemelen daha uzun derleme süresine neden olur, ancak hataları / uyarıları çözer.WinSock2.hwinsock.h


14
WIN32_LEAN_AND_MEANbenim için çözüm çok
tanktı

Hakkında _WINSOCK_çözümü: Her iki tanımlamalar aynıysa Makro yeniden tanımlanması uyarısı grt olmamalıdır. Yaygın hata, insanların herhangi bir değer ayarlamadan projeye tanım eklemeleri ve boş tanım beklemeleri. Ancak, -D_WINSOCK_cmd satırına eklerseniz , _WINSOCK_1 olarak ayarlanır . Boş tanım oluşturmak -D_WINSOCK_=için iletilmelidir.
Paweł Stankowski

Kullanıyorsanız , koşullarınıza bağlı olarak #define _WINSOCKAPI_da ihtiyacınız olabilir #define _WINSOCK_DEPRECATED_NO_WARNINGS.
Lorien Brune

16

Oh - Windows'un çirkinliği ... İçerme sırası burada önemlidir. Windowss.h'dan önce winsock2.h eklemeniz gerekir. Windows.h muhtemelen önceden derlenmiş başlığınıza (stdafx.h) dahil olduğundan, oradan winsock2.h'yi eklemeniz gerekir:

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

14

"Başlık korumaları" kullanarak:

#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
Sanırım yanılıyorum (şimdiye kadar 4 oy), ama koruma görevlilerini kullanmak bir kez pragma ile aynı olduğunu düşünüyorum, ikisini de koyuyorsunuz?
Svetlozar Angelov

1
Eh, bir zamanlar afaik aynı başlık muhafızları olan #pragma var
akif

2
@Angelov: Evet, aynı şeyler olduklarını söylüyorum. Sorun benim başlık dosyaları ile değil, ama bence <winsock2.h> başlık korumaları yok ya da başka bir şey olabilir.
akif

1
Tanım gereği #pragma derleyiciye bağımlıdır (standart dışı). Tüm derleyicilerde çalışmayabilir. Visual studio'nun #pargma'yı bir kez kabul ettiğini biliyorum. Gcc'nin emin olup olmadığından emin değilim. Ben korumaları içerir biliyorum HER ZAMAN çalışır. Her iki #pragma'yı bir kez kullanıyorum ve maksimum protabilite için korumalar dahil ediyorum. Görünüşe göre MSVC, #pragma'nın bir kez işlenmesini optimize etti ve gcc, içerme korumalarının işlenmesini optimize etti. Standart başlığımdaki tek fark #praga'nın bir kez içerme korumalarının dışında olmasıdır.
KitsuneYMG

1
'#Pragma' komutu, ANSI standardında isteğe bağlı uygulama tanımlı bir etkiye sahip olacak şekilde belirtilmiştir. GNU C ön işlemcisinde, '#pragma' ilk önce 'haydut' oyununu çalıştırmaya çalışır; bu başarısız olursa, oyunu 'hack' çalıştırmaya çalışır; bu başarısız olursa, Hanoi Kulesi'ni gösteren GNU Emacs çalıştırmaya çalışır; bu başarısız olursa, önemli bir hata bildirir. Her durumda, ön işleme devam etmez. - Richard M. Stallman, GNU C Ön
İşlemcisi

7

Görünüşe göre üstbilgileri karışıklık içinde windows.h bir yere dahil bir üçüncü taraf paketi çekmeye çalışırken bu sorunla karşılaştım. _WINSOCKAPI_Proje düzeyinde tanımlamak , çorbalarında dolaşmaktan ve sorunlu içerme düzeltmekten çok daha kolaydı (daha sürdürülebilir değil).


1
Qt, DEFINES += _WINSOCKAPI_
.pro

@phyatt: Bunu bir cevaba dönüştürmelisin, eğer yapmazsam!
Leif Gruenwoldt

@LeifGruenwoldt bunun için git! Yardımcı olduğuma sevindim.
phyatt

6

VS 2015'te aşağıdakiler işe yarayacaktır:

#define _WINSOCKAPI_

Aşağıdakiler olmaz:

#define WIN32_LEAN_AND_MEAN

6

Ben (yinelemeli) dahil başlık dosyalarını benekli, özyinelemeli içerir kontrol bazı #include "windows.h"ve #include "Winsock.h"bir yazma #include "Winsock2.h". bu dosyalara ekledim#include "Winsock2.h" ilk dahil olarak .

Sadece bir sabır meselesi, teker teker içerir ve bu düzeni önce belirler, #include "Winsock2.h"sonra#include "windows.h"


5

Benim için harika çalışan bir alternatifi olan windowss.h ve winsock2.h bağlantılarını buldum :

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

Sorunun nerede meydana geldiğini bulmakta sorun yaşıyordum ama #define ekleyerek çözmeden yapmayı başardım.


4

Sadece FILENAME_H kullanmam ama

#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

Her zaman bir postfix kılavuzu kullandım. Birkaç yıl önce aynı dosya adına sahip farklı başlık dosyalarına sahip ve bekçi içeren çok kötü bir kod tabanıyla karşılaştım. Söz konusu dosyalar aynı ada sahip bir sınıf tanımlamıştı. Yalnızca ad alanları kullanılmış olsaydı. Bazı projeler derlenmiş, bazıları ise derlememiştir. Benzersiz korumalar kullanmak, üstbilgileri ve içeriklerini farklılaştırmada çözümün bir parçasıydı.

Visual Studio ile Windows'ta guugengen.exe, Linux uuidgen -t kullanın.


4

Aynı sorunla karşılaştım ve işte şimdiye kadar keşfettiğim şey:

Bu çıktı parçasından -

c: \ program dosyaları \ microsoft sdks \ windows \ v6.0a \ include \ ws2def.h (91): uyarı C4005: 'AF_IPX': makro yeniden tanımlama
c: \ program dosyaları \ microsoft sdks \ windows \ v6.0a \ include \ winsock.h (460): 'AF_IPX'in önceki tanımına bakın

- Görünüşe göre hem ws2def.h hem de winsock.h çözümünüze dahil edildi.

Ws2def.h dosyasına bakarsanız aşağıdaki yorumla başlar -

/*++

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

--*/

Son satıra dikkat edin - "Bu dosya WINSOCK.H içeren bir modül tarafından eklenemez."

Hala kodda değişiklik yapmadan sorunu gidermeye çalışıyoruz.

Bunun mantıklı olup olmadığını bana bildirin.


2

Başlık koruyucusu kullanmalısınız.

bu satırı başlık dosyasının en üstüne koy

#ifndef PATH_FILENAME_H
#define PATH_FILENAME_H

ve altta

#endif

1
#pragma bir kez ve korumaları dahil etmek aynı şeyler değil mi?
akif

Tam olarak aynı değiller - başlık muhafızları, dosyanın önişlemci düzeyinde yeniden eklenmesini engelleyecek, ayrıca bir kez #pragma'dan biraz daha taşınabilirler.
Timo Geusch

1
Ben aynı amaçlar için inşa edildi demek istedim :)
akif

2
#pragma once standart dışı, afaik
ntcong

2

#pragma oncedosya adının tam yolunu temel alır. Muhtemelen farklı dizinlerde MyClass.h veya Winsock2.h'nin iki özdeş kopyası var.


sembolik bir bağlantı veya NTFS bağlantısı da sistemin bozulmasına neden olur.
Thomi

1

#pragma onceMS derleyicilerinde bile kesiktir ve diğer birçok derleyici tarafından desteklenmez. Diğer birçok insanın da belirttiği gibi, içerme korumalarını kullanmak gidilecek yoldur. Hiç kullanmayın #pragma once- hayatınızı daha kolay hale getirecektir.


3
Ne yazık ki, sıfırdan fazla bot koruması, ya bir yazım hatası, koruyucunun gerçekten çalışmadığı anlamına gelir ya da farklı dizinlerdeki aynı addaki dosyaların aynı jetonu kullandığı veya kullanılan jetonun bir çiftle başladığı yerlerde korumaları içerdiğini gördüm. alt çizgi veya alt çizgi sonra büyük harf (ve bir kez #pragma gibi taşınabilir değildir). Yani doğal olarak taşınabilir olmayan kod için, winsock.h kullanan herhangi bir şey gibi, #pragma tarafından bir keresinde lapa lapa olduğunu söylediğiniz noktaya kadar derinden rahatsız oldum. Ne zaman desteklenmiyor, ne zaman başarısız oluyor?
Steve Jessop

3
Kullanırken #pragma once, derleyici başlık dosyası düğümü adını benzersiz kimlik olarak alır. Kaynak ağacınızda (düşündüğünüzden daha yaygın) sembolik bağlarınız veya NTFS bağlantılarınız varsa veya başka bir sistem içerme dizininde aynı ada sahip bir dosyanız olsa bile (bu, daha önce geldiğimde) sürüm 1 ve aynı kitaplığın sürüm 2 iki farklı sisteme yüklü yolları içerir). Alt satır: benim için, daha fazla kontrole sahip olmayı ve ara sıra ıslak yazılım hatası ile yaşamayı tercih ederim, derleyicinin benim için yapmasını sağlamak yerine.
Thomi


1

Projemde (VS 2008 SP1 kullanıyorum) sonraki çözüm çalışıyor:

Başlık dosyası:

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

Cpp sınıfı:

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

burada #include "winsock2class.h", winsock2.h'yi uygulayan sınıf anlamına gelir:

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

0

Aslında winsock2.h'yi ilk içerme olarak tanımlamak zorunda kaldığım bir sorunla karşılaştım, diğer paketlerin içerdiği diğer sorunlar var gibi görünüyor. Umarım bu, sadece windows.h değil, aynı zamanda tüm sorunları içerir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.