undefined reference to `WinMain#16' mingw converting to DLL - c

I am trying to convert the given C code to DLL file I tried to compile the given code but it doesn't work it gives me an error
.\sample.cpp:16:66: warning: passing NULL to non-pointer argument 5 of 'void* CreateThread(LPSECURITY_ATTRIBUTES, DWORD, LPTHREAD_START_ROUTINE, PVOID, DWORD, PDWORD)' [-Wconversion-null]
c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe: c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../libmingw32.a(main.o):(.text.startup+0xb0): undefined reference to `WinMain#16'
collect2.exe: error: ld returned 1 exit status
I have already tried looking up the answers available online, along with looking at the syntax which seems to be okay.
My Code
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
extern "C" __declspec(dllexport)
DWORD WINAPI MessageBoxThread(LPVOID lpParam) {
MessageBox(NULL, "Hello world!", "Hello World!", NULL);
return 0;
}
extern "C" __declspec(dllexport)
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
CreateThread(NULL, NULL, MessageBoxThread, NULL, NULL, NULL);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

I'm using Visual Studio 2017 community edition, version 15.8.1 for reference. I created a simple DLL project (using File | New | Project) and removed all files except dllmain.cpp I had to modify the project properties to disable the use of precompiled headers. The code in dllmain.cpp is:
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
extern "C" __declspec(dllexport)
DWORD WINAPI MessageBoxThread(LPVOID lpParam)
{
MessageBoxA(NULL, "Hello World", "Hello World", MB_YESNO);
return 0;
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
DWORD dwTID;
CreateThread(nullptr, 0, MessageBoxThread, nullptr, 0, &dwTID);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
I've made a few modifications from your code,
I passed MB_YESNO as the final argument to MessageBox instead of a null pointer. This will give your message box YES and NO buttons, and this matches the type expected (uint) for the fourth parameter.
I used MessageBoxA to force ASCII argument instead of MessageBox, which is a typedef that resolves to MessageBoxW. This effects the type of strings that is expected, and is based on if you are using Unicode or not.
I passed a value of zero for the second argument (dwStackSize) and the fifth argument (dwCreationFlags) of CreateThread instead of NULL. Both of these arguments have type DWORD. Notice that this fixes the first line of your error message ".\sample.cpp:16:66: warning: passing NULL to non-pointer argument 5"
I declared a variable dwTID and pass a pointer to it as the sixth argument of CreateThread.
I added a break statement to the first case. This should not have any consequence in the code. I just think it is a good idea.
The above code compiles without warnings or errors. Thus I believe that your code should also compile as well. Thus I strongly suspect that the errors you are seeing are due to the compiler and linker flags you are using. The command lines that are being used are
for compilation:
/JMC /permissive- /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm- /Od /sdl /Fd"Debug\vc141.pdb" /Zc:inline /fp:precise /D "WIN32" /D "_DEBUG" /D "TESTDLL_EXPORTS" /D "_WINDOWS" /D "_USRDLL" /D "_WINDLL" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /FC /Fa"Debug\" /EHsc /nologo /Fo"Debug\" /Fp"Debug\testDll.pch" /diagnostics:classic
for linking:
/OUT:"D:\GNUHome\Projects\testDll\Debug\testDll.dll" /MANIFEST /NXCOMPAT /PDB:"D:\GNUHome\Projects\testDll\Debug\testDll.pdb" /DYNAMICBASE "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib"/IMPLIB:"D:\GNUHome\Projects\testDll\Debug\testDll.lib" /DEBUG /DLL /MACHINE:X86 /INCREMENTAL /PGD:"D:\GNUHome\Projects\testDll\Debug\testDll.pgd" /SUBSYSTEM:WINDOWS /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile:"Debug\testDll.dll.intermediate.manifest" /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
Because you are not using native Microsoft toos (CL and LINK), you are going to need to find or prepare a mapping between the tool chain you are using (which you did not mention, but it appears to be mingw from the error messages) and Microsoft's tool chain.
If'n I had to guess, I would suspect that the issue is due to the /DLL flag in the linking command line. You might have to use something line -shared with mingw. However this is just a guess.

Related

How do I create a static library (.lib) which depends on the dynamic (.dll) tensorflow library?

I have created a static C library in Visual Studio 2019 on Windows 10 which depends on the tensorflow library, which is dynamic (.dll). My library, lets call it A.lib, contains a function which takes data, pass it to a tensorflow model and returns the model's output. The compilation seems to work well and creates an A.lib file.
Now I want to use my static library in another project to create an .exe. Lets call it B. I copied the header A.h and the A.lib into the B project and adapt the project properties so that my library can be found.
The problem is that I get LNK2001 errors, because the linker can not find the definitions of the tensorflow functions which I call in my A.lib.
I tried to copy the tensorflow lib into my project B as well. But that did not help.
What do I have to do to include the libraries correctly? Or is there a simpler alternative to deploy a convolutional neural network in C?
Here's a [SO]: How to create a Minimal, Reproducible Example (reprex (mcve)).
dll00.h:
#if defined(_WIN32)
# if defined(DLL00_EXPORTS)
# define DLL00_EXPORT_API __declspec(dllexport)
# else
# define DLL00_EXPORT_API __declspec(dllimport)
# endif
#else
# define DLL00_EXPORT_API
#endif
#if defined(__cplusplus)
extern "C" {
#endif
DLL00_EXPORT_API int dll00Func00();
#if defined(__cplusplus)
}
#endif
dll00.c:
#define DLL00_EXPORTS
#include "dll00.h"
#include <stdio.h>
int dll00Func00() {
printf("%s - %d - %s\n", __FILE__, __LINE__, __FUNCTION__);
return -3;
}
lib00.h:
#if defined(__cplusplus)
extern "C" {
#endif
int lib00Func00();
#if defined(__cplusplus)
}
#endif
lib00.c:
#include "lib00.h"
#include "dll00.h"
#include <stdio.h>
int lib00Func00() {
printf("%s - %d - %s\n", __FILE__, __LINE__, __FUNCTION__);
return dll00Func00() - 3;
}
main00.c:
#include "lib00.h"
#include <stdio.h>
int main() {
printf("%s - %d - %s\n", __FILE__, __LINE__, __FUNCTION__);
int res = lib00Func00();
printf("Lib func returned: %d\n", res);
printf("\nDone.\n");
return 0;
}
Output:
[cfati#CFATI-5510-0:e:\Work\Dev\StackOverflow\q069197545]> sopr.bat
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
[prompt]> "c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\VC\Auxiliary\Build\vcvarsall.bat" x64 >nul
[prompt]> dir /b
dll00.c
dll00.h
lib00.c
lib00.h
main00.c
[prompt]> :: Build .dll (1 step)
[prompt]> cl /nologo /MD /DDLL dll00.c /link /NOLOGO /DLL /OUT:dll00.dll
dll00.c
Creating library dll00.lib and object dll00.exp
[prompt]> :: Build .lib (2 steps)
[prompt]> cl /c /nologo /MD /Folib00.obj lib00.c
lib00.c
[prompt]> lib /NOLOGO /OUT:lib00.lib lib00.obj
[prompt]> :: Build .exe (1 step)
[prompt]> cl /nologo /MD /W0 main00.c /link /NOLOGO /OUT:main00_pc064.exe lib00.lib dll00.lib
main00.c
[prompt]> dir /b
dll00.c
dll00.dll
dll00.exp
dll00.h
dll00.lib
dll00.obj
lib00.c
lib00.h
lib00.lib
lib00.obj
main00.c
main00.obj
main00_pc064.exe
[prompt]> main00_pc064.exe
main00.c - 7 - main
lib00.c - 9 - lib00Func00
dll00.c - 8 - dll00Func00
Lib func returned: -6
Done.
So, it works (at least this trivial example). As seen, when building the .exe I also passed the .dll's .lib to the linker (meaning that the .dll (together with all its (recurring) dependents) is required at runtime). For info on how to do it on the VStudio project, check [SO]: How to include OpenSSL in Visual Studio (#CristiFati's answer).

Why does setjmp() take 2 args on windows but only 1 arg on linux?

This setjmp.c builds in windows under Microsoft Visual Studio Professional 2019 (Version 16.10.1)
Rebuild started...
1>------ Rebuild All started: Project: setjmp, Configuration: Release x64 ------
1>setjmp.c
1>C:\Users\john\source\repos\setjmp\setjmp.c(48,10): warning C4013: 'setjmp' undefined; assuming extern returning int
1>Generating code
1>Previous IPDB not found, fall back to full compilation.
1>All 1 functions were compiled because no usable IPDB/IOBJ from previous compilation was found.
1>Finished generating code
1>setjmp.vcxproj -> C:\Users\john\source\repos\setjmp\x64\Release\setjmp.exe
1>Done building project "setjmp.vcxproj".
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========
The actual cl.exe C compiler command is
1> C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30037\bin\HostX86\x64\CL.exe /c /Zi /nologo /W3 /WX- /diagnostics:column /sdl /O2 /Oi /GL /D NDEBUG /D _CONSOLE /D _UNICODE /D UNICODE /Gm- /EHsc /MD /GS /Gy /fp:precise /permissive- /Zc:wchar_t /Zc:forScope /Zc:inline /Fo"x64\Release\\" /Fd"x64\Release\vc142.pdb" /external:env:EXTERNAL_INCLUDE /external:W3 /Gd /TC /FC /errorReport:prompt setjmp.c
The source code is
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
typedef uint64_t QWORD;
typedef uint32_t DWORD;
typedef uint16_t WORD;
typedef uint8_t BYTE;
typedef struct MSTJMP_FLOAT128
{
QWORD Part[2];
} MSTJMP_FLOAT128;
typedef struct JUMP_BUFFER
{
QWORD Frame0;
QWORD Rbx0;
QWORD Rsp0;
QWORD Rbp0;
QWORD Rsi0;
QWORD Rdi0;
QWORD R120;
QWORD R130;
QWORD R140;
QWORD R150;
QWORD Rip0;
DWORD MxCsr4;
WORD FpCsr2;
WORD Spare2;
struct MSTJMP_FLOAT128 Xmm6x;
struct MSTJMP_FLOAT128 Xmm7x;
struct MSTJMP_FLOAT128 Xmm8x;
struct MSTJMP_FLOAT128 Xmm9x;
struct MSTJMP_FLOAT128 Xmm10x;
struct MSTJMP_FLOAT128 Xmm11x;
struct MSTJMP_FLOAT128 Xmm12x;
struct MSTJMP_FLOAT128 Xmm13x;
struct MSTJMP_FLOAT128 Xmm14x;
struct MSTJMP_FLOAT128 Xmm15x;
} JUMP_BUFFER;
int main() {
struct JUMP_BUFFER jumpbuffer;
setjmp(&jumpbuffer, 0);
return 0;
}
The disassembly for setjmp() call is
setjmp(&jumpbuffer, 0);
00007FF641B51019 xor edx,edx
00007FF641B5101B lea rcx,[jumpbuffer]
00007FF641B51020 call __intrinsic_setjmp (07FF641B51C20h)
which leads to the setjmp() code
--- d:\a01\_work\2\s\src\vctools\crt\vcruntime\src\eh\amd64\setjmp.asm ---------
00007FF82B6F0300 mov qword ptr [rcx],rdx
00007FF82B6F0303 mov qword ptr [rcx+8],rbx
00007FF82B6F0307 mov qword ptr [rcx+18h],rbp
so everything is functioning correctly without any errors because windows is using a C-runtime intrinsic within setjmp.asm
However, under linux, it generates an error:
error: macro "setjmp" passed 2 arguments, but takes just 1
Google'ing found this code snippet:
#if defined(_WIN64)
/* On w64, setjmp is implemented by _setjmp which needs a second parameter.
* If this parameter is NULL, longjump does no stack unwinding.
* That is what we need for QEMU. Passing the value of register rsp (default)
* lets longjmp try a stack unwinding which will crash with generated code. */
# undef setjmp
# define setjmp(env) _setjmp(env, NULL)
#endif
To sum up, windows can take 2 args:
setjmp(&jumpbuffer, 0);
and linux can take 1 arg:
setjmp(&jumpbuffer);
To verify that linux likes that setjmp, I traced with gdb as follows:
Your issue is that you didn't #include <setjmp.h> so the compiler doesn't know the function signature and assumes that setjmp is some function returning int and accepts an unknown number of parameters of unknown types. When you declare func() then it's a function returning int in older C standards and you can call func(), func(1, 2, 3) or func(1, "abc", 'd', 2, 3)... - all are valid
Notice the warning right from your compiler output
setjmp.c(48,10): warning C4013: 'setjmp' undefined; assuming extern returning int
It can also be reproducible on godbolt, with the same warning from MSVC. And you can see that the compiler doesn't report any errors even though I've added some dummy setjmp calls like
setjmp(&jumpbuffer, 0);
setjmp();
setjmp(1, 2, "abc");
setjmp(&jumpbuffer, 0, 3, 4, 5);
See
Implicit function declarations sometimes work in C?
Why does declaration of function with int return type is not compulsory in C?
Are prototypes required for all functions in C89, C90 or C99?
warning: implicit declaration of function
Implicit function declarations in C
Is implicit function declaration legal in C89?
Is it portable to define and declare the function after calling it in main in C?

Re-write segment of a compiled C program

I've a C program structured in this way:
#include <Windows.h>
#include <stdio.h>
#include <stdint.h>
#pragma section(".code",execute, read, write)
#pragma comment(linker,"/SECTION:.code,ERW")
#pragma code_seg(".code")
//Code to decrypt
#pragma section(".stub", execute, read, write)
#pragma code_seg(".stub")
void decryptor(){
//Retrieve virtual address of the pointer to the .code section
//Retrieve the virtual size of the pointer to the .code section
for(int i = 0; i<size; i++){
//HERE THE PROGRAM STOPS
ptrCode[0] = //Reverse function of the encryptor
}
}
int main(){
decryptor();
mainFunctionDecrypted();
return 0;
}
Basically i've an encryptor which first encrypt the .code segment in the exe of this program after compilation.
Then when i execute the modified exe i want to be able to first decrypt it and then execute the decrypted part. However it seems like i cannot write to the .code segment loaded in memory (I think because it's a part memory dedicated to code to be executed).
Is there any way to write to executable memory?
Is there any workaroud you would do?
Windows and other operating systems go out of their way to prevent you from doing this (modifying the code sections of a running application).
Your immediate options, then, are
1) decrypt the code to some other memory area allocated dynamically for that purpose (code must then either use only position-independent instructions, or contain custom fixups for the instructions that have position-specific data).
2) use a separate program that decrypts the program on disk before it is executed.
Obfuscating a program in this way is inherently futile. Whatever your "decryptor" does, a human who is determined to reverse engineer your program can also do. Spend your effort instead on making your program desirable enough that people want to pay you for it, and benevolent enough that you don't have to hide what it's doing.
I need to modify the code in the following way. Moreover there are important compiler option to set in visual studio, for example to disable the Data Execution Prevention.
Compiler option used:
/permissive- /GS /TC /GL /analyze- /W3 /Gy /Zc:wchar_t /Gm- /O2 /sdl /Zc:inline /fp:precise /Zp1 /D "_MBCS" /errorReport:prompt /WX- /Zc:forScope /GR- /Gd /Oy- /Oi /MD /FC /nologo /diagnostics:classic
Linker option used:
/MANIFEST /LTCG:incremental /NXCOMPAT:NO /DYNAMICBASE:NO "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /FIXED /MACHINE:X86 /OPT:REF /SAFESEH /INCREMENTAL:NO /SUBSYSTEM:CONSOLE /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /MAP /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
#pragma section(".code", execute, read)
#pragma section(".codedata", read, write)
#pragma comment(linker,"/SECTION:.code,ERW")
#pragma comment(linker,"/SECTION:.codedata,ERW")
#pragma comment(linker, "/MERGE:.codedata=.code")
//All the following will go in code
#pragma code_seg(".code")
#pragma data_seg(".codedata")
#pragma const_seg(".codedata")
//CODE TO DECRYPT
// .stub SECTION
#pragma section(".stub", execute, read)
#pragma section(".stubdata", read, write)
#pragma comment(linker,"/SECTION:.stub,ERW")
#pragma comment(linker,"/SECTION:.stubdata,ERW")
#pragma comment(linker, "/MERGE:.stubdata=.stub")
//All the following will go in .stub segment
#pragma code_seg(".stub")
#pragma data_seg(".stubdata")
#pragma const_seg(".stubdata")
/*This function needs to be changed to whatever correspond to the decryption function of the encryotion function used by the encryptor*/
void decryptCodeSection(){
//Retrieve virtual address of the pointer to the .code section
//Retrieve the virtual size of the pointer to the .code section
for(int i = 0; i<size; i++){
//HERE THE PROGRAM STOPS
ptrCode[0] = //Reverse function of the encryptor
}
void main(int argc, char* argv[]){
decryptor();
mainFunctionDecrypted();
}
Doing this way i was able to first decrypt the segment and then execute the function.

What is the stack limit when MATLAB calls function in DLL

I am trying to figure out, what is the stack size limitation, when MATLAB calls function in DLL.
Is there a way to configure the limit?
I am using loadlibrary, and calllib functions to call function implemented in C (in Dynamic-link library).
I created a test to figure out the stack limit.
I am using MATLAB 2016a (64 bits), and Visual Studio 2010 for building the DLL.
Here is my MATLAB source code:
loadlibrary('MyDll','MyDll.h')
size_in_bytes = 1000000;
res = calllib('MyDll', 'Test', size_in_bytes);
if (res == -1)
disp(['Stack Overflow... (size = ', num2str(size_in_bytes), ')']);
else
disp(['Successful stack allocation... (size = ', num2str(size_in_bytes), ')']);
end
unloadlibrary MyDll
Here is my C source code:
MyDll.h
// MyDll.h : DLL interface.
#ifndef MY_DLL_H
#define MY_DLL_H
#ifdef MY_DLL_EXPORTS
#define MY_DLL_API __declspec(dllexport)
#else
#define MY_DLL_API __declspec(dllimport)
#endif
extern MY_DLL_API int Test(int size);
#endif
MyDll.c
// MyDll.c
#include "MyDll.h"
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
//Allocate <size> bytes in stack using _alloca(size).
//Return 0 if OK.
//Return (-1) in case of stack overflow.
int Test(int size)
{
//Not allocated on the stack...
static wchar_t errorMsg[100];
static wchar_t okMsg[100];
int errcode = 0;
void *pData = NULL;
//Prepare messages from advance.
swprintf_s(errorMsg, 100, L"Stack Overflow (size = %d)", size);
swprintf_s(okMsg, 100, L"Successful stack allocation (size = %d)", size);
__try
{
pData = _alloca(size);
}
// If an exception occurred with the _alloca function
__except (GetExceptionCode() == STATUS_STACK_OVERFLOW)
{
MessageBox(NULL, errorMsg, TEXT("Error"), MB_OK | MB_ICONERROR);
// If the stack overflows, use this function to restore.
errcode = _resetstkoflw();
if (errcode)
{
MessageBox(NULL, TEXT("Could not reset the stack!"), TEXT("Error"), MB_OK | MB_ICONERROR);
_exit(1);
}
pData = NULL;
};
if (pData != NULL)
{
//Fill allocated buffer with zeros
memset(pData, 0, size);
MessageBox(NULL, okMsg, TEXT("OK"), MB_OK);
return 0;
}
return -1;
}
The __try and __except block is taken from Microsoft example:
https://msdn.microsoft.com/en-us/library/wb1s57t5.aspx
DLL Compiler flags:
/Zi /nologo /W4 /WX- /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_USRDLL" /D "MY_DLL_EXPORTS" /D "_WINDLL" /D "_UNICODE" /D "UNICODE" /Gm /EHsc /RTC1 /MTd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Fp"x64\Debug\MyDll.pch" /Fa"x64\Debug\" /Fo"x64\Debug\" /Fd"x64\Debug\vc100.pdb" /Gd /errorReport:queue
DLL Linker flags:
/OUT:"x64\Debug\MyDll.dll" /INCREMENTAL:NO /NOLOGO /DLL "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /MANIFEST /ManifestFile:"x64\Debug\MyDll.dll.intermediate.manifest" /ALLOWISOLATION /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"c:\Tmp\MyDll\x64\Debug\MyDll.pdb" /SUBSYSTEM:CONSOLE /PGD:"c:\Tmp\MyDll\x64\Debug\MyDll.pgd" /TLBID:1 /DYNAMICBASE /NXCOMPAT /MACHINE:X64 /ERRORREPORT:QUEUE
I executed the MATLAB code using different values of size_in_bytes:
size_in_bytes = 1000000: Pass!
size_in_bytes = 10000000: Pass!
size_in_bytes = 50000000: Pass!
size_in_bytes = 60000000: Pass!
size_in_bytes = 70000000: Stack Overflow!
Looks like the limit in my system is about 64MByte (but I don't know if this number is true for all systems).
I tried to modify stack size of Matlab.exe using editbin tool.
I tried the following command (for example):
editbin /STACK:250000000 "c:\Program Files\MATLAB\R2016a\bin\matlab.exe".
This option sets the size of the stack in bytes and takes arguments in decimal or C-language notation. The /STACK option applies only to an executable file.
It seems to have no affect...
Seems that on windows the size of the stack is set at compile time. So you can use option /F or the binary EDITBIN.
For example, you could to edit the following file:
EDITBIN /STACK:134217728 "C:\Program Files\MATLAB\R2016a\bin\win64\MATLAB.exe"
This would set the stack size to 128 MB (128 x 1024 x 1024 Bytes = 134217728 Bytes).
Note: be aware that editing the C:\Program Files\MATLAB\R2016a\bin\matlab.exe will have no effect.

VC rejecting hexadecimal floating-point constant

I'm writing a program which converts CIL bytecode to C source code for machine consumption. I was concerned about inaccuracy in floating-point constants due to conversion to and from decimal. After doing some research, I discovered that C (but not C++) is supposed to be able to accept a hexadecimal notation for floating-point constants.
I decided to try it out, but MS VC9 gives me errors no matter what I try. Here is what I'm trying:
// Switches: /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /FD /MDd /Fo"Debug\\" /Fd"Debug\vc90.pdb" /W3 /nologo /c /ZI /TC
#include <tchar.h>
#include <stdio.h>
int _tmain(int argc, _TCHAR* argv[])
{
double d = 0x1.0p+1; // error C2059
//double d = 0x1p+1; // doesn't work either
//double d = 0x1p1; // doesn't work either
//double d = 0x1.0p1; // doesn't work either
printf( "%f\n", d );
return 0;
}
I expected this to print out 2, from 1x2^1, but instead it gives me this compiler error:
error C2059: syntax error : 'bad suffix on number'
I realize C++ doesn't support this syntax (or so I've read,) but notice this is compiled with /TC so it should be straight C, and I used a *.c filename for good measure also.
Am I doing something wrong here, or is VC9 just not standards compliant?
There's nothing wrong with your code. Floating-point hexadecimal constants were added to C in the C99 standard, but MSVC only supports the older C90 standard (with some extensions, like // single-line comments and the long long type).
C++17 standard added full support of C99 hexadecimal floating-point literals. Visual C++ will have them available in Visual Studio 2017 15.6 release.

Resources