在c ++ 11中,根据en.cppreference.com,
对于有符号和非负数a,如果它在返回类型中可表示,则<< b的值为 *2 b,否则行为未定义.
我的理解是,由于255*2 24不能表示为a int32_t,因此对(int32_t) 255 << 24
产量的评估是未定义的行为.那是对的吗?这可能是编译器依赖的吗?这是一个IP16环境,如果重要的话.
背景:这来自我与arduino.stackexchange.com上的用户的争论.根据他的说法,"根本就没有任何不确定":
你注意到大部分的位移是"实现定义".所以你不能从规范中引用章节和经文.您必须转到GCC文档,因为这是唯一可以告诉您实际情况的地方. gnu.org/software/gnu-c-manual/gnu-c-manual.html#Bit-Shifting - 对于负移位值,它只是"未定义".
编辑:从目前为止的答案来看,似乎我对C++ 11标准的阅读是正确的.然后我的问题的关键部分是这个表达式是否在gcc中调用未定义的行为.正如davmac在他的评论中所说,我问"GCC,一个实现,是否定义了一种行为,即使它未被语言标准定义".
从我链接到的gcc手册,看起来确实已经定义了,虽然我发现本手册的措辞听起来更像是教程而不是"语言法".从PSkocik的答案(以及Kane对该答案的评论)来看,它似乎是未定义的.所以我仍然有疑问.
我想我的梦想是在一些gcc文档中有明确的声明,说明1)gcc没有定义标准中明确未定义的任何行为,或者2)gcc确实从版本XX.XX定义了这种行为并且提交到保持在所有后续版本中定义.
编辑2:PSkocik删除了他的答案,我发现这很不幸,因为它提供了有趣的信息.根据他的回答,凯恩对答案的评论以及我自己的实验:
(int32_t)255<<24 使用clang和编译时产生运行时错误 -fsanitize=undefined-fsanitize=undefined(int32_t)256<<24 编译时会出现运行时错误
g++ -std=c++11 -fsanitize=undefined第2点与C++ 11模式中gcc比标准更广泛地定义左移的解释是一致的.根据第3点,这个定义可能只是C++ 14的定义.但是,第3点
与引用的手册是gcc(C++ 11模式)的完整定义的想法不一致,因为该手册没有提供可能未定义的提示.<<(int32_t)256<<24
标题可能是错误的选择,但我找不到这个问题的好的一行摘要.我的问题是我无法弄清楚我的编译器在做什么,我想知道我是否在编译器中发现了一个错误......或者我对C语言的理解.
我的理解是:
- 1UL == ULONG_MAX这是安全的,因为无符号数的溢出行为已被很好地定义(- 1UL) * 1.0f涉及将左操作数转换为float,并且此转换保留ULONG_MAX除了舍入错误之外的值(即)到目前为止,我的编译器同意,除非1UL来自变量.这是我的测试程序,其输出为注释:
#include <stdio.h>
int main(void)
{
unsigned long one = 1;
unsigned long minus_one = - one;
printf("%lu\n", - one); // 18446744073709551615
printf("%g\n", minus_one * 1.0f); // 1.84467e+19
printf("%g\n", (- one) * 1.0); // 1.84467e+19
printf("%g\n", (- 1UL) * 1.0f); // 1.84467e+19
printf("%g\n", (- one) * 1.0f); // -1
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我无法理解最后的输出.我尝试了各种优化级别和各种语言标准(C90,C99和C11),结果相同.谁有线索?
环境:gcc 4.8.1/Ubuntu Linux 14.04/x86-64(I32LP64)
编辑:我刚刚注意到我的问题可能是一元减号和浮点数转换组合的重复.