[OT] - Microsoft Madness: "strcpy_s" (And Friends) Does Not Compile On Linux - Help!

Hi,

I loaded my SDL2 game into Visual Studio 2019 but it would not compile.
It complained about “strcpy” (and friends).

I fixed all the errors and it builds on Visual Studio.
Only issue is it won’t build on Linux now?

“strcpy_s” (and friends) does not work on Linux?
Any ideas on how to fix the above, thanks!

Jesse

Annex K, which the _s functions come from is only supported on Windows so far. (And it’s not 100% standard compliant, but that’s another detail)

For most of them you could just make a wrapper using the preprocessor, but some of them get kind of tough to deal with. The most notable for me is the scanf family of functions that requires you to pass the length of strings right after them.

The two options you have are:

  • Use SDL’s libc if you have SDL in your project.
  • get rid of the _s warnings for Windows.

The latter you can be achieve by putting:

  • add_definitions​(-D_CRT_SECURE_NO_WARNINGS) ​#​ Disables warnings on _s functions (4996)
    In your CMakeLists.txt, or
  • #define _CRT_SECURE_NO_WARNINGS before any include of stdio.h

The option to make a “wrapper” would look like such:


#define __STDC_WANT_LIB_EXT1__ 1 //Not necessary on Windows, but technically required by standard

#include <stdio.h>

#if __STDC_LIB_EXT1__
#define MYFUNC(x, y, ...) myfunc_s(x, y, __VA_ARGS__)
#else
#define MYFUNC(x, y, ...) myfunc(x, y, __VA_ARGS__)
#endif

You’d want to put this in its own header and import that in every file that needs stdio.h.

Hope that was helpful!

As Petruska said, use SDL’s libc functions instead. If you can replace all your VC runtime library functions with SDL’s own then you don’t have to have a dependency on the horrible VC DLLs.

Have a look at SDL_strlcpy.

1 Like

Hi,

I have three functions that do not build on Linux:

  1. strcpy_s → SDL_strlcpy
  2. strcat_s → ???
  3. sprintf_s → ???

What should I use for the other two to have one code building on Windows and Linux?
Thanks!

Jesse

SDL_snprintf < you just have to add a maxlen, like you did with SDL_strlcpy.

SDL_strlcat < again with the maxlan, same as strlcpy.

SDL provides a pretty extensive replacement of the std stuff. Have a look at SDL_stdinc.h for a fill list.

1 Like

Are these 3 functions in the SDL2 Wiki somewhere?

There’s more than 3, about 100, all replacements of these good old stdio/stdlib C functions. Unfortunately they’re not picked up in the Wiki. Best place to go is the header file I mentioned (/SDL2/include/SDL_stdinc.h). If you want to find out what they all do then google the part without “SDL_”. So if you wanted to know how SDL_atoi works, google “atio”. A trick that works in Visual Studio is if you start typing “SDL_” and then the function you want, it will give you a list of matches in knows (picked up from the project’s header files) while you type, including the parameters it takes.

1 Like

Got it, thanks!

extern DECLSPEC size_t SDLCALL SDL_strlcpy(SDL_OUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen);

extern DECLSPEC size_t SDLCALL SDL_strlcat(SDL_INOUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen);

extern DECLSPEC int SDLCALL SDL_snprintf(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, SDL_PRINTF_FORMAT_STRING const char *fmt, ... ) SDL_PRINTF_VARARG_FUNC(3);
1 Like

Hi,

I have “SDL_strlcpy” and “SDL_strlcat” both working.

I am stuck on how to convert:
sprintf_s( temp, sizeof temp, “%c”, (65+indexOffset) );
to
“SDL_snprintf”

Any help would be appreciated, thanks!

Jesse

It looks like the function arguments in your sprintf_s example are in precisely the same order as the expected arguments of SDL_snprintf (as in buf, bufsize, format, ...rest). You could just swap in the SDL function name for that call.

Hmm, this is probably mostly academic in this particular instance but Microsoft’s version seems to behave a bit differently in cases where the buffer is too small to hold the full string. snprintf will merely truncate a string to fit the buffer whereas sprintf_s will only write a NUL byte to buf[0] in such cases. Sadly MS’ documentation is a bit too vague to my liking.

printf(3) ( printf(3): formatted output conversion - Linux man page ):

The functions snprintf() and vsnprintf() do not write more than size bytes (including the terminating null byte (’\0’)). If the output was truncated due to this limit, then the return value is the number of characters (excluding the terminating null byte) which would have been written to the final string if enough space had been available. Thus, a return value of size or more means that the output was truncated.

MS *printf_s* ( sprintf_s, _sprintf_s_l, swprintf_s, _swprintf_s_l | Microsoft Docs ):

sprintf_s returns the number of bytes stored in buffer, not counting the terminating null character.

The other main difference between sprintf_s and sprintf is that sprintf_s takes a length parameter specifying the size of the output buffer in characters. If the buffer is too small for the formatted text, including the terminating null, then the buffer is set to an empty string by placing a null character at buffer[0], and the invalid parameter handler is invoked.

What in the world were they thinking? I guess it works if you bother reading up on the details but still.

0Errors0Warnings

1 Like

Are they in the public SDL2 API, and therefore entirely legitimate to call from my programs, or are they private functions for SDL internal use (which would explain them not being in the Wiki)? Perhaps I’m untypical, but I care about such things!

I can understand the caution. They’re public. No need to #include anything extra. No need to call SDL_Init before using them. Perfectly safe because there are plenty of us using them and they’ve been refined a lot. I’d encourage everyone to use them and remove the need for any horrible visual-c runtime DLLs. Some functions are missing, but it should be enough to cover everyone.

You’re looking for safeclib.
It’s available in the Ubuntu repositories; I also built it for Fedora Core.

I’m in the middle of porting a very large legacy code base from Windows to Linux, and safeclib allowed me to preserve all the calls to secure-string functions.