-
-
Save dgoguerra/7194777 to your computer and use it in GitHub Desktop.
| #include <stdio.h> | |
| #include <stdlib.h> // atoll | |
| #include <stdint.h> // uint64_t | |
| #include <inttypes.h> // PRIu64 | |
| static const char *humanSize(uint64_t bytes) | |
| { | |
| char *suffix[] = {"B", "KB", "MB", "GB", "TB"}; | |
| char length = sizeof(suffix) / sizeof(suffix[0]); | |
| int i = 0; | |
| double dblBytes = bytes; | |
| if (bytes > 1024) { | |
| for (i = 0; (bytes / 1024) > 0 && i<length-1; i++, bytes /= 1024) | |
| dblBytes = bytes / 1024.0; | |
| } | |
| static char output[200]; | |
| sprintf(output, "%.02lf %s", dblBytes, suffix[i]); | |
| return output; | |
| } | |
| int main(int argc, char **argv) | |
| { | |
| if (argc == 1) { | |
| fprintf(stderr, "Usage: %s <bytes>\n", *argv); | |
| return 1; | |
| } | |
| uint64_t bytes = atoll(argv[1]); | |
| printf("%" PRIu64 " Bytes: %s\n", bytes, humanSize(bytes)); | |
| return 0; | |
| } |
How does this work? how can you return a pointer to a stack array, wouldnt the pointer point to garbage??
I'm sorry, I should have explained this more. I prefer not to return pointers to static data. Here's an example of usage:
int main(int argc, char **argv)
{
char *humanSize(uint64_t, char *);
char hrbytes[BUFSIZ];
printf("bytes = %s\n", humanSize(12345, hrbytes));
}
Here is a way to do it without functions or scary static memory and in constant time.
#define PriByte "%.02lf %s"
#define PriByte__value(b) ( \
(unsigned long long)b >= ((((1ull << 10) << 10) << 10) << 10) ? (double)b / (double)((((1ull << 10) << 10) << 10) << 10) : \
(unsigned long long)b >= (((1ull << 10) << 10) << 10) ? (double)b / (double)(((1ull << 10) << 10) << 10) : \
(unsigned long long)b >= ((1ull << 10) << 10) ? (double)b / (double)((1ull << 10) << 10) : \
(unsigned long long)b >= (1ull << 10) ? (double)b / (double)(1ull << 10) : \
(double)b \
)
#define PriByte__unit(b) ( \
(unsigned long long)b >= ((((1ull << 10) << 10) << 10) << 10) ? "TiB" : \
(unsigned long long)b >= (((1ull << 10) << 10) << 10) ? "GiB" : \
(unsigned long long)b >= ((1ull << 10) << 10) ? "MiB" : \
(unsigned long long)b >= (1ull << 10) ? "KiB" : \
"B" \
)
#define PriByteArg(b) PriByte__value(b), PriByte__unit(b)Usage: printf("My size is "PriByte, PriByteArg(1024));
Here are some tests comparing it with the humanSize function from OP, check it out:
CLICK TO EXPAND.
size_t b = 2;
for (int i = 0; i < 100; ++i) {
b += b / 2;
printf("1 Macro "PriByte"\n", PriByteArg(b));
printf("2 Func %s\n", humanSize(b));
}
printf("---Next test---\n");
b = 1;
for (int i = 0; i < 64; ++i) {
printf("1 Macro "PriByte"\n", PriByteArg(b));
printf("2 Func %s\n", humanSize(b));
b = b << 1;
}1 Macro 3.00 B
2 Func 3.00 B
1 Macro 4.00 B
2 Func 4.00 B
1 Macro 6.00 B
2 Func 6.00 B
1 Macro 9.00 B
2 Func 9.00 B
1 Macro 13.00 B
2 Func 13.00 B
1 Macro 19.00 B
2 Func 19.00 B
1 Macro 28.00 B
2 Func 28.00 B
1 Macro 42.00 B
2 Func 42.00 B
1 Macro 63.00 B
2 Func 63.00 B
1 Macro 94.00 B
2 Func 94.00 B
1 Macro 141.00 B
2 Func 141.00 B
1 Macro 211.00 B
2 Func 211.00 B
1 Macro 316.00 B
2 Func 316.00 B
1 Macro 474.00 B
2 Func 474.00 B
1 Macro 711.00 B
2 Func 711.00 B
1 Macro 1.04 KiB
2 Func 1.04 KiB
1 Macro 1.56 KiB
2 Func 1.56 KiB
1 Macro 2.34 KiB
2 Func 2.34 KiB
1 Macro 3.51 KiB
2 Func 3.51 KiB
1 Macro 5.27 KiB
2 Func 5.27 KiB
1 Macro 7.90 KiB
2 Func 7.90 KiB
1 Macro 11.85 KiB
2 Func 11.85 KiB
1 Macro 17.78 KiB
2 Func 17.78 KiB
1 Macro 26.67 KiB
2 Func 26.67 KiB
1 Macro 40.00 KiB
2 Func 40.00 KiB
1 Macro 60.01 KiB
2 Func 60.01 KiB
1 Macro 90.01 KiB
2 Func 90.01 KiB
1 Macro 135.01 KiB
2 Func 135.01 KiB
1 Macro 202.52 KiB
2 Func 202.52 KiB
1 Macro 303.78 KiB
2 Func 303.78 KiB
1 Macro 455.67 KiB
2 Func 455.67 KiB
1 Macro 683.51 KiB
2 Func 683.51 KiB
1 Macro 1.00 MiB
2 Func 1.00 MiB
1 Macro 1.50 MiB
2 Func 1.50 MiB
1 Macro 2.25 MiB
2 Func 2.25 MiB
1 Macro 3.38 MiB
2 Func 3.38 MiB
1 Macro 5.07 MiB
2 Func 5.07 MiB
1 Macro 7.60 MiB
2 Func 7.60 MiB
1 Macro 11.40 MiB
2 Func 11.40 MiB
1 Macro 17.11 MiB
2 Func 17.11 MiB
1 Macro 25.66 MiB
2 Func 25.66 MiB
1 Macro 38.49 MiB
2 Func 38.49 MiB
1 Macro 57.74 MiB
2 Func 57.74 MiB
1 Macro 86.60 MiB
2 Func 86.60 MiB
1 Macro 129.91 MiB
2 Func 129.91 MiB
1 Macro 194.86 MiB
2 Func 194.86 MiB
1 Macro 292.29 MiB
2 Func 292.29 MiB
1 Macro 438.43 MiB
2 Func 438.43 MiB
1 Macro 657.65 MiB
2 Func 657.65 MiB
1 Macro 986.48 MiB
2 Func 986.47 MiB
1 Macro 1.45 GiB
2 Func 1.44 GiB
1 Macro 2.17 GiB
2 Func 2.17 GiB
1 Macro 3.25 GiB
2 Func 3.25 GiB
1 Macro 4.88 GiB
2 Func 4.88 GiB
1 Macro 7.32 GiB
2 Func 7.32 GiB
1 Macro 10.97 GiB
2 Func 10.97 GiB
1 Macro 16.46 GiB
2 Func 16.46 GiB
1 Macro 24.69 GiB
2 Func 24.69 GiB
1 Macro 37.03 GiB
2 Func 37.03 GiB
1 Macro 55.55 GiB
2 Func 55.55 GiB
1 Macro 83.33 GiB
2 Func 83.33 GiB
1 Macro 124.99 GiB
2 Func 124.99 GiB
1 Macro 187.49 GiB
2 Func 187.49 GiB
1 Macro 281.23 GiB
2 Func 281.23 GiB
1 Macro 421.85 GiB
2 Func 421.85 GiB
1 Macro 632.77 GiB
2 Func 632.77 GiB
1 Macro 949.16 GiB
2 Func 949.16 GiB
1 Macro 1.39 TiB
2 Func 1.39 TiB
1 Macro 2.09 TiB
2 Func 2.08 TiB
1 Macro 3.13 TiB
2 Func 3.13 TiB
1 Macro 4.69 TiB
2 Func 4.69 TiB
1 Macro 7.04 TiB
2 Func 7.04 TiB
1 Macro 10.56 TiB
2 Func 10.56 TiB
1 Macro 15.84 TiB
2 Func 15.84 TiB
1 Macro 23.76 TiB
2 Func 23.75 TiB
1 Macro 35.63 TiB
2 Func 35.63 TiB
1 Macro 53.45 TiB
2 Func 53.45 TiB
1 Macro 80.18 TiB
2 Func 80.17 TiB
1 Macro 120.26 TiB
2 Func 120.26 TiB
1 Macro 180.39 TiB
2 Func 180.39 TiB
1 Macro 270.59 TiB
2 Func 270.59 TiB
1 Macro 405.89 TiB
2 Func 405.89 TiB
1 Macro 608.83 TiB
2 Func 608.83 TiB
1 Macro 913.25 TiB
2 Func 913.25 TiB
1 Macro 1369.87 TiB
2 Func 1369.87 TiB
1 Macro 2054.81 TiB
2 Func 2054.81 TiB
1 Macro 3082.22 TiB
2 Func 3082.21 TiB
1 Macro 4623.32 TiB
2 Func 4623.32 TiB
1 Macro 6934.98 TiB
2 Func 6934.98 TiB
1 Macro 10402.48 TiB
2 Func 10402.48 TiB
1 Macro 15603.72 TiB
2 Func 15603.71 TiB
1 Macro 23405.57 TiB
2 Func 23405.57 TiB
1 Macro 35108.36 TiB
2 Func 35108.36 TiB
1 Macro 52662.54 TiB
2 Func 52662.54 TiB
1 Macro 78993.81 TiB
2 Func 78993.81 TiB
1 Macro 118490.71 TiB
2 Func 118490.71 TiB
1 Macro 177736.07 TiB
2 Func 177736.07 TiB
1 Macro 266604.11 TiB
2 Func 266604.10 TiB
1 Macro 399906.16 TiB
2 Func 399906.16 TiB
1 Macro 599859.24 TiB
2 Func 599859.24 TiB
---Next test---
1 Macro 1.00 B
2 Func 1.00 B
1 Macro 2.00 B
2 Func 2.00 B
1 Macro 4.00 B
2 Func 4.00 B
1 Macro 8.00 B
2 Func 8.00 B
1 Macro 16.00 B
2 Func 16.00 B
1 Macro 32.00 B
2 Func 32.00 B
1 Macro 64.00 B
2 Func 64.00 B
1 Macro 128.00 B
2 Func 128.00 B
1 Macro 256.00 B
2 Func 256.00 B
1 Macro 512.00 B
2 Func 512.00 B
1 Macro 1.00 KiB
2 Func 1024.00 B
1 Macro 2.00 KiB
2 Func 2.00 KiB
1 Macro 4.00 KiB
2 Func 4.00 KiB
1 Macro 8.00 KiB
2 Func 8.00 KiB
1 Macro 16.00 KiB
2 Func 16.00 KiB
1 Macro 32.00 KiB
2 Func 32.00 KiB
1 Macro 64.00 KiB
2 Func 64.00 KiB
1 Macro 128.00 KiB
2 Func 128.00 KiB
1 Macro 256.00 KiB
2 Func 256.00 KiB
1 Macro 512.00 KiB
2 Func 512.00 KiB
1 Macro 1.00 MiB
2 Func 1.00 MiB
1 Macro 2.00 MiB
2 Func 2.00 MiB
1 Macro 4.00 MiB
2 Func 4.00 MiB
1 Macro 8.00 MiB
2 Func 8.00 MiB
1 Macro 16.00 MiB
2 Func 16.00 MiB
1 Macro 32.00 MiB
2 Func 32.00 MiB
1 Macro 64.00 MiB
2 Func 64.00 MiB
1 Macro 128.00 MiB
2 Func 128.00 MiB
1 Macro 256.00 MiB
2 Func 256.00 MiB
1 Macro 512.00 MiB
2 Func 512.00 MiB
1 Macro 1.00 GiB
2 Func 1.00 GiB
1 Macro 2.00 GiB
2 Func 2.00 GiB
1 Macro 4.00 GiB
2 Func 4.00 GiB
1 Macro 8.00 GiB
2 Func 8.00 GiB
1 Macro 16.00 GiB
2 Func 16.00 GiB
1 Macro 32.00 GiB
2 Func 32.00 GiB
1 Macro 64.00 GiB
2 Func 64.00 GiB
1 Macro 128.00 GiB
2 Func 128.00 GiB
1 Macro 256.00 GiB
2 Func 256.00 GiB
1 Macro 512.00 GiB
2 Func 512.00 GiB
1 Macro 1.00 TiB
2 Func 1.00 TiB
1 Macro 2.00 TiB
2 Func 2.00 TiB
1 Macro 4.00 TiB
2 Func 4.00 TiB
1 Macro 8.00 TiB
2 Func 8.00 TiB
1 Macro 16.00 TiB
2 Func 16.00 TiB
1 Macro 32.00 TiB
2 Func 32.00 TiB
1 Macro 64.00 TiB
2 Func 64.00 TiB
1 Macro 128.00 TiB
2 Func 128.00 TiB
1 Macro 256.00 TiB
2 Func 256.00 TiB
1 Macro 512.00 TiB
2 Func 512.00 TiB
1 Macro 1024.00 TiB
2 Func 1024.00 TiB
1 Macro 2048.00 TiB
2 Func 2048.00 TiB
1 Macro 4096.00 TiB
2 Func 4096.00 TiB
1 Macro 8192.00 TiB
2 Func 8192.00 TiB
1 Macro 16384.00 TiB
2 Func 16384.00 TiB
1 Macro 32768.00 TiB
2 Func 32768.00 TiB
1 Macro 65536.00 TiB
2 Func 65536.00 TiB
1 Macro 131072.00 TiB
2 Func 131072.00 TiB
1 Macro 262144.00 TiB
2 Func 262144.00 TiB
1 Macro 524288.00 TiB
2 Func 524288.00 TiB
1 Macro 1048576.00 TiB
2 Func 1048576.00 TiB
1 Macro 2097152.00 TiB
2 Func 2097152.00 TiB
1 Macro 4194304.00 TiB
2 Func 4194304.00 TiB
1 Macro 8388608.00 TiB
2 Func 8388608.00 TiB Shorter version:
#define PriByte "%.02lf %s"
#define PriByteArg(b) (\
(unsigned long long)(b) >= (1ull << 40) ? (double)(b) / (double)(1ull << 40) : \
(unsigned long long)(b) >= (1ull << 30) ? (double)(b) / (double)(1ull << 30) : \
(unsigned long long)(b) >= (1ull << 20) ? (double)(b) / (double)(1ull << 20) : \
(unsigned long long)(b) >= (1ull << 10) ? (double)(b) / (double)(1ull << 10) : \
(double)(b)),( \
(unsigned long long)(b) >= (1ull << 40) ? "TiB" : \
(unsigned long long)(b) >= (1ull << 30) ? "GiB" : \
(unsigned long long)(b) >= (1ull << 20) ? "MiB" : \
(unsigned long long)(b) >= (1ull << 10) ? "KiB" : \
"B")WARNING: Beware of multiple evaluation, don't pass an expensive expression.
EDIT: OK so! after spending too many hours thinking about this I ended up using this:
const char *PriByteHuman(uint64_t b) {
enum { BUF_EXP_SIZE = 4, BUF_SIZE = 32 };
static int idx = 0;
static char storage_buf[1 << BUF_EXP_SIZE][BUF_SIZE];
char *buf = storage_buf[idx];
idx = (idx + 1) & ((1 << BUF_EXP_SIZE) -1);
snprintf(buf, BUF_SIZE, "%.02lf(%s)",
b >= (1ull << 40) ? (double)(b) / (double)(1ull << 40) :
b >= (1ull << 30) ? (double)(b) / (double)(1ull << 30) :
b >= (1ull << 20) ? (double)(b) / (double)(1ull << 20) :
b >= (1ull << 10) ? (double)(b) / (double)(1ull << 10) :
(double)(b),
b >= (1ull << 40) ? "TiB" : b >= (1ull << 30) ? "GiB" :
b >= (1ull << 20) ? "MiB" : b >= (1ull << 10) ? "KiB" : "B");
return buf;
// 28 bytes -> "9223372036854775807.00(TiB)\0"
}
#define PRIbyte "%s"
#define PRIbytearg(x) PriByteHuman((uint64_t)(x))I just couldn't have peace of mind knowing the previous method has the POTENTIAL of misuse thanks to multiple evaluation so I had to do it like this. The good part is that you can have up to 16 unique instances on a singular call. And it's impossible to misuse!!
Like this but imagine 16 instances instead of 5:
for (int i = 1; i < 10; ++i) {
printf(PRIbyte" "PRIbyte" "PRIbyte" "PRIbyte" "PRIbyte" \n",
PRIbytearg(i<<1), PRIbytearg(i<<2), PRIbytearg(i<<3), PRIbytearg(i<<4), PRIbytearg(i<<5)
);
}
Another variation: