I am implementing a simple if statement in c, where I am comparing the value of integer 'tile' to four other integers: w, a, s and d.
Here is my code:
if(tile == w || tile == a || tile == s || tile == d )
{
printf("legal\n");
return true;
}
While the above is correct, the syntax is tiresome. Is there a more elegant way of writing the condition "'tile' is one of the following integers..."
I'm a novice in programming so I apologise as I suspect the answer is very obvious. I've failed to find it addressed elsewhere though.
While eyalm's answer is maybe the one you're looking for, just wanted to chime in to point you to a more important factor here (as you mentioned, "I'm a novice in programming"), which is "Write code which is easier for humans to understand".
While the bitwise approach is shorter, it generally appears to be more difficult to understand a maintain, as it grows.
A cleaner approach will be (while it takes more effort to write the code), stick to the if ( a || b || c) syntax, or a fall-though switch case. It gives better readability.
In case your options grows longer (that you may need a horizontal scroll bar), you can consider adding a function to get the required value checked and use the return value in the condition in the if statement.
The bottom line is, there is no right or wrong way, only choose the way which make the code more readable and maintainable.
Two options i can think of...
bitwise
#define TILE_W 0x0001
#define TILE_A 0x0002
#define TILE_S 0x0004
#define TILE_D 0x0008
if (tile&(TILE_w|TILE_A|TILE_S|TILE_D))
{
printf("legal\n");
return true;
}
switch-case
switch (tile)
{
case w:
case a:
case s:
case d:
printf("legal\n");
return true;
default:
return false;
}
Solution for improvement can depend on values which you compare with.
If w, a, s and d are integer numbers that have consecutive values (e.g. 10, 11, 12 and 13), if-statement can use condition for boundaries:
if( tile >= w && tile <= d) { printf("legal\n"); }
If values are disparate (e.g. 6, 32, 142, 55), you can use switch..case construction, like
switch (tile)
{
case w:
case a:
case s:
case d:
printf("legal\n");
break;
default:
printf("ILLEGAL\n");
break;
}
Also you can use setting flag in one or multiple if as
int legal = 0;
// checking can be in different places of code
if (tile == w)
legal = 1;
if (tile == a || tile == s)
legal = 1;
if (tile == d)
legal = 1;
if( legal )
{
printf("legal\n");
}
And consider storing w, a, s and d values as array of valid values, so loop can be used for checking:
int valArr[] = {101, 151, 333, 7}; // you can add any number of values here
int i;
int legal = 0;
for(i = 0; i < ( sizeof(valArr)/sizeof(valArr[0]) ); i++)
{
if(valArr[i] == tile)
{
legal = 1;
break;
}
}
if( legal )
{
printf("legal\n");
}
else
{
printf("ILLEGAL\n");
}
Related
I have various array content "templates" of type uint8_t that I'd like to define in a special header file. Those content templates also have different lengths:
#define CONTENT_VARIANT_A { 5, 3, 8, 1, 4, 23 }
#define CONTENT_VARIANT_B { 1, 10, 2 }
#define CONTENT_VARIANT_C { 4, 39, 2, 39 }
// '0' is not a valid element value (=> can be used for loop termination)
#define CONTENT_MAX_SIZE = 20;
In my code, I'd like to have a method to set the content of an array buffer to one of those pre-defined values. This is my code so far, using switch and memcpy:
Method to set the content:
void SetBuffer(uint8_t *my_buffer, uint8_t chosen_content) {
memset(my_buffer, 0, CONTENT_MAX_SIZE);
switch (chosen_content) {
case CHOICE_VARIANT_A: {
uint8_t new_content[] = CONTENT_VARIANT_A;
memcpy(my_buffer, new_content, sizeof(new_content));
break;
}
case CHOICE_VARIANT_B: {
uint8_t new_content[] = CONTENT_VARIANT_B;
memcpy(my_buffer, new_content, sizeof(new_content));
break;
}
case CHOICE_VARIANT_C: {
uint8_t new_content[] = CONTENT_VARIANT_C;
memcpy(my_buffer, new_content, sizeof(new_content));
break;
}
}
}
Usage:
// Buffer declaration (done once)
uint8_t my_buffer[CONTENT_MAX_SIZE] = { 0 };
// Buffer population + usage (executed multiple times, with varying values for 'chosen_content')
SetBuffer(my_buffer, chosen_content);
uint8_t i = 0;
while (i < CONTENT_MAX_SIZE && my_buffer[i] > 0) {
// ...
++i;
}
I'm a C# programmer, and new to C; the code in SetBuffer seems overly complicated to me, but is the only thing my mind could come up with that should work (with regards to what I think I know about C), and that also compiles. Is it the correct way of doing what I want, or is it pell-mell and should be done completely different?
In case the zero-out isn't necessary, you can shave the function down to something like this:
void SetBuffer(uint8_t *my_buffer, uint8_t chosen_content) {
switch (chosen_content) {
case CHOICE_VARIANT_A: memcpy(my_buffer, (uint8_t[])CONTENT_VARIANT_A, sizeof((uint8_t[])CONTENT_VARIANT_A)); break;
case CHOICE_VARIANT_B: memcpy(my_buffer, (uint8_t[])CONTENT_VARIANT_B, sizeof((uint8_t[])CONTENT_VARIANT_B)); break;
case CHOICE_VARIANT_C: memcpy(my_buffer, (uint8_t[])CONTENT_VARIANT_C, sizeof((uint8_t[])CONTENT_VARIANT_C)); break;
}
}
Where (uint8_t[])CONTENT_VARIANT_A is not a cast but together with the macro forms a compound literal. Essentially a local, anonymous temporary array. The sizeof expression is similar and calculated at compile-time.
If you must zero-out non-used cells, then replace (uint8_t[]) with (uint8_t[CONTENT_MAX_SIZE]). C guarantees that items not contained in the initializer list gets set to zero.
Yet another alternative for speed over readability is an evil macro:
#define SetBuffer(my_buffer, content) \
memcpy(my_buffer, \
(uint8_t[])CONTENT_VARIANT_##content, \
(uint8_t[])CONTENT_VARIANT_##content)
Call as SetBuffer(buf, A); etc. It's fairly type safe since unknown letter prefixes will result in compiler errors. You might also want to ask yourself why you aren't simply using memcpy on the caller side.
Given the code:
#include <stdlib.h>
enum one {
A, B
};
enum two {
AA
};
int main(int argc, char *argv[])
{
enum one one = atoi(argv[1]);
enum two two = atoi(argv[2]);
if ((one != A && one != B) || two != AA)
return 1;
switch (one) {
case A:
switch (two) {
case AA:
return 2;
}
case B:
return 3;
}
return 0;
}
When I compile it using using gcc -Wimplicit-fallthrough test_fallthrough.c I get the following warning
test_fallthrough.c: In function 'main':
test_fallthrough.c:21:3: warning: this statement may fall through [-Wimplicit-fallthrough=]
21 | switch (two) {
| ^~~~~~
test_fallthrough.c:25:2: note: here
25 | case B:
| ^~~~
What is it trying to warn against and what can I do so that it does not warn (I would prefer to avoid adding comments such as /* Falls through. */)
Why does gcc throw an implicit-fallthrough warning?
Well, because it may fallthrough.
What is it trying to warn against
A fallthrough from case A into case B when two != AA.
what can I do so that it does not warn
On gcc lower then 7 use a comment, ie. one of the markers that disable the warning:
/* falls through */
On gcc above 7 you could use a attribute:
__attribute__((__fallthrough__));
On gcc above 10 you could use the attribute from C2x:
[[fallthrough]];
--
Note that if (one != A || one != B || two != AA) is not really checking anything, as one != A || one != B will always be true. I guess you meant to do like if ((one != A && one != B) || two != AA). Still the -Wimplicit-falthrough= warning is not taking that if into account anyway.
You're missing a break in the first switch statement, it may fallthrough to the sencond case, it can execute case A and afterwards Case B, hence the warning.
//...
switch (one)
{
case A:
switch (two)
{
case AA:
return 2;
}
break; //breaking case A removes the warning.
case B:
return 3;
}
//...
Side note:
Using argc to check if argv[1] and argv[2] are present is always a good idea.
Usually, compiler checks for a break statement after every case body, so that it can ensure the program flow (fallthrough) is not a mistake.
In your case, case A body does not have a break, letting the execution to continue for case B also, when the switch statement matches that of case A.
switch (one) {
case A:
switch (two) {
case AA:
return 2;
}
// <------ no break here, flow will continue, or fall-through to next case body
case B:
return 3;
}
return 0;
}
For those of you who didn't understand - I KNOW this is NOT how a good code should look like... The purpose of this tricky question is to write a code without if-statements in order to practice boolean logic...
I'm trying to solve a question in C which restricts the programmer from using if/else/switch statements. cant use ternary operators either.
The idea is to use boolean based logical statements to get the "wanted path".
i.e - instead of:
if (1 > 0)
printf("TRUE")
else
printf("FALSE")
I would use:
bool res = true;
res = (1 > 0 && printf("TRUE")) || printf("FALSE")
(this is the general idea, using the boolean statement processing logic to manipulate different actions.
The only problem I ran into was to replace a part that looks somewhat like this (where i want the program to skip a certain part of the loop if A is equal to B):
while (...)
{
if (A == B)
continue;
//code
}
Do you know if this is possible to execute without using if/else/switch statements?
Thanks!!
The equivalent of your
while (condition)
{
foo();
if (A == B)
continue;
bar();
baz();
}
is
while (condition)
{
foo();
(A != B) && bar();
(A != B) && baz();
}
This assumes bar() doesn't change A or B. If it does, use a temporary variable:
while (condition)
{
foo();
bool cond = A != B;
cond && bar();
cond && baz();
}
Do you know if this is possible to execute without using if/else/switch statements?
With gcc extension statement expressions you can do this:
int main() {
int A, B;
while (1) {
A == B && ({continue;0;});
}
}
Please don't do this and please don't do res = (1 > 0 && printf("TRUE")) || printf("FALSE"). Just write ifs.
Assuming OK to use state variable then
while (...)
{
if (A == B)
continue;
//code
}
Can be implemented as
state = true ;
while ( ... ) {
...
while ( a == b ) {
state = false ;
break ;
} ;
while ( !state ) {
// code here
break ;
} ;
}
Or with fewer clutter, if allowed:
while (...)
{
state = A == B ;
while ( state ) {
//code here
break ;
} ;
}
With relatively minor performance penalty from having to double-test.
Side note: In my undergrad studies (many years ago), I recall hearing a lecture that explain that ALL control flow commands (if, while, do {} while, switch, with the exception of goto), can be implemented using the while. I wish I can find the reference/proof for that. This was part of a lecture about code verification.
if (1 > 0)
printf("TRUE")
else
printf("FALSE")
I would use:
bool res = true;
res = (1 > 0 && printf("TRUE")) || printf("FALSE")
If I see such a code written by any programmer in my team I would fire him/her.
Why? Your version is not human readable, it is error prone and almost not debugable.
Background:
Often, we developers must check if a single variable is at least one of many options. For example,
if ( (data == 125) || (data == 500) || (data == 750) )
{
/* ... do stuff ...*/
}
The suggestion here (albeit written in C#), provides an elegant solution to use a switch statement like so,
switch ( data )
{
case 125:
case 500:
case 750:
/* ... do stuff ...*/
break;
default:
/* ... do nothing ... */
break;
}
This works well for "or" conditionals, but is ugly for negated "or" conditionals like the following,
if ( !( (data == 125) || (data == 500) || (data == 750) ) )
{
/* ... do stuff ...*/
}
which could be written as
switch ( data )
{
case 125:
case 500:
case 750:
/* ... do nothing ... */
break;
default:
/* ... do stuff ...*/
break;
}
and seems a bit hackish.
Question:
Is there a more succinct way to check if a single variable is none of many options, like the negated "or" conditional above?
References:
C++ Most efficient way to compare a variable to multiple values?
C# Comparing a variable to multiple values
I think the latter is fine.
You can formalize it better, though:
static bool in_sprawling_set(int data)
{
switch ( data )
{
case 125:
case 500:
case 750:
return true;
}
return false;
}
and then where you want to do the work:
if(!in_sprawling_set(data))
{
/* do the work, not in set */
}
This puts the "in set" logic in a function of its own, makes it mildly self-documenting, and the actual use-place much cleaner since the ! becomes more prominent and the final if is very readable ("if not in sprawling set").
Note: if the number of values is really large, I'd probably go for using a pre-sorted array and a binary search, rather than a huge switch. I realize a sufficiently clever compiler can do that transform by itself, but the readability of a huge switch would be rather low (especially if you like to put only one case per line). There's bsearch() for the searching:
static int cmp_int(const void *ap, const void *bp)
{
const int a = *(const int *) ap, b = *(const int *) bp;
return a < b ? -1 : a > b;
}
static bool in_sprawling_set(int data)
{
static const int values[] = { 125, 500, 750 };
return bsearch(&data, values, sizeof values / sizeof *values, sizeof *values, cmp_int) != 0;
}
There's quite a lot of boilerplate going on, but you can see how the part that lists the actual values (the only thing that'll grow as more values are added) is more compact.
Instead of negating the condition, you can always use De-morgans laws to simplify the expression
if (data != 125 && data != 500 && data != 750) ...
Is there a more succinct way to check if a single variable is none of many options?
The switch() statement is certainly a fine solution.
As an alternative, if the product does not over flow, code could use a single branch test:
unsigned data = foo();
if ( (data - 125) * (data - 500) * (data - 750) ) {
/* ... do stuff as long as data is not 125, 500 or 750 ...*/
}
If it more clear - not really, Is it faster than switch()? it has potential.
I have this code inside a class:
void SendStones()
{
int currenthole = hole;
int lastplace = 0;
for(int i=0;i<stns.size();i++)
{
while(1)
{//Calculate new currenthole
if(currenthole == 13) { currenthole = 7; break;}
if(currenthole == 14) { currenthole = 6; break;}
if((currenthole<=12 && currenthole > 7) || (currenthole<=6 && currenthole > 1)) { currenthole--; break;}
}
lastplace = stns.size()-1;
hole[currenthole]->ReciveStone(stns[lastplace]);//PROBLEM
stns.pop_back();
}
}
vector<Stones*> stns;
so it makes this error:
invalid types `int[int]' for array subscript
what's the problem?i don't understand.
Thanks.
It looks like hole is a simple int, and you're trying to subscript it. Is that what you mean to do? Where is hole declared?
Hole is a really big class,
SendStones is a function member in the class.
I won't send the whole file but i can say that
hole[currenthole] is a Hole *hole[14];
It's a big program and project so i sent the related code needed.
Here's the code of the ReciveStones function:
void ReciveStone(Stone *rcvstone)
{
stns.push_back(rcvstone);
}
Based on what you said in your answer, hole is a pointer to n Hole objects. That means your code isn't doing what you think it's doing.
int currenthole = hole;
This is storing an address value pointing to the first object in your array collection, which means that this code
if(currenthole == 13) { currenthole = 7; break;}
if(currenthole == 14) { currenthole = 6; break;}
if((currenthole<=12 && currenthole > 7) || (currenthole<=6 && currenthole > 1)) { currenthole--; break;}
is probably nonsense.
It doesn't explain why you're getting the "invalid types `int[int]' for array subscript" error. Are you sure that there's not a second declaration of type int named hole?
--Actually, re-reading what you wrote, I'm even more certain you're not doing what you think you're doing. SendStones is a member of the class Hole, correct? Check that your Hole class doesn't have a hole member variable inside it. That is probably the problem, since it will be found before any global variable called hole (if I remember my scoping rules correctly).