c语言编译时字符串长度,c ++ - 在编译时计算C字符串的长度。 这真的是一个constexpr吗?...

c ++ - 在编译时计算C字符串的长度。 这真的是一个constexpr吗?

我正在尝试在编译时计算字符串文字的长度。 为此,我使用以下代码:

#include

int constexpr length(const char* str)

{

return *str ? 1 + length(str + 1) : 0;

}

int main()

{

printf("%d %d", length("abcd"), length("abcdefgh"));

}

一切都按预期工作,程序打印4和8.由clang生成的汇编代码显示结果在编译时计算:

0x100000f5e: leaq 0x35(%rip), %rdi ; "%d %d"

0x100000f65: movl $0x4, %esi

0x100000f6a: movl $0x8, %edx

0x100000f6f: xorl %eax, %eax

0x100000f71: callq 0x100000f7a ; symbol stub for: printf

我的问题:length函数将在编译时评估标准吗?

如果这是真的,编译时字符串文字计算的大门刚刚为我打开...例如,我可以在编译时计算哈希值等等......

6个解决方案

64 votes

不保证在编译时计算常量表达式,我们只有草案C ++标准部分constexpr中的非规范性引用。

[...]> [注意:可以在期间评估常量表达式   翻译 - 结束说明]

您可以将结果分配给constexpr变量以确保它在编译时进行评估,我们可以从Bjarne Stroustrup的C ++ 11参考中看到这一点(强调我的):

除了能够在编译时评估表达式,我们   希望能够要求在编译时评估表达式   时间; 变量定义前面的constexpr就是这样做的(和   暗示const):

例如:

constexpr int len1 = length("abcd") ;

Bjarne Stroustrup总结了我们何时可以确保此isocpp博客条目中的编译时评估,并说:

[...]正确的答案 - 如上所述   通过Herb - 是根据标准constexpr功能可能   在编译器时间或运行时进行评估,除非它被用作a   常量表达式,在这种情况下必须对其进行求值  编译时间。 为了保证编译时评估,我们必须使用   它需要一个常量表达式(例如,作为一个数组绑定或   作为案例标签)或使用它来初始化constexpr。 我希望   没有自尊的编译器会错过优化   有机会做我最初说的话:“constexpr功能是   如果所有参数都是常量,则在编译时进行评估  表述“。

因此,这概述了应在编译时对其进行评估的两种情况:

在需要常量表达式的地方使用它,这似乎是草案标准中使用短语constexpr或shall be ... constant expression的任何位置,例如数组绑定。

用它来初始化constexpr,如上所述。

Shafik Yaghmour answered 2019-05-09T05:40:14Z

24 votes

很容易确定对constexpr函数的调用是否会导致核心常量表达式或仅仅是优化:

在需要常量表达式的上下文中使用它。

int main()

{

constexpr int test_const = length("abcd");

std::array test_const2;

}

Ben Voigt answered 2019-05-09T05:40:47Z

16 votes

请注意,现代编译器(如gcc-4.x)在编译时为字符串文字执行strlen,因为它通常被定义为内部函数。 未启用优化。 虽然结果不是编译时常量。

例如。:

printf("%zu\n", strlen("abc"));

结果是:

movl $3, %esi # strlen("abc")

movl $.LC0, %edi # "%zu\n"

movl $0, %eax

call printf

Maxim Egorushkin answered 2019-05-09T05:41:18Z

12 votes

让我提出另一个函数,它在编译时计算字符串的长度而不是递归的。

template< size_t N >

constexpr size_t length( char const (&)[N] )

{

return N-1;

}

在ideone上查看此示例代码。

user2436830 answered 2019-05-09T05:41:52Z

6 votes

无法保证在编译时评估if函数,但任何合理的编译器都会在启用适当的优化级别时执行此操作。 另一方面,必须在编译时评估模板参数。

我使用以下技巧在编译时强制进行评估。 不幸的是,它只适用于整数值(即不使用浮点值)。

template

struct static_eval

{

static constexpr T value = V;

};

现在,如果你写

if (static_eval::value > 7) { ... }

您可以确定if语句是编译时常量,没有运行时开销。

5gon12eder answered 2019-05-09T05:42:40Z

1 votes

维基百科关于广义常量表达式的简短解释:

在函数上使用constexpr会对函数的作用施加一些限制。 首先,该函数必须具有非void返回类型。 其次,函数体不能声明变量或定义新类型。 第三,正文可能只包含声明,空语句和单个return语句。 必须存在参数值,以便在参数替换后,return语句中的表达式生成常量表达式。

在函数定义之前使用constexpr关键字指示编译器检查是否满足这些限制。 如果是,并且使用常量调用函数,则返回的值保证是常量,因此可以在需要常量表达式的任何位置使用。

kaedinger answered 2019-05-09T05:43:22Z

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值