在C中函数的参数中声明变量
我有一种奇怪的愿望;我不知道是否有任何编译器或语言扩展允许这样做 我希望能够在函数调用中声明变量,如下所示:在C中函数的参数中声明变量,c,function,variables,declaration,invocation,C,Function,Variables,Declaration,Invocation,我有一种奇怪的愿望;我不知道是否有任何编译器或语言扩展允许这样做 我希望能够在函数调用中声明变量,如下所示: 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", v
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;
}
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;
}
因为var的范围遵循ret的范围
我更喜欢写作
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 */
}
我的问题是,有没有编译器支持这一点?如果我使用正确的方法,gcc是否支持它?是否有C或C++(草案)规格有这个?
编辑:刚刚意识到在我的第一个代码示例中,我的int-ret声明在C99中也不好;我想我已经被这个循环宠坏了。我也想要这个功能;想象
while(int condition = check_condition()) {
switch(condition) {
...
}
}
或者类似的 使用空范围,如下所示:
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;
}
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;
}
或
我的问题是,有没有编译器支持这一点?如果我使用正确的方法,gcc是否支持它?是否有C或C++(草案)规格有这个?
这不是C。if语句或while语句的子句必须是表达式,不能是声明
对于for
iteration语句,在其第一个子句中只能有一个自C99以来的声明:
for (clause-1; expression-2; expression-3)
子句-1可以是一个声明或表达式。除了块范围声明之外,在C99中,基本上还有两种声明变量的方法,根据定义,这些变量仅限于它们出现的语句:
- 复合文字的形式为
(类型名称){initializers}
,并声明存在于当前块中的局部变量。例如,对于函数调用,您可以使用test(&(int){0})
for
范围变量仅具有for
语句本身和依赖语句或块的范围李>
如果你的表达式带有局部变量,你可以做一些奇怪的事情,比如
for (bool cntrl = true; cntrl; cntrl = false)
for (int ret = something; cntrl && test(&ret); cntrl = false) {
// use ret inside here
}
小心,这样的东西很快就看不懂了。另一方面,优化器非常有效地将此类代码简化为基本代码,并且很容易发现test
和for
块的内侧只计算一次 没有编译器支持这一点。我看不出这有什么意义
减少源代码行的数量并不一定会导致更高效的程序,这是一个常见的误解。在C语言中99%的情况下,将这样的语句重写为更紧凑的语句是没有意义的。它只会导致可读性较差的代码,最终会得到完全相同的机器代码
你应该做的是:
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
}
}
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
}
}
}
您不应该做的是:
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
}
}
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
}
}
}
好的例子和坏的例子将产生完全相同的机器代码。了解这一点非常重要
首先,坏例子中变量范围的缩小不会导致更有效的程序:编译器非常能够知道何时第一次使用变量以及何时不再使用变量。在这两个示例中,编译器将变量ret和var存储在CPU寄存器或堆栈中
还注意,变量是否在函数的中间(C99/C11)或在开始(C90或C99/C11)中声明并不重要,效率如何。在一个作用域中声明变量仅仅是一种编程风格特征:你正在告诉读者代码,这个变量从此点开始变得重要。与阅读代码的人不同,编译器并不关心您在哪里编写声明
如果我们省略了ret,只是检查了test()的结果,那也不会有任何区别——函数的结果仍然必须保存在某个地方,要么保存在程序员显式声明的变量中,要么保存在编译器隐式创建的临时变量中。机器代码将是相同的,只是如果没有ret变量就更难调试
这些例子之间的主要区别在于,坏的例子包含广泛认可的坏编程实践,例如内部条件赋值(MISRA-C:2004 13.1)和非布尔变量的针对零的隐式测试(MISRA-C:2004 13.2)。添加不必要的、模糊的、额外的局部范围
因此,我的建议是研究一些汇编程序(或反汇编程序),了解C代码实际上是如何翻译成机器代码的。当您知道这一点时,您就不会觉得有必要用错误的假设来混淆代码,以为您正在改进它。是的,这确实有效;但它缺乏简洁性。我想我的建议不是那么简洁,但我希望至少有一点语法上的甜点。这不是C,如果子句必须是一个表达式,不能是来自OP:-)的声明复制粘贴,我将声明移动到与var相同的级别。你会为了简洁而牺牲清晰度吗?我确实说过“奇怪的愿望”:-p我通常认为简洁可以提高清晰度;这就是为什么我更喜欢在我能找到它们的地方使用让我简洁的习语。“不过,我在这个成语上可能运气不好。”瓦卡尼诺说。你知道现在键盘要多少钱吗?我们所说的键盘成本每十年至少10美元!显然,键盘的磨损应该是任何成功程序员最关心的问题。@zmccord您可能应该澄清您的兴趣是在生产代码中使用它,还是只是对C语言的内部工作方式感到好奇。如果是后者,请在帖子中添加“语言律师”标签,以防止其获得接近票数的选票;我也知道,尽管我在最初的帖子中没有充分阐明这一点,但这在C99中并不是标准的,我更多地是在寻找具有这一特征的扩展方言。我正在做的项目中的例子是认真的;我希望此功能可以简化我的代码,并帮助compi