Hi guys why this program return 2 not 3
When we do this arithmetic 'a' <= (s[++i]) && (s[++i]) <= 'z'?(s[++i]) - 'a' + 'A': (s[++i])
First we test s[++i] = 1
, second going to be tested s[++i]
should be 2 and this test fails and last one happen s[++i] == 3
, so why compiler return = 2?
Thank you for answering.
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;
}
The right hand side of &&
, which is && (s[++i]) <= 'z'
is not evaluated because the left hand side is already false ( 'a' <= (s[++i])
resolves to 'a' <= '1'
, which is false).
Thus, only the left hand side of &&
, as well as the right hand side of :
are evaluated.
Initial state:
s = "0123"
i = 0
The execution of the expression in steps:
'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'
Note 1: C standard doesn't say systems use ascii encoding, but majority of platforms used today use ascii.
First we test s[++i] = 1, second going to be tested s[++i] should be 2
No, because &&
is short-circuit evaluated . If the left side of &&
is false then the right side of &&
will not be executed.
First let's split on ternary operators like this
'a' <= (s[++i]) && (s[++i]) <= 'z' ?
(s[++i]) - 'a' + 'A':
(s[++i])
and evaluate the first condition 'a' <= (s[++i]) && (s[++i]) <= 'z'
well 'a'
<= ([s++i])
returns false because 'a'
which is 97
is bigger than s[++i]
i
was 0
so ++i
returns 1
and s[1]
is '1'
wich is 49
so 97 <= 49
is false and because of that the &&
stops there and returns 0
(false) and that makes the ternary operators statement executes the else condition which then returns s[++i]
remember that i
has been incremented once when the first condition was evaluated that means s[++i]
is s[2]
which is '2'
and that's the value that should be returned
Let's analyze this statement:
putchar(('a' <= (s[++i]) && (s[++i]) <= 'z' ?(s[++i]) - 'a' + 'A': (s[++i])));
We can first remove redundant parentheses:
putchar('a' <= s[++i] && s[++i] <= 'z' ? s[++i] - 'a' + 'A' : s[++i]);
The argument expression is a ternary expression. Let's transform this into an equivalent if
/ else
statement:
if ('a' <= s[++i] && s[++i] <= 'z')
putchar(s[++i] - 'a' + 'A');
else
putchar(s[++i]);
The left part of the &&
operator is evaluated: 'a'
is compared to s[1]
and i
is incremented. In the ASCII character set, 'a'
is larger than '1'
so this comparison evaluates to 0
and i
is set to 1
.
The right part of &&
is not evaluated because the left part is false.
The else
branch of the if
statement is evaluated: s[2]
is passed to putchar()
and i
is incremented and set to 2
.
Hence the program outputs 2
and i
is set to 2
.
Note that the different parts of the expression are separated by sequence points at &&
, ?
and :
and there is a single ++
operator incrementing i
in each part, so the expression does not have undefined behavior as it might seem at first glance.
The code shows what would happen with macros that evaluate their argument more than once. For example one could define islower
and toupper
as macros:
// 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))
With these definitions, putchar(toupper(s[++i]));
would expand as:
putchar(('a' <= (s[++i]) && (s[++i]) <= 'z' ?(s[++i]) - 'a' + 'A': (s[++i])));
which has multiple side effects and does not correctly test s[1]
nor output s[1]
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.