2012-01-12 3 views
0

У меня есть супер-простой класс, представляющий собой десятичный # с фиксированной точностью, и когда я хочу, чтобы отформатировать его, я сделать что-то вроде этого:Bizarre поведение от Sprintf в C++/VS2010

assert(d.DENOMINATOR == 1000000); 
char buf[100]; 
sprintf(buf, "%d.%06d", d._value/d.DENOMINATOR, d._value % d.DENOMINATOR); 

Поразительно (для меня по крайней мере) это не сработает. Член% 06d выдает все 0s, даже если d.DENOMINATOR не равномерно делит d._value. И если я выложу лишний% d в строке формата, я вижу, что правильное значение появляется в третьем месте - так что это похоже на то, что тайно создается дополнительный аргумент между моими двумя.

Если я вычисляю два члена за пределами вызова sprintf, все ведет себя так, как я ожидаю. Я подумал воспроизвести это с помощью более простого тестового примера:

char testa[200]; 
char testb[200]; 
int x = 12345, y = 1000; 
sprintf(testa, "%d.%03d", x/y, x%y); 
int term1 = x/y, term2 = x%y; 
sprintf(testb, "%d.%03d", term1, term2); 

... но это работает должным образом. Поэтому я полностью озадачен тем, что происходит, как его избежать в будущем и т. Д. Может ли кто-нибудь пролить свет на это для меня?

(EDIT: проблема закончилась тем, что d._value и d.DENOMINATOR являются длинными длинными, поэтому% d не хватает. Большое спасибо комментарию Сержа, ниже которого указана проблема, и ответ Марка, представленный вскоре после этого .)

+5

Каково определение типа «d» –

+2

Просьба показать выходные примеры. Кроме того, каковы типы d; _value и d.DENOMINATOR? –

+0

Вам лучше показать нам эту суперпростую реализацию. –

ответ

3

Почти наверняка компоненты вашего термина являются 64-разрядными (возможно, long в 64-разрядной системе), которые передаются в небезопасный sprintf. Таким образом, при создании промежуточного значения int размер правильный, и он работает нормально.

g ++ предупредит об этом и многих других полезных вещах с помощью -Wall. Предпочтительным решением является, конечно, использование iostreams C++ для вашего форматирования, поскольку они полностью безопасны для типов.

Альтернативное решение состоит в том, чтобы придать результат вашего выражения типу, который вы сказали sprintf, чтобы ожидать, чтобы он вытащил нужное количество байтов из памяти.

Наконец, никогда не используйте sprintf, когда почти каждый компилятор поддерживает snprintf, который предотвращает всевозможные глупые ошибки. Теперь ваш код в порядке, но когда кто-то изменяет его позже, и он заканчивается с конца буфера, вы можете потратить дни, отслеживая коррупцию.

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