假设我有一个名为LengthOf(array)
的宏:
sizeof array / sizeof array[0]
当我创建一个大小为23的新数组时,LengthOf
我不应该回23吗?
WCHAR* str = new WCHAR[23];
str[22] = '\0';
size_t len = LengthOf(str); // len == 4
为什么len == 4
?
更新:我输错了,WCHAR*
,而不是WCHAR**
。
答案 0 :(得分:12)
因为str
这里是指向指针的指针,而不是数组。
这是指针和数组之间的细微差别之一:在这种情况下,您的指针位于堆栈上,指向已在其他位置分配的23个字符的数组(可能是堆)
答案 1 :(得分:11)
WCHAR** str = new WCHAR[23];
首先,这甚至不应该编译 - 它会尝试将pointer to WCHAR
分配给pointer to pointer to WCHAR
。编译器应该根据这种不匹配拒绝代码。
其次,sizeof(array)/sizeof(array[0])
宏的一个已知缺点是,当应用于指针而不是真实数组时,它可以并且将完全失败。在C ++中,您可以使用模板来获取拒绝的代码:
#include <iostream>
template <class T, size_t N>
size_t size(T (&x)[N]) {
return N;
}
int main() {
int a[4];
int *b;
b = ::new int[20];
std::cout << size(a); // compiles and prints '4'
// std::cout << size(b); // uncomment this, and the code won't compile.
return 0;
}
答案 2 :(得分:0)
正如其他人所指出的那样,如果将指针传递给它而不是实际数组,则宏无法正常工作。不幸的是,因为指针和数组在大多数表达式中的评估方式相似,所以除非你使宏更复杂,否则编译器无法让你知道存在问题。
对于类型安全的宏的C ++版本(如果传递指针而不是数组类型将生成错误),请参阅:
它不会完全“修复”你的问题,但它会让你知道你做错了什么。
对于在C中工作并且更安全的宏(许多指针将诊断为错误,但有些指针会毫无错误地通过 - 不幸的是包括你的指针):
当然,使用#ifdef __cplusplus
的强大功能,您可以将它们都放在通用标头中,并让编译器为C ++构建选择更安全的版本,并在C ++不生效时为C兼容版本选择。< / p>
答案 3 :(得分:0)
问题是sizeof
运算符检查它的参数大小。您的示例代码中传递的参数为WCHAR*
。因此,sizeof(WCHAR *)是4.如果你有一个数组,例如WCHAR foo[23]
,并取sizeof(foo)
,那么传递的类型基本上是WCHAR[23]
,并且会产生{{ 1}}。编译类型sizeof(WCHAR) * 23
和WCHAR*
的有效类型是不同的,虽然您和我可以看到WCHAR[23]
的结果在功能上等同于new WCHAR[23]
,但实际上,返回type为WCHAR[23]
,绝对没有大小信息。
作为一个项目,由于你的平台上WCHAR*
等于4,你显然正在处理指针为4个字节的架构。如果您在x64平台上构建它,则会发现sizeof(new WCHAR[23])
将返回8。
答案 4 :(得分:0)
您写道:
WCHAR* str = new WCHAR[23];
如果23是一个静态值,(在程序的整个生命周期中不是变量),最好使用#define或const而不仅仅是硬编码 23.
#define STR_LENGTH 23
WCHAR* str = new WCHAR[STR_LENGTH];
size_t len = (size_t) STR_LENGTH;
或C ++版
const int STR_LENGTH = 23;
WCHAR* str = new WCHAR[STR_LENGTH];
size_t len = static_cast<size_t>(STR_LENGTH);