Почему в таблицу значений записывается 0 вместо 1 при использовании квалификаторов числа?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В практике разработки на платформе 1С:Предприятие часто возникает необходимость работы с типизированными коллекциями данных. При программном создании объекта ТаблицаЗначений мы стремимся жестко определить типы ее колонок, чтобы избежать ошибок при дальнейшей обработке. Однако здесь разработчиков подстерегает неочевидная ловушка: при записи корректного ненулевого числа (например, единицы, прочитанной из файла DBF или полученной расчетным путем) в колонке таблицы значений внезапно оказывается 0.

В этой статье мы подробно разберем, почему возникает такое поведение платформы, как именно 1С рассчитывает разрядность чисел «под капотом», и рассмотрим несколько надежных способов решения данной проблемы.

Анализ исходной ситуации и кода

Рассмотрим классический пример создания типизированной колонки, с которым столкнулся автор темы. Нам необходимо создать таблицу значений с колонкой OBRAZ, которая должна хранить целое число длиной в один символ (например, двоичный флаг: 0 или 1). Разработчик пишет следующий код:


КЧ_1_ = Новый КвалификаторыЧисла(1, 0); 
Массив = Новый Массив; 
Массив.Добавить(Тип("Число")); 
ОписаниеТиповЧ_1_ = Новый ОписаниеТипов(Массив, , , КЧ_1_); 

ТЗ_ = Новый ТаблицаЗначений; 
ТЗ_.Колонки.Добавить("OBRAZ", ОписаниеТиповЧ_1_); 

НС = ТЗ_.Добавить(); 
НС.OBRAZ = Число(ДБФ1.OBRAZ); // В источнике ДБФ1.OBRAZ хранится единица

При пошаговой отладке выясняется странная деталь: в переменной-источнике ДБФ1.OBRAZ гарантированно находится число 1. Однако сразу после выполнения строки присваивания значение НС.OBRAZ принимает значение 0. При этом, если присвоить значение напрямую через литерал НС.OBRAZ = 1, в некоторых случаях платформа может отобразить единицу в отладчике, но при дальнейшей обработке или выгрузке данных значение все равно превращается в ноль.

Давайте разберемся, почему так происходит.

Выясняем техническую причину: секреты работы КвалификаторыЧисла

Главная причина кроется в поведении конструктора КвалификаторыЧисла и механизме резервирования разрядов платформой 1С. Когда мы объявляем квалификатор следующим образом:

КЧ_1_ = Новый КвалификаторыЧисла(1, 0);

Мы передаем в него два параметра: общую длину числа (1) и количество знаков после запятой (0). Третий параметр конструктора — ДопустимыйЗнак — не указан. По умолчанию платформа 1С принимает его равным значению системного перечисления ДопустимыйЗнак.Любой. Это означает, что число может быть как положительным, так и отрицательным.

Для представления знака числа (плюса или минуса) платформе требуется зарезервировать ровно **один разряд**. Расчет доступной разрядности для целой части числа в 1С происходит по следующей строгой формуле:

Разрядность целой части = Общая длина - Дробная часть - Позиция под знак (если знак "Любой")

Подставим наши значения в эту формулу:

Разрядность целой части = 1 (общая длина) - 0 (дробная часть) - 1 (знак) = 0 знаков

Таким образом, для хранения самого числа у платформы остается ровно 0 разрядов! Любое целое число, которое мы попытаемся записать в эту колонку (будь то 1, 5 или 9), из-за нулевой разрядности целой части будет автоматически округлено платформой до 0. Это фундаментальное ограничение типизации данных в 1С.

Способы решения проблемы

Для устранения этой проблемы мы можем пойти несколькими путями в зависимости от архитектурных требований к разрабатываемому алгоритму. Рассмотрим каждый способ подробно.

Способ 1. Явное указание знака «Неотрицательный» (Рекомендуемый)

Если в вашей колонке гарантированно будут храниться только положительные числа или нули (например, статусы, флаги, булевы маркеры 0 и 1), позицию под знак резервировать не требуется. Для этого при инициализации квалификатора необходимо явно передать третий параметр:


// Указываем допустимый знак как "Неотрицательный"
КЧ_1_ = Новый КвалификаторыЧисла(1, 0, ДопустимыйЗнак.Неотрицательный); 
ОписаниеТиповЧ_1_ = Новый ОписаниеТипов("Число", , , КЧ_1_);

ТЗ_ = Новый ТаблицаЗначений; 
ТЗ_.Колонки.Добавить("OBRAZ", ОписаниеТиповЧ_1_); 

При таком подходе формула расчета примет вид: 1 - 0 - 0 = 1. Под целую часть числа будет выделен полноценный 1 разряд. Теперь цифры от 0 до 9 запишутся в таблицу значений корректно и без искажений.

Способ 2. Увеличение общей разрядности квалификатора

Если ваше число все-таки может принимать отрицательные значения (например, -1), вам необходимо увеличить общую длину числа как минимум до двух символов, чтобы один символ остался под знак, а второй — под цифру:


// Увеличиваем общую длину до 2, оставляя знак "Любой" по умолчанию
КЧ_1_ = Новый КвалификаторыЧисла(2, 0); 
ОписаниеТиповЧ_1_ = Новый ОписаниеТипов("Число", , , КЧ_1_);

В данном случае расчет будет следующим: 2 - 0 - 1 = 1. Мы получим возможность записывать в колонку числа в диапазоне от -9 до 9.

Способ 3. Отказ от жесткой типизации колонки (Динамический тип)

Если создаваемая ТаблицаЗначений является временным объектом в рамках одной процедуры, не передается в жестко типизированные схемы (например, в СКД или внешние СУБД) и используется только для промежуточных вычислений, лучшим решением будет отказаться от явного указания типов при добавлении колонки:


ТЗ_ = Новый ТаблицаЗначений; 
// Добавляем колонку без указания ОписанияТипов
ТЗ_.Колонки.Добавить("OBRAZ"); 

При таком подходе колонка получит неопределенный тип. Платформа 1С автоматически определит тип значения непосредственно в момент записи первой строки. Это полностью исключит любые проблемы с округлением и усечением разрядов, избавив вас от необходимости ручной настройки квалификаторов.

Резюме

Проанализировав данную проблему, мы выяснили, что неявное поведение платформы 1С при работе с объектом КвалификаторыЧисла может приводить к потере данных. Всегда обращайте внимание на количество разрядов, выделяемых под знак числа. Если вы работаете с положительными числами-индикаторами, всегда явно используйте параметр ДопустимыйЗнак.Неотрицательный.

← На главную