当我初始化下面的数组时,所有输出看起来都没问题,除了values[3].出于某种原因,values[3]初始化为values[0]+values[5]输出非常大的数字.我的猜测是,我在尝试分配values[0]+values[5]之前将它们妥善存储在内存中,但是如果有人能够解释那将是很好的.
int main (void)
{
int values[10] = {
[0]=197,[2]=-100,[5]=350,
[3]=values[0] + values[5],
[9]= values[5]/10
};
int index;
for (index=0; index<10; index++)
printf("values[%i] = %i\n", index, values[index]);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出如下:
values[0] = 197
values[1] = 0
values[2] = -100
values[3] = -1217411959
values[4] = 0
values[5] = 350
values[6] = 0
values[7] = 0
values[8] = 0
values[9] = 35
Run Code Online (Sandbox Code Playgroud) c arrays runtime-error designated-initializer unspecified-behavior
编辑说明:最初的问题说非法,现在说未指定。
感谢最近 Jason Turner 视频的视频评论部分,我了解到这std::complex<int>是未指定的。
但所有(AFAIK)实现似乎都可以愉快地编译
std::complex<int>
Run Code Online (Sandbox Code Playgroud)
但有些功能如std::abs()已被破坏std::complex<int>,因此它实际上在那些主流实现中不可用。
我想知道是否有某种原因导致从未实现“不良”类型的检测。我知道 std lib 实现需要与较旧的标准一起工作,因此它们不能只是std::floating_point在各处停留概念,但即使在 C++20 之前,我们也有方法来约束模板。
换句话说:这只是“很好,但我们没有时间”问题,还是存在某些兼容性原因来保持此编译。我唯一能想到的是,有些人正在使用 std::complex 和 std lib“制造商”不想明显破坏他们已经损坏的代码。
c++ complex-numbers language-lawyer unspecified-behavior c++20
我写了一个打印表格的程序.我没有在main函数中包含返回语法,但每当我输入echo $时仍然如此?它显示12.
我的源代码:
#include <stdio.h>
int main(void)
{
int ans,i,n;
printf("enter the no. : ");
scanf("%d",&n);
for(i=1;i<=10;i++)
{
ans = n*i;
printf("%d * %d = %d\n",n,i,ans);
}
}
Run Code Online (Sandbox Code Playgroud)
我没有写回12,但每次执行程序时它仍返回12.
谢谢.
等于运算符对指针的关系运算符有语义限制:
==(等于)和!=(不等于)运算符具有与关系运算符相同的语义限制,转换和结果类型,除了它们的优先级和真值结果.[C++03§5.10p2]
关系运算符对比较指针有限制:
如果同一类型的两个指针p和q指向不是同一个对象的成员或同一个数组的元素或不同函数的不同对象,或者只有其中一个为null,则p <q,p的结果> q,p <= q,p> = q未指定.[§5.9p2]
这是一个由等式运算符"继承"的语义限制吗?
具体来说,给出:
int a[42];
int b[42];
Run Code Online (Sandbox Code Playgroud)
很明显,(a + 3)<(b + 3)是未指定的,但是(a + 3)==(b + 3)也未指定?
如果我写的话f(x)->g(args, ...)可以f(x)在评估之前依赖序列点args, ...吗?我可以通过两种方式看到论点:
this,好像我写的g(f(x), args, ...)那样表明它就像一个参数,因此未指定.该->操作是不正常的二元运算符,因为显然g(...) 不能被评估之前f(x),如果我写的是它可以f(x) + g(...).我很惊讶我找不到一些具体的说法.
通常人们会对正在编码的特定平台做出假设,例如,有符号整数使用两个补码存储,或者那个(0xFFFFFFFF == -1)或那些性质的东西.
是否存在可以检查代码库以查找最常见的违反这类事件的工具(对于我们这些想要可移植代码但没有奇怪的非二进制补充机器的人)?
(我上面的示例特定于有符号整数,但我也对其他错误(例如对齐或字节顺序)感兴趣)
虽然在SO上有很多关于这个主题的链接,但我认为有些东西缺失:用简单的语言明确解释未指定行为(UsB),未定义行为(UB)和实现定义行为(IDB )之间的区别)详细但容易解释任何用例和示例.
注意:为了这个WIKI的紧凑性,我提出了UsB的首字母缩略词,但是不要指望在其他地方使用它.
我知道这可能看起来与其他帖子(它更接近的是这个)的重复,但在任何人将此标记为重复之前,请考虑我已经找到的所有材料的问题(我将要制作这个帖子中的社区WIKI):
太多分散的例子.当然,例子并不坏,但有时人们无法找到一个很好地适应他手头问题的例子,因此它们可能会令人困惑(特别是对于新手).
示例通常只是代码,但解释很少.在这些微妙的问题上,特别是(相对)新手,更自上而下的方法可能更好:首先是一个清晰,简单的解释与抽象(但不是法律)的描述,然后是 一些简单的例子,解释为什么他们触发一些行为.
有些帖子经常混合使用C和C++示例.C和C++有时与他们认为的UsB,UB和IDB不一致,所以一个例子可能会误导那些不熟悉这两种语言的人.
当给出UsB,UB和IDB的定义时,通常它是标准的简单引用,有时可能不清楚或难以为新手消化.
有时引用标准是不完整的.许多帖子只引用了对手头问题有用的部分标准,这很好,但缺乏一般性.此外,对标准的引用通常没有任何解释(对初学者不利).
由于我自己不是这个主题的超级专家,我将建立一个社区WIKI,以便任何有兴趣的人都可以贡献并改进答案.
为了不破坏我创建一个结构良好的初学友好的WIKI的目的,我希望海报在编辑WIKI时遵循一些简单的指导原则:
对您的用例进行分类.尝试将您的示例/代码放在已存在的类别下(如果适用),否则创建一个新类别.
首先是简单的单词描述.首先用简单的词语描述(当然,不要过于简单化 - 质量第一!)你想要做的例子或要点.然后放入代码示例或引用.
引用标准参考.不要发布各种标准的片段,但要提供明确的参考资料(例如C99 WG14/N ......第1.4.7节,第......段),并在可能的情况下发布相关资源的链接.
喜欢免费的在线资源.如果你想引用书籍或非免费可用的资源(可能会提高WIKI的质量),但尝试添加一些免费资源的链接.这对ISO标准尤为重要.欢迎您添加官方标准的链接,但也尝试添加等效链接以免费提供草稿.请不要将参考链接替换为参考官方标准,添加到它们.甚至某些大学的某些计算机科学系也没有ISO标准的副本,更不用说大多数程序员了!
除非确实需要,否则不要发布代码.仅在仅使用普通英语的解释尴尬或不清楚时才发布代码.尝试将代码示例限制为单行.发布指向其他SO Q&A的链接.
不要发布C++示例.我希望这能成为C的一种常见问题解答(如果有人想为C++启动一个双线程,那将是很棒的).与C++的相关差异是受欢迎的,但仅作为附注.这是在你彻底解释C案例之后,你可以添加一些关于C++的陈述,如果这对C程序员在切换到C++时会有所帮助,但我不希望看到的例子超过20%的C++.通常一个简单的注释,如"(C++在这种情况下表现不同)"加上相关链接就足够了.
因为我对SO很新,所以我希望通过这种方式开始问答我不会破坏任何规则.对不起,如果是这样的话.欢迎mods让我知道它.
假设以下代码:
#include <iostream>
using namespace std;
char one()
{
cout << "one\n";
return '1';
}
char two()
{
cout << "two\n";
return '2';
}
int main(int,char**)
{
// 1:
cout << one()
<< '\n'
<< two()
<< '\n';
// 2:
operator<<(
operator<<(
operator<<(
operator<<(
cout,
one()),
'\n'),
two()),
'\n');
}
Run Code Online (Sandbox Code Playgroud)
执行标记为1和的行,并2使用ideone编译时执行相同的操作,它打印如下:
two
one
1
2
Run Code Online (Sandbox Code Playgroud)
从我的观点来看,我们在这里观察到的是未指定的行为,因为未指定解析函数参数的顺序.
这是一个在采访中的问题,打印上面给出的序列(没有任何替代方案)应该是正确答案,但它是否真的正确?
如果C++ 14
实现在a的基础字节中包含填充位unsigned int,那么标准是否指定是否必须在填充位上执行按位运算?
另外,C++ 14标准是否指定相等和关系运算符是否必须忽略填充位?
如果在这个问题上缺乏规范,那么这些运算符在填充位上的预期行为是否存在某种共识?
我在Stack Overflow上找到了相互矛盾的答案.轨道中的亮度竞赛和ecatmur说,按位运算符不适用于算术,因为它们应用于所有位(包括填充位),而Christoph和Bartek Banachewicz表示按位运算符处理整数的逻辑值并忽略填充.
相关的答案:在填充比特的存在(1, 2, 3),在没有明确的C++规范(4).
C++中填充位的定义14 - 第3.9.1节 - 基本类型:
对于窄字符类型,对象表示的所有位都参与值表示.对于无符号窄字符类型,值表示的所有可能位模式表示数字.这些要求不适用于其他类型.
C++中对象表示和值表示的定义14 - §3.9 - 类型:
类型对象的对象表示是由类型对象占据
T的N个unsigned char对象的序列T,其中N等于sizeof(T).对象的值表示是保存type值的位集T.对于简单的可复制类型,值表示是对象表示中的一组位,用于确定值,该值是实现定义的值集的一个离散元素.44脚注44)意图是C++的内存模型与ISO/IEC 9899编程语言C的内存模型兼容.
C++中按位AND的定义14 - §5.11 - 按位AND运算符:
执行通常的算术转换; 结果是操作数的按位AND功能.运算符仅适用于整数或无范围的枚举操作数.
C++中添加的定义14 …
c++ bitwise-operators unsigned-integer unspecified-behavior c++14
我正在讨论使用具有不确定值的变量导致未指定的行为,而不是未定义的行为,如此处所述。这假设具有自动存储持续时间的变量已获取其地址并且陷阱表示不适用。
在具体情况下,讨论了ptr之后发生的情况free(ptr),在这种情况下 C17 6.2.4 适用:
当指针指向(或刚刚过去)的对象到达其生命周期结束时,指针的值变得不确定。
我做了这个例子:
#include <stdlib.h>
#include <stdio.h>
int main (void)
{
int* ptr = malloc(sizeof *ptr);
int* garbage;
int*volatile* dummy = &garbage; // take the address
free(ptr);
puts("This should always print");
fflush(stdout);
if(ptr == garbage)
{
puts("Didn't see that one coming.");
}
else
{
puts("I expect this to happen");
}
puts("This should always print");
}
Run Code Online (Sandbox Code Playgroud)
我提出的论点是,从理论上讲,我们无法知道是ptr == garbage真是假,因为此时它们都是不确定的。因此编译器甚至不需要读取这些内存位置 - 因为它可以推断两个指针都保存不确定的值,所以在优化期间可以根据需要自由地将表达式评估为 true 或 false。(实际上大多数编译器可能不会这样做。)
我在 x86_64 编译器 …