What is the syntax in c to combine statements as a parameter - c

I have an inkling there is an old nasty way to get a function run as a parameter is calculated, but sine I do not know what it is called I cannot search out the rules.
An example
char dstr[20];
printf("a dynamic string %s\n", (prep_dstr(dstr),dstr));
The idea is that the "()" will return the address dstr after having executed the prep_dstr function.
I know it is ugly and I could just do it on the line before - but it is complicated...
#
Ok - in answer to the pleading not to do it.
I am actually doing a MISRA cleanup on some existing code (not mine don't shoot me), currently the 'prep_dstr' function takes a buffer modifies it (without regard to the length of the buffer) and returns the pointer it was passed as a parameter.
I like to take a small step - test then another small step.
So - a slightly less nasty approach than returning a pointer with no clue about its persistence is to stop the function returning a pointer and use the comma operator (after making sure it does not romp off the end of the buffer).
That gets the MISRA error count down, when it all still works and the MISRA errors are gone I will try to get around to elegance - perhaps the year after next :).

Comma operator has the appropriate precedence and, besides, it gives a sequence point, that is, it defines a point in the execution flow of the program where all the previous side effects are resolved.
So, whatever your function prep_dstr() does to the string dstr, it's completely performed before the comma operator is reached.
On the other hand, comma operator gives an expression whose value is the rightest operand.
The following examples give you the value dstr, as you want:
5+3, prep_dstr(dstr), sqrt(25.0), dstr;
a+b-c, NULL, dstr;
(prep_dstr(dstr), dstr);
Of course, such expression can be used wherever you need the string dstr.
Theerefore, the syntax you employed in the question, then, it does the job perfectly.
Since you are open to play with the syntax, there is another possibility you can use.
By taking in account that the function printf() is a function, it is, in particular, an expression.
In this way, it can be put in a comma expression:
prep_dstr(dstr), printf("Show me the string: %s\n", dstr);
It seems that every body is telling you that "don't write code in this way and so and so...".
This kind of religious advices in the programming style are overestimated.
If you need to do something, just do it.
One of the principles of C says: "Don't prevent the programmer of doing what have be done."
However, whatever you do, try to write readable code.

Yes, the syntax you use will work for your purpose.
However, please consider writing clean and readable code. For instance,
char buffer[20];
char *destination = prepare_destination_string(buffer);
printf("a dynamic string %s\n", destination);
Everything can be cleanly named & understood, and intended behaviour easy to infer. You could even omit certain parts if you so would, like destination, or perform easier error checking.

Your inkling and your code are both correct. That said, please don't do this. Putting prep_dstr on its own line makes it much easier to reason about what happens and when.
What you're thinking of is the comma operator. In a context where the comma doesn't already have another meaning (such as separating function arguments), the expression a, b has the value of b, but evaluates a first. The extra parentheses in your code cause the comma to be interpreted this way, rather than as a function argument separator.

Related

Need to understand syntax in C program

I have been tasked with studying and modifying a C program. Generally, I write code in pl/sql, but not C. I have been able to decipher most of the code, but the program flow is still eluding me. After looking up several C references guides, I am not understanding how the C code works. I'm hoping someone here can answer a few syntax questions and tell me what each statement is trying to do.
Here is one sample, with my guesses below.
input(ask_fterm,TM_NLS_Get("0004","FROM TERM: "),6,ALPHA);
if ( !*ask_fterm ) goto opt_fterm;
tmstrcpy(fterm,ask_fterm);
goto nextparmb;
opt_fterm:
tmstrcpy(parm_no,_TMC("02"));
sel_optional_ind(FIRST_ROW);
if ( compare(rpt_optional_ind,_TMC("O"),EQS) ) goto nextparmb;
goto missing_parms;
First, I don't understand !*. What does the exclamation asterisk combination?
Second I assume that if must be ended with endif, unless it is on a single line?
Third tmstrcopy() apparently copies the value of the 2nd parameter into the 1st parameter?
I also have several parameters which I don't understand. I'm hoping someone gives me a hint.
tmstrcpy(valid_ind,_TMC("N"));
input(ask_toterm,TM_NLS_Get("0005","TO TERM: "),6,ALPHA);
I don't know where to find _TMC and TM_NLS_Get.
First, I don't understand !*. What does the exclamation asterisk combination?
That's two separate operators. ! is logical negation. Unary * is for dereferencing a pointer. Put together, they each have their separate effect, so !*ask_fterm means determine the value of the object to which pointer ask_fterm points (this is *); if that value is 0 then the result is 1, else the result is 0 (this is !). If ask_fterm is a pointer to the first character of a string, then that's a check for whether the string is empty (zero-length), because C strings are terminated by a character with value 0.
Second I assume that if must be ended with endif, unless it is on a single line?
There is no endif in C. An if construct controls exactly one statement, but that can be and often is a compound one (which you can recognize by the { and } delimiters enclosing it). There may also be an else clause, also controlling exactly one statement, which can be a compound one.
Third tmstrcopy() apparently copies the value of the 2nd parameter into the 1st parameter?
That appears to be a user-defined function. It is certainly not from the C standard library. If I were to guess based on the name and usage, I would guess that it copies a trimmed version of the string to which the right-hand argument points into the space to which the left-hand argument points.
I don't know where to find _TMC and TM_NLS_Get.
Those are not standard C features. Possibly they are recognized directly by your C implementation, or possibly they are macros defined earlier in the file or in one of the header files it includes.

Why we need to declare variable data type before assigning a return value from a function in C?

I am new to C. Suppose we have a function get_float(); it should return a float value.
but in C, we should explicitly declare a float type variable first before we assign the float value to it.
float number = get_float("what's the number");
I was wondering any reasons for designing such rule.
It seems to decrease mistakes if we can declare a variable without declaring its data type in the case of assigning function return value. Programmers don't need to worry that they declare a wrong data types that don't match with the function return value.
number = get_float("what's the number");
There are languages which are not strictly typed as Python for example.
The reason for a strictly typed language is that it will make it easier to know what a variable is of.
For example, in Python you could have a function:
def foo(number):
if number == 1:
return "This is a string"
else:
return 200
This function will return two different values and valuetypes. This would mean that the return value have to be handled of the caller of the function which may create a lot of troubles.
The same goes for variables within classes, what you believe may be assigned to a variable in Python you have to double check that it contains what you believe when in a strictly typed language you'll always have a stric ttype of the variable.
In a way, as in your example, the typing check is done when assigning your variable to a float. Even the IDE or the compiler will tell you that the function may not return a float value and therefore should not compile/be run.
You're right that forcing the programmer to provide a type for each variable means a little more work for the programmer. But this is designed to reduce the possibility for error, and in most cases, it does.
You brought up the example
float number = get_float("what's the number");
and you compared it with the "simpler"
number = get_float("what's the number");
and you wrote "Programmers don't need to worry that they declare a wrong data types that don't match with the function return value."
But here you're assuming that the only mistake a programmer might make is picking the wrong type for the variable. You're assuming that the expression the programmer writes on the right-hand sign of the = is always correct, so it would always be correct for the compiler to just guess a type for the variable based on the type on the right-hand side. But that's not necessarily true. There are lots of different errors that programmers can make. And trying to guess the programmer's intent when the programmer starts making mistakes can be an arbitrarily tricky process.
For example, suppose a careless programmer believed that the fgets function returned the length of the line it had just read. Suppose this programmer wrote
line = fgets(stdin);
if(line == 0)
printf("empty line\n");
else printf("you typed %d characters\n");
This code is obviously pretty wrong. But if the compiler picked a type for the programmer's line variable, the type it would pick would be char *, which would not be what the programmer wanted. Moreover, by chance, the program would almost seem to work, because the test if(line == 0) would test to see whether fgets returned a null pointer, which is how it indicates an error. So there wouldn't be a compiler warning on that line, either. The line printf("you typed %d characters\n") would print a very strange result, but depending on the compiler, it might not generate a warning, either. (Some compilers warn when you try to print a pointer using %d, but some don't.)
Forcing the programmer to explicitly pick a type for every variable, as C does, is not to make things easy on the programmer in the shortest term. It's supposed to be better in the long term.
Yes, it's more work to have to pick the type of every variable up-front, and yes, it might seem easier if the compiler could guess the right type at least some of tie time. Yes, the errors when you forget to declare a variable, or when you declare it with the wrong type, force you to go back and figure things out and fix things up, when it might seem easier for the compiler to fix them up for you or something.
But the bottom line is that forcing you to pick a type for every variable does, sooner or later, catch a lot of errors. Forcing you to pick a type for every variable introduces a useful form of redundancy, and just like in human languages, redundancy helps eliminate an important class of mistakes.
Of course, forcing you to pick a type for every variable isn't the only possible strategy. There are successful languages that don't force you to pick — but C simply isn't one of them.
The main reason why name = ... won't work in this fashion is the scope of the variables. Imagine a case:
int name; // global variable
int main() {
name = 1;
}
Should the name refer to the global variable or rather to the a newly create local variable?
There is a need for distinction between a variable declaration (even if the type is automatically deducted) and the assignment.
This problem appeared in B programming language, the grand-pa of C, grand-grand-pa of C++ and other offspring.
The issue was solved by marking that an expression is actually a declaration with initializers by adding auto keyword.
auto name = 42;
Note that B supported only a single type, a cpu register which was more-or-less equivalent of int.
With advent of C a new typing system was introduced forcing to place a type before the variable to mark the declaration.
int name = 42;
However to keep existing B code the keyword auto and implicit int type rule was added.
C++ kept the C syntax, and auto as a reserved keyword. From C++11 the auto is used for declaration with a type automatically deducted from the type of the initializer.
There is some chance that this feature will be added to upcomming C23 standard. See proposal.
On the other hand, Python took the other approach where an assignment creates a new variable but now developers are forced to use global or nonlocal statements to bound the scope of the variable.

Is there a way to print what an if statement or any other conditional expression evaluates to in LLDB?

Is there a way to print what the condition of an if statement evaluates to in LLDB ? Or the value value of any conditionnal expression at some point in of the execution of the program ?
I know how to print a variable with var or print, how to print an array's values with parray 10 arr,
how to get the return value of a function by stepping-out of it and thread info but I
don't know how to get the value of a conditional expression.
Any debugging tips much appreciated.
Edit : I just learned from a comment below that one can just use print with some conditionnal expression to see what it evaluates to.
Still, is there somme command that allows to see that without typing the whole condition and have lldb evalluate it again from the state of the variables but to print what a specific condition has evaluated to at some specific point in the program ?
There isn't such a command.
It would be pretty hard to write one that would be fully general since individual source lines are very often not complete statements, and we'd have to do something sensible in that case, etc...
Also, I don't think you actually want "evaluate this line as an expression", you want something more complex. I imagine you have a source line like:
if (!strncmp(token_table[i].token, input , token_table[i].len))) {
That's not an expression in C, so we couldn't evaluate the whole source line directly. You really want "find anything that looks like it's a conditional in this source line, pull it out and evaluate that." That looks tractable in simple cases like the one above, but in the general case this starts to get complicated, and it would be hard to get it right.
OTOH, it would be pretty straightforward to write a Python command that only handles simple instances of an if conditional, using the SB API's to pull out the source line, then some Python parsing to pull out the condition, then SBFrame.EvaluateExpression to evaluate it. So you could certainly use the Python API's to whip up something that's good enough for your purposes.
More details about the Python affordances in lldb are here:
https://lldb.llvm.org/use/python-reference.html
and the lldb API's are documented here:
https://lldb.llvm.org/python_reference/index.html

"Simplify" to one line

just doing my Homeworks and discovered this piece
A[j]=A[j-1];
j--;
is there a way to simplify this to one line? edit one statement?
I've tried
A[j--]=A[j];
but it doesn't seem to work well.
the code is from an InsertSort algorithm
edit this question is not required to do my homework, i am just curious
From the standard:
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.
That is, A[j] = A[--j]; will result in undefined behavior. Don't do it. A[j]=A[j-1]; j--; is perfectly clear, concise, and satisfactory.
If the goal is just to eliminate the ; in the middle so you can use this in a macro context or as a single statement without braces, try using the comma operator:
A[j]=A[j-1], j--;
or if you want the assigned value as the result of the expression:
j--, A[j+1]=A[j];
Both should generate identical code on a decent compiler if the result of the expression is not used.
As others have said, any attempt to do this without the comma operator will result in undefined behavior due to sequence point issues. If you don't have a good reason for condensing code like this, I would recommend not even doing it. Unless you're very experienced with C, you're almost sure to mess it up and introduce subtle bugs (some of which may manifest not with your current compiler, but in future versions of it, creating hell for whoever gets stuck debugging the code).
There is actually a way
A[j+1]=A[--j];
is works well in VC but causes UB on g++

Syntactic errors

I'm writing code for the exercise 1-24, K&R2, which asks to write a basic syntactic debugger.
I made a parser with states normal, dquote, squote etc...
So I'm wondering if a code snippet like
/" text "
is allowed in the code? Should I report this as an error? (The problem is my parser goes into comment_entry state after / and ignores the ".)
Since a single / just means division it should not be interpreted as a comment. There is no division operator defined for strings, so something like "abc"/"def" doesn't make much sense, but it should not be a syntax error. Figuring out if this division is possible should not be done by the parser, but be left for later stages of the compilation to be decided there.
That is syntactically valid, but not semantically. It should parse as the division operator followed by a string literal. You can't divide stuff by a string literal, so it's not legal code, overall.
Comments start with a two-character token, /*, and end with */.
As a standalone syntactical element this should be reported as an error.
Theoretically (as part of an expression) it would be possible to write
a= b /"text"; / a = b divided through address of string literal "text"
which is also wrong (you can't divide through a pointer).
But on the surface level would seem okay because it would syntactically decode as: variable operator variable operator constant-expression (address of string).
The real error would probably have to be caught in a deeper state of syntactical analysis (i.e. when checking if given types are suitable for the division operator).

Resources