保持同步

ODBC 应用程序中的对齐问题通常与任何其他应用程序中的对齐问题没有什么不同。 也就是说,大多数 ODBC 应用程序在对齐方面很少有或没有问题。 不对齐地址的不利后果因硬件和操作系统不同而异,可能是小到轻微的性能损失,也可能是大到致命的运行时错误。 因此,ODBC 应用程序(尤其是可移植 ODBC 应用程序)应注意正确对齐数据。

ODBC 应用程序遇到对齐问题的一个示例情形是,当它们分配大型内存块并将该内存的不同部分绑定到结果集中的列时。 当泛型应用程序必须在运行时确定结果集的形状并相应地分配和绑定内存时,很可能会发生这种情况。

例如,假设应用程序执行由用户输入的 SELECT 语句,并从该语句中提取结果。 由于编写程序时此结果集的形状未知,因此应用程序必须在创建结果集并相应地绑定内存后确定每个列的类型。 执行此操作的最简单方法是分配一个大型内存块,并将该块中的不同地址绑定到每个列。 为了访问列中的数据,应用程序会强制转换绑定到该列的内存。

下图显示了一个示例结果集,以及如何可以使用每种 SQL 数据类型的默认 C 数据类型将内存块绑定到该结果集。 每个“X”表示内存的单个字节。 (此示例仅显示绑定到列的数据缓冲区。这样做是为了简单起见。在实际代码中,长度/指示器缓冲区也必须对齐。)

Binding by default C data type to SQL data type

假设绑定地址存储在 Address 数组中,应用程序使用以下表达式访问绑定到每个列的内存:

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

请注意,绑定到第二列和第三列的地址以奇数字节开头,绑定到第三列的地址不能被 4(即 SDWORD 的大小)整除。 在某些计算机上,这不会是问题;在其他计算机上,这将会导致轻微的性能损失;且在其他计算机上,会导致致命的运行时错误。 更好的解决方案是,在其自然对齐边界上对齐每个绑定地址。 假设 UCHAR 为 1,SWORD 为 2,SDWORD 为 4,则会给出下图中所示的结果,其中“X”表示所使用的内存字节,“O”表示未使用的内存字节。

Binding by natural alignment boundary

虽然此解决方案不使用应用程序的所有内存,但它不会遇到任何对齐问题。 遗憾的是,实现此解决方案需要大量代码,因为每个列均必须根据其类型单独对齐。 一种更简单的解决方案是,在最大对齐边界的大小上对齐所有列,在下图所示的示例中为 4。

Binding by largest alignment boundary

尽管此解决方案会留下较大的漏洞,但实现它的代码相对简单且快速。 在大多数情况下,这样会抵消在未使用的内存中所付出的惩罚。 有关使用此方法的示例,请参阅 Using SQLBindCol