我想定义几个宏来计算类型的大小。以下是正常运行的示例。
#include <stdio.h>
#define A sizeof(long long) / sizeof(int)
#define B 36 / A
int main(){
printf("%zu %zun", A, B); // print out: 2 1
}
虽然在使用 SIMD 向量时会变得很奇怪,例如(A 的定义)
#include <x86intrin.h>
#include <stdio.h>
#define A sizeof(__m128i) / sizeof(int)
#define B 36 / A
int main(){
printf("%zu %zun", A, B); // print out 4 0
}
问题出在哪里?
请记住,宏不是变量:它们只是替换的标记。 所以B
扩展到
36 / sizeof(__m128i) / sizeof(int)
C 和 C++ 中的划分从左到右关联,因此这相当于
(36 / sizeof(__m128i)) / sizeof(int)
如果sizeof(__m128i)
为 16,sizeof(int)
为 4,则此表达式为(36 / 16) / 4
。 现在 C 和 C++ 中的整数除法,所以36/16
是2
,2/4
是0
。
因此,应始终将扩展到表达式的宏括起来:
#define A (sizeof(__m128i) / sizeof(int))
#define B (36 / A)
如果使用C++,更好的解决方案是根本不使用宏;C++中的常量功能非常齐全,并避免此问题。
constexpr std::size_t A = sizeof(__m128i) / sizeof(int);
constexpr std::size_t B = 36 / A;
#define A sizeof(__m128i) / sizeof(int)
#define B 36 / A
然后宏B
将扩展为36 / sizeof(__m128i) / sizeof(int)
评估为(36 / sizeof(__m128i)) / sizeof(int)
。
第一次除法的结果将为零,零除以任何值为零。这就是你得到的结果。
与使用宏时一样,解决方案几乎总是在宏定义中添加显式括号:
#define A (sizeof(__m128i) / sizeof(int))
#define B (36 / A)