C和C++中未定义,未指定和实现定义的行为有什么区别?
c c++ undefined-behavior unspecified-behavior implementation-defined-behavior
我在我的代码中发布了一个问题,其唯一的#include指令如下:
#include <bits/stdc++.h>
Run Code Online (Sandbox Code Playgroud)
我的老师告诉我这样做,但在评论部分,我被告知我不应该这样做.
为什么?
c++ portability c++-faq turbo-c++ implementation-defined-behavior
我在标准文档中找不到答案.C++语言标准是否要求sizeof(bool)始终为1(1个字节),还是要定义此大小的实现?
我在Quora帖子中看到了以下代码:
#include <stdio.h>
struct mystruct { int enabled:1; };
int main()
{
struct mystruct s;
s.enabled = 1;
if(s.enabled == 1)
printf("Is enabled\n"); // --> we think this to be printed
else
printf("Is disabled !!\n");
}
Run Code Online (Sandbox Code Playgroud)
在C&C++中,代码的输出都是意外的,
被禁用 !!
虽然在那篇文章中给出了"符号位"相关的解释,但是我无法理解,我们如何设置某些内容然后它没有反映出来.
有人可以给出更详细的解释吗?
c c++ bit-fields signed-integer implementation-defined-behavior
昨天,有人给我看了这个代码:
#include <stdio.h>
int main(void)
{
unsigned long foo = 506097522914230528;
for (int i = 0; i < sizeof(unsigned long); ++i)
printf("%u ", *(((unsigned char *) &foo) + i));
putchar('\n');
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这导致:
0 1 2 3 4 5 6 7
Run Code Online (Sandbox Code Playgroud)
我很困惑,主要是for循环中的行。据我所知,似乎&foo是被强制转换为 anunsigned char *然后被i. 我觉得*(((unsigned char *) &foo) + i)是一个更详细的书写方式((unsigned char *) &foo)[i],但是这使得它看起来像foo,一个unsigned long被索引。如果是这样,为什么?循环的其余部分似乎是典型的打印数组的所有元素,所以一切似乎都表明这是真的。演员unsigned char *阵容让我更加困惑。我试图寻找有关转换的整数类型,以char *对谷歌而言,但我的研究得到了一些后无用的搜索结果停留约铸造int …
c pointers casting char-pointer implementation-defined-behavior
这是一个简单的函数,试图从big-endian缓冲区读取一个通用的二进制补码整数,我们假设std::is_signed_v<INT_T>:
template<typename INT_T>
INT_T read_big_endian(uint8_t const *data) {
INT_T result = 0;
for (size_t i = 0; i < sizeof(INT_T); i++) {
result <<= 8;
result |= *data;
data++;
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,这是未定义的行为,因为最后一个<<=转移到符号位.
所以现在我们尝试以下方法:
template<typename INT_T>
INT_T read_big_endian(uint8_t const *data) {
std::make_unsigned_t<INT_T> result = 0;
for (size_t i = 0; i < sizeof(INT_T); i++) {
result <<= 8;
result |= *data;
data++;
}
return static_cast<INT_T>(result);
}
Run Code Online (Sandbox Code Playgroud)
但我们现在正在调用实现定义的行为static_cast,从unsigned转换为signed.
如何在"明确定义"的领域中做到这一点?
[conv.fpint] p2 说
\n\n\n如果要转换的值在可以表示的值范围内,但无法准确表示该值,则它是下一个较低或较高可表示值的实现定义选择。
\n
[intro.abstract] p2 说
\n\n\n抽象机的某些方面和操作在本文档中被描述为实现定义的(例如,
\nsizeof(int))。这些构成了抽象机的参数。每个实现都应包括描述其在这些方面的特征和行为的文档。此类文档应定义与该实现相对应的抽象机的实例(下面称为\xe2\x80\x9c对应实例\xe2\x80\x9d)。
[intro.abstract] p5 说
\n\n\n执行格式良好的程序的一致实现应产生与具有相同程序和相同输入的抽象机的相应实例的可能执行之一相同的可观察行为。但是,如果任何此类执行包含未定义的操作,则本文档对使用该输入执行该程序的实现没有任何要求(甚至不涉及第一个未定义操作之前的操作)。
\n
考虑有一个实现,它不能16777217准确地表示 float 类型的对象中的值,并且这样的值的选择可以是16777216或者16777218。对于转换评估的所有奇数次,它选择较低的可表示值,对于转换评估的所有偶数次,它选择较高的可表示值。这是一个符合要求的实施吗?
float a1 = 16777217; // 16777216\nfloat a2 = 16777217; // 16777218\n.\n.\n.\nfloat a<2n-1> = 16777217; // 16777216\nfloat a<2n> = 16777217; // 16777218\nRun Code Online (Sandbox Code Playgroud)\n类似案例:
\nsizeof(int); // 4\nsizeof(int); // 8\n.\n.\n.\nsizeof(int); // 4\nsizeof(int); // 8\nRun Code Online (Sandbox Code Playgroud)\n对于所有奇数次的评估sizeof(int),结果都是全部4 …
为什么像字节中的位数这样基本的东西仍然由 C 标准实现定义?有没有这可能有用的例子?
从 C99,3.6(可在此处链接)
3.6 字节
数据存储的可寻址单元足够大,可以容纳执行环境基本字符集的任何成员
注 1:可以唯一地表达对象的每个单独字节的地址。
注 2:一个字节由连续的位序列组成,其数量由实现定义。最低有效位称为低位;最高有效位称为高位。
编辑:我问的是一些基本问题,为什么 C 标准在字节大小的位数方面提供了灵活性。不更具体地询问 sizeof(char) CHAR_BIT != 8 有什么好处。如果问题仍然看起来重复,请否决它,我将关闭问题。
#include <limits.h>
int main(){
int a = UINT_MAX;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我这个 UB 或实现定义?
链接说它的 UB
https://www.gnu.org/software/autoconf/manual/autoconf-2.63/html_node/Integer-Overflow-Basics
链接说它的实现定义
转换规则说:
否则,新类型是有符号的,值不能在其中表示;要么结果是实现定义的,要么引发实现定义的信号。
我们不是将 a 转换max unsigned value为 asigned value吗?
我所看到的方式,gcc 只是截断了结果。
案例 A:C11,6.6 常量表达式,语义,5:
如果在翻译环境中计算浮动表达式,则算术范围和精度应至少与在执行环境中计算表达式一样大。116)
这需要以下程序返回 0:
#include <float.h>
#define EXPR DBL_MIN * DBL_MAX
double d1 = EXPR;
double d2;
#pragma STDC FENV_ACCESS ON
int main(void)
{
d2 = EXPR;
return d1 == d2 ? 0 : 1;
}
Run Code Online (Sandbox Code Playgroud)
案例 B:C11,6.10.1 条件包含,语义,4:
这些字符常量的数值是否与表达式中(#if 或 #elif 指令除外)中出现相同字符常量时获得的值匹配是实现定义的。168)
它不需要以下程序返回 0:
#define EXPR 'z' - 'a' == 25
int main(void)
{
_Bool b1 = 0;
_Bool b2;
#if EXPR
b1 = 1;
#endif
b2 = EXPR;
return b1 == b2 …Run Code Online (Sandbox Code Playgroud) c constants language-lawyer c-preprocessor implementation-defined-behavior
当源值无法在目标类型中表示时,根据cppreference将整数转换为有符号类型
- 实现定义(C++20 之前)
- 目标类型的唯一值等于源值模 2^n ,其中 n 是用于表示目标类型的位数 (C++20 起)
GCC实现定义的行为中还指定了
为了转换为宽度为 N 的类型,该值会以 2^N 为模减少到该类型的范围内;没有发出任何信号。
我猜也有人说同样的话。我的问题是减少/模数结果是否仍然可能超出目标签名类型的范围?比如说signed char c = 255,255 模 2^8 仍然是 255,没有变化。这个模数结果如何适合目标类型?
这个答案展示了一种方法,首先将值反转并加 1,然后在前面添加一个有符号位。我不确定这是否是实际所做的。
解释强调部分的正确/标准方法是什么?
c++ implicit-conversion c++20 implementation-defined-behavior
implementation-defined-behavior ×11
c++ ×7
c ×6
bit-fields ×1
boolean ×1
c++-faq ×1
c++20 ×1
casting ×1
char-pointer ×1
constants ×1
pointers ×1
portability ×1
sizeof ×1
turbo-c++ ×1