Я пытаюсь написать функцию на C, которая обрабатывает long в строку, которая имеет long в качестве единицы хранения (например, 1400000 -> 1,40 МБ). Однако числа, которые он выводит, смешны, например, 4096 байт становятся 4233576455 КБ вместо 4,09 КБ. Я пробовал много исправлений, таких как приведение делителя и дивиденда и изменение формата в sprintf. Вот МРЭ:
#include <malloc.h>
#include <math.h>
long double rround(long double in,int places) {
long double ir = in * pow(10,places);
return roundl(ir) / pow(10,places);
}
char* parse_size(long indata) {
char* final = (char*)malloc(30);
if (indata < 0) {
indata = -indata;
}
indata = (long double)indata;//Force long double over long with no floating point
if (indata > (long double)2000000000) {
sprintf(final,"%lld GB",rround(indata/1000000000.0,2));
} else if (indata > (long double)2000000) {
sprintf(final,"%lld MB",rround(indata/1000000.0,2));
} else if (indata > (long double)2000) {
sprintf(final,"%lld KB",rround(indata/1000.0,2));
} else {
sprintf(final,"%lld bytes",rround(indata,2));
}
return final;
}
int main() {
long bytes = 4096;
printf("Expected: 4.09 KB\n");
printf("Actual: %s\n",parse_size(bytes));
}
Если вы запустите эту программу здесь, вы получите этот вывод
Expected: 4.09 KB
Actual: 4233576455 KB
%lld
— это спецификатор формата для long long int. Ваша функция возвращает длинный двойной...
%lld утверждает, что вы пройдете long long int; вы передаете long double, поэтому вы печатаете мусор (в лучшем случае он будет пытаться напечатать некоторые биты, представляющие long double, как если бы они представляли long long; во многих системах это будет чтение из совершенно не связанного регистра, который не имеет t даже не был инициализирован чем-то конкретным, и вы получите полный мусор). Вам нужен код формата %Lf или %.2Lf, чтобы ограничиться двумя цифрами после запятой.
Спасибо, но сейчас печатается Actual: 0.000000 KB
@ Enderbyte09: У меня отлично работает. Попробуйте онлайн! Печатает 4.10, а не 4.09, но 4.10 все равно правильнее.
Большое спасибо! Я поставил %lf вместо %Lf
@ Enderbyte09: Да, правила довольно строгие, и в них нет четкой рифмы или причины (обычно это исторический крафт, который заставляет такие вещи). Вам просто нужно проверить таблицы спецификаторов преобразования и модификаторов длины.
char* parse_size(long long indata) {
char* final = (char*)malloc(30);
long double indataLD = (long double)abs(indata);
if (indata > 2000000000) {
sprintf(final,"%.2Lf GB",(indataLD/1000000000.0));
} else if (indata > 2000000) {
sprintf(final,"%.2Lf MB",(indataLD/1000000.0));
} else if (indata > 2000) {
sprintf(final,"%.2Lf KB",(indataLD/1000.0));
} else {
sprint(final,"%.2Lf Bytes",indataLD);
}
return final;
}
int main() {
long long bytes = 4096;
printf("Expected: 4.09 KB\n");
printf("Actual: %s\n",parse_size(bytes));
}
Это дает
c++ version is 201703
g++ 8.1.0
Expected: 4.09 KB
Actual: 4.10 KB
indata = (long double)indata;
может только потерять данные (когдаlong
больше битов, чемlong double
может представить в целочисленном смысле), потому что вы назначаете его обратноindata
, который являетсяlong
. В этой строке полная фигня. И%lld
для печатиlong long int
, а неlong double
.