Operands in "int i = 0" - c

I would like to ask if this short code:
int i = 0;
has 1 operand or 2? The i is an operand, but is 0 too? According to wikipedia, 0 shouldn't (or maybe I misunderstand). If 0 isn't operand, is it a constant or something?
If it is important, the code is in C99.

In int i = 0;, = is not an operator. It's simply a part of the variable initializaton syntax. On the other hand, in int i; i = 0; it would be an operator.
Since = here is not an operator, there are no operands. Instead, 0 is the initializer.

Since you've tagged the question as "C", one way to look at it is by reading the C standard. As pointed out by this answer, initialization (such as int i = 0) is not an expression in itself, and by a strict reading of the standard, the = here is not an operator according to the usage of those terms in the standard.
It is not as clear whether i and 0 are operands, however. On one hand, the C standard does not seem to refer to the parts of the initialization as operands. On the other hand, it doesn't define the term "operand" exhaustively. For example, one could interpret section 6.3 as calling almost any non-operator part of an expression an "operand", and therefore at least the 0 would qualify as one.
(Also note that if the code was int i; i = 0; instead, the latter i and the 0 would definitely both be operands of the assignment operator =. It remains unclear whether the intent of the question was to make a distinction between assignment and initialization.)
Apart from the C standard, you also refer to Wikipedia, in particular:
In computing, an operand is the part of a computer instruction which specifies what data is to be manipulated or operated on, while at the same time representing the data itself.
If we consider the context of a "computer instruction", the C code might naively be translate to assembly code like mov [ebp-4], 0 where the two operands would clearly be the [ebp-4] (a location where the variable called i is stored) and the 0, which would make both i and 0 operands by this definition. Yet, in reality the code is likely to be optimized by the compiler into a different form, such as only storing i in a register, in which case zeroing it might become xor eax, eax where the 0 no longer exists as an explicit operand (but is the result of the operation). Or, the whole 0 might be optimized away and replaced by some different value that inevitably gets assigned. Or, the whole variable might end up being removed, e.g., if it is used as a loop counter and the loop is unrolled.
So, in the end, either it is something of a philosophical question ("does the zero exist as an operand if it gets optimized away"), or just a matter of deciding on the desired usage of the terms (perhaps depending on the context of discussion).

The i is an operand, but is 0 too? According to wikipedia, 0 shouldn't
(or maybe I misunderstand).
The question links to the Wikipedia page describing the term "operand" in a mathematical context. This likely factors in to your confusion about whether the 0 on the right-hand side of the = is an operand, because in a mathematical statement of equality such as appears in the article, it is in no way conventional to consider = an operator. It does not express a computation, so the expressions it relates are not operated upon. I.e. they do not function as operands.
You have placed the question in C context, however, and in C, = can be used as an assignment operator. This is a bona fide operator in that it expresses a (simple) operation that produces a result from two operands, and also has a side effect on the left-hand operand. In an assignment statement such as
i = 0;
, then, both i and 0 are operands.
With respect to ...
If 0 isn't operand, is it a constant or something?
... 0 standing on its own is a constant in C, but that has little to do with whether it serves as an operand in any given context. Being an operand is a way an expression, including simply 0, can be used. More on that in a moment.
Now it's unclear whether it was the intent, but the code actually presented in the question is very importantly different from the assignment statement above. As the other answers also observe,
int i = 0;
is a declaration, not a statement. In that context, the i is the identifier being declared, the 0 is used as its initializer, and just as the = in a mathematical equation is not an operator, the = introducing an initializer in a C declaration is not an operator either. No operation is performed here, in that no value computation is associated with this =, as opposed to when the same symbol is used as an assignment operator. There being no operator and no operation being performed, there also are no operands in this particular line of code.

Related

how logical NOT operator works in c?

How the logical NOT operator ! actually works in c?
How it turns all non-zero int into 0 and vice-versa?
For example:
#include <stdio.h>
void main() {
if(!(-76))
printf("I won't print anything");
if(!(2))
printf("I will also not print anything");
}
doesn't print anything, which could mean -76 and 2 was turned into zero...
So, I tried this:
#include <stdio.h>
void main() {
int x = !4;
printf("%d", x);
}
which indeed printed 0
and now I don't get how, is it flipping all the bits to 0 or what?
Most CPU architectures include an instruction to compare to zero; or even check the result against zero for most operations run on the processor. How this construct is implemented will differ from compiler to compiler.
For example, in x86, there are two instructions: JZ and JNZ: jump zero and jump not zero, which can be used if your test is an if statement. If the last value looked at was zero, jump (or don't jump) to a new instruction.
Given this, it's trivial to implement int x = !4; at assembly level as a jump if 4 is zero or not, though this particular example would be likely calculated at compile time, since all values are constant.
Additionally, most versions of the x86 instruction set support the SETZ instruction directly, which will set a register directly to 1 or 0, based on whether the processors zero flag is currently set. This can be used to implement the logical NOT operation directly.
6.5.3.3 Unary arithmetic operators
Constraints
1 The operand of the unary + or - operator shall have arithmetic type; of the ~ operator, integer type; of the ! operator, scalar type.
Semantics
...
5 The result of the logical negation operator ! is 0 if the value of its operand compares unequal to 0, 1 if the value of its operand compares equal to 0. The result has type int. The expression !E is equivalent to (0==E).
C 202x Working Draft
So, that's what language definition says should happen; if the expression x evaluates to non-zero, then the expression !x should evaluate to zero; if x evaluates to zero, then !x should evaluate to 1. The bits of the operand are not affected.
How that's accomplished in the machine code is up to the specific implementation; it depends on the available instruction set, the compiler, and various other factors such that no one answer works everywhere. It could translate to a branch statement, it could take advantage of specialized instructions, etc.

-Wint-in-bool-context warning issue in some compilers

I am a getting warning:
warning: '<<' in boolean context, did you mean '<' ? [-Wint-in-bool-context]
for the code similar to the following:
int a=7,b=3;
int index=((a<<1)||b)&&5;
To explain the rationale behind such warnings:
C did get a boolean type _Bool/bool as per C99, but no changes were done to the behavior of the various logical operators of the language. That is:
Equality operators ==/!=
Relational operators <,<=,>,>=
Logical AND &&
Logical OR ||
Logical negation !.
Despite C having a boolean type, all of these operators return type int with value 1 or 0. Unlike C++ where all of these operators actually return type bool with value true/false. This is a known flaw of C.
It's common good practice however to treat such expressions as if they were boolean. Coding guidelines like MISRA C encourage the use of a fictional type "essentially boolean", meaning any expression that could be treated as _Bool. The reason for this is that it makes code more self-documenting and also makes it harder to create various typo-related bugs.
For example if(str) could mean check for NULL, or it could mean check for null termination but oops we forgot to dereference. Same thing with if(*str). Whereas if we only pass the result of a logical operator to if, the code becomes much clearer and it becomes harders to write bugs: if(str != NULL) could only mean check for NULL and if(*str != '\0') could only mean check for null termination.
In your case, the || operator only cares if the operands are zero or non-zero ("essentially boolean"). In case a is non-zero then a<<1 will not change that. In case a is zero, then a<<1 is zero as well. Since the result is passed on to a logical operator, "in a boolean context", the shift is pointless - hence the warning. But of course a<<1 might take all kinds of other values in another context such as for example if(a<<1 & mask).
It would be reasonable to strongly suspect that you actually meant to write a<1 instead. Because that would yield either 0 or 1, where < is also a logical operator like ||.
I got the solution. We should avoid integers using with logical operators (eg. ||,&&). Using integers with bitwise operators (eg. <<,&,|,etc.) is fine.
Sometimes we don't get this problem while running on compilers because of low priority warning filters. In complex and warning sensitive compilers it comes up.
Thanks

How exactly is the program running?

I am a beginner in C and I came across a code which went like this:
#include<stdio.h>
int main()
{
int k=35;
printf("%d %d %d",k==35,k=50,k>40);
return 0;
}
I tried to find the output without writing the code in my computer and 'actually' running it first. So here's how I figured out what the output might be:
In the precedence table, among assignment (==), equality (=) and greater than (>) operators, the greater than operator will be implemented first. So, initially, k=35 and thus k>40 is false (the integer thus will be 0). Next up is the equality operator (==). Now, k==35 is true initially. So this will return an integer 1. Finally, the assignment operator (=) will do its job, set the value of k to 50(and ultimately, returning 50) and the program will exit. Thus, based on this logic, I 'guessed' that final output will be like:
1 50 0
Now I ran the code in my IDE (I'm coming to my IDE a bit later) and the result it gave was:
0 50 0
So, my confusion is, in which order are the operators being implemented?
Any help or hints are very much welcome.
NOTE: I noticed a bit closer and found that the only way possible is: First the > operator does its job, then the = operator and finally, the == operator.
I changed my printf line a bit and wrote:
printf("%d %d %d",k==35,k>40,k=50);
Here, I found that the output was:
0 1 50
which, again was not according to what I 'guessed' initially with my logic.
I tried all the possible ordering of the syntax inside the printf() function. After looking at all those outputs, I doubt: Is the program being implemented in a right-to-left order here irrespective of the ordering in the precedence table?
NOTE: Regarding my IDE, I use Dev C++ 5.11. I use it as our instructor has advised us to use it for our course. As this IDE is not so much well-received among many others, I tried an online compiler, but the results are the same.
The behavior is undefined - the result is not guaranteed to be predictable or repeatable.
First, precedence only controls which operators are grouped with which operands - it does not control the order in which expressions are evaluated.
Second, the order in which function arguments are evaluated is unspecified - they can be evaluated right-to-left, left-to-right, or any other order1.
Finally, you are updating k (k = 50) and attempting to use it in a value computation (k == 35, k > 40) without an intervening sequence point, which is explicitly called out by the language definition as undefined behavior.
So the result can literally be anything, even what you expect it to be. You can’t rely on it to be consistent or predictable.
This is not the same as the order in which they are passed to the function.
printf("%d %d %d",k==35,k=50,k>40);
This is undefined behavior.
The order of evaluation of the arguments is simply unspecified.
See here and here for further explanation.
Order of evaluation of the operands of any C operator, including the order of evaluation of function arguments in a function-call expression, and the order of evaluation of the subexpressions within any expression is unspecified[...]. The compiler will evaluate them in any order, and may choose another order when the same expression is evaluated again.

Is it safe to use foo() && 0 in C?

Imagine i have the following piece of C-code where foo() produces a side effect and returns an integer:
if(bar) {
foo();
return 0;
}
Now, say I really like making my code compact, possibly at the reader's expense, and I change it into this:
if (bar)
return foo() && 0;
Can I be sure these two pieces of code will produce the same behavior, or would I risk the call to foo() not being executed due to possible compiler optimizations or something like that, thus not producing the desired side-effect?
NOTE: This is not a question about which piece of code is better, but whether the two pieces actually produce the same behavior in all cases. I think the majority (and I) can agree that the former piece of code should be used.
Yes, those two are the same. foo() will always be called (assuming bar is true).
The two forms you give are equivalent. The C11 standard (draft n1570) states,
6.5.13 Logical AND operator
...
Semantics
3 The && operator shall yield 1 if both of its operands compare unequal to 0;
otherwise, it yields 0. The result has type int.
4 Unlike the bitwise binary & operator, the && operator guarantees left-to-right
evaluation; if the second operand is evaluated, there is a sequence point between
the evaluations of the first and second operands. If the first operand compares
equal to 0, the second operand is not evaluated.
Similar language appeared in all C standards so far.
You should probably prefer using the comma operator here (return foo(), 0;) because:
It's shorter (one character versus two for the operator, and you can get away with removing the left space character when using a comma, for a total of two fewer characters).
It gives you more flexibility, as you can return non-scalar types (such as structs), and a wider range of integers than just 0 or 1.
It conveys the intent better: "Discard return value of foo() and return something else (0) instead".
Now if you do chance upon a compiler that deletes the call to foo(), then either the compiler managed to prove that foo() is a function with no visible side-effects, or more likely it has a serious bug and you should report it.
Why obfuscate your code in the latter?
Use the former.
Easier to read i.e. this is easier to understand
if(bar) {
foo();
return 0;
}
Or unless got a problem with job security

Does the C99 standard permit assignment of a variable to itself?

Does the C99 standard allow variables to be assigned to themselves? For instance, are the following valid:
int a = 42;
/* Case 1 */
a = a;
/* Case 2 */
int *b = &a;
a = *b;
While I suspect Case 1 is valid, I'm hesitant to say the same for Case 2.
In the case of an assignment, is the right side completely evaluated before assigning the value to the variable on the left -- or is a race condition introduced when dereferencing a pointer to the variable being assigned?
Both cases are perfectly valid, since the value of a is only used to determine the value that is to be stored, not to determine the object in which this value is to be store.
In essence in an assignment you have to distinguish three different operations
determine the object to which the value is to be stored
evaluate the RHS
store the determined value in the determined object
the first two of these three operations can be done in any order, even in parallel. The third is obviously a consequence of the two others, so it will come after.
This is perfectly valid, you are only using the previous value to determine the value to be stored. This is covered in the draft C99 standard section 6.5.2 which says:
Between the previous and next sequence point an object shall have its
stored value modified at most once by the evaluation of an
expression.Furthermore, the prior value shall be read only to
determine the value to be stored.
One of the examples of valid code is as follows:
i = i + 1;
The C and C++ section here covers the different places where a sequence point can occur.
C99 6.5.16.1 Simple assignment
3 If the value being stored in an object is read from another object that overlaps in any way
the storage of the first object, then the overlap shall be exact and the two objects shall
have qualified or unqualified versions of a compatible type; otherwise, the behavior is
undefined.
I think the example code qualifies the "overlap" condition. Since they do have qualified version of a compatible type, the result is valid.
Also 6.5.16 Assignment operators
4 The order of evaluation of the operands is unspecified. If an attempt is made to modify
the result of an assignment operator or to access it after the next sequence point, the
behavior is undefined.
Still, there's no "attempt to modify the result" so the result is valid.
Assuming the compiler doesn't optimize the first instruction out by simply removing it, there is even a race condition here. On most architecture, if a is stored in memory a = a will be compiled in two move instructions (mem => reg, reg => mem) and therefore is not atomic.
Here is an example:
int a = 1;
int main()
{ a = a; }
Result on an Intel x86_64 with gcc 4.7.1
4004f0: 8b 05 22 0b 20 00 mov 0x200b22(%rip),%eax # 601018 <a>
4004f6: 89 05 1c 0b 20 00 mov %eax,0x200b1c(%rip) # 601018 <a>
I can't see a C compiler not permitting a = a. Such an assignment may occur serendipitously due to macros without a programmer knowing it. It may not even generate any code for that is an optimizing issue.
#define FOO (a)
...
a = FOO;
Sample code readily compiles and my review of the C standard shows no prohibition.
As to race conditions #Yu Hao answers that well: no race condition.

Categories

Resources