I need to convert an unsigned 64-bit integer into a string. That is in Base 36, or characters 0-Z. ulltoa does not exist in the Linux manpages. But sprintf DOES. How do I use sprintf to achieve the desired result? i.e. what formatting % stuff?
Or if snprintf does not work, then how do I do this?
You can always just write your own conversion function. The following idea is stolen from heavily inspired by this fine answer:
char * int2base36(unsigned int n, char * buf, size_t buflen)
{
static const char digits[] = "0123456789ABCDEFGHI...";
if (buflen < 1) return NULL; // buffer too small!
char * b = buf + buflen;
*--b = 0;
do {
if (b == buf) return NULL; // buffer too small!
*--b = digits[n % 36];
n /= 36;
} while(n);
return b;
}
This will return a pointer to a null-terminated string containing the base36-representation of n, placed in a buffer that you provide. Usage:
char buf[100];
std::cout << int2base36(37, buf, 100);
If you want and you're single-threaded, you can also make the char buffer static -- I guess you can figure out a suitable maximal length:
char * int2base36_not_threadsafe(unsigned int n)
{
static char buf[128];
static const size_t buflen = 128;
// rest as above
Related
There are tons of questions on this issue and I have been attempting the various solutions. There seems to be dozens of ways to do this however none of them are working. I am very new to C++ and VS, working for about a month, and I am trying to code an auto Excel program using VC++. I am stuck trying to concatenate a wchar_t * and an unsigned long long. I assume the first step is to "convert" the unsigned long long to wchar_t *. I apologize for throwing in the whole code but I think it may help with showing what I am aiming for and if there are any other weaknesses in the code.
wchar_t * ex(wchar_t * dest, unsigned long long num);
int main()
{
unsigned long long num = 10;
wchar_t *dest= L"A2:B";
wchar_t * Path=ex(dest, num);
VARIANT param;
param.vt = VT_BSTR;
// param.bstrVal = SysAllocString(L"A2:B10");
param.bstrVal = SysAllocString(Path);
getchar();
return 0;
}
wchar_t * ex(wchar_t * dest, unsigned long long num)
{
// Convert num to wchar_t *
wchar_t *rangeMax = (wchar_t *)num;
// I think this is used to eliminate extra space in other solutions
// but not here. It could be useful.
const int MAX_CHARS = 50;
size_t count = wcsnlen_s(dest, MAX_CHARS);
wprintf(L"The length of the string is %ld characters\n", count);
// Throw dest into buf
wchar_t buf[25] = { 0 };
int r = wcscpy_s(buf, 25, dest);
if (r != 0) {
wprintf(L"wcscpy_s() failed %ld", r);
}
r = wcscat_s(buf, 25, rangeMax);
if (r != 0) {
wprintf(L"wcscat_s() failed %ld", r);
}
wprintf_s(buf);
return buf;
}
ex is an edited example from zetcode. I think it is close to being the solution, however when combining buf and rangeMax the code throws all sorts of memory exceptions and fails.
As you can see the final destination for the concatenated wchar_t * is as a BSTR in a VARIANT through SysAllocString.
I appreciate any suggestions on code improvement as well as how to make the code actually run!
As suggested using wstring functioned as intended. Thank you for pointing out I was returning a pointer to a local variable! Once back in main the type was changed to wchar_t * which passed nicely to SysAllocString() for use with my main program.
std::wstring ex(wchar_t * dest, unsigned long long num);
int main()
{
unsigned long long num = 10;
wchar_t *dest= L"A2:B";
std::wstring PathString= ex(dest, num);
wchar_t *wPath = (WCHAR *)PathString.c_str();
std::wcout << L"In main\n";
std::wcout << wPath << L'\n';
VARIANT param;
param.vt = VT_BSTR;
//param.bstrVal = SysAllocString(L"A2:B10");
param.bstrVal = SysAllocString(wPath);
getchar();
return 0;
}
std::wstring ex(wchar_t * dest, unsigned long long num)
{
std::wstring rangeMax = std::to_wstring(num);
std::wstring string(dest);
string += rangeMax;
std::wcout << L"In function\n";
std::wcout<<string<<L'\n';
return string;
}
I'm trying to update some "legacy" code to comply with the latest security updates to MSVC, and am facing some trouble migrating from _vsnprintf to _vsnprintf_s.
In particular, I was calling _vsnprintf with a null buffer and zero for the count/length, getting the result, allocating a buffer of the needed size (return value + 1), and then calling _vsnprintf again with the newly-allocated buffer and known-correct size:
size_t length = _vsntprintf(nullptr, 0, mask, params);
TCHAR *final = new TCHAR [length + 1];
_vsntprintf(final, length + 1, mask, params);
This behavior is documented on MSDN:
If the buffer size specified by count is not sufficiently large to contain the output specified by format and argptr, the return value of vsnprintf is the number of characters that would be written if count were sufficiently large. If the return value is greater than count - 1, the output has been truncated.
I'm trying to do the same with _vsnprintf_s, but its documentation does not contain the same. It instead says
If the storage required to store the data and a terminating null exceeds sizeOfBuffer, the invalid parameter handler is invoked, as described in Parameter Validation, unless count is _TRUNCATE, in which case as much of the string as will fit in buffer is written and -1 returned.
Trying it out anyway with the following:
size_t length = _vsntprintf_s(nullptr, 0, 0, mask, params);
This results in a "length" of zero. If you pass in _TRUNCATE (-1) as the count instead, the following assertion fails:
Expression: buffer != nullptr && buffer_count > 0
I presume it is possible to override _set_invalid_parameter_handler and somehow find out what the length should be, but there has to be an easier way?
size_t length = _vscprintf(mask, va_list);
TCHAR *final = new TCHAR [length + 1];
_vsntprintf_s(final, length, _TRUNCATE, mask, va_list);
How about rolling your own vsnprintf variant that doesn't "violate the rules" to get the length:
int
printf_size(const char *fmt,int count,va_list ap)
{
char buf[2000000];
int len;
len = vsnprintf_s(buf,sizeof(buf),count,fmt,ap);
return len;
}
Since the returned will [most likely] be less than sizeof(buf) you should be fine.
Or, do:
int
printf_size(const char *fmt,int count,va_list ap)
{
char *buf;
int siz;
int len;
for (siz = 2000000; ; siz <<= 1) {
buf = malloc(siz);
len = vsnprintf_s(buf,siz,count,fmt,ap);
free(buf);
if (len < siz)
break;
}
return len;
}
Or, doing a one stop shop function:
int
sprintf_secure(char **buf,const char *fmt,int count,va_list ap)
{
char *bp;
int siz;
int len;
for (siz = 2000000; ; siz <<= 1) {
bp = malloc(siz);
len = vsnprintf_s(bp,siz,count,fmt,ap);
if (len < siz)
break;
}
bp = realloc(bp,len + 1);
*buf = bp;
return len;
}
I was looking at a way to achieve sprintf() functionality with std::string and I found a good answer from std::string formatting like sprintf. This is somewhat hacky though because it writes directly to the pointer returned from string.c_str(). So I reimplemented it using a char * with malloc() and realloc().
std::string string_format(const char * format, ...) {
size_t size;
size_t n;
va_list args;
char * buffer;
std::string str;
size = 100;
buffer = malloc(size);
for (;;) {
va_start(args, format);
n = vsnprintf(buffer, size, format, args);
va_end(args);
if (n > -1) {
if (n < size) {
size = n;
break;
}
size = n + 1;
} else {
size *= 2;
}
buffer = realloc(buffer, size);
}
str = std::string(buffer, size);
free(buffer);
return str;
}
I know I could just do:
str = std::string(buffer);
But then it will have to essentially do strlen(buffer). I could make it a little better by:
str = std::string(buffer, size);
But would using string.swap() be more efficient by swapping the internal buffer instead of copying it?
str.swap(std::string(buffer, size));
Is there a better way to do this?
Just use str.assign(buffer, size);
I want to receive bytes into conbuf.buffer. either of test 1 or test2 is ok. I am not seeing any value in printf statement. Am I passing in the pointer correctly? How do I allocate memory to a char pointer inside a struct.
typedef struct cBuf
{
int size;
char *buffer;
} cbuf;
class A
{
cbuf conbuf;
void test();
}
void A::test()
{
int buffersize = 20;
char buf[buffersize];
conbuf.buffer = (char *)malloc(buffersize * sizeof(char *));
// test 1
int n = socket.receivebytes(conbuf.buffer, buffersize);
// test 2
//int n = socket.receivebytes(buf, buffersize);
//strcpy(conbuf.buffer, buf);
printf("conbuf.buffer %s \n", conbuf.buffer);
}
this
conbuf.buffer = (char *)malloc(buffersize * sizeof(char *));
should be
conbuf.buf = (char *)malloc(buffersize * sizeof(char)); //allocate space for char not pointer to char. Your struct only has buf member not "buffer"
Use this:
conbuf.buffer = (char *)calloc( (buffersize * sizeof(char))+1,1);
since printf requires last char of string to be null terminated, this ensures it. But data received from network may already contain NUL in the middle. So instead of using printf you should use fwrite:
fwrite(conbuf.buffer,buffersize , STDOUT);
I'd suggest you to redirect it in a file and do a hex dump to see the output.
The send function in winsock2 accepts only char pointers.
How do I send integers or objects through it too?
const char *buf which you need to pass to send() function as an argument is just a pointer to array of bytes. You need to convert integers to bytes:
const int MAX_BUF_SIZE = 1024;
int int_data = 4;
const char *str_data = "test";
char *buf = (char*) malloc(MAX_BUF_SIZE);
char *p = buf;
memcpy(&int_data, p, sizeof(int_data));
p += sizeof(int_data);
strcpy(p, str_data);
p += strlen(str_data) + 1;
send(sock, buf, p - buf, 0);
free(buf);
and reading code:
const int MAX_BUF_SIZE = 1024;
int int_data = 0;
const char *str_data = NULL;
char *buf = (char*) malloc(MAX_BUF_SIZE);
char *p = buf;
recv(sock, buf, MAX_BUF_SIZE, 0);
memcpy(p, &int_data, sizeof(int_data));
p += sizeof(int_data);
str_data = malloc(strlen(p) + 1);
strcpy(str_data, p);
p += strlen(p) + 1;
free(buf);
and complex objects needs to be serialized to stream of bytes.
Note 1: The code sample is valid iff both server and client use the same platforms (x32 / x64 / ...) that means int has the same amount of bytes and byte order is the same.
Note 2: Writing code should check that there is no buffer (MAX_BUF_SIZE) overflow on each step.
Just store the value into a variable and then type-cast the variable to char*. The send() and recv() functions operate on binary data, despite taking char* parameters.
Sending:
int int_data = 4;
send(sock, (char*) &int_data, sizeof(int), 0);
Reading:
int int_data;
recv(sock, (char*) &int_data, sizeof(int), 0);
Generally, the easiest way is to print the integer or object to a string, and send that string. Textual representations are more portable, and also easier to debug.
std::stringstream may be a useful class both to create the string and parse it on the other end.