问题标签 [unspecified-behavior]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c - 您遇到的 C 的常见未定义/未指定行为是什么?
C 语言中未指定行为的一个示例是函数参数的求值顺序。它可能是从左到右或从右到左,你只是不知道。这将影响评估方式foo(c++, c)
或foo(++c, c)
评估方式。
还有哪些其他未指明的行为会让不知情的程序员感到惊讶?
c++ - 未定义、未指定和实现定义的行为
什么是C 和 C++ 中的未定义行为(UB)?未指定的行为和实现定义的行为呢?它们之间有什么区别?
c - 为什么没有return语句的main函数返回值12?
我写了一个打印表格的程序。我没有在主函数中包含返回语法,但是每当我输入 echo $? 它显示 12。
我的源代码:
我没有写return 12,但每次执行程序时它仍然返回12。
谢谢。
c - 在 C99 中, f()+g() 是未定义的还是仅仅是未指定的?
我曾经认为在 C99 中,即使函数的副作用f
和g
干扰,虽然表达式f() + g()
不包含序列点,f
并且g
会包含一些,所以行为是未指定的:要么 f() 会在之前调用g() 或 g() 在 f() 之前。
我不再那么肯定了。如果编译器内联函数(即使未声明函数,编译器也可能决定这样做inline
)然后重新排序指令怎么办?可以得到与上述两者不同的结果吗?换句话说,这是未定义的行为吗?
这不是因为我打算写这种东西,这是为了在静态分析器中为这样的语句选择最佳标签。
c - 如何在没有中间副本的情况下在标准 C 中实现 memmove?
从我系统上的手册页:
void *memmove(void *dst, const void *src, size_t len);
描述
memmove() 函数将 len 个字节从字符串 src 复制到字符串 dst。
两个字符串可能重叠;复制始终以非破坏性
方式完成。
来自 C99 标准:
6.5.8.5 比较两个指针时,结果取决于所指向对象在地址空间中的相对位置。如果两个指向对象或不完整类型的指针都指向同一个对象,或者都指向同一个数组对象的最后一个元素之后,它们比较相等。如果指向的对象是同一个聚合对象的成员,则指向稍后声明的结构成员的指针比较大于指向结构中较早声明的成员的指针,并且指向具有较大下标值的数组元素的指针比较大于指向同一数组的元素的指针具有较低的下标值。所有指向同一个联合对象成员的指针比较相等。如果表达式
P
指向数组对象的一个元素,而表达式 Q 指向同一个数组对象的最后一个元素,则指针表达式Q+1
比较大于P
。在所有其他情况下,行为是 undefined。
重点是我的。
参数dst
和src
可以转换为指针以char
减轻严格的别名问题,但是是否可以比较两个可能指向不同块内的指针,以便在它们指向同一块内时以正确的顺序进行复制?
显而易见的解决方案是if (src < dst)
,但如果src
和dst
指向不同的块,那是未定义的。“未定义”意味着您甚至不应该假设条件返回 0 或 1(这在标准词汇中被称为“未指定”)。
另一种选择是if ((uintptr_t)src < (uintptr_t)dst)
,至少未指定,但我不确定标准是否保证src < dst
定义时,它等同于(uintptr_t)src < (uintptr_t)dst)
。指针比较是从指针算术定义的。例如,当我阅读关于加法的第 6.5.6 节时,在我看来,指针算术可能会朝着与uintptr_t
算术相反的方向发展,也就是说,兼容的编译器可能有, whenp
是 type char*
:
这只是一个例子。一般来说,将指针转换为整数时似乎很少保证。
这是一个纯粹的学术问题,因为memmove
是与编译器一起提供的。在实践中,编译器作者可以简单地将未定义的指针比较提升为未指定的行为,或者使用相关的 pragma 来强制他们的编译器memmove
正确编译它们。例如,这个实现有这个片段:
我仍然想用这个例子来证明标准在未定义的行为方面走得太远,如果确实memmove
不能在标准 C 中有效地实现。例如,在回答这个 SO question时没有人打勾。
c++ - 是否有任何 C++ 工具可以检查常见的未指定行为?
通常人们会假设一个正在编码的特定平台,例如有符号整数使用二进制补码存储,或者那个(0xFFFFFFFF == -1)
,或者那种性质的东西。
是否存在一种工具可以检查代码库中最常见的违规行为(对于我们这些想要可移植代码但没有奇怪的非二进制补码机器的人)?
(我上面的示例特定于有符号整数,但我也对其他错误(例如对齐或字节顺序)感兴趣)
c++ - 未定义、实现定义、未指定的行为
C++03
$5.3.3/2 - “最大派生类的大小应大于零 (1.8)。”
$1.8/4 - “除非它是位字段 (9.6),否则最派生的对象应具有非零大小并应占用一个或多个字节的存储空间。”
那么我的问题是:
空类的大小是否未指定,实现是否已定义?它应该由编译器文档记录吗?据我的理解是正确的,这两个引用让它如此开放。
c++ - 比较指向不同数组的指针是否相等是未指定的行为吗?
等式运算符具有关系运算符对指针的语义限制:
==(等于)和 !=(不等于)运算符与关系运算符具有相同的语义限制、转换和结果类型,但它们的优先级较低和真值结果除外。[C++03 §5.10p2]
并且关系运算符对比较指针有限制:
如果相同类型的两个指针 p 和 q 指向不同的对象,这些对象不是同一对象的成员或同一数组的元素或指向不同的函数,或者如果其中只有一个为空,则 p<q, p 的结果>q、p<=q 和 p>=q 未指定。[§5.9p2]
这是相等运算符“继承”的语义限制吗?
具体来说,给定:
很明显 (a + 3) < (b + 3) 是未指定的,但 (a + 3) == (b + 3) 是否也未指定?
c++ - 为什么不同的 C++ 编译器对这段代码给出不同的结果?
我正在编写一些 C++ 代码以供娱乐和练习,以了解有关语言功能的更多信息。我想更多地了解静态变量及其在递归函数中的行为。在 g++ 编译器中尝试这段代码,我得到了预期的结果:
但是我的朋友在 Microsoft Visual C++ 6 中测试了相同的代码。输出是50, 80, 90
我用其他 C++ 编译器(Linux、Win 和 Mac 下的 g++、Borland、Code::blocks 和 MingW)测试它的输出是110, 100, 40
. 我无法理解输出如何50, 80, 90
......
为什么 MSVC 的输出不同?
scala - Scala 的 Map.unzip 返回的原因 (Iterable, Iterable)
前几天我想知道为什么 scala.collection.Map 将其 unzip 方法定义为
由于该方法“仅”返回一对 Iterable 而不是一对 Seq,因此不能保证原始映射中的键/值对出现在返回序列中的匹配索引处,因为 Iterable 不保证遍历的顺序。所以如果我有一个
,然后在调用之后
我可能最终得到
和
虽然我可以想象这背后与存储相关的原因(例如,想想 HashMaps),但我想知道你们对这种行为的看法。Map.unzip 方法的用户可能会认为这些项目是以相同的配对顺序返回的(我敢打赌,这可能几乎总是如此),但因为不能保证这反过来会产生难以发现的错误图书馆用户的代码。
也许应该在随附的 scaladoc 中更明确地表达这种行为?
编辑:请注意,我并不是将地图称为有序集合。我只对解压缩后的“匹配”序列感兴趣,即
它适用于所有 i (keys(i), values(i)) 是原始映射的一个元素。