2

I tried to parse uint64_t array to an array of char (result in decimal, separated by comma).

I used memcpy, every time I get a random values. iota() function converts max uint32_t values. I tried separate uint64_t to 2 uint32_t, but I never get a right result.

    uint64_t numbers[10] = { 201234567890123456, 
                           12345678901234567890, 
                           98765432109876543, 
                           65432109887, 
                           12345234512345,
                           217631276371261627,
                           12354123512453124,
                           2163521442531,
                           2341232142132321,
                           1233432112 };
    char array[1000] = "";

Expected result:

array = "201234567890123456,12345678901234567890,98765432109876543,65432109887,12345234512345,217631276371261627,12354123512453124,2163521442531,2341232142132321,1233432112"

I tried int64ToChar from this topic, but result is:

    void uint64ToChar(char a[], int64_t n) {
         memcpy(a, &n, 10);
    }

    uint64_t number = 12345678900987654;
    char output[30] = "";

    uint64ToChar(output, number);

    Result:
    �g]T�+

Thanks for any help.

maghost
  • 39
  • 1
  • 7
  • 2
    You want to print the representation of a number using ascii characters in base 10. Use `snprintf`. – KamilCuk Mar 22 '20 at 18:54
  • Does this answer your question? [How do I convert a 64bit integer to a char array and back?](https://stackoverflow.com/questions/9695720/how-do-i-convert-a-64bit-integer-to-a-char-array-and-back) – Papooch Mar 22 '20 at 18:56
  • 1
    It would help if you showed the code that you tried. – user3386109 Mar 22 '20 at 18:59
  • @Papooch: I don't think the suggested Q&A is very helpful. I'm not convinced by the answers I see, either. – Jonathan Leffler Mar 22 '20 at 19:10
  • 1
    Your `uint64_t` array initialisation won't work like that: it needs braces around the `={` data `};`. – Weather Vane Mar 22 '20 at 19:16
  • 2
    P.S. the sixth element in your array `21763127637126371627` is larger than a 64 bit unsigned integer. Use a smaller number. – Joshua Yonathan Mar 22 '20 at 19:40

4 Answers4

2

Ue snpintf() to convert the 64-bit numbers:

#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>

int main() {
    uint64_t numbers[10] = { 201234567890123456, 
                             12345678901234567890, 
                             98765432109876543, 
                             65432109887, 
                             12345234512345,
                             21763127637126371627,
                             12354123512453124,
                             2163521442531,
                             2341232142132321,
                             1233432112 };
    char array[1000];
    size_t i, n = sizeof(numbers) / sizeof(numbers[0]), pos = 0;

    for (i = 0; i < n && pos < sizeof(array); i++) {
        pos += snprintf(array + pos, sizeof(array) - pos, "%"PRIu64"%s", numbers[i],
                        i < n - 1 ? "," : "");
    }
    printf("%s\n", array);
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • @KamilCuk: Yes Indeed! Answer amended. I keep wondering why these macros are not defined in ``. – chqrlie Mar 22 '20 at 19:56
  • Thanks, It helped me a little bit. On PC it works well. I compiled this code for embedded platform (ESP-IDF) and I my result is : lulululululululululululululululululu... and so on. – maghost Mar 22 '20 at 20:32
  • @maghost: Your platform seems to have conformity issues. Try changing `"%"PRIu64"%s", numbers[i],` to `"%llu%s", (unsigned long long)numbers[i],` or possibly `"%lu%s", (unsigned long)numbers[i],` – chqrlie Mar 22 '20 at 22:15
  • @maghost: if you use the Arduino C platform, be aware that this C variant has substantial differences from C, including subtle shortcomings in its standard library. – chqrlie Mar 22 '20 at 22:31
  • I don't use an Arduino platform, but I use ESP-RTOS-SDK for ESP8266. I found the issue - newlib library is in "nano" version (for stack and heap optimalization), which don't support u64 as printf functions, The "normal" version crashes when I used NVS partition with it. Maybe there is some other way except snprintf? – maghost Mar 22 '20 at 23:29
  • 1
    @maghost: you can write your own 64-bit to decimal conversion routine. – chqrlie Mar 23 '20 at 08:33
2

If all the data is available at compile-time, there's no obvious reason why you should use slow run-time conversion functions like s*printf. Simply do it all at pre-processor stage:

#define INIT_LIST           \
  201234567890123456,       \
  12345678901234567890,     \
  98765432109876543,        \
  65432109887,              \
  12345234512345,           \
  217631276371261627,       \
  12354123512453124,        \
  2163521442531,            \
  2341232142132321,         \
  1233432112

#define STR_(...) #__VA_ARGS__
#define STR(x) STR_(x)

int main (void)
{
  uint64_t numbers[10] = { INIT_LIST };
  char array[] = STR(INIT_LIST);
  puts(array);
}

More advanced alternatives with "X macros" are possible, if you want to micro-manage comma and space placement between numbers etc.

Please note that 12345678901234567890 is too large to be a valid signed integer constant on my 64 bit system, the max is 2^63 - 1 = 9.22*10^18 but this number is 12.34*10^18. I have to change it to 12345678901234567890ull to get this program to compile, since the maximum number is then 18.44*10^18.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Thanks for hint, but data isn't known at compile time. Only for that this is an variable array of numbers, not const. – maghost Mar 23 '20 at 14:59
1

You can accomplish this by using sprintf_s in a for loop.

#include <stdio.h>
#include <stdint.h>
#include <string.h>

#define BUFSIZE 22                  /* string buffer size to support a single 64 bit unsigned integer */
#define ARRSIZE 10                  /* size of the unsigned integer array */
#define STRSIZE BUFSIZE * ARRSIZE   /* max size of the string of unsigned integer array */

int main()
{
    int i;
    char num_str[STRSIZE] = "";
    uint64_t num_arr[ARRSIZE] = {
        201234567890123456,
        12345678901234567890,
        98765432109876543,
        65432109887,
        12345234512345,
        2176312763712637162,
        12354123512453124,
        2163521442531,
        2341232142132321,
        1233432112
    };

    for (i = 0; i < ARRSIZE; i++)
    {
        /* convert an unsigned integer to a string and concatenate to previous string every loop */
        sprintf_s(num_str + strlen(num_str), BUFSIZE, "%llu,", num_arr[i]);
    }

    num_str[strlen(num_str) - 1] = 0;   /* truncate the trailing comma */

    printf("%s", num_str);

    return 0;
}

This results in:

num_str = "201234567890123456,12345678901234567890,98765432109876543,65432109887,12345234512345,2176312763712637162,12354123512453124,2163521442531,2341232142132321,1233432112"
Joshua Yonathan
  • 490
  • 1
  • 5
  • 16
  • 1
    Why use `sprintf_s` if you are going to pass an incorrect size argument? – chqrlie Mar 22 '20 at 19:43
  • Thanks, It helped me a little bit. I changed sprintf_s -> snprintf() because I work on Linux. On PC it works well. I compiled this code for embedded platform (ESP-IDF) and I my result is : lu,lu,lu,lu,lu,lu,lu,lu,lu,lu – maghost Mar 22 '20 at 20:12
1

The memcpy function copies byte by byte from one location to another. What you're attempting to do is take 10 bytes of a 64 bit number (which only contains 8 bytes) and reinterpret each of them as an ASCII character. Not only will this not give the results you expect, but you also invoke undefined behavior by reading past the memory bounds of an object.

Guessing at what functions do is a bad way to learn C. You need to read the documentation for these functions (run "man function_name" on Linux for the function in question or search learn.microsoft.com for MSVC) to understand what they do.

If you use the sprintf function, you can convert a 64 bit integer to a string. The %lld identifier accepts a long long int, which is at least as big as a uint64_t.

sprintf(a, "%lld", (unsigned long long)n);
dbush
  • 205,898
  • 23
  • 218
  • 273
  • 2
    Technically, `unsigned long long` can represent all 64-bit values, but for complete portability you should either cast the `uint64_t` argument as `sprintf(a, "%llu", (unsigned long long)n);` or use the C99 formatting macros: `sprintf(a, "%"PRIu64"", n);` – chqrlie Mar 22 '20 at 19:52