提问人:cxxl 提问时间:1/4/2014 最后编辑:Communitycxxl 更新时间:8/21/2015 访问量:2829
Visual C++有 __builtin_constant_p() 吗?
Is there a __builtin_constant_p() for Visual C++?
问:
Microsoft Visual Studio 是否有类似 GCC 的功能?据我了解,如果参数是常量,则该函数返回非零,就像字符串文字一样。__builtin_constant_p()
在这里的答案(如何拥有“constexpr 和运行时”别名)是一个很好的用例。
编辑:我的想法是,而不是写这样的东西:
#include <string.h>
int foo() {
return strlen("text");
}
我可以写:
#include <string.h>
// template_strlen() would be a function that gets the length of a compile-time const string via templates
#define STRLEN(a) (__builtin_constant_p(a) ? template_strlen(a) : strlen(a))
int foo() {
return STRLEN("text");
}
(我想这与链接问题中所写的内容有关。
我所需要的只是 的变体。__builtin_constant_p()
答:
在 Visual Studio 2012 和 Visual Studio 2013 中,有一个使用 std::is_literal_type 的_IS_LITERAL_TYPE宏,该宏记录在 http://www.cplusplus.com/reference/type_traits/is_literal_type/ 中。
以下是is_literal_type文档的相关摘录。
“”“标识 T 是否为文本类型的 Trait 类。
文本类型是可以限定为 constexpr 的类型。
也许这就足够了。
以下摘录自 __builtin_constant_p 文档,让我相信它会的。
“您可以使用内置函数 __builtin_constant_p 来确定某个值在编译时是否已知为常量...”
对我来说,短语“is a literal type”、“constexpr”和“known to be constant-time”具有相同的含义。也许我错了。
话又说回来,我将是第一个承认我不确定的人。
评论
is_literal_type
std::is_literal_type<const char*>::value
true
strlen(some_const_ptr)
strlen("abc")
const char*
strlen(some_const_ptr)
strlen("abc")
const char&[4]
如果is_literal_type不是您想要的,则以下函数可能有用。有了它,我能够分辨出定义如下的 char 字符串和在堆上分配的字符串之间的区别。
LPCTSTR constString = _T("Hello World!");
我对constant_p的实现如下。
int constant_p(const void *p)
{
static bool s_init = false;
static ULONGLONG s_TextSegmentStartVirtualAddress = 0;
static ULONGLONG s_TextSegmentEndVirtualAddress = 0;
static ULONGLONG s_RDataSegmentStartVirtualAddress = 0;
static ULONGLONG s_RDataSegmentEndVirtualAddress = 0;
if (! s_init)
{
s_init = true;
PIMAGE_NT_HEADERS pNtHeaders = ::ImageNtHeader(
reinterpret_cast<PVOID>(::GetModuleHandle(NULL)));
if (! pNtHeaders)
{
return 0;
}
ULONGLONG ImageBase = pNtHeaders->OptionalHeader.ImageBase;
PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)(pNtHeaders + 1);
for (WORD i = 0; i < pNtHeaders->FileHeader.NumberOfSections; ++i)
{
char *name = (char*)pSectionHeader->Name;
if (0 == ::strcmp(name, ".text"))
{
s_TextSegmentStartVirtualAddress = ImageBase
+ pSectionHeader->VirtualAddress;
s_TextSegmentEndVirtualAddress = s_TextSegmentStartVirtualAddress
+ pSectionHeader->SizeOfRawData;
}
else if (0 == ::strcmp(name, ".rdata"))
{
s_RDataSegmentStartVirtualAddress = ImageBase
+ pSectionHeader->VirtualAddress;
s_RDataSegmentEndVirtualAddress = s_RDataSegmentStartVirtualAddress
+ pSectionHeader->SizeOfRawData;
}
pSectionHeader++;
}
}
if (0 == s_TextSegmentStartVirtualAddress)
{
// Something went wrong. Give up.
return 0;
}
ULONGLONG test = reinterpret_cast<ULONGLONG>(p);
if (
s_TextSegmentStartVirtualAddress <= test
&& test <= s_TextSegmentEndVirtualAddress
)
{
return 1;
}
else if (
s_RDataSegmentStartVirtualAddress <= test
&& test <= s_RDataSegmentEndVirtualAddress
)
{
return 1;
}
return 0;
}
请注意,您需要包含 DbgHelp.h 并与 DbgHelp.lib 链接才能正常工作。
我希望我提出的解决方案之一对您有用。我想知道。
评论
下面是一个关于如何获得字符串长度的编译时检测的示例(这不是第一个问题的答案,而是第二个问题的答案)
但是请注意,大多数编译器在第一个优化级别中已经被 3 替换,因此我怀疑它在现实中是否有任何用处。strlen("bob")
template <typename T>
struct StrLenHelper
{
static constexpr size_t len(T) { return 0; }
};
template <size_t sel>
struct StrLenHelper<const char (&)[sel]>
{
static constexpr size_t len(const char (&a)[sel]) { return sel-1; }
};
template <>
struct StrLenHelper<const char*>
{
static size_t len(const char * a) { return strlen(a); }
};
#define StrLen(X) StrLenHelper<decltype(X)>::len(X)
证明它适用于最近的编译器:
template <size_t A>
struct Test { enum T { value = A }; };
// Outputs "5 5 4" if your program is called "test"
int main(int a, char**b)
{
printf("%u %u %u\n", Test<StrLen("bobby")>::value, StrLen("bobby"), StrLen(b[0]));
return 0;
}
一些奇怪的编码实践不会触发编译时行为,例如 ,这将调用运行时版本,因为在调用时类型是(不是您可以在模板中选择的修饰符,或者我不知道如何)constexpr const char * b = "bob";
const char*
constexpr
评论
_mm_set1_epi8()