Поделиться через


Точное понимание

Проблемы выравнивания в приложении ODBC обычно не отличаются от других приложений. То есть большинство приложений ODBC имеют мало проблем с выравниванием. Штрафы за отсутствие выравнивания адресов зависят от оборудования и операционной системы и могут быть незначительными, как незначительный штраф производительности или как крупный, как неустранимая ошибка во время выполнения. Поэтому приложения ODBC и переносимые приложения ODBC, в частности, должны быть осторожны, чтобы правильно выровнять данные.

Один из примеров, когда приложения ODBC сталкиваются с проблемами выравнивания, заключается в том, что они выделяют большой блок памяти и привязывают различные части этой памяти к столбцам в результирующем наборе. Это, скорее всего, происходит, когда универсальное приложение должно определить форму результирующий набор во время выполнения и выделить и привязать память соответствующим образом.

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

На следующей схеме показан пример результирующий набор и привязка блока памяти к нему с помощью типа данных C по умолчанию для каждого типа данных SQL. Каждый элемент "X" представляет один байт памяти. (В этом примере показаны только буферы данных, привязанные к столбцам. Это делается для простоты. В фактическом коде буферы длины и индикатора также должны быть выровнены.)

Binding by default C data type to SQL data type

Если привязанные адреса хранятся в массиве адресов , приложение использует следующие выражения для доступа к памяти, привязанной к каждому столбцу:

(SQLCHAR *)       Address[0]  
(SQLSMALLINT *)   Address[1]  
(SQLINTEGER *)    Address[2]  

Обратите внимание, что адреса, привязанные ко второму и третьему столбцам, начинаются с нечетных байтов, и адрес, привязанный к третьему столбцу, не делится на четыре, что является размером SDWORD. На некоторых компьютерах это не будет проблемой; на других, это приведет к небольшой пенальти производительности; в других случаях это приведет к неустранимой ошибке во время выполнения. Лучшее решение — выровнять каждый связанный адрес по своей границе естественного выравнивания. Если это значение равно 1 для UCHAR, 2 для МЕЧа и 4 для SDWORD, это даст результат, показанный на следующем рисунке, где "X" представляет байт используемой памяти, а "O" представляет байт памяти, который не используется.

Binding by natural alignment boundary

Хотя это решение не использует всю память приложения, она не сталкивается с проблемами выравнивания. К сожалению, для реализации этого решения требуется достаточное количество кода, так как каждый столбец должен быть выровнен по отдельности по своему типу. Проще всего выровнять все столбцы по размеру самой большой границы выравнивания, которая составляет 4 в примере, показанном на следующем рисунке.

Binding by largest alignment boundary

Хотя это решение оставляет более крупные отверстия, код для реализации его относительно простой и быстрой. В большинстве случаев это смещает штраф, оплаченный в неиспользуемой памяти. Пример использования этого метода см. в разделе Using SQLBindCol.