Reputation: 2612
I have a sort of bizarre wish; I don't know if any compiler or language extension out there allows this.
I want to be able to declare variables inside a function invocation, like this:
int test(int *out_p) {
*out_p = 5;
return 1;
}
int main()
{
if (int ret = test(int &var)) { // int var declared inside function invocation
fprintf(stderr, "var = %d\n", var); // var in scope here
}
return 0;
}
because then the scoping of var follows the scoping of ret. For another example (from a project I'm working on now), I have
cmd_s = readline();
int x, y, dX, dY, symA, symB;
if (sscanf(cmd_s, "placeDomino:%d %d atX:%d y:%d dX:%d dY:%d",
&symA, &symB, &x, &y, &dX, &dY) == 6) {
do_complicated_stuff(symA, symB, x, y, dX, dY);
} else if (sscanf(cmd_s, "placeAtX:%d y:%d dX:%d dY:%d", &x, &y, &dX, &dY) == 4) {
do_stuff(x, y, dX, dY);
/* symA, symB are in scope but uninitialized :-( so I can accidentally
* use their values and the compiler will let me */
}
and I would prefer to write
cmd_s = readline();
if (sscanf(cmd_s, "placeDomino:%d %d atX:%d y:%d dX:%d dY:%d",
int &symA, int &symB, int &x, int &y, int &dX, int &dY) == 6) {
do_complicated_stuff(symA, symB, x, y, dX, dY);
} else if (sscanf(cmd_s, "placeAtX:%d y:%d dX:%d dY:%d", int &x, int &y, int &dX, int &dY) == 4) {
do_stuff(x, y, dX, dY);
/* Now symA, symB are out of scope here and I can't
* accidentally use their uninitialized values */
}
My question is, does any compiler support this? Does gcc support it if I rub it the right way? Is there a C or C++ (draft) spec that has this?
Edit: just realized that in my first code example, my declaration of int ret is also no good in C99; I guess I'm spoiled by for loops. I want that feature too; imagine
while(int condition = check_condition()) {
switch(condition) {
...
}
}
or something like that.
Upvotes: 5
Views: 11692
Reputation: 213892
No compiler supports this. I fail to see where this would make sense.
To reduce the number of source code lines does not necessarily lead to a more efficient program, this is a common misunderstanding. In 99% of the cases in C, it does not make sense to rewrite a statement like this to a more compact one. It only leads to less readable code, you would get the very same machine code in the end.
What you should do is this:
void some_func (void) // good example
{
... lots of code here
int ret;
int var;
ret = test(&var);
if(ret == SOMETHING)
{
fprintf(stderr, "var = %d\n", var); // var in scope here
}
}
What you should not do is this:
void some_func (void) // bad example
{
... lots of code here
{
int ret;
int var;
if((ret = test(&var))
{
fprintf(stderr, "var = %d\n", var); // var in scope here
}
}
}
The good example and the bad example will yield exactly the same machine code. This is very important to understand!
First of all, the reduced scope of the variables in the bad example will not lead to a more effective program: the compiler is very capable of knowing when a variable is used for the first time and when it is not used any longer. In both examples the compiler will store the variables ret and var in CPU registers or on the stack.
Also note that whether the variables are declared in the middle of the function (C99/C11 only) or at the beginning (C90 or C99/C11) doesn't matter what-so-ever for efficiency. Declaring variables in the middle of a scope is just a programming style feature: you are telling the reader of the code that this variable starts to matter from this point on. The compiler, as opposed to the human reading the code, doesn't care where you wrote the declaration.
Had we omitted ret and just checked the result of test(), that wouldn't have made any difference either - the result of the function must still be saved somewhere, either in a variable explicitly declared by the programmer or in a temporary variable implicitly created by the compiler. The machine code will be the same, just harder to debug if there is no ret variable.
The main difference between the examples is that the bad one contains widely-recognized bad programming practice, such as assignment inside condition (MISRA-C:2004 13.1) and implicit test against zero for non-boolean variables (MISRA-C:2004 13.2). Add the needless, obscure, additional local scope to that.
So my advice is to study some assembler (or disassembly) and learn how C code is actually translated to machine code. When you know that, you won't feel the need to needlessly obfuscate code with the false assumption that you are improving it.
Upvotes: 0
Reputation: 1124
Use an empty scope, like this:
int test(int *out_p) {
*out_p = 5;
return 1;
}
int main()
{
{
int var, ret;
if (ret = test(&var)) {
fprintf(stderr, "var = %d\n", var); // var in scope here
}
}
// var not in scope
return 0;
}
Upvotes: 0
Reputation: 78923
Besides block scope declarations, in C99 there are basically two other ways to declare variables that are by definition restricted to the statement in which they occur:
(type name){ initializers }
and declare a local variable that lives in the current block. E.g for a function call you could use test(&(int){ 0 })
.for
scope variables only have the scope of the for
statement itself and the depending statement or block. Your if
expression with local variable you could do something weird like
for (bool cntrl = true; cntrl; cntrl = false)
for (int ret = something; cntrl && test(&ret); cntrl = false) {
// use ret inside here
}
Be careful, such things quickly become unreadable. On the other hand, optimizers reduce such code quite efficiently to the essential and easily find out that test
and the inner side of the for
block are only evaluated once.
Upvotes: 5
Reputation: 145839
while(int condition = check_condition()) {
switch(condition) {
...
}
}
or
if (int ret = test(int &var))
My question is, does any compiler support this? Does gcc support it if I rub it the right way? Is there a C or C++ (draft) spec that has this?
This is not C. The clause for an if
statement or a while
statement has to be an expression and cannot be a declaration.
You can only have a declaration since C99 for the for
iteration statement in its first clause:
for (clause-1; expression-2; expression-3)
The clause-1 can be a declaration or an expression.
Upvotes: 1