Reputation: 30293
Why do I get different output every time I run this code (Ideone):
#include <iostream>
#include <stdio.h>
using namespace std;
int main() {
const char* _user = "FOO";
const char* _password = "BAR";
char login[21];
sprintf(login,
"\x15\x00\x01%-8s%-10s",
_user,
_password);
for (int i = 0; i < 21; i++) {
printf(" %02x", login[i] & 0xff);
}
return 0;
}
But not this code (Ideone):
#include <iostream>
#include <stdio.h>
using namespace std;
int main() {
const char* _user = "FOO";
const char* _password = "BAR";
const char* _session = "ABCDEFGHIJ";
int _expectedSeq = 123;
char login[38];
sprintf(login,
"L%-6s%-10s%10s%10d\xA",
_user,
_password,
_session,
_expectedSeq);
for (int i = 0; i < 38; i++) {
printf(" %02x", login[i] & 0xff);
}
return 0;
}
Deep in our application code, I came across this:
char login[38];
sprintf(login,
"L%-6s%-10s%10s%10d\xA",
_user,
_password,
_session,
_expectedSeq);
Now, I need to write a (simpler) variant of this code:
char login[21];
sprintf(login,
"\x15\x00\x01%-8s%-10s",
_user,
_password);
Somehow, this doesn't work! What's weird is that the latter produces different results every time.
The former example only has a hex literal at the end. Is this masking the issue in the former's case?
Or, am I actually messing up my debug output, printf
? (By the way, I got the & 0xff
thing from Printing hexadecimal characters in C.)
Could it have something to do with using char
instead of unsigned char
? But then, why does the former case work?
Upvotes: 2
Views: 354
Reputation: 154005
Your issue is that second format string contains a null character (\x00
) which terminates it prematurely. Change the string to use %c
instead and have a null character printed there.
Upvotes: 2
Reputation: 98486
The problem is that your string literal has an embedded NUL byte, and that marks the end of the string as far as sprintf
is concerned. So your call is identical to:
sprintf(login,
"\x15",
_user,
_password);
And that writes into the login
array only two bytes: 0x15 0x00
.
There are several approaches to solve this mixing of bytes and characters. My choice would be something along the lines of:
memcpy(login, "\x15\x00\x01", 3);
sprintf(login + 3,
"%-8s%-10s",
_user,
_password);
The call to memcpy
takes as parameter the number of bytes, so it is immune to the embedded NUL problem.
But note that sprintf
automaticall adds a NUL byte at the end of the output string, so you actually need 22 bytes: 3 + 8 + 10 + 1 = 22:
char login[22];
Upvotes: 6