çözümlenmemiş harici sembol __imp__fprintf ve __imp____iob_func, SDL2


108

Birisi ne olduğunu açıklayabilir mi

__imp__fprintf

ve

__imp____iob_func

çözülmemiş dış araçlar?

Çünkü derlemeye çalışırken şu hataları alıyorum:

1>SDL2main.lib(SDL_windows_main.obj) : error LNK2019: unresolved external symbol __imp__fprintf referenced in function _ShowError
1>SDL2main.lib(SDL_windows_main.obj) : error LNK2019: unresolved external symbol __imp____iob_func referenced in function _ShowError
1>E:\Documents\Visual Studio 2015\Projects\SDL2_Test\Debug\SDL2_Test.exe : fatal error LNK1120: 2 unresolved externals

Zaten sorunun yanlış bağlantıdan kaynaklanmadığını söyleyebilirim. Her şeyi doğru bir şekilde bağladım, ancak nedense derlenmiyor.

SDL2 kullanmaya çalışıyorum.

Derleyici olarak Visual Studio 2015 kullanıyorum.

Linker -> Input -> Ek Bağımlılıklar'da SDL2.lib ve SDL2main.lib'e bağlandım ve VC ++ Dizinlerinin doğru olduğundan emin oldum.


1
Lütfen bağlayıcı ayarlarınızı göstererek bunu kanıtlayabilir misiniz?
πάντα ῥεῖ

@ πάνταῥεῖ, giriş bağlayıcı ayarlarında SDL2.lib ve SDL2main.lib ile bağlantı kurdum ve dizinlerin doğru dizini gösterdiğinden emin oldum.
RockFrenzy

Yanıtlar:


123

Sonunda bunun neden olduğunu anladım!

Visual Studio 2015'te stdin, stderr, stdout şu şekilde tanımlanmıştır:

#define stdin  (__acrt_iob_func(0))
#define stdout (__acrt_iob_func(1))
#define stderr (__acrt_iob_func(2))

Ancak daha önce şu şekilde tanımlanıyorlardı:

#define stdin  (&__iob_func()[0])
#define stdout (&__iob_func()[1])
#define stderr (&__iob_func()[2])

Artık __iob_func artık tanımlanmadı ve bu da visual studio'nun önceki sürümleriyle derlenmiş bir .lib dosyası kullanıldığında bağlantı hatasına yol açıyor.

Sorunu çözmek için, aşağıdakileri __iob_func()içeren bir dizi döndürmesi gereken kendinizi tanımlamayı deneyebilirsiniz {*stdin,*stdout,*stderr}.

Stdio işlevleriyle ilgili diğer bağlantı hataları ile ilgili olarak (benim durumumda öyleydi sprintf()), bağlayıcı seçeneklerinize legacy_stdio_definitions.lib ekleyebilirsiniz .


1
Bunu izlediğiniz için teşekkürler. IIRC {* stdin, * stdout, * stderr} ile ilgili sorun, farklı derleme birimlerinin kendi stdin kopyalarına sahip olabilmeleridir, bu nedenle bu işlevler doğrudan çağrılmıştır.
Steven R. Loomis

3
benim için de çözüldü extern "C", beyanda / tanımda kullanmak için sadece bir hatırlatma .
Vargas

4
Birisi tam olarak değiştirme işlevinin nasıl görünmesi gerektiğini yazabilir mi? Farklı varyantları denedim ve derleme hataları almaya devam ediyorum. Teşekkürler.
Milan Babuškov

55
extern "C" { FILE __iob_func[3] = { *stdin,*stdout,*stderr }; }
PoL0

1
Yukarıdaki iob_func tanımı çalışmıyor, doğru tanım için MarkH'nin cevabına bakın. (Bir işlevi yalnızca bir dizi olarak tanımlayıp çağrıların çalışmasını bekleyemezsiniz.)
Hans Olsson

59

Milan Babuškov, IMO'ya göre, değiştirme işlevi tam olarak böyle görünmelidir :-)

FILE _iob[] = {*stdin, *stdout, *stderr};

extern "C" FILE * __cdecl __iob_func(void)
{
    return _iob;
}

5
MSVC ve MSVC <2015 sürümü için bir #ifdef eksik
paulm

1
MarkH'nin, doğru görünen ancak işe yaramayacak başka bir yanıtta belirttiği gibi.
Hans Olsson

4
@paulm Demek istediğini düşünüyorum #if defined(_MSC_VER) && (_MSC_VER >= 1900).
Jesse Chisholm

@JesseChisholm, bunun MSVC'nin bilinen tüm gelecekteki sürümleri için de geçerli olup olmadığına bağlı olabilir;)
paulm

42

Microsoft'un bununla ilgili özel bir notu var ( https://msdn.microsoft.com/en-us/library/bb531344.aspx#BK_CRT ):

Printf ve scanf ailesi işlevleri artık satır içi olarak tanımlanmıştır.

Tüm printf ve scanf işlevlerinin tanımları satır içi olarak stdio.h , conio.h ve diğer CRT başlıklarına taşınmıştır . Bu, uygun CRT başlıklarını dahil etmeden bu işlevleri yerel olarak bildiren herhangi bir program için bağlayıcı hatasına (LNK2019, çözülmemiş harici sembol) yol açan bir son değişikliktir. Mümkünse, kodu CRT başlıklarını (yani, #include ekleyin) ve satır içi işlevleri içerecek şekilde güncellemelisiniz, ancak kodunuzu bu başlık dosyalarını içerecek şekilde değiştirmek istemiyorsanız, alternatif bir çözüm, ek bir kitaplık bağlayıcı girdinize , legacy_stdio_definitions.lib .

Bu kitaplığı IDE'deki bağlayıcı girişinize eklemek için, proje düğümü için bağlam menüsünü açın, Özellikler'i seçin, ardından Proje Özellikleri iletişim kutusunda Bağlayıcı'yı seçin ve virgülle legacy_stdio_definitions.lib eklemek için Bağlayıcı Girişini düzenleyin ayrılmış liste.

Projeniz, 2015'ten önceki bir Visual C ++ sürümüyle derlenmiş statik kitaplıklarla bağlantı kuruyorsa, bağlayıcı çözülmemiş bir harici sembolü bildirebilir. Bu hatalar _iob , _iob_func için dahili stdio tanımlarına veya __imp_ * biçiminde belirli stdio işlevleri için ilgili içe aktarmalara başvurabilir. Microsoft, bir projeyi yükselttiğinizde tüm statik kitaplıkları Visual C ++ derleyicisinin ve kitaplıklarının en son sürümüyle yeniden derlemenizi önerir. Kitaplık, kaynağın mevcut olmadığı bir üçüncü taraf kitaplığı ise, üçüncü kişiden güncelleştirilmiş bir ikili dosya istemeniz veya bu kitaplık kullanımınızı Visual C ++ derleyicisinin eski sürümüyle derlediğiniz ayrı bir DLL'ye kapsüllemeniz gerekir. ve kütüphaneler.


7
Veya #pragma comment(lib, "legacy_stdio_definitions.lib")- ama bu düzeltmez __imp___iob_func- bunun için de eski bir kitaplık var mı?
bytecode77

29

Yukarıda cevaplandığı gibi, doğru cevap her şeyi VS2015 ile derlemektir, ancak ilgi için aşağıdaki benim problem analizimdir.

Bu sembol, Microsoft tarafından VS2015'in bir parçası olarak sağlanan herhangi bir statik kitaplıkta tanımlanmamış gibi görünmektedir; bu, diğerleri olduğu için oldukça tuhaftır. Nedenini keşfetmek için, bu işlevin bildirimine ve daha da önemlisi nasıl kullanıldığına bakmamız gerekir.

İşte Visual Studio 2008 üstbilgilerinden bir snippet:

_CRTIMP FILE * __cdecl __iob_func(void);
#define stdin (&__iob_func()[0])
#define stdout (&__iob_func()[1])
#define stderr (&__iob_func()[2])

Böylece, fonksiyonun işinin bir FILE nesnesi dizisinin başlangıcını döndürmek olduğunu görebiliriz (tutamaçlar değil, "FILE *" tutamaçtır, FILE, önemli durum güzelliklerini depolayan temel opak veri yapısıdır). Bu işlevin kullanıcıları, çeşitli fscanf, fprintf tarzı çağrılar için kullanılan üç makrodur. Stdin, stdout ve stderr.

Şimdi, Visual Studio 2015'in aynı şeyleri nasıl tanımladığına bir göz atalım:

_ACRTIMP_ALT FILE* __cdecl __acrt_iob_func(unsigned);
#define stdin (__acrt_iob_func(0))
#define stdout (__acrt_iob_func(1))
#define stderr (__acrt_iob_func(2))

Dolayısıyla, değiştirme işlevinin artık dosya nesneleri dizisinin adresi yerine dosya tutamacını döndürmesi için yaklaşım değişti ve makrolar, yalnızca bir tanımlayıcı numarada geçen işlevi çağırmak için değişti.

Öyleyse neden uyumlu bir API sağlayamıyoruz / biz sağlayamıyoruz? __İob_func aracılığıyla orijinal uygulamaları açısından Microsoft'un ihlal edemeyeceği iki temel kural vardır:

  1. Öncekiyle aynı şekilde dizine eklenebilen üç FILE yapısı dizisi olmalıdır.
  2. FILE’ın yapısal düzeni değiştirilemez.

Yukarıdakilerden herhangi birindeki herhangi bir değişiklik, buna bağlı mevcut derlenmiş kodun, bu API çağrılırsa çok yanlış olacağı anlamına gelir.

FILE'ın nasıl tanımlandığına bir göz atalım.

İlk olarak VS2008 FILE tanımı:

struct _iobuf {
        char *_ptr;
        int   _cnt;
        char *_base;
        int   _flag;
        int   _file;
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname;
        };
typedef struct _iobuf FILE;

Ve şimdi VS2015 FILE tanımı:

typedef struct _iobuf
{
    void* _Placeholder;
} FILE;

Yani işin püf noktası var: yapı şekil değiştirdi. __İob_func'a atıfta bulunan mevcut derlenmiş kod, döndürülen verilerin hem indekslenebilen bir dizi olmasına hem de bu dizideki öğelerin birbirinden aynı uzaklıkta olmasına dayanır.

Bu satırlar boyunca yukarıdaki cevaplarda bahsedilen olası çözümler, birkaç nedenden dolayı (çağrıldıysa) işe yaramayacaktır:

FILE _iob[] = {*stdin, *stdout, *stderr};

extern "C" FILE * __cdecl __iob_func(void)
{
    return _iob;
}

FILE _iob dizisi VS2015 ile derlenecek ve bu nedenle bir void * içeren yapılar bloğu olarak yerleştirilecektir. 32 bitlik hizalama varsayıldığında, bu öğeler 4 bayt ayrı olacaktır. Dolayısıyla, _iob [0] ofset 0'da, _iob [1] ofset 4'te ve _iob [2] ofset 8'de. Çağrı kodu bunun yerine FILE'ın çok daha uzun olmasını, sistemimde 32 bayta hizalanmasını bekler, vb. döndürülen dizinin adresini alacak ve sıfır elemanına ulaşmak için 0 bayt ekleyecektir (bu tamamdır), ancak _iob [1] için 32 bayt eklemesi gerektiği sonucuna varacak ve _iob [2] için sonuç çıkaracaktır 64 bayt eklemesi gerektiğini (çünkü VS2008 başlıklarında böyle görünüyordu). Ve gerçekten de VS2008 için demonte edilen kod bunu gösteriyor.

Yukarıdaki çözümle ilgili ikincil bir sorun , FILE * tutamacının değil, FILE yapısının (* stdin) içeriğini kopyalamasıdır . Yani herhangi bir VS2008 kodu, VS2015'ten farklı bir temel yapıya bakıyor olacaktır. Yapı yalnızca işaretçiler içeriyorsa bu işe yarayabilir, ancak bu büyük bir risk. Her halükarda, ilk konu bunu ilgisiz kılar.

Hayal edebildiğim tek hack, __iob_func'un hangi gerçek dosya tutamacını aradıklarını bulmak için çağrı yığınını yürüttüğü (döndürülen adrese eklenen ofsete dayalı olarak) ve hesaplanan bir değer döndürdüğüdür. doğru cevabı verir. Bu, göründüğü kadar çılgınca ama sadece x86 için prototip (x64 değil) eğlenmeniz için aşağıda listelenmiştir. Deneylerimde iyi çalıştı, ancak kilometreniz değişebilir - üretim kullanımı için önerilmez!

#include <windows.h>
#include <stdio.h>
#include <dbghelp.h>

/* #define LOG */

#if defined(_M_IX86)

#define GET_CURRENT_CONTEXT(c, contextFlags) \
  do { \
    c.ContextFlags = contextFlags; \
    __asm    call x \
    __asm x: pop eax \
    __asm    mov c.Eip, eax \
    __asm    mov c.Ebp, ebp \
    __asm    mov c.Esp, esp \
  } while(0);

#else

/* This should work for 64-bit apps, but doesn't */
#define GET_CURRENT_CONTEXT(c, contextFlags) \
  do { \
    c.ContextFlags = contextFlags; \
    RtlCaptureContext(&c); \
} while(0);

#endif

FILE * __cdecl __iob_func(void)
{
    CONTEXT c = { 0 };
    STACKFRAME64 s = { 0 };
    DWORD imageType;
    HANDLE hThread = GetCurrentThread();
    HANDLE hProcess = GetCurrentProcess();

    GET_CURRENT_CONTEXT(c, CONTEXT_FULL);

#ifdef _M_IX86
    imageType = IMAGE_FILE_MACHINE_I386;
    s.AddrPC.Offset = c.Eip;
    s.AddrPC.Mode = AddrModeFlat;
    s.AddrFrame.Offset = c.Ebp;
    s.AddrFrame.Mode = AddrModeFlat;
    s.AddrStack.Offset = c.Esp;
    s.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
    imageType = IMAGE_FILE_MACHINE_AMD64;
    s.AddrPC.Offset = c.Rip;
    s.AddrPC.Mode = AddrModeFlat;
    s.AddrFrame.Offset = c.Rsp;
    s.AddrFrame.Mode = AddrModeFlat;
    s.AddrStack.Offset = c.Rsp;
    s.AddrStack.Mode = AddrModeFlat;
#elif _M_IA64
    imageType = IMAGE_FILE_MACHINE_IA64;
    s.AddrPC.Offset = c.StIIP;
    s.AddrPC.Mode = AddrModeFlat;
    s.AddrFrame.Offset = c.IntSp;
    s.AddrFrame.Mode = AddrModeFlat;
    s.AddrBStore.Offset = c.RsBSP;
    s.AddrBStore.Mode = AddrModeFlat;
    s.AddrStack.Offset = c.IntSp;
    s.AddrStack.Mode = AddrModeFlat;
#else
#error "Platform not supported!"
#endif

    if (!StackWalk64(imageType, hProcess, hThread, &s, &c, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
    {
#ifdef LOG
        printf("Error: 0x%08X (Address: %p)\n", GetLastError(), (LPVOID)s.AddrPC.Offset);
#endif
        return NULL;
    }

    if (s.AddrReturn.Offset == 0)
    {
        return NULL;
    }

    {
        unsigned char const * assembly = (unsigned char const *)(s.AddrReturn.Offset);
#ifdef LOG
        printf("Code bytes proceeding call to __iob_func: %p: %02X,%02X,%02X\n", assembly, *assembly, *(assembly + 1), *(assembly + 2));
#endif
        if (*assembly == 0x83 && *(assembly + 1) == 0xC0 && (*(assembly + 2) == 0x20 || *(assembly + 2) == 0x40))
        {
            if (*(assembly + 2) == 32)
            {
                return (FILE*)((unsigned char *)stdout - 32);
            }
            if (*(assembly + 2) == 64)
            {
                return (FILE*)((unsigned char *)stderr - 64);
            }

        }
        else
        {
            return stdin;
        }
    }
    return NULL;
}

Doğru cevap bu, en kolay düzeltme belirtildiği gibi projeyi VS2015'e yükseltmek ve sonra derlemektir.
Akumaburn

2
Benim durumumda, Visual Studio 2013 Güncellemesi 3'ü kullanmak için Visual Studio 2013'ten birçok projeyi (C ++ ve C # projeleri) yükseltmem gerekiyor. C ++ projeleri oluştururken VC100'ü (Visual studio 2010 C ++ derleyicisini) korumak istiyorum ancak aynı hatalara sahibim yukarıdaki gibi. Bağlayıcıya legacy_stdio_definitions.lib ekleyerek imp _fprintf'i düzelttim . _İmp____iob_func'ı da nasıl düzeltebilirim ?
Mohamed BOUZIDI

Önceki sorumu cevaplamadan önce, C ++ projelerini derlemek için msbuild 14 ve IntelCompiler 2016 ve VC100 kullanılırken bu hataların meydana gelmesi normal mi?
Mohamed BOUZIDI

1
x64 derlemesi için ne yapabilirim?
athos

28

VS2015'te aynı sorunu yaşadım. VS2015'te SDL2 kaynaklarını derleyerek çözdüm.

  1. Http://libsdl.org/download-2.0.php adresine gidin ve SDL 2 kaynak kodunu indirin.
  2. VS2015'te SDL_VS2013.sln'yi açın . Projeleri dönüştürmeniz istenecektir. Yap.
  3. SDL2 projesini derleyin.
  4. SDL2main projesini derleyin.
  5. VS2015'teki SDL 2 projenizde yeni oluşturulan SDL2main.lib, SDL2.lib ve SDL2.dll çıktı dosyalarını kullanın.

4
BTW, SDL 2.0.3'ü derlemek için Haziran 2010 DirectX SDK'nın kurulmasını gerektirir.
Joe

1
Benim için çalıştı, teşekkürler !! Ama sadece derleyip SDL2mainkopyalamam gerekiyorduSDL2main.lib
kgwong

10

Neden bilmiyorum ama:

#ifdef main
#undef main
#endif

İçermelerden sonra ancak ana öğeniz benim deneyimlerime göre düzeltmelidir.


1
.... Tamam .... bunu denemeden önce kendi kendime sesli bir şekilde bunun işe yarayacağından bir şekilde şüphelendiğimi söyledim ama tamamen işe yaradı ..... Bunun neden işe yaradığını açıklayabilir misiniz ...?
Trevor Hart

1
@TrevorHart "Hatalı" bir SDL ana belleğinin "tanımsız" arabelleklere yapılan referansları içermediğine inanıyorum ve sizin arabelleklerinizi kullanıyorsa, o zaman her şey yolunda ve iyi çalışıyor.
XGood

2
Bu korkunç kötü pratik hackler ama 3 satır ve işe yarıyor ve beni SDL'yi inşa etmek için rabbithole zorunda kalmaktan kurtardı, bu yüzden ... güzelce yapıldı.
Cheezmeister

1
@Cheezmeister Her şey için genellikle kötü uygulama ve hackler gerekir. Özellikle onlara ihtiyaç duymaması gereken şeyler.
XGood


7

Bağlanmak, düzgün çalışmamak demektir. VS2012 ve VS2015'in stdio.h'sini araştırırken, aşağıdakiler benim için çalıştı. Ne yazık ki, birden fazla değil, {stdin, stdout, stderr} 'den biri için çalışıp çalışmayacağına karar vermelisiniz.

extern "C" FILE* __cdecl __iob_func()
{
    struct _iobuf_VS2012 { // ...\Microsoft Visual Studio 11.0\VC\include\stdio.h #56
        char *_ptr;
        int   _cnt;
        char *_base;
        int   _flag;
        int   _file;
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname; };
    // VS2015 has only FILE = struct {void*}

    int const count = sizeof(_iobuf_VS2012) / sizeof(FILE);

    //// stdout
    //return (FILE*)(&(__acrt_iob_func(1)->_Placeholder) - count);

    // stderr
    return (FILE*)(&(__acrt_iob_func(2)->_Placeholder) - 2 * count);
}

7

Tavsiyem __iob_func'u uygulamamak (denememek).

Bu hataları düzeltirken:

libpngd.v110.lib(pngrutil.obj) : error LNK2001: unresolved external symbol ___iob_func curllib.v110.lib(mprintf.obj) : error LNK2001: unresolved external symbol ___iob_func

Diğer cevapların çözümlerini denedim, ancak sonunda bir FILE*C dizisi döndürmek , Windows'un dahili IOB yapıları dizisiyle eşleşmiyor. @Volker stdin, stdoutveya birden fazlası için asla çalışmayacağı konusunda haklı stderr.

Bir kütüphane gerçekten bu akışlardan birini KULLANIRsa , çökecektir . Programınız kütüphanenin onları kullanmasına neden olmadığı sürece asla bilemezsiniz . Örneğin , CRC, PNG'nin meta verilerinde eşleşmediğinde png_default_erroryazar stderr. (Normalde çökmeye değer bir sorun değildir)

Sonuç: stdin, stdout ve / veya stderr kullanıyorlarsa, VS2012 (Platform Toolset v110 / v110_xp) ve VS2015 + kitaplıklarını karıştırmak mümkün değildir.

Çözüm: __iob_funcÇözümlenmemiş semboller içeren kitaplıklarınızı mevcut VS sürümünüz ve eşleşen bir Platform Araç Seti ile yeniden derleyin .



2

Bu sorunu aşağıdaki işlevle çözüyorum. Visual Studio 2019 kullanıyorum.

FILE* __cdecl __iob_func(void)
{
    FILE _iob[] = { *stdin, *stdout, *stderr };
    return _iob;
}

çünkü stdin Makro tanımlı işlev çağrısı, "* stdin" ifadesi genel dizi başlatıcı kullanılamaz. Ancak yerel dizi başlatıcısı mümkündür. üzgünüm, ingilizcede zayıfım.


1

Hala yukarıdaki hilelerin işe yaramadığı bir cevap arayan herkes için. Statik bağlantı, bu sorunu çözmenin yoludur. Çalışma Zamanı kitaplığı ayarlarınızı aşağıdaki gibi değiştirin

Project properties --> C/C++ --> Code generation --> Runtime Library --> Multi-threaded Debug (/MTd) instead of /MDd


İşte bu çözümle ilgili bir tartışma: social.msdn.microsoft.com/Forums/vstudio/en-US/…
Sisir

0

Sorunu çözmeyi başardım.

Hatanın kaynağı, SDLmain kaynak kodunda bulunabilen bu kod satırıydı.

fprintf(stderr, "%s: %s\n", title, message);

Yaptığım şey, o satırın SDLmain'deki kaynak kodunu da düzenlemekti:

fprintf("%s: %s\n", title, message);

Ve sonra SDLmain'i oluşturdum ve SDL2 kitaplık dizinimdeki eski SDLmain.lib'i kopyalayıp yeni oluşturulmuş ve düzenlenmiş olanla değiştirdim.

Daha sonra programımı SDL2 ile çalıştırdığımda hiçbir hata mesajı gelmedi ve kodlama sorunsuz çalıştı.

Bu beni daha sonra ısırır mı bilmiyorum, ama bu yüzden her şey harika gidiyor.


Değişikliğiniz kendi başına bir hatadır ve sorunuzda açıklanan sorunu çözmezdi. Artık bağlayıcı hataları almamanız bir tesadüftür, bu muhtemelen yalnızca kitaplığı nasıl yeniden oluşturduğunuzdan kaynaklanmaktadır.
Ross Ridge

@RossRidge, oh evet bu sadece olabilirdi. Ah peki.
RockFrenzy

0

Bu, iyi bir plan olan msvcr10.dll (veya benzeri) yerine msvcrt.dll'ye bağlandığınızda ortaya çıkabilir. Çünkü, Visual Studio'nuzun çalışma zamanı kitaplığını son yazılım paketinizin içinde yeniden dağıtmak için sizi serbest bırakacaktır.

Bu geçici çözüm bana yardımcı oluyor (Visual Studio 2008'de):

#if _MSC_VER >= 1400
#undef stdin
#undef stdout
#undef stderr
extern "C" _CRTIMP extern FILE _iob[];
#define stdin   _iob
#define stdout  (_iob+1)
#define stderr  (_iob+2)
#endif

Bu kod parçacığı, Visual Studio 6 ve derleyicisi için gerekli değildir. Bu nedenle #ifdef.


0

Zaten zengin olan bu iş parçacığında daha fazla kafa karışıklığı yaratmak için, fprintf'te aynı çözülmemiş harici ile karşılaştım.

main.obj : error LNK2019: unresolved external symbol __imp__fprintf referenced in function _GenerateInfoFile

Benim durumumda oldukça farklı bir bağlamda olsa bile: Visual Studio 2005 (Visual Studio 8.0) altında ve hata üçüncü bir taraf değil, kendi kodumda (derlemekte olduğum şeyin aynısı) oluyordu.

Derleyici bayraklarımda bu hata / MD seçeneği tarafından tetiklendi. / MT'ye geçmek sorunu ortadan kaldırdı. Bu garip çünkü genellikle statik olarak (MT) bağlanmak dinamik olarak (MD) olduğundan daha fazla sorun yaratır ... ama tam da diğerine hizmet etmesi durumunda, onu oraya koyarım.


0

Benim durumumda, bu hata, yürütülebilir dosyalarımdaki fazla yağı kaldırmak için MSVC sürümüne bağlı çalışma zamanı kitaplığı DLL'sine (msvcr10.dll veya benzeri) bağımlılıkları ve / veya statik çalışma zamanı kitaplığını da kaldırma denememden geliyor.

Bu yüzden / NODEFAULTLIB bağlayıcı anahtarını, kendi yaptığım "msvcrt-light.lib" (ihtiyacınız olduğunda google için) ve mainCRTStartup()/ WinMainCRTStartup()girişlerini kullanıyorum.

Visual Studio 2015'ten beri IMHO, bu yüzden eski derleyicilere bağlı kaldım.

Ancak, _NO_CRT_STDIO_INLINE sembolünü tanımlamak tüm zorlukları ortadan kaldırır ve basit bir "Merhaba Dünya" uygulaması yine 3 KB küçüktür ve olağandışı DLL'lere bağlı değildir. Visual Studio 2017'de test edilmiştir.


-2

Bu kodu kaynak dosyalarınızdan herhangi birine yapıştırın ve yeniden oluşturun. Benim için çalıştı!

#include stdio.h

FILE _iob [3];

FILE * __cdecl __iob_func (void) {

_iob [0] = * stdin;

_iob [0] = * stdout;

_iob [0] = * stderr;

dönüş _iob;

}


`` '' ile biçimlendirme ve ayrıca bazı açıklamalar
eklemelisiniz

Bu kod soruyu çözebilirken, sorunun nasıl ve neden çözüldüğüne dair bir açıklama da dahil olmak üzere , gönderinizin kalitesini artırmaya gerçekten yardımcı olur ve muhtemelen daha fazla oy almanıza neden olur. Sadece şu anda soran kişi için değil, gelecekte okuyucular için soruyu yanıtladığınızı unutmayın. Açıklamalar eklemek ve hangi sınırlamaların ve varsayımların geçerli olduğuna dair bir gösterge vermek için lütfen yanıtınızı düzenleyin .
Brian
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.