Printf с sizeof на платформах 32 и 64: как обрабатывать формат кода в независимой платформе?
У меня есть код, который печатает объем памяти, используемый программой. Линия похожа на следующую:
printf("The about of RAM used is %u", anIntVariable*sizeof(double) );
где anIntVariable является переменной int для числа элементов двойного массива. Во всяком случае, на 32-битных системах у меня никогда не было никаких проблем, но в 64-битных системах я получаю предупреждение о компиляторе об использовании "% u" для целых чисел без знака. Использование "% lu" в качестве кода формата устраняет проблему на 64-битной, но заставляет компилятор жаловаться на 32-битный, потому что тип возвращается к unsigned int. Я обнаружил, что, действительно, sizeof (double) возвращает другое значение в 32-битных 64-битных системах. Я нашел несколько руководств для веб-страниц, чтобы преобразовать код с 32-бит на 64 бит. Но я бы предпочел иметь код, который работает на обоих, вместо того, чтобы просто конвертировать назад и вперед.
Как написать эту строку независимым от платформы способом? Я знаю много способов сделать это с помощью препроцессорных директив, но это похоже на взломать. Конечно, там элегантный способ, который я не понимаю.
Ответы
Ответ 1
Идентификаторы переносимых принтеров содержатся в файле include inttypes.h
.
Этот файл включает много переносных идентификаторов для вашей конкретной среды выполнения. Для вашего примера вы хотите PRIuPTR, что означает " PR intf I dentifier u nsigned с размером до размера указателя.
Ваш пример будет следующим:
printf("The amount of RAM used is %" PRIuPTR, anIntVariable*sizeof(double) );
Результаты на 64-битном Linux с GCC 4.3 (int anIntVariable = 1
):
$ gcc test.c -m32 -o test && ./test
The amount of RAM used is 8
$ gcc test.c -o test && ./test
The amount of RAM used is 8
Для полноты полноты есть идентификаторы для scanf, префиксы которых - SCN.
Ответ 2
Возвращаемое значение sizeof является size_t. Если вы используете компилятор, совместимый с C99, похоже, вы можете использовать %zd
%zu
для этого.
D'oh: %zu
(без знака), конечно. Спасибо, они.
Ответ 3
Прежде всего, вы должны сопоставить спецификатор "%" с фактическим типом данных, который вы хотите распечатать. sizeof возвращает тип данных size_t, и так же, как вы не должны пытаться распечатать float с помощью спецификатора "% d", вы не должны пытаться распечатать size_t с "% u" или "% d" или что-либо, что на самом деле не означает size_t.
Другие ответы дали несколько хороших способов справиться с новыми компиляторами ( "% z" и PRIu32), но способ, которым мы это делали, состоял в простое преобразование size_t в unsigned long, а затем его печать с использованием "% лу":
printf("The amount of RAM used is %lu", (unsigned long)(anIntVariable*sizeof(double)) );
Это не будет работать в системах, где size_t шире, чем длинный, но я не знаю никаких таких систем, и я даже не уверен, разрешает ли это стандарт.