当我运行这个玩具程序时,
#include<stdio.h>
int main(void)
{
int arr[] = {11, 22, 33};
int *ptr = arr;
printf("ptr at: %p\n", (void *)ptr);
printf("Result of expression: %d\n", *ptr++); // line 8
printf("ptr at: %p\n", (void *)ptr);
}
我得到的输出是:
ptr at: 0x7fffffffdbf0
Result of expression: 11
ptr at: 0x7fffffffdbf4
我对line 8
上发生的事情的理解是,根据优先规则(后增量++
的优先级高于取消引用*
),表达式*ptr++
是等效的到*(ptr++)
。我Here是一个很好的解释。但是,在那个解释中没有提到序列点。
在混合中投掷序列点,我假设打印11
,因为ptr
仅在序列点之后递增(在所有参数之后 达到了printf
已被评估)。并且,后增量运算符实际上是在序列点之后完成它(增加和写入)的工作。我的理解是否正确?
答案 0 :(得分:6)
我假设打印11是因为ptr仅在序列点之后递增(恰好在printf的所有参数之后进行评估)
不。这与序列点无关。后增量表达式递增其参数,但表达式的值是增量之前的参数的值。
对于int*
,后增量看起来很像这个函数:
int* postInc(int** p)
{
int* tmp = *p;
*p = *p + 1;
return tmp;
}
*p++
看起来像这样:
*postInc(&p);
答案 1 :(得分:5)
我对第8行发生的事情的理解是,根据优先规则(后增量++的优先级高于取消引用*),表达式* ptr ++相当于*(ptr ++)
这是正确的。
在混合中投掷序列点......
这与序列点本身没有任何关系,而是与postfix ++的行为有关,指定为(6.5.2.4):
postfix ++运算符的结果是操作数的值。作为副作用, 操作数对象的值递增 / - /
结果的值计算在侧面之前排序 更新操作数存储值的效果。
简单地说,这意味着表达式ptr++
将首先“返回”ptr
的值,该值将用作表达式的结果,然后递增ptr
由1。
对于整个表达式printf("Result of expression: %d\n", *ptr++);
,在评估所有函数参数之后但在调用函数之前有一个序列点。再加上一些。
程序流程如下:
"Result of expression: %d\n"
和*ptr++
。这可以按任何顺序完成。对于子表达式*ptr++
,请计算其子表达式。运算符优先级指示ptr++
生成一个子表达式。因此,将此表达式计算为ptr
的值并存储结果。
a)使用存储结果作为操作数评估*
运算符。存储评估结果,传递给函数
b)将ptr
增加1.
3a)和3b)可以按任何顺序相互排序。
;
的序列点。如您所见,序列点与*ptr++
表达式的评估大多无关。序列点发挥作用的唯一时间是C指示++必须在它之前发生。但++可以发生在2)和5)之间的任何地方。
答案 2 :(得分:1)
否。使用值11是因为表达式$().ready(function() {
// validate signup form on keyup and submit
$.validator.addMethod("custom_number", function(value, element) {
return this.optional(element) || value === "NA" ||
value.match(/^[0-9,\-]+$/);
}, "Please enter a valid number, or 'NA'");
$("#getForm").validate({
rules: {
name: "required",
company: "required",
email: {required: true, email: true},
number: {required: true, number: true,custom_number: true},
textarea: "required",
partners: "required"
},
messages: {
name: "Please enter name",
company: "Please enter your company name",
email: "Please enter a valid email address",
number: "Please enter a valid phone number",
textarea: "Please enter your requirements",
partners: "Partners can't be blank"
}
});
的值在递增之前是ptr++
的值。完全停止。这里没有序列点!
序列点确实在函数调用中输入函数之前发生,序列点的相关性是在输入函数之前必须发生ptr的增量。
以下是显示正在发生的代码:
ptr
典型输出:
#include <stdio.h>
int arr[] = {11, 22, 33};
int *ptr = arr;
int indirect(const char *fmt,int val){
printf("peek: %p (%d)\n",ptr,*ptr);
return printf(fmt,val);
}
int main(void)
{
printf("ptr at: %p\n", (void *)ptr);
indirect("Result of expression: %d\n", *ptr++); // line 8
printf("ptr at: %p\n", (void *)ptr);
}
有关序列点的规则告诉您第二个必须显示ptr at: 0x2ac98105b030
peek: 0x2ac98105b034 (22)
Result of expression: 11
ptr at: 0x2ac98105b034
递增,并且最后必须有ptr
。
如果我们在最后一行看到(22)
但peek: 0x2ac98105b030 (11)
,则会违反函数调用序列点规则。
这意味着在输入ptr at: 0x2ac98105b034
后发生副作用(即ptr
的增量)。
优先顺序定义评估顺序,但序列点指定必须发生副作用的点。
理解它们的一个好方法是将评估和副作用的问题分开。通过评估表达式并记下所有副作用,然后查看序列点规则,告诉您它们何时必须发生。
如果你这样做(第8行的关键步骤):
indirect()
)。int
值的值。ptr
。 步骤4是一个序列点,因此我们必须确保第4步发生在4之前。 但它可能发生在3之前。
很容易在C中混淆,因为增量前和后增量运算符在定义中都有序列化。
将p ++视为“取p值和副作用增量p”。 将++ p视为“将p + 1的值和副作用增量p”而不是视为“增量p并取其值”。
printf()
的第二个措辞意味着标准不保证的顺序,并且可能发生的顺序绝对不能保证。