计算算术数组下标表达式作为 C 中条件运算符的操作数的一部分
Evaluation of arithmetic array subscript expression as part of operand to the conditional-operator in C
大家好,为什么这个程序 return 2 而不是 3
当我们做这个算术时'a' <= (s[++i]) && (s[++i]) <= 'z' ?(s[++i]) - 'a' + 'A': (s[++i])
首先我们测试 s[++i] = 1
,第二个要测试的 s[++i]
应该是 2 并且这个测试失败并且最后一个发生 s[++i] == 3
,所以为什么编译器 return = 2?
感谢您的回答。
int main()
{
int i=0;
char s[10];
strcpy(s, "0123");
putchar(('a' <= (s[++i]) && (s[++i]) <= 'z' ?(s[++i]) - 'a' + 'A': (s[++i])));
printf("\n");
return 0;
}
&&
的右侧 && (s[++i]) <= 'z'
未计算,因为左侧已经为假('a' <= (s[++i])
解析为 'a' <= '1'
,即假)。
因此,仅评估 &&
的左侧以及 :
的右侧。
初始状态:
s = "0123"
i = 0
表达式的执行步骤:
'a' <= (s[++i]) && (s[++i]) <= 'z' ? (s[++i]) - 'a' + 'A' : (s[++i])
// execute ++i -> i = 1
'a' <= s[i] && (s[++i]) <= 'z' ? (s[++i]) - 'a' + 'A' : (s[++i])
'a' <= s[1] && (s[++i]) <= 'z' ? (s[++i]) - 'a' + 'A' : (s[++i])
'a' <= '1' && (s[++i]) <= 'z' ? (s[++i]) - 'a' + 'A' : (s[++i])
// we look at http://www.asciitable.com/ Note1
97 <= 49 && (s[++i]) <= 'z' ? (s[++i]) - 'a' + 'A' : (s[++i])
0 && (s[++i]) <= 'z' ? (s[++i]) - 'a' + 'A' : (s[++i]))
// because of short-circuiting in && operator we do not evaluate right side of &&
// Note `a && b ? c : d` is equal to `(a && b) ? c : d`
// Note `&&` introduces a sequence point
0 ? (s[++i]) - 'a' + 'A' : (s[++i])
// Note `?` introduces a sequence point
(s[++i])
s[++i]
// execute ++i -> i = 2
s[2]
'2'
注 1:C 标准没有说系统使用 ascii 编码,但当今使用的大多数平台都使用 ascii。
First we test s[++i] = 1 , second going to be tested s[++i] should be 2
不,因为 &&
是 short-circuit evaluated。如果 &&
的左边为 false 那么 &&
的右边将不会被执行。
首先让我们像这样拆分三元运算符
'a' <= (s[++i]) && (s[++i]) <= 'z' ?
(s[++i]) - 'a' + 'A':
(s[++i])
并评估第一个条件
'a' <= (s[++i]) && (s[++i]) <= 'z'
很好 'a'
<= ([s++i])
returns 错误
因为 'a'
即 97
大于
s[++i]
i
是 0
所以 ++i
returns 1
和
s[1]
是 '1'
即 49
所以 97 <= 49
是假的
因此,&&
停在那里,returns
0
(false) 这使得三元运算符
语句执行 else 条件
然后 returns s[++i]
记住 i
已经
当第一个条件是时增加一次
评估这意味着 s[++i]
是 s[2]
这
是 '2'
并且这是应该返回的值
我们来分析一下这个语句:
putchar(('a' <= (s[++i]) && (s[++i]) <= 'z' ?(s[++i]) - 'a' + 'A': (s[++i])));
我们可以先去掉多余的括号:
putchar('a' <= s[++i] && s[++i] <= 'z' ? s[++i] - 'a' + 'A' : s[++i]);
参数表达式是一个三元表达式。让我们将其转换为等效的 if
/ else
语句:
if ('a' <= s[++i] && s[++i] <= 'z')
putchar(s[++i] - 'a' + 'A');
else
putchar(s[++i]);
计算 &&
运算符的左侧部分:将 'a'
与 s[1]
进行比较,并递增 i
。在 ASCII 字符集中,'a'
大于 '1'
,因此此比较的计算结果为 0
,而 i
设置为 1
。
&&
的右侧部分 未被评估 因为左侧部分为假。
if
语句的 else
分支被评估: s[2]
传递给 putchar()
并且 i
递增并设置为 2
.
因此程序输出 2
并且 i
设置为 2
。
请注意,表达式的不同部分由 &&
、?
和 :
处的序列点分隔,并且有一个 ++
运算符递增 i
在每个部分中,因此表达式没有乍看之下的未定义行为。
该代码显示了多次计算其参数的宏会发生什么。例如,可以将 islower
和 toupper
定义为宏:
// These macros are incorrect and have multiple evaluation of their argument
// do not use these, they are only used to illustrate the problems
#define islower(c) 'a' <= (c) && (c) <= 'z'
#define toupper(c) (islower(c) ?(c) - 'a' + 'A': (c))
根据这些定义,putchar(toupper(s[++i]));
将扩展为:
putchar(('a' <= (s[++i]) && (s[++i]) <= 'z' ?(s[++i]) - 'a' + 'A': (s[++i])));
有多种副作用,不能正确测试 s[1]
也不能输出 s[1]
.
大家好,为什么这个程序 return 2 而不是 3
当我们做这个算术时'a' <= (s[++i]) && (s[++i]) <= 'z' ?(s[++i]) - 'a' + 'A': (s[++i])
首先我们测试 s[++i] = 1
,第二个要测试的 s[++i]
应该是 2 并且这个测试失败并且最后一个发生 s[++i] == 3
,所以为什么编译器 return = 2?
感谢您的回答。
int main()
{
int i=0;
char s[10];
strcpy(s, "0123");
putchar(('a' <= (s[++i]) && (s[++i]) <= 'z' ?(s[++i]) - 'a' + 'A': (s[++i])));
printf("\n");
return 0;
}
&&
的右侧 && (s[++i]) <= 'z'
未计算,因为左侧已经为假('a' <= (s[++i])
解析为 'a' <= '1'
,即假)。
因此,仅评估 &&
的左侧以及 :
的右侧。
初始状态:
s = "0123"
i = 0
表达式的执行步骤:
'a' <= (s[++i]) && (s[++i]) <= 'z' ? (s[++i]) - 'a' + 'A' : (s[++i])
// execute ++i -> i = 1
'a' <= s[i] && (s[++i]) <= 'z' ? (s[++i]) - 'a' + 'A' : (s[++i])
'a' <= s[1] && (s[++i]) <= 'z' ? (s[++i]) - 'a' + 'A' : (s[++i])
'a' <= '1' && (s[++i]) <= 'z' ? (s[++i]) - 'a' + 'A' : (s[++i])
// we look at http://www.asciitable.com/ Note1
97 <= 49 && (s[++i]) <= 'z' ? (s[++i]) - 'a' + 'A' : (s[++i])
0 && (s[++i]) <= 'z' ? (s[++i]) - 'a' + 'A' : (s[++i]))
// because of short-circuiting in && operator we do not evaluate right side of &&
// Note `a && b ? c : d` is equal to `(a && b) ? c : d`
// Note `&&` introduces a sequence point
0 ? (s[++i]) - 'a' + 'A' : (s[++i])
// Note `?` introduces a sequence point
(s[++i])
s[++i]
// execute ++i -> i = 2
s[2]
'2'
注 1:C 标准没有说系统使用 ascii 编码,但当今使用的大多数平台都使用 ascii。
First we test s[++i] = 1 , second going to be tested s[++i] should be 2
不,因为 &&
是 short-circuit evaluated。如果 &&
的左边为 false 那么 &&
的右边将不会被执行。
首先让我们像这样拆分三元运算符
'a' <= (s[++i]) && (s[++i]) <= 'z' ?
(s[++i]) - 'a' + 'A':
(s[++i])
并评估第一个条件
'a' <= (s[++i]) && (s[++i]) <= 'z'
很好 'a'
<= ([s++i])
returns 错误
因为 'a'
即 97
大于
s[++i]
i
是 0
所以 ++i
returns 1
和
s[1]
是 '1'
即 49
所以 97 <= 49
是假的
因此,&&
停在那里,returns
0
(false) 这使得三元运算符
语句执行 else 条件
然后 returns s[++i]
记住 i
已经
当第一个条件是时增加一次
评估这意味着 s[++i]
是 s[2]
这
是 '2'
并且这是应该返回的值
我们来分析一下这个语句:
putchar(('a' <= (s[++i]) && (s[++i]) <= 'z' ?(s[++i]) - 'a' + 'A': (s[++i])));
我们可以先去掉多余的括号:
putchar('a' <= s[++i] && s[++i] <= 'z' ? s[++i] - 'a' + 'A' : s[++i]);
参数表达式是一个三元表达式。让我们将其转换为等效的 if
/ else
语句:
if ('a' <= s[++i] && s[++i] <= 'z')
putchar(s[++i] - 'a' + 'A');
else
putchar(s[++i]);
计算 &&
运算符的左侧部分:将 'a'
与 s[1]
进行比较,并递增 i
。在 ASCII 字符集中,'a'
大于 '1'
,因此此比较的计算结果为 0
,而 i
设置为 1
。
&&
的右侧部分 未被评估 因为左侧部分为假。
if
语句的 else
分支被评估: s[2]
传递给 putchar()
并且 i
递增并设置为 2
.
因此程序输出 2
并且 i
设置为 2
。
请注意,表达式的不同部分由 &&
、?
和 :
处的序列点分隔,并且有一个 ++
运算符递增 i
在每个部分中,因此表达式没有乍看之下的未定义行为。
该代码显示了多次计算其参数的宏会发生什么。例如,可以将 islower
和 toupper
定义为宏:
// These macros are incorrect and have multiple evaluation of their argument
// do not use these, they are only used to illustrate the problems
#define islower(c) 'a' <= (c) && (c) <= 'z'
#define toupper(c) (islower(c) ?(c) - 'a' + 'A': (c))
根据这些定义,putchar(toupper(s[++i]));
将扩展为:
putchar(('a' <= (s[++i]) && (s[++i]) <= 'z' ?(s[++i]) - 'a' + 'A': (s[++i])));
有多种副作用,不能正确测试 s[1]
也不能输出 s[1]
.