刚刚在这里学到,-Wsequence-point当代码可以调用UB时,comiplation标志会弹出警告.我在类似的声明上尝试过
int x = 1;
int y = x+ ++x;
Run Code Online (Sandbox Code Playgroud)
它工作得非常好.到目前为止,我已编译gcc或g++仅使用-ansi -pedantic -Wall.你有没有其他有用的标志来使代码更安全和健壮?
结构成员初始化表达式之间是否有一个序列点?
例如,是否明确定义下面的代码将始终打印"a,b"?
#include <stdio.h>
typedef struct {
char *bytes;
int position;
int length;
} Stream;
typedef struct {
char a;
char b;
} Pair;
char streamgetc(Stream *stream) {
return (stream->position < stream->length) ? stream->bytes[stream->position++] : 0;
}
int main(void) {
Stream stream = {.bytes = "abc", .position = 0, .length = 3};
Pair pair = {.a = streamgetc(&stream), .b = streamgetc(&stream)};
printf("%c, %c\n", pair.a, pair.b);
return 0;
}
Run Code Online (Sandbox Code Playgroud) 我刚读了这篇关于未定义行为和序列点的SO C++ FAQ,并进行了一些实验.在下面的代码中gcc-4.5.2,只在代码注释中提到的行中给出了警告,尽管之前的一行也显示了未定义的行为,不是吗?您不能说首先执行哪个加法操作数(因为+没有序列点).为什么gcc也没有在这一行给我一个警告?
int i=0;
int j=0;
int foo(void) {
i=1;
return i;
}
int main(void) {
i = i + foo();
j = j + (j=1); //Here is a rightly warning
return 0;
}
Run Code Online (Sandbox Code Playgroud)
谢谢你的帮忙.
可能重复:未
测序的值计算(也称为序列点)
未定义的行为和序列点
运算符优先级与评估顺序
我仍然试图围绕以下表达式如何导致未定义的行为:
a = a++;
Run Code Online (Sandbox Code Playgroud)
在搜索SO时,我发现了以下问题:
我仔细阅读了所有答案,但我仍然对细节有困难.其中一个答案描述了我的上述代码示例的行为在a修改方面是不明确的.例如,它可以归结为以下任何一种:
a=(a+1);a++;
a++;a=a;
Run Code Online (Sandbox Code Playgroud)
究竟什么使a修改变得模棱两可?这是否与不同平台上的CPU指令有关,以及优化器如何利用未定义的行为?换句话说,由于生成的汇编程序,它似乎未定义?
我没有看到编译器使用的原因a=(a+1);a++;,它只是看起来古怪而且没有多大意义.什么会让编译器使它以这种方式运行?
编辑:
为了清楚起见,我确实理解正在发生的事情,我只是不明白当有关于运算符优先级的规则(它基本上定义了表达式的求值顺序)时它是如何被定义的.在这种情况下,赋值最后发生,因此a++需要首先进行评估,以确定要分配的值a.所以我期望的是a,在修复后增量期间首先修改,但随后产生一个值以分配回a(第二次修改).但运算符优先级的规则似乎使我的行为非常清楚,我没有找到任何"摆动空间",因为它有未定义的行为.
这是另一个序列点问题,但是一个相当简单的问题:
#include <stdio.h>
void f(int p, int) {
printf("p: %d\n", p);
}
int g(int* p) {
*p = 42;
return 0;
}
int main() {
int p = 0;
f(p, g(&p));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是未定义的行为吗?或者调用g(&p)充当序列点?
标题有点模糊,因为我真的不知道如何定义这个问题.
它与以下代码有关:
for (match = root,
m_matchBase = match->requestedBase,
m_matchLength = match->length;
match != NULL;
match = match->next,
m_matchBase = match->requestedBase,
m_matchLength = match->length)
{
if (m_matchBase <= m_base && m_matchBase + m_matchLength > m_base)
break;
// other stuff...
}
Run Code Online (Sandbox Code Playgroud)
for循环中的语句是否保证按顺序运行?
例如,m_matchBase = match->requestedBase保证运行之后match = match->next?
我知道以下是未定义的,因为我试图在同一个表达式中读取和写入变量的值,即
int a=5;
a=a++;
Run Code Online (Sandbox Code Playgroud)
但如果是这样,那么为什么以下代码片段未定义
int a=5;
a=a+1;
Run Code Online (Sandbox Code Playgroud)
在这里我也试图修改它的值a并同时写入它.
还解释了为什么标准没有解决这个问题或者删除这个未定义的行为,尽管事实上他们知道它是未定义的?
我知道这是未定义的行为:
int i = 0;
int a[4];
a[i] = i++; //<--- UB here
Run Code Online (Sandbox Code Playgroud)
因为i左手侧和右手侧的评估顺序是不确定的(这;是唯一的序列点).
把这个推理更进一步,在我看来,这将是 未定义 未指明的行为:
int i = 0;
int foo(){
return i++;
}
int main(){
int a[4];
a[i] = foo();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
尽管在=我理解的情况下,在右侧有一些序列点仍然存在未定义未指定是否f()或a[i]首先评估.
我的假设是否正确?当我在作业的左侧使用全局或静态变量时,我是否必须小心谨慎,右手在任何情况下都不会修改它?
Pre-C++ 11我们知道运营商需要短路和评估顺序,&&因为:
1.9.18
在评估以下表达式时
Run Code Online (Sandbox Code Playgroud)a && b a || b a ? b : c a , b使用这些表达式中运算符的内置含义,在评估第一个表达式(12)之后有一个序列点.
但是C++ 11中不再存在序列点,因此标准部分在哪里说:
if (ptr && ptr->do_something())
{
}
Run Code Online (Sandbox Code Playgroud)
是安全的?
在这篇文章中,OP包含有很多错误的代码,但是1行让我特别好奇,因为我无法查看任何东西,不允许它.这是具体的一行:
int n = 100000, arr[n];
Run Code Online (Sandbox Code Playgroud)
是否确保了声明和初始化的顺序?
所以在这里我会假设它甚至可能发生n在arr获得声明时没有被初始化,看起来很不好.
但是我无法在iso/iec 9899草案中找到任何关于此的陈述,既没有说明未定义也没有定义它.
这是因为我假设未定义的行为?或者是吗?
无论哪种方式,该结果适用的规则是什么?5
编辑:
这对C99也有效吗?