I have created a function in my C application intended to return values like “1.25GB”, “4.60MB”, “1.40KB” rather than the numeric values they represent (I hope I said that properly). It’s based on a PHP bit of code I’ve had forever that works like this:
public function humanFileSize(?float $size, string $unit="") {
if (is_null($size))
return '?size' ;
if ( (!$unit && $size >= 1<<30) || $unit == "GB")
return number_format($size/(1<<30), 2) . "GB" ;
if( (!$unit && $size >= 1<<20) || $unit == "MB")
return number_format($size/(1<<20), 2) . "MB";
if( (!$unit && $size >= 1<<10) || $unit == "KB")
return number_format($size/(1<<10),2) . "KB";
return number_format($size) . " bytes";
}
In C, I have converted this as such:
char *humanSize(unsigned long long size) {
char *p = malloc(12) ;
unsigned long long GB = (unsigned long long) (1ULL >> 30) ;
unsigned long long MB = (unsigned long long) (1ULL >> 20) ;
unsigned long long KB = (unsigned long long) (1ULL >> 10) ;
if (size >= GB) {
sprintf(p, "%.2f%s", ((double) size / (double) (1ULL <<30)), "GB") ;
} else if (size >= MB) {
sprintf(p, "%.2f%s", ((double) size / (double) (1ULL <<20)), "MB") ;
} else if (size >= KB) {
sprintf(p, "%.2f%s", ((double) size / (double) (1ULL <<10)), "KB") ;
} else {
sprintf(p, "%d", (int) size) ;
}
return p ;
}
I thought that would work, based upon other SO articles that mentioned shifting ULL in C (like this one: bit shifting with unsigned long type produces wrong results and this one: Bit-shifting unsigned longs in C). But this doesn’t work for me (first IF is always true), and debug shows me that GB, MB and KB each have a value of zero. What is the proper way to shift unsigned long long for this result? (I know that I could specify the actual (shifted) numeric values but I like the readability of the above. And besides, there is almost certainly also a problem with the other shift attempts, given that those don’t work.)