我已经实现了一个循环缓冲区,我想要一个简洁的方法来更新缓冲区指针,同时正确处理环绕.
假设一个大小为10的数组,我的第一个响应是:
size_t ptr = 0;
// do some work...
p = ++p % 10;
Run Code Online (Sandbox Code Playgroud)
静态分析,以及gcc -Wall -Wextra,由于序列点违规而正确地拍了我的手腕以查找未指定的行为.明显的修复方法如下:
p++;
p %= 10;
Run Code Online (Sandbox Code Playgroud)
然而,我正在寻找更简洁的东西(即一个单行)来"封装"这个操作.建议?除了p ++之外; p%= 10; :-)
我是 C 初学者。当我尝试运行以下代码时:
#include <stdio.h>
int main(void) {
int a = 3, b;
b = printf("%d %d", a, a++);
a = printf(" %d", b);
printf(" %d", a);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它向我展示:
error: operation on 'a' may be undefined [-Werror=sequence-point]
b = printf("%d %d", a, a++);
^
Run Code Online (Sandbox Code Playgroud)
但在这里我只改变了一次的值。那为什么会出现序列点错误呢?
我正在使用 -Wall -Werror 标志。
根据序列点定义,序列点是" 执行序列中称为序列点的指定点,以前的评估的所有副作用都保证完整 "
因此,在下面的程序中,++操作符的所有副作用必须在进入&&操作符的第二部分之前执行,即,i应该像&&序列点一样递增到1 .
#include<stdio.h>
int main()
{
int i=0,a;
a=i++&&1;
printf("%d",a);
getchar();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
预期产量:
1(
1&&1=1)
实际产量:
0
为什么i第二部分之前不增加?
使用三元运算符也可以提供相同的输出:
#include<stdio.h>
int main()
{
int i=0,a;
a=(i++)?1:0;
printf("%d",a);
getchar();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
三元运算符也是序列点.那么这不应该给出输出1而不是0吗?
正如我所了解的那样,条件运算符(三元运算符“?”)保证了其操作数的求值顺序,我想知道是否向变量分配了?在两个表达式之一中使用该变量的返回值。是否成为UB。这是我所拥有的:
我编写了这个程序,尝试根据字符串是否str包含有效的数字字符将字符串转换为整数,例如:+-.0123456789,因此我在一个表达式中使用了std::stoiwith std::string::find_first_of和conditional运算符:
std::string str = "a^%^&fggh67%$hf#$";
std::size_t pos = 0;
auto val = (((pos = str.find_first_of("0123456789.+-")) != std::string::npos) ?
std::stoi(str.substr(pos)) : -1);
std::cout << val << std::endl; // 67
str = "a^%^&fggh__#$!%$hf#$";
pos = 0;
val = (((pos = str.find_first_of("0123456789.+-")) != std::string::npos) ?
std::stoi(str.substr(pos)) : -1);
std::cout << val << std::endl; // -1
Run Code Online (Sandbox Code Playgroud)
正如你所看到的一段代码看起来做工精细,我知道,如果值-1是在无意中发现str,我们不知道是否val拥有-1成功运作或失败(?运营商)的。但是我只想知道我编写的这段代码是否具有UB?
正如在这个godbolt链接上看到的
c++14 模式下的 clang(但不是 c++17)和 c++17 模式下的 GCC 会产生关于排序的警告。我假设在 C++17 中,= 的 rhs 上的所有内容都在 lhs 之前进行评估,所以我不确定 gcc 警告是否正确。
Code is:
static int index =0;
void f(int* pindex){
pindex[index] = 5;
pindex[index] = index++;
}
int main(){
}
Run Code Online (Sandbox Code Playgroud)
gcc警告是:
:在函数“void f(int*)”中::4:30: 警告:对“索引”的操作可能未定义 [-Wsequence-point]Run Code Online (Sandbox Code Playgroud) :4:30: 警告:对“索引”的操作可能未定义 [-Wsequence-point]4 | pindex[index] = index++; | ~~~~~^~编译器返回:0
注意:我知道标准没有指定警告,指定问题wrt警告比谈论序列点/排序保证要容易得多。
#include<stdio.h>
int main()
{
int i=7,j;
j=(i++,++i,j*i);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
j =(i ++,++ i,j*i);这个定义得很好吗?让我清楚我的怀疑.
想象一下,我们有以下代码:
int i = 1;
int j = i++ + ++i;
Run Code Online (Sandbox Code Playgroud)
我知道这是一个未定义的行为,因为在分号之前,它是一个序列点,的值i已经改变了不止一次。这意味着即使运算符 plus 的优先级是从左到右,编译器也可能有两种可能性:
情况1)
i++--- 的值为i1++i--- 的值为i2j并执行副作用i++(此步骤的顺序也未定义,但我们不在乎,因为它不会改变结果)情况 2)
i++--- 的值为i1i++---的副作用i是 2++i---当前值为i3j如果这里没有问题,我有一个问题:
int j = ++i + i++;
上面的代码仍然是未定义的行为吗?
在我看来,只有一种可能:
++i---的副作用i是 2i++--- 的值为i2j并执行副作用 …关于C中序列点的维基百科条目具有以下序列点:
与输入/输出格式说明符关联的每次转换后.例如,在表达式printf("foo%n%d",&a,42)中,在评估%n之后和打印之前有一个序列点42
但C标准也说:
函数指示符的评估顺序,实际参数和实际参数中的子表达式是未指定的,但在实际调用之前有一个序列点.
对于像这样的代码,这两点似乎是矛盾的
int i=1;
printf("%d, %d and %d\n", i++, i++, i--);
Run Code Online (Sandbox Code Playgroud)
根据每个格式说明符后的维基百科条目,有一个序列点,所以它将打印如下:
1,2,3
但根据C标准中未指明的beaviour条目,它可以打印任何东西.
c stdio operator-precedence undefined-behavior sequence-points
我知道如下的语句(逗号代替分号)看起来很奇怪:
if(a<b)printf("Hello\n"),a+=5,b/=5,printf("%d,%d",a,b);
Run Code Online (Sandbox Code Playgroud)
但它完全正常,我读过它是因为comma这里作为一个序列点.我可以理解这一点.但我只是不明白为什么以下失败然后我也使用了一个else:
if(a<b)printf("Hi\n"),else printf("Bye\n"),a+=5,b/=5,printf("%d,%d",a,b);
Run Code Online (Sandbox Code Playgroud)
它给出了错误expected expression before 'else'.
为什么第二个语句会出错?在第一个语句中,我们看到它comma作为一个序列点.那么为什么它之前没有这样做else?第二个导致错误的情况有什么特别之处?这是我的完整程序:
#include<stdio.h>
int main(void)
{
int a=30,b=45;
//if(a<b)printf("Hello\n"),a+=5,b/=5,printf("%d,%d",a,b); //Works well
if(a<b)printf("Hi\n"),else printf("Bye\n"),a+=5,b/=5,printf("%d,%d",a,b);
}
Run Code Online (Sandbox Code Playgroud) signed char ch=5;
while(ch = ch--)
printf("%d",ch);
Run Code Online (Sandbox Code Playgroud)
我看了这个.清楚地说明了声明和声明(;)的结尾是序列点.
所以我不明白为什么上面的那个运行无限时间并打印相同的值[5].
sequence-points ×10
c ×7
c++ ×3
c++17 ×1
c99 ×1
comma ×1
if-statement ×1
side-effects ×1
stdio ×1