2013-08-08 1 views
4

Если у вас возникли проблемы с заголовком для этого вопроса.c: unsigned long long присваивается неправильное значение только для HP-UX

Недавно я полезла в мир С.

У меня есть немного кода, который в основном показывает емкость и свободное пространство на диске. Он отлично работает на нескольких разных дистрибутивах Linux, которые я пробовал, а также Solaris и AIX. Недавно я собрал пакет HP-UX PA-RISC и получил (по-моему) действительно странную ошибку.

struct statfs fsStat; 
err = statfs(rootPath,&fsStat); 
unsigned long long totalBytes = (unsigned long long)(fsStat.f_bsize * fsStat.f_blocks); 

В GDB, когда я делаю:

p (fsStat.f_bsize * fsStat.f_blocks) 

В результате 1335205888 Но после того, как расчет выполняется, когда я

p totalByes 

В результате 18446744071562067968

Любая информация, которая может даже дать мне представление о том, что попробовать здесь, будет rea очень здорово. Используется думать, что я знал, как программировать, пока я не начал делать мульти платформу C :(

+2

В большинстве случаев тип выражения C (который определяет условия, в котором он будет переполняться) определяется самим выражением, а не контекстом, в котором он появляется. 'fsStat.f_bsize * fsStat.f_blocks' оценивается с типом, определяемым типами его операндов, а не типом, в который преобразуется результат. Приведение операндов к 'unsigned long long' должно устранить проблему. (И окончательный отбор не нужен, назначение или инициализатор неявно преобразует любое числовое выражение в целевой тип.) –

+0

Спасибо за ваш комментарий. Вы помогли мне лучше понять, как обрабатывается инструкция. Теперь я осознаю ошибку в том, что она завершает умножение в парензисе, что приводит к значению этого типа (которое в этом случае переполнено). Первоначально у меня не было ни броска, ни оценки, и он просто пытался это сделать. Ваше решение было правильным и теперь имеет для меня гораздо больше смысла. Спасибо. –

ответ

6

Гипотеза:.

умножение переполнена, поэтому fsStat.f_bsize * fsStat.f_blocks произвел результат перетока -2147483648 Когда это было преобразовано в unsigned long long,. он произвел 18446744071562067968, который равен 0xffffffff80000000, результат обертывания -2147483648 в 64-битном неподписанном формате. GDB использует различную арифметику, чем C, поэтому он отображает математически правильный результат.

Чтобы исправить это, измените (unsigned long long) (fsStat.f_bsize * fsStat.f_blocks) на (unsigned long long) fsStat.f_bsize * fsStat.f_blocks, чтобы преобразовать в более широкий целочисленный формат перед умножением.

Лучше, чем unsigned long long, использовать либо uint64_t (от <stdint.h>), либо тип, поставляемый платформой (некоторый заголовок Linux) для работы с размерами дисков.

+0

Какой замечательный ответ. Конечно, вы были абсолютно правы. Печать реального значения умножения произвела -2147483648. Решение, как вы сказали, должно было сделать так (unsigned long long) fsStat.f_bsize * (unsigned long long) fsStat.f_blocks. Я попытался использовать , чтобы получить uint64_t, но не доступен на машине HP-UX, которую я использую. Я подозревал какую-то проблему с памятью (переполнение), но не знал, как ее обрабатывать. Не могу вас поблагодарить. –

4

Я думаю, что f_bsize и f_blocks имеют типа int. Значение, вероятно, переполненную в отрицательное значение.

Попробуйте литье каждого из этих значений в unsigned long long, прежде чем их умножения

+0

Лучшим способом, чем литье, является использование правильного типа в первую очередь, что в данном случае должно быть 'size_t' – Jocke

+4

@Jocke:' size_t' гарантированно подходит для размеров объектов в памяти. Размеры дисковых пространств, возможно, должны быть больше. –

+0

В 64-битных системах размер 'size_t' должен быть 64 бита.который может составлять около 18 446 744 ТБ. У вас столько дискового пространства? Но да, я полагаю, было бы безопасно следовать стандарту и не использовать size_t для дискового пространства. – Jocke

Смежные вопросы