-2

I've been getting "0xC0000005: Access violation reading location errors" in Visual Studio on Windows with a C/C++ program and have attempted to simplify to illustrate my question. The code below runs just fine:

char tmp[1000];
ULONG64 val1 = 1;
sprintf_s(tmp, 1000, "%lu, %s, %s", val1, "true", "false");

However, when I add an extra unsigned long to the format, I get an access violation, like with the code below:

char tmp[1000];
ULONG64 val1 = 1;
ULONG64 val2 = 2;
sprintf_s(tmp, 1000, "%lu, %lu, %s, %s", val1, val2, "true", "false");
Steve Friedl
  • 3,929
  • 1
  • 23
  • 30
public wireless
  • 767
  • 8
  • 20
  • 3
    "_with a C/C++ program_" There's no such language as "C/C++". It's either C, **or** C++. Which are you, actually, using? Once you have the answer to this question: remove the tag of the language, that you are not using. – Algirdas Preidžius Dec 13 '19 at 18:22
  • Minor tidbit not weighing into the problem, but it's really wise to derive the size of a buffer from the variable itself rather than repeat the number: `sprintf_s(tmp, sizeof tmp, ...)`. This avoids unhappy surprises if you change one and forget to change the other. – Steve Friedl Dec 13 '19 at 18:24
  • The program uses Windows C libraries but I try to use C++ whereever possible, like std::string – public wireless Dec 13 '19 at 18:25
  • @publicwireless So, C++ then. – Lightness Races in Orbit Dec 13 '19 at 18:28
  • 1
    @WeatherVane That's not a note, it's an answer! – Lightness Races in Orbit Dec 13 '19 at 18:29
  • @publicwireless "_The program uses Windows C libraries_" You are asking about your code, are you not? Hence it doesn't matter what external libraries, your code links to. Only thing, that matters is what language you are writing your code with (i.e. which compiler you are compiling your code with). And it's either C, or C++. Tagging your question with both C, and C++ tags are acceptable only if you are asking about interop between C, and C++, or you are asking about differences between C, and C++. – Algirdas Preidžius Dec 13 '19 at 18:29
  • @AlgirdasPreidžius It's definately the Visual Studio C++ compiler but I was under the impression sprintf_s is one of the old legacy C libraries. As you can see I'm new to these 2 languages – public wireless Dec 13 '19 at 18:33
  • If you want to use C++ whereever possible, the whole question would demand a different answer -- because the answer shouldn't tell you the errors you made in using the (C) function `sprintf_s`, but instead show you how to use `std::string` and `std::stringstream` instead of `char[]` and `sprintf_s`... *do not* learn "the C way" first. Most of what you learn there needs to be *unlearned* to write good C++ eventually. – DevSolar Dec 13 '19 at 18:34
  • @publicwireless Please re-read my comment. I already mentioned: how external libraries, you are using, are compiled - doesn't matter. All that matters is what you are using to compile the code, that you are showing. – Algirdas Preidžius Dec 13 '19 at 18:55
  • @publicwireless If you're using `sprintf_s()` because Visual Studio "suggested" you do so, read this: https://stackoverflow.com/questions/59239734/why-strcpy-s-is-safer-than-strcpy/59240176#59240176 – Andrew Henle Dec 13 '19 at 21:51

3 Answers3

7

The format specifier %lu is for unsigned long which is 32 bits not 64 on MSVC.

So the stacked arguments are misalinged, and MSVC should warn about this.

You could hedge with %llu but ideally use the proper format to guarantee a match for a fixed width variable.

If the type were uint64_t then for example when using printf you should have

printf("%" PRIu64 "\n", val1);

for example.

Weather Vane
  • 33,872
  • 7
  • 36
  • 56
1

It seems like %lu is not a correct format specifier.

Passing value of inproper type will lead to undefined behavior.

You should use the format specifier %I64u instead.

because:

MikeCAT
  • 73,922
  • 11
  • 45
  • 70
0

You mentioned in a comment that you'd prefer to use C++ where possible. Then do it, and eschew all that type-unsafe C!

#include <sstream>
#include <string>

int main()
{
    unsigned long val1 = 1;
    unsigned long val2 = 2;
    std::ostringstream sstr;

    // the true/false being a bit nonsensical, but to
    // stay close to your original code
    sstr << val1 << ", " << val2 << ", " << "true" << ", " << "false";

    std::string tmp{ sstr.str() };
}
DevSolar
  • 67,862
  • 21
  • 134
  • 209