ký hiệu bên ngoài chưa được giải quyết __imp__fprintf và __imp____iob_func, SDL2


108

Ai đó có thể giải thích những gì

__imp__fprintf

__imp____iob_func

phương tiện bên ngoài chưa được giải quyết?

Bởi vì tôi gặp những lỗi này khi tôi cố gắng biên dịch:

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

Tôi đã có thể nói rằng vấn đề không phải do liên kết sai. Tôi đã liên kết mọi thứ một cách chính xác, nhưng vì lý do nào đó mà nó không biên dịch được.

Tôi đang cố gắng sử dụng SDL2.

Tôi đang sử dụng Visual Studio 2015 làm trình biên dịch.

Tôi đã liên kết với SDL2.lib và SDL2main.lib trong Trình liên kết -> Đầu vào -> Phụ thuộc bổ sung và tôi đã đảm bảo rằng Thư mục VC ++ là chính xác.


1
Bạn có thể cải thiện điều đó bằng cách hiển thị cài đặt trình liên kết của bạn không.
πάντα ῥεῖ

@ πάνταῥεῖ, Tôi đã liên kết với SDL2.lib và SDL2main.lib trong cài đặt trình liên kết đầu vào và tôi đã đảm bảo rằng các thư mục đang trỏ đến đúng thư mục.
RockFrenzy

Câu trả lời:


123

Cuối cùng tôi đã tìm ra lý do tại sao điều này lại xảy ra!

Trong visual studio 2015, stdin, stderr, stdout được định nghĩa như sau:

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

Nhưng trước đây, chúng được định nghĩa là:

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

Vì vậy, bây giờ __iob_func không được định nghĩa nữa, dẫn đến lỗi liên kết khi sử dụng tệp .lib được biên dịch với các phiên bản trước của visual studio.

Để giải quyết vấn đề, bạn có thể thử __iob_func()tự xác định cái nào sẽ trả về một mảng có chứa {*stdin,*stdout,*stderr}.

Về các lỗi liên kết khác về các hàm stdio (trong trường hợp của tôi là như vậy sprintf()), bạn có thể thêm inherit_stdio_definitions.lib vào tùy chọn trình liên kết của mình.


1
Cảm ơn vì đã theo dõi điều này. IIRC vấn đề với {* stdin, * stdout, * stderr} có thể là các đơn vị biên dịch khác nhau có thể có bản sao stdin 'riêng' của chúng, đó là lý do tại sao các hàm này được gọi trực tiếp.
Steven R. Loomis

3
điều đó cũng giải quyết được cho tôi, chỉ là một lời nhắc để sử dụng extern "C"trong khai báo / định nghĩa.
Vargas

4
Ai đó có thể viết chính xác hàm thay thế trông như thế nào không? Tôi đã thử các biến thể khác nhau và tôi tiếp tục gặp lỗi biên dịch. Cảm ơn.
Milan Babuškov

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

1
Định nghĩa iob_func ở trên không hoạt động, hãy xem câu trả lời của MarkH để biết định nghĩa chính xác. (Bạn không thể chỉ định nghĩa một hàm dưới dạng một mảng và mong đợi các lệnh gọi hoạt động.)
Hans Olsson

59

Đối với Milan Babuškov, IMO, đây chính xác là hàm thay thế sẽ trông như thế nào :-)

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

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

5
Chỉ thiếu #ifdef cho MSVC và cho phiên bản MSVC <2015
paulm

1
Như MarkH lưu ý trong một câu trả lời khác có vẻ đúng, nhưng sẽ không hoạt động.
Hans Olsson

4
@paulm Tôi nghĩ bạn có nghĩa là #if defined(_MSC_VER) && (_MSC_VER >= 1900).
Jesse Chisholm

@JesseChisholm có lẽ, tùy thuộc vào điều này có áp dụng cho mọi phiên bản MSVC đã biết trong tương lai hay không;)
paulm

42

Microsoft có một lưu ý đặc biệt về điều này ( https://msdn.microsoft.com/en-us/library/bb531344.aspx#BK_CRT ):

Họ các hàm printf và scanf hiện đã được định nghĩa nội tuyến.

Các định nghĩa của tất cả các hàm printf và scanf đã được chuyển nội dòng vào stdio.h , conio.h và các tiêu đề CRT khác. Đây là một thay đổi vi phạm dẫn đến lỗi trình liên kết (LNK2019, ký hiệu bên ngoài chưa được giải quyết) cho bất kỳ chương trình nào đã khai báo các chức năng này cục bộ mà không bao gồm các tiêu đề CRT thích hợp. Nếu có thể, bạn nên cập nhật mã để bao gồm các tiêu đề CRT (nghĩa là thêm #include) và các hàm nội tuyến, nhưng nếu bạn không muốn sửa đổi mã của mình để bao gồm các tệp tiêu đề này, giải pháp thay thế là thêm một bổ sung thư viện vào đầu vào trình liên kết của bạn, inherit_stdio_definitions.lib .

Để thêm thư viện này vào đầu vào trình liên kết của bạn trong IDE, hãy mở menu ngữ cảnh cho nút dự án, chọn Thuộc tính, sau đó trong hộp thoại Thuộc tính dự án, chọn Trình liên kết và chỉnh sửa Đầu vào trình liên kết để thêm inherit_stdio_definitions.lib vào dấu chấm phẩy -danh sách riêng biệt.

Nếu dự án của bạn liên kết với các thư viện tĩnh đã được biên dịch với bản phát hành Visual C ++ sớm hơn năm 2015, trình liên kết có thể báo cáo một ký hiệu bên ngoài chưa được giải quyết. Các lỗi này có thể tham chiếu đến các định nghĩa stdio nội bộ cho _iob , _iob_func hoặc các phép nhập có liên quan cho các hàm stdio nhất định ở dạng __imp_ *. Microsoft khuyến nghị bạn nên biên dịch lại tất cả các thư viện tĩnh với phiên bản mới nhất của trình biên dịch Visual C ++ và các thư viện khi bạn nâng cấp dự án. Nếu thư viện là thư viện của bên thứ ba mà nguồn không có sẵn, bạn nên yêu cầu tệp nhị phân được cập nhật từ bên thứ ba hoặc đóng gói việc sử dụng thư viện đó của bạn thành một DLL riêng biệt mà bạn biên dịch bằng phiên bản cũ hơn của trình biên dịch Visual C ++ và các thư viện.


7
Hoặc #pragma comment(lib, "legacy_stdio_definitions.lib")- nhưng điều này không khắc phục được __imp___iob_func- có một lib kế thừa cho điều này không?
bytecode77

29

Như đã trả lời ở trên, câu trả lời đúng là biên dịch mọi thứ với VS2015, nhưng đối với sự quan tâm, sau đây là phân tích của tôi về vấn đề.

Biểu tượng này dường như không được xác định trong bất kỳ thư viện tĩnh nào do Microsoft cung cấp như một phần của VS2015, điều này khá kỳ lạ so với tất cả các thư viện khác. Để tìm hiểu lý do tại sao, chúng ta cần xem xét khai báo của hàm đó và quan trọng hơn là cách nó được sử dụng.

Đây là một đoạn mã từ các tiêu đề Visual Studio 2008:

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

Vì vậy, chúng ta có thể thấy rằng công việc của hàm là trả về phần bắt đầu của một mảng các đối tượng FILE (không phải xử lý, "FILE *" là xử lý, FILE là cấu trúc dữ liệu không rõ ràng bên dưới lưu trữ các tính năng quan trọng của trạng thái). Người dùng của hàm này là ba macro stdin, stdout và stderr được sử dụng cho các lệnh gọi kiểu fscanf, fprintf khác nhau.

Bây giờ chúng ta hãy xem cách Visual Studio 2015 xác định những thứ tương tự:

_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))

Vì vậy, cách tiếp cận đã thay đổi để hàm thay thế bây giờ trả về xử lý tệp thay vì địa chỉ của mảng đối tượng tệp và các macro đã thay đổi để chỉ cần gọi hàm truyền vào một số nhận dạng.

Vậy tại sao họ / chúng tôi không thể cung cấp một API tương thích? Có hai quy tắc chính mà Microsoft không thể trái ngược về cách triển khai ban đầu của họ thông qua __iob_func:

  1. Phải có một mảng gồm ba cấu trúc FILE có thể được lập chỉ mục theo cách tương tự như trước đây.
  2. Bố cục cấu trúc của FILE không thể thay đổi.

Bất kỳ thay đổi nào ở một trong hai điều trên có nghĩa là mã đã biên dịch hiện có được liên kết với điều đó sẽ bị sai nghiêm trọng nếu API đó được gọi.

Hãy xem cách FILE được / được định nghĩa.

Đầu tiên là định nghĩa FILE VS2008:

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

Và bây giờ là định nghĩa FILE VS2015:

typedef struct _iobuf
{
    void* _Placeholder;
} FILE;

Vì vậy, mấu chốt của nó: cấu trúc đã thay đổi hình dạng. Mã đã biên dịch hiện tại đề cập đến __iob_func dựa trên thực tế là dữ liệu trả về là một mảng có thể được lập chỉ mục và trong mảng đó, các phần tử cách nhau một khoảng cách.

Các giải pháp khả thi được đề cập trong các câu trả lời ở trên dọc theo những dòng này sẽ không hoạt động (nếu được gọi) vì một số lý do:

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

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

Mảng FILE _iob sẽ được biên dịch với VS2015 và do đó, nó sẽ được đặt dưới dạng một khối cấu trúc chứa khoảng trống *. Giả sử căn chỉnh 32-bit, các phần tử này sẽ cách nhau 4 byte. Vì vậy, _iob [0] ở độ lệch 0, _iob [1] ở độ lệch 4 và _iob [2] ở độ lệch 8. Thay vào đó, mã gọi sẽ mong đợi FILE dài hơn nhiều, được căn chỉnh ở 32 byte trên hệ thống của tôi, v.v. nó sẽ lấy địa chỉ của mảng được trả về và thêm 0 byte để đến phần tử 0 (cái đó được), nhưng đối với _iob [1], nó sẽ suy ra rằng nó cần thêm 32 byte và đối với _iob [2] thì nó sẽ suy ra rằng nó cần thêm 64 byte (vì đó là cách nó trông như thế nào trong tiêu đề VS2008). Và thực sự mã được tháo rời cho VS2008 thể hiện điều này.

Một vấn đề thứ hai với giải pháp trên là nó sao chép nội dung của cấu trúc FILE (* stdin), không phải xử lý FILE *. Vì vậy, bất kỳ mã VS2008 nào cũng sẽ xem xét một cấu trúc cơ bản khác với VS2015. Điều này có thể hoạt động nếu cấu trúc chỉ chứa con trỏ, nhưng đó là một rủi ro lớn. Trong mọi trường hợp, vấn đề đầu tiên làm cho điều này không liên quan.

Cách hack duy nhất mà tôi có thể mơ ước là một trong đó __iob_func đi qua ngăn xếp cuộc gọi để tìm ra xử lý tệp thực sự mà họ đang tìm kiếm (dựa trên phần bù được thêm vào địa chỉ trả về) và trả về một giá trị được tính toán sao cho nó đưa ra câu trả lời đúng. Điều này nghe có vẻ điên rồ một chút, nhưng nguyên mẫu chỉ dành cho x86 (không phải x64) được liệt kê bên dưới để bạn giải trí. Nó hoạt động ổn trong các thử nghiệm của tôi, nhưng số dặm của bạn có thể thay đổi - không được khuyến nghị sử dụng trong sản xuất!

#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;
}

Câu trả lời đúng là cái này, cách khắc phục đơn giản nhất như đã nêu là nâng cấp dự án lên VS2015 và sau đó biên dịch.
Akumaburn

2
Trong trường hợp của tôi, tôi cần nâng cấp nhiều dự án (dự án C ++ và C #) từ visual studio 2013 để sử dụng Visual Studio 2015 Update 3. Tôi muốn giữ lại VC100 (Visual studio 2010 C ++ compiler) khi xây dựng các dự án C ++ nhưng tôi bị lỗi tương tự như trên. Tôi đã sửa imp _fprintf bằng cách thêm inherit_stdio_definitions.lib vào trình liên kết. Tôi cũng có thể sửa lỗi _imp____iob_func như thế nào?
Mohamed BOUZIDI

Trước khi trả lời câu hỏi trước của tôi, Có bình thường những lỗi này xảy ra khi sử dụng msbuild 14 và IntelCompiler 2016 và VC100 để biên dịch các dự án C ++ không?
Mohamed BOUZIDI

1
tôi có thể làm gì để biên dịch x64?
athos

28

Tôi đã gặp vấn đề tương tự trong VS2015. Tôi đã giải quyết nó bằng cách biên dịch các nguồn SDL2 trong VS2015.

  1. Tới http://libsdl.org/download-2.0.php và tải SDL 2 mã nguồn.
  2. Mở SDL_VS2013.sln trong VS2015 . Bạn sẽ được yêu cầu chuyển đổi các dự án. Làm đi.
  3. Biên dịch dự án SDL2.
  4. Biên dịch dự án SDL2main.
  5. Sử dụng các tệp đầu ra được tạo mới SDL2main.lib, SDL2.lib và SDL2.dll trong dự án SDL 2 của bạn trong VS2015.

4
BTW, xây dựng SDL 2.0.3 yêu cầu cài đặt DirectX SDK tháng 6 năm 2010.
Joe

1
Làm việc cho tôi, cảm ơn !! Nhưng tôi chỉ cần biên dịch SDL2mainvà sao chépSDL2main.lib
kgwong

10

Tôi không biết tại sao nhưng:

#ifdef main
#undef main
#endif

Sau khi bao gồm nhưng trước khi chính của bạn nên sửa chữa nó từ kinh nghiệm của tôi.


1
.... Được rồi .... vì vậy trước khi thử cái này, tôi đã tự nói với bản thân rằng bằng cách nào đó tôi nghi ngờ điều này sẽ hoạt động nhưng nó đã hoàn toàn thành công ..... bạn có thể giải thích tại sao nó hoạt động ...?
Trevor Hart

1
@TrevorHart Tôi tin rằng nó xác định một chính SDL "bị lỗi" bao gồm các tham chiếu đến các bộ đệm "không xác định" và nếu của bạn sử dụng bộ đệm của mình, thì nó hoạt động tốt và tốt.
The XGood

2
Đây là một thủ thuật thực hành tồi tệ khủng khiếp nhưng nó có 3 dòng và nó hoạt động và nó đã giúp tôi khỏi phải xây dựng SDL một cách ... tuyệt vời.
Cheezmeister

1
@Cheezmeister Thực hành xấu và hack thường được yêu cầu cho mọi thứ. Đặc biệt là những thứ không cần thiết.
The XGood


7

Liên kết có nghĩa là không hoạt động bình thường. Đào vào stdio.h của VS2012 và VS2015, điều sau đây phù hợp với tôi. Than ôi, bạn phải quyết định xem nó có hoạt động cho một trong các {stdin, stdout, stderr} hay không, không bao giờ nhiều hơn một.

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

Lời khuyên của tôi là không (cố gắng) triển khai __iob_func.

Trong khi sửa các lỗi này:

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

Tôi đã thử các giải pháp của các câu trả lời khác, nhưng cuối cùng, trả về một FILE*mảng C không khớp với một mảng cấu trúc IOB nội bộ của Windows. @Volker là đúng rằng nó sẽ không bao giờ làm việc cho nhiều hơn một trong stdin, stdouthoặc stderr.

Nếu thư viện thực sự SỬ DỤNG một trong những luồng đó , nó sẽ bị sập . Miễn là chương trình của bạn không khiến lib sử dụng chúng, bạn sẽ không bao giờ biết được . Ví dụ: png_default_errorghi vào stderrkhi CRC không khớp trong siêu dữ liệu của PNG. (Thông thường không phải là vấn đề đáng gặp)

Kết luận: Không thể trộn các thư viện VS2012 (Platform Toolset v110 / v110_xp) và VS2015 +, nếu chúng sử dụng stdin, stdout và / hoặc stderr.

Giải pháp: Biên dịch lại các thư viện của bạn có __iob_funccác ký hiệu chưa được giải quyết với phiên bản VS hiện tại của bạn và Bộ công cụ nền tảng phù hợp.



2

Tôi giải quyết vấn đề này với chức năng sau. Tôi sử dụng Visual Studio 2019.

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

bởi vì stdin lệnh gọi hàm được định nghĩa Macro, biểu thức "* stdin" không thể sử dụng bộ khởi tạo mảng toàn cục. Nhưng trình khởi tạo mảng cục bộ là có thể. xin lỗi, tôi kém tiếng anh.


1

Đối với bất kỳ ai vẫn đang tìm kiếm câu trả lời nơi các thủ thuật trên không hoạt động. Liên kết tĩnh là cách để giải quyết vấn đề này. Thay đổi cài đặt thư viện Thời gian chạy của bạn như bên dưới

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


Đây là một cuộc thảo luận về giải pháp này: social.msdn.microsoft.com/Forums/vstudio/en-US/…
Sisir

0

Tôi đã quản lý để khắc phục sự cố.

Nguồn của lỗi là dòng mã này, có thể được tìm thấy trong mã nguồn SDLmain.

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

Vì vậy, những gì tôi đã làm là chỉnh sửa mã nguồn trong SDLmain của dòng đó:

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

Và sau đó tôi đã xây dựng SDLmain và sao chép và thay thế SDLmain.lib cũ trong thư mục thư viện SDL2 của tôi bằng tệp mới được xây dựng và chỉnh sửa.

Sau đó, khi tôi chạy chương trình của mình với SDL2, không có thông báo lỗi nào xuất hiện và mã chạy trơn tru.

Tôi không biết liệu điều này có cắn tôi sau này không, nhưng vì vậy mọi thứ đang diễn ra rất tốt.


Thay đổi của bạn là một sai lầm tự thân và sẽ không khắc phục được sự cố được mô tả trong câu hỏi của bạn. Chỉ là ngẫu nhiên khi bạn không còn gặp lỗi trình liên kết nữa, đây có thể chỉ là kết quả của cách bạn xây dựng lại thư viện.
Ross Ridge

@RossRidge, oh yeah, đó có thể là điều đó. À tốt.
RockFrenzy

0

Điều này có thể xảy ra khi bạn liên kết đến msvcrt.dll thay vì msvcr10.dll (hoặc tương tự), đây là một kế hoạch tốt. Bởi vì nó sẽ giúp bạn giải phóng để phân phối lại thư viện thời gian chạy của Visual Studio bên trong gói phần mềm cuối cùng của bạn.

Cách giải quyết đó giúp tôi (tại Visual Studio 2008):

#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

Đoạn mã này không cần thiết cho Visual Studio 6 và trình biên dịch của nó. Do đó, #ifdef.


0

Để mang lại nhiều nhầm lẫn hơn trong chủ đề vốn đã phong phú này, tôi đã tình cờ gặp phải cùng một bên ngoài chưa được giải quyết trên fprintf

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

Ngay cả khi trong trường hợp của tôi, nó ở trong một bối cảnh khá khác: trong Visual Studio 2005 (Visual Studio 8.0) và lỗi đang xảy ra trong mã của chính tôi (chính là mã mà tôi đang biên dịch), không phải bên thứ ba.

Đã xảy ra lỗi này do tùy chọn / MD kích hoạt trong cờ trình biên dịch của tôi. Chuyển sang / MT đã loại bỏ sự cố. Điều này thật kỳ lạ vì thông thường, liên kết tĩnh (MT) nảy sinh nhiều vấn đề hơn liên kết động (MD) ... nhưng chỉ trong trường hợp nó phục vụ cho việc khác, tôi đặt nó ở đó.


0

Trong trường hợp của tôi, lỗi này xuất phát từ việc tôi dùng thử để loại bỏ các phụ thuộc vào thư viện thời gian chạy phụ thuộc phiên bản MSVC DLL (msvcr10.dll hoặc hơn) và / hoặc cũng xóa thư viện thời gian chạy tĩnh, để loại bỏ mỡ thừa khỏi tệp thực thi của tôi.

Vì vậy, tôi sử dụng công tắc trình liên kết / NODEFAULTLIB, "msvcrt-light.lib" do tôi tự tạo (google cho nó khi bạn cần) và mainCRTStartup()/ WinMainCRTStartup()các mục nhập.

Đó là IMHO kể từ Visual Studio 2015, vì vậy tôi mắc kẹt với các trình biên dịch cũ hơn.

Tuy nhiên, việc xác định ký hiệu _NO_CRT_STDIO_INLINE sẽ loại bỏ mọi rắc rối và một ứng dụng "Hello World" đơn giản lại nhỏ hơn 3 KB và không phụ thuộc vào các tệp DLL bất thường. Đã thử nghiệm trong Visual Studio 2017.


-2

Dán mã này vào bất kỳ tệp nguồn nào của bạn và xây dựng lại. Đã làm cho tôi !

#include stdio.h

TẬP TIN _iob [3];

FILE * __cdecl __iob_func (void) {

_iob [0] = * stdin;

_iob [0] = * stdout;

_iob [0] = * stderr;

return _iob;

}


bạn nên thêm định dạng với `` 'và cũng có một số giải thích
Antonin GAVREL

Mặc dù mã này có thể giải quyết câu hỏi, bao gồm giải thích về cách thức và lý do tại sao điều này giải quyết vấn đề sẽ thực sự giúp cải thiện chất lượng bài đăng của bạn và có thể dẫn đến nhiều phiếu bầu hơn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai, không chỉ người hỏi bây giờ. Vui lòng chỉnh sửa câu trả lời của bạn để thêm giải thích và đưa ra dấu hiệu về những giới hạn và giả định áp dụng.
Brian
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.