【发布时间】:2016-04-16 00:31:11
【问题描述】:
我的目标是为strcpy 编写安全替换,以防在编译期间知道目标缓冲区大小的情况,并且我希望推断缓冲区大小,因此用户不需要知道它。例如:
char xs[2] = { 0 };
strcpy(xs, "abc"); // buffer overflow!
printf("[%s]\n", xs);
输出将(希望)是:
[abc]
对于简单的情况,当传递C风格的数组时,可以毫不费力地写出来:
template<size_t N>
char * safe_strcpy(char (& dst)[N], const char * src) noexcept {
std::snprintf(dst, N, "%s", src);
return & dst[0];
}
推导出数组的大小,snprintf 负责放置终止空字节,瞧。
我也可以让它适应 std::array:
template<size_t N>
typename std::array<char, N>::pointer
safe_strcpy(std::array<char, N> & dst, const char * src) noexcept {
std::snprintf(dst.data(), N, "%s", src);
return dst.data();
}
但这个版本并不是真正的替代品:
std::array<char, 2> ys = {};
strcpy(ys.data(), "abc"); // overflow!
safe_strcpy(ys, "abc"); // ok, but I needed to remove .data()
我希望以下情况正常工作:
safe_strcpy(ys.data(), "abc"); // "a" should appear in buffer
ys.data() 的依赖类型是 std::array<char, 2u>::pointer {aka char*},所以我认为应该可以从中推断出数组大小,但我不知道如何:/
当我尝试这样的事情时:
template<size_t N>
typename std::array<char, N>::pointer
safe_strcpy(typename std::array<char, N>::pointer & dst, const char * src) {
// etc...
}
编译失败并出现错误:
error: no matching function for call to ‘safe_strcpy(std::array<char, 2u>::pointer, const char [4])’
safe_strcpy(ys.data(), "abc");
^
(...)
note: template argument deduction/substitution failed:
note: couldn't deduce template parameter ‘N’
我尝试使用 gcc 5.1.1 和 clang 3.5.0,两者的错误基本相同。是否可以从 C++ 中的依赖类型中推断出类型?
[编辑]
对所有善良的人说,我应该使用 std::string - 你错过了这里的重点。我可以用任何 STL 容器和::iterator 而不是::pointer 写同样的问题。
【问题讨论】:
-
不可能,抱歉。
-
认真的吗?但是编译器知道这种类型(它甚至在错误消息中打印它......)。
-
编译器知道您编写调用时的类型,但它不知道函数内的类型。额外的信息只是用于调试 -
.data()ischar*。编译器错误消息是“这个char*来自这个类型表达式”,但这不是类型的名称。 -
从
char*,你不可能推断出是std::array<char,2>::pointer还是std::array<char,3>::pointer。但是,您可以想象创建一个sized_pointer:coliru.stacked-crooked.com/a/44c24a8463b6673b -
@PatrykObara,你为什么不做一个没有
.data()部分的std::array的重载?然后你就可以推断出大小了。