我在一个非常大的应用程序中发现了这个问题,从中做了一个SSCCE.我不知道代码是否有未定义的行为或-O2打破它.
用gcc a.c -o a.exe -O2 -Wall -Wextra -Werror它编译时打印5.
但是在编译时没有(例如)或取消注释2条注释行之一(防止内联)时打印25.-O2-O1
#include <stdio.h>
#include <stdlib.h>
// __attribute__((noinline))
int f(int* todos, int input) {
int* cur = todos-1; // fixes the ++ at the beginning of the loop
int result = input;
while(1) {
cur++;
int ch = *cur;
// printf("(%i)\n", ch);
switch(ch) {
case 0:;
goto end;
case 1:;
result = result*result;
break;
}
}
end:
return result;
}
int main() …Run Code Online (Sandbox Code Playgroud) 我最近写了一个简单的程序来反转一个字符串,我的程序只是接受来自用户的输入字符串然后反转它.这一切都是用2个指针完成的.关于程序中的指针安全性,我编写了一个复制给定字符串的函数,该函数为新的(相同长度)字符串分配内存,然后逐个复制字符.
我的问题是当我运行这个程序时,虽然它做了我需要的东西,它打印出一些神秘的额外输出.在接受用户的输入之前,它每次都这样做.这是我运行程序时发生的情况.
C:\Users\0xEDD1E\Desktop\revstr>revstr.exe
[C]
[.]
[revstr.exe]
hello
[hello]
olleh
Run Code Online (Sandbox Code Playgroud)
这里最后三行是输入和输出,没关系,问题出在前3行
[C]
[.]
[revstr]
Run Code Online (Sandbox Code Playgroud)
那些是什么?无论如何,这是我的计划
#include <stdio.h>
#include <stdlib.h>
#define swap(a, b) (((a) ^ (b)) && ((a) ^= (b), (b) ^= (a), (a) ^= (b)))
unsigned long strlen_(char *);
char *strdup(char *s);
char *reverseString(char *, int);
int main(void)
{
//fflush(stdout);
char *str = (char *) malloc(1024 * sizeof (char));
scanf("%[^\n]s", str);
int slen = strlen_(str);
printf("%s\n", reverseString(str, slen));
return 0;
}
unsigned long strlen_(char *s)
{
char *p = s;
while …Run Code Online (Sandbox Code Playgroud) 根据该主题,允许将指针与数组对象的最后一个元素之一进行比较.
根据@jalf注释,禁止在数组对象的第一个元素之前将指针与一个进行比较.
例1
int array[10];
int *ptr;
for(ptr=&array[9]; ptr>(array-1); ptr--) {...}
Run Code Online (Sandbox Code Playgroud)
例题
int array[10];
int *ptr;
for(ptr=&array[9]; ptr>=(array); ptr--) {...}
Run Code Online (Sandbox Code Playgroud)
1)是否禁止example1和example2?
2)C标准是否有证据表明禁止在数组对象的第一个元素之前比较指针?
在寻找关于以下内容的相关或重复问题后无济于事(我只能用边际正义来描述用C标记的指针算术和后减法问题的绝对数量,但足以说"船载"做了一个坟墓对结果集的不公平)我把它扔在戒指中,希望澄清或转介给我的副本.
如果将后递减运算符应用于如下所示的指针(数组序列的简单反向迭代),以下代码是否会调用未定义的行为?
#include <stdio.h>
#include <string.h>
int main()
{
char s[] = "some string";
const char *t = s + strlen(s);
while(t-->s)
fputc(*t, stdout);
fputc('\n', stdout);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
最近向我提出6.5.6.p8 Additive运算符,结合6.5.2.p4,Postfix递增和递减运算符,指定甚至在它已经包含调用未定义行为的基地址时执行后递减,无论是否评估(不是表达式结果)的结果值.我只是想知道是否确实如此.tstt--
标准的引用部分是:
6.5.6加法运算符
- 如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出; 否则,行为未定义.
和...几乎紧密耦合的关系......
6.5.2.4后缀增量和减量运算符约束
- 后缀增量或减量运算符的操作数应具有原子,限定或非限定的实数或指针类型,并且应为可修改的左值.
语义
postfix ++运算符的结果是操作数的值.作为副作用,操作数对象的值递增(即,将相应类型的值1添加到其中).有关约束,类型和转换以及操作对指针的影响的信息,请参阅加法运算符和复合赋值的讨论.在更新操作数的存储值的副作用之前,对结果的值计算进行排序.对于不确定顺序的函数调用,后缀++的操作是单个评估.具有原子类型的对象上的Postfix ++是具有memory_order_seq_cst内存顺序语义的读 - 修改 - 写操作.98)
所述后缀-操作者是类似于后缀++操作,不同的是操作数的值被递减(即,相应的类型的值1被从中减去).
前向参考:加法运算符(6.5.6),复合赋值(6.5.16.2).
在发布的示例中使用post-decrement运算符的原因是为了避免针对数组的基址评估最终无效的地址值.例如,上面的代码是以下的重构:
#include <stdio.h>
#include <string.h>
int main()
{
char s[] = "some string";
size_t len = strlen(s);
char *t = …Run Code Online (Sandbox Code Playgroud)