天道酬勤,学无止境

Evaluation in return statement

问题
//prog1.c    
#include <stdio.h>
    int f(int *a,int *b,int c) {
      if(c == 0) return 1;
      else {
        *a = *a + 1;
        *b = *b - 1;
         c =  c - 1;
         return (*a + f(a,b,c) + *b);
      }
    }
    int main() {
      int a = 3,b = 3,c = 3;
      printf("%d\n",f(&a,&b,c));
      return 0;
    }

我使用gccclang-3.5执行了程序,发现 output = 16

我认为可能有一些特定于实现的行为,例如以下代码

//prog2.c
#include <stdio.h>
int f(int *x,int *y,int *z) {
  *x = *x + 1;
  *y = *y + 1;
  *z = *z + 1;
  return 0;
}
int main() {
  int a=0,b=0,c=0;
  printf("%d %d %d\n",a,f(&a,&b,&c),b);;
  return 0;
}
// gcc output : 1 0 0
// clang-3.5 :  0 0 1

prog1.c中, return语句中是否有任何特定于实现的行为? 如果不是,它是如何评估的?

我可能不知道某种undefined behaviour或者unspecified behaviour 。 请解释。 谢谢

回答1

正如评论和几乎重复的问题中所指出的(这是 C 中未定义的行为吗?如果不是,请从逻辑上预测输出。),这两个程序的结果都没有完全由 C 标准定义——它们会产生“未指定的行为”,因为第一个的return语句和第二个调用的printf()中术语的评估顺序不是由语言指定的,而是由编译器决定的。 (请注意,它是“未指定的行为”而不是正式的“未定义的行为”——参见评论中的讨论。它也不是“实现定义的”行为;实现不需要记录它的作用。)

这意味着就问题而言,任何实现给出的结果都是“特定于实现的”。 不同的实现可能会合理地产生不同的答案。

第一个程序是:

#include <stdio.h>

int f(int *a,int *b,int c) {
  if(c == 0) return 1;
  else {
    *a = *a + 1;
    *b = *b - 1;
     c =  c - 1;
     return (*a + f(a,b,c) + *b);
  }
}

int main() {
  int a = 3,b = 3,c = 3;
  printf("%d\n",f(&a,&b,c));
  return 0;
}

有问题的部分是return (*a + f(a,b,c) + *b); 因为*a可以在递归函数调用之前或之后进行评估,并且f()修改了ab指向的值,因此评估的顺序很重要。 不同的编译器可以合法地产生不同的结果。 同一个编译器可以在不同的时间,或者在不同的优化标志下,或者根据它的选择产生不同的结果。 *a*b都可以在调用之前进行评估,也可以在调用之后进行评估,或者其中一个可以在之前评估,另一个在之后评估——这只是列出了 4 个可能的替代方案。

第二个程序是:

#include <stdio.h>
int f(int *x,int *y,int *z) {
  *x = *x + 1;
  *y = *y + 1;
  *z = *z + 1;
  return 0;
}
int main() {
  int a=0,b=0,c=0;
  printf("%d %d %d\n",a,f(&a,&b,&c),b);;
  return 0;
}

问题是标准没有指定为调用printf()评估af(&a, &b, &c)b的顺序,并且根据编译器选择的顺序,您会得到不同的结果。 你展示了 GCC 和 Clang 产生不同的结果——根据标准,这些结果都是可以接受的,其他很多结果也是如此。

回答2

在 prog1.c 中,return 语句中是否有任何特定于实现的行为? 如果不是,它是如何评估的?

return语句没有任何问题,除了如果您最初使用cf的调用是否定的,则递归调用将是无止境的。

您的函数f的目的尚不清楚 - 但终止条件应该更好地写成:

if(c <= 0) return 1;

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • Python-“ if”语句中的逻辑求值顺序(Python - logical evaluation order in “if” statement)
    问题 在Python中,我们可以这样做: if True or blah: print("it's ok") # will be executed if blah or True: # will raise a NameError print("it's not ok") class Blah: pass blah = Blah() if blah or blah.notexist: print("it's ok") # also will be executed 有人可以指出我有关此功能的文档吗? 它是语言的实现细节或功能吗? 利用此功能是否是良好的编码风格? 回答1 or和and短路,请参见布尔运算文档: 表达式x and y首先计算x ; 如果x为false,则返回其值;如果x为false,则返回其值。 否则,将评估y并返回结果值。 表达式x or y首先计算x ; 如果x为true,则返回其值;如果x为true,则返回其值。 否则,将评估y并返回结果值。 请注意,仅当x值为True时, y for and y进行求值。 相反,对于or ,仅当x评估值为False时才评估y 。 对于第一个表达式True or blah ,这意味着blah永远不会被求值,因为第一部分已经是True 。 此外,您的自定义Blah类被认为是True: 在布尔运算的上下文中
  • Evaluation in return statement
    //prog1.c #include <stdio.h> int f(int *a,int *b,int c) { if(c == 0) return 1; else { *a = *a + 1; *b = *b - 1; c = c - 1; return (*a + f(a,b,c) + *b); } } int main() { int a = 3,b = 3,c = 3; printf("%d\n",f(&a,&b,c)); return 0; } I executed the program using gcc and clang-3.5 and found output = 16. I think there might be some implementation specific behaviour like the follwoing code //prog2.c #include <stdio.h> int f(int *x,int *y,int *z) { *x = *x + 1; *y = *y + 1; *z = *z + 1; return 0; } int main() { int a=0,b=0,c=0; printf("%d %d %d\n",a,f(&a,&b,&c),b);; return 0; } // gcc output : 1 0 0
  • Lazy evaluation of Oracle PL/SQL statements in SELECT clauses of SQL queries
    I have a performance problem with an Oracle select statement that I use in a cursor. In the statement one of the terms in the SELECT clause is expensive to evaluate (it's a PL/SQL procedure call, which accesses the database quite heavily). The WHERE clause and ORDER BY clauses are straightforward, however. I expected that Oracle would first perform the WHERE clause to identify the set of records that match the query, then perform the ORDER BY clause to order them, and finally evaluate each of the terms in the SELECT clause. As I'm using this statement in a cursor from which I then pull results
  • Operator Precedence vs Order of Evaluation
    The terms 'operator precedence' and 'order of evaluation' are very commonly used terms in programming and extremely important for a programmer to know. And, as far as I understand them, the two concepts are tightly bound; one cannot do without the other when talking about expressions. Let us take a simple example: int a=1; // Line 1 a = a++ + ++a; // Line 2 printf("%d",a); // Line 3 Now, it is evident that Line 2 leads to Undefined Behavior, since Sequence points in C and C++ include: Between evaluation of the left and right operands of the && (logical AND), || (logical OR), and comma
  • SQL Server中的所有评估与任何评估(ALL vs ANY evaluation in SQL Server)
    问题 我现在正在尝试以下查询: SELECT DISTINCT code, CASE WHEN id = ANY (SELECT DISTINCT u.id FROM unit u LEFT JOIN unit_const uc ON u.id = uc.hid WHERE u.property = 502 AND type = 'Acq') THEN 1 ELSE 0 END AS Case_Eval, (SELECT DISTINCT u.id FROM unit u LEFT JOIN unit_const uc ON u.id = uc.hid WHERE u.property = 502 AND type = 'Acq') AS Evaluation FROM unit WHERE property = 502 正确给出以下结果: +---------------------------------------+ | Code Case_Eval Evaluation | +---------------------------------------+ | TP2_U1 0 NULL | | TP2_U2 0 NULL | | TP2_U3 0 NULL | | TP2_U4 0 NULL | +-------------------------------------
  • std::cout 语句评估顺序 [重复](std::cout statements evaluation order [duplicate])
    问题 这个问题在这里已经有了答案: cout << 调用它打印的函数的顺序? (3 个回答) 6年前关闭。 pop() 函数有什么问题,为什么它不能正常工作? class stack{ int *p, *Cursor; int size ; public: stack(int sz) {Cursor = p = new int[size=sz+1];} //consider the stack empty when its size is 1 ~stack() {delete[] p;} //Cursor and P will be destroyed when the program finishes void push(int x) {Cursor+=1; *Cursor=x; size++;} int pop() {if(Cursor == p) return -1; int temp = *Cursor; Cursor--; size--; return (temp);} bool isEmpty(){return(Cursor == p);} bool isFull(){return(Cursor == p+size);} }; 这是我的测试: stack A(3); std::cout<<"Empty: "<<A.isEmpty()<<std::endl; std
  • if then else conditional evaluation
    I have a language which basically is meant to map columns to a new structure in an array. The language is meant for product managers to define mappings without having to know a lot of programming details. I'm sure there is a lot more to improve here but this is what I have. The language works, mostly. The problem I have is with conditional statements. My parser has the following rule: conditionalexpr : IF^ LPAREN! (statement) RPAREN! THEN! LCURLY! statement RCURLY! (ELSE! LCURLY! statement RCURLY!)?; Which works to generate a tree with three children. My problem is to avoid evaluating the
  • Python布尔评估顺序(Python boolean evaluation order)
    问题 我正在使用 Python 中的链接列表,但无法弄清楚它发出的错误语句。 这是我从列表头部开始递增节点的代码: while current.next_node is not None and value > current.next_node.data: current = current.next_node current.next_node = Node(value, current.next_node) 虽然上述工作,这不会: while value > current.next_node.data and current.next_node is not None: current = current.next_node current.next_node = Node(value, current.next_node) 我认为只要 while 语句评估为真或假,它就会相应地表现。 相反,当它尝试单独运行value > current.next_node.data并意识到 current.next_node 不存在时,它会抛出错误。 为什么是这样? 回答1 Python 会进行短路评估,这就是为什么您会看到自己的行为。 这类似地在and和or子句中发挥作用。 使用and子句,如果左侧的表达式计算结果为False ,则整个语句无法计算为True (False
  • 为什么 printf 不在这里打印?(why printf is not printing here?)
    问题 字符} 现在在这个例子中我使用了多个 printf's 和现在。, /* As far as i was cocerned Precedence of && is more than ||, *and these logical operators check from left to right *So compiler should come to hello and print "hello" then "nice to see you" then "hie" *as all are true it should print "hola" *but i wonder, why here the output is only "hie" and "hola"? */ #include<stdio.h> main() { if(printf("hie")|| printf("hello")&& printf("nice to see you")) printf("\thola\n"); } 回答1 成功时printf()返回写入的字符总数。 因此printf("hie")返回 3,这足以用于逻辑“或”条件的惰性求值。 printf("hie")|| printf("hello") // --> 3 || whatever --> // true || whatever --
  • C order of evaluation of assignment statement
    I've been encountered on a case where cross-platform code was behaving differently on a basic assignment statement. One compiler evaluated the Lvalue first, Rvalue second and then the assignment. Another compiler did the Rvalue first, Lvalue second and then the assignment. This may have impact in case Lvalue influence the value of Rvalue as shown in the following case: struct MM { int m; } int helper (struct MM** ppmm ) { (*ppmm) = (struct MM *) malloc (sizeof (struct MM)); (*ppmm)->m = 1000; return 100; } int main() { struct MM mm = {500}; struct MM* pmm = &mm pmm->m = helper(&pmm); printf("
  • ALL vs ANY evaluation in SQL Server
    I'm just trying out now the below query: SELECT DISTINCT code, CASE WHEN id = ANY (SELECT DISTINCT u.id FROM unit u LEFT JOIN unit_const uc ON u.id = uc.hid WHERE u.property = 502 AND type = 'Acq') THEN 1 ELSE 0 END AS Case_Eval, (SELECT DISTINCT u.id FROM unit u LEFT JOIN unit_const uc ON u.id = uc.hid WHERE u.property = 502 AND type = 'Acq') AS Evaluation FROM unit WHERE property = 502 which correctly gives the below result: +---------------------------------------+ | Code Case_Eval Evaluation | +---------------------------------------+ | TP2_U1 0 NULL | | TP2_U2 0 NULL | | TP2_U3 0 NULL | |
  • Weird evaluation order in chained functions
    I have this code, which is used to build a graphic interface on a LCD display on a controller; the code is compiled for 2 different architectures using both AVR and PIC32: FishinoTftGuiLabel *l1; FishinoTftGui .Page(F("Page1")) .Label(50, 140, 0, 24, LabelAlign::Left, F("Slider value:")) .getElement(l1) -- .Label(l1->x() + l1->w() + 10, 140, 0, 24, LabelAlign::Left, F("pippo")) ; Each member function return the same object (or a related one); so for example the Label() function returns the FishinoTftGuiLabel reference, which can be used for chaining other calls. The getElement(T *&) is simply
  • C中带有++运算符的语句的短路评估(Short circuit evaluation of a statement with ++ operator in C)
    问题 我在 Windows 7 上的 Code::Blocks 10.05 中执行了以下代码。 int a=0,b=0,c; c=a++&&b++; printf("\na=%d\nb=%d\nc=%d\n\n",a,b,c); 我得到的输出如下, a=1 b=0 c=0 由于短路评估,这是完全合理的。 表达式a++是后增量, 0返回到逻辑和 ( && )。 因此,由于0 && 0和0 && 1计算结果都为0因此不会评估部分b++ 。 但这里出现了我的怀疑。 运算符的优先级值清楚地表明++比&&具有更高的优先级。 所以我的理解是这样的, a++和b++都被评估,然后&&只检查表达式a++的结果来做出决定。 但这并没有发生,只是在这里评估了a++ 。 这种行为的原因是什么? &&作为序列点是否与这种行为有关? 如果是这样,为什么我们说&&优先级低于++ ? 回答1 您对评估的优先级和顺序感到困惑。 优先级定义了操作符的分组方式,即 c = a++ && b++; 相当于: c = ((a++) && (b++)); 求值顺序定义了表达式的求值方式, &&的短路表示首先对a++求值,如果为零,则结束; 如果它不为零,则计算b++ 。 再举一个例子: c = (a++) + (b++); a++在b++之前评估吗? 答案是我们不知道。 大多数运算符没有定义求值顺序。 &
  • 即使参数是函数调用,C 是否也使用短路评估?(Does C use short circuit evaluation even when arguments are function calls?)
    问题 我知道逻辑运算符会进行短路检查。 也就是说,如果有像A && B && C这样的语句,那么如果A为假,则不评估B和C 但是在B和C是函数调用的情况下也是如此吗? 例如,这段代码中的 return 语句: bool areIdentical(struct node * root1, struct node *root2) { /* base cases */ if(root1 == NULL && root2 == NULL) return true; if(root1 == NULL || root2 == NULL) return false; /* Check if the data of both roots is same and data of left and right subtrees are also same */ return (root1->data == root2->data && //I am talking about this statement areIdentical(root1->left, root2->left) && areIdentical(root1->right, root2->right) ); } 回答1 是的,如果root1->data == root2->data为false则不会调用这些函数。 简单的检查是这样做:
  • C 赋值语句的求值顺序(C order of evaluation of assignment statement)
    问题 我遇到过跨平台代码在基本赋值语句中表现不同的情况。 一个编译器首先评估左值,然后是右值,然后是赋值。 另一个编译器先做右值,然后是左值,然后是赋值。 如果 Lvalue 影响 Rvalue 的值,这可能会产生影响,如下例所示: struct MM { int m; } int helper (struct MM** ppmm ) { (*ppmm) = (struct MM *) malloc (sizeof (struct MM)); (*ppmm)->m = 1000; return 100; } int main() { struct MM mm = {500}; struct MM* pmm = &mm pmm->m = helper(&pmm); printf(" %d %d " , mm.m , pmm->m); } 上面的例子中,行pmm->m = helper(&mm); ,取决于评估的顺序。 如果先计算 Lvalue,则 pmm->m 等效于 mm.m,如果先计算 Rvalue,则 pmm->m 等效于分配在堆上的 MM 实例。 我的问题是是否有一个 C 标准来确定评估的顺序(没有找到),或者每个编译器都可以选择做什么。 还有其他类似的陷阱我应该注意吗? 回答1 评估=表达式的语义包括 更新左操作数的存储值的副作用在左操作数和右操作数的值计算之后排序。
  • Order of evaluation of assignment statement in C++
    map<int, int> mp; printf("%d ", mp.size()); mp[10]=mp.size(); printf("%d\n", mp[10]); This code yields an answer that is not very intuitive: 0 1 I understand why it happens - the left side of the assignment returns reference to mp[10]'s underlying value and at the same time creates aforementioned value, and only then is the right side evaluated, using the newly computed size() of the map. Is this behaviour stated anywhere in C++ standard? Or is the order of evaluation undefined? Result was obtained using g++ 5.2.1.
  • Short circuit evaluation of a statement with ++ operator in C
    I have executed the following code in Code::Blocks 10.05 on Windows 7. int a=0,b=0,c; c=a++&&b++; printf("\na=%d\nb=%d\nc=%d\n\n",a,b,c); The output I obtained is given below, a=1 b=0 c=0 This makes perfect sense because of short circuit evaluation. The expression a++ is post increment and 0 is returned to the logical and (&&). Hence the part b++ is not evaluated since both 0 && 0 and 0 && 1 evaluates to 0. But here arises my doubt. The precedence value of operators clearly states that ++ is having higher precedence over &&. So my understanding was like this, both a++ and b++ are evaluated and
  • if elif 语句中的表达式求值(expression evaluation in if elif statements)
    问题
  • CASE 和 COALESCE 短路评估适用于 PL/SQL 中的序列,但不适用于 SQL(CASE and COALESCE short-circuit evaluation works with sequences in PL/SQL but not in SQL)
    问题 当在 SQL 中使用时, CASE和COALESCE()文档中描述的短路评估是否适用于序列? 这似乎不会发生。 关于 CASE 的 Oracle 文档指出: Oracle 数据库使用短路评估。 对于一个简单的CASE表达式...如果先前的 compare_expr 等于 expr,则 Oracle 永远不会评估 compare_expr。 对于搜索的 CASE 表达式,如果前一个条件为真,则数据库...从不评估条件。 同样对于COALESCE()文档指出: Oracle 数据库使用短路评估。 数据库评估每个 expr 值并确定它是否为 NULL,而不是在确定它们中的任何一个是否为 NULL 之前评估所有 expr 值。 从 SQL 调用序列时,情况似乎并非如此; 如您所见,没有发生短路并且序列增加。 SQL> create sequence tmp_test_seq start with 1 increment by 1; SQL> select tmp_test_seq.nextval from dual; NEXTVAL ---------- 1 SQL> select tmp_test_seq.currval from dual; CURRVAL ---------- 1 SQL> select coalesce(1, tmp_test_seq.nextval)
  • C ++中赋值语句的求值顺序(Order of evaluation of assignment statement in C++)
    问题 map<int, int> mp; printf("%d ", mp.size()); mp[10]=mp.size(); printf("%d\n", mp[10]); 这段代码给出的答案不是很直观: 0 1 我知道为什么会发生这种情况-赋值的左侧返回对mp[10]的基础值的引用,并同时创建上述值,然后才使用新计算的size()评估右侧。地图。 这种行为在C ++标准的任何地方都有说明吗? 还是评估顺序不确定? 使用g ++ 5.2.1获得结果。 回答1 是的,这是标准所涵盖的,并且是未指定的行为。 最近的C ++标准提案中涉及了这种特殊情况:N4228:完善惯用C ++的表达式评估顺序,该规则旨在完善评估规则的顺序,以使其在某些情况下得到很好的指定。 它描述此问题如下: 表达式评估顺序是C ++社区中经常讨论的话题。 简而言之,给定诸如f(a,b,c)的表达式,子表达式f,a,b,c的求值顺序未由标准指定。 如果这些子表达式中的任何两个碰巧在不插入序列点的情况下修改了同一对象,则该程序的行为是不确定的。 例如,表达式f(i ++,i)(其中i是整数变量)会导致未定义的行为, v [i] = i ++也是如此。 即使行为不是未定义的,评估表达式的结果仍然可以是任何人的猜测。 考虑以下程序片段: #include <map> int main() { std::map<int