C函数不写return以及调用无参函数时传参会出现什么结果

1. 问题描述

  偶然间重新拿起了三年前的C语言,遇到了以前没有遇到过的问题:
1. C语言中普通函数声明了返回类型但是不用return返回结果,也能够编译通过,如下:

#include <stdio.h>

int test1(int a) {
    return 10;
}
int test2(int a) {

}
int main() {
    int a = 1;
    test1(a);
    printf("%d\n", test2(a));//结果为1,如果不是传入变量而是直接传入数值,则结果为10
    return 0;
}
  1. 调用无参函数时传入参数,能够编译通过,如下:
#include <stdio.h>

int test1() {

}
int main() {
    int a = 1;
    printf("%d\n", test1(a));//1,如果不传入变量而传入值,则结果无法理解
    return 0;
}

2. 问题分析

  
  可以肯定的是执行时和使用的寄存器有关
1. 编译能够通过,说明gcc编译器为了效率不会检查是否有return关键字以及无参函数调用时是否传入了参数。
2. 没有return仍然能够拿到值,说明和寄存器有关,我们或多或少听说过eax寄存器,可以通过gdb反汇编查看究竟。

汇编代码太累赘,查看过程略过,下面直接记录结论。

3. 结论

  通过查看函数调用的汇编代码,可以得出以下结论:

  1. C中函数调用的时候的会将实参从右向左依次入栈,这么做的好处是有利于可变参数实现,调用无参函数时可以传参,但是函数内取不到参数的值。而有参函数必须保证实参和形参数量一致,否则会报参数过多或过少的错误。
  2. 如果传入的参数是变量,则依次放在eax寄存器中,根据上面的入栈顺序,就是说eax中保存的是第一个参数的值;如果传入的参数是直接量,则不会使用eax寄存器,也就是说上面的test2(a)和test2(1)在传参的时候,只有前者会将1保存在eax中。
  3. 使用return关键字会将右边表达式的结果保存在eax寄存器中,如果不写return,则eax中可能是之前传入参数的值,也可能是上一次return的值,看情况分析。

请看下面的例子:

#include <stdio.h>

int test1() {

}
int test2() {

}
int main() {
    int a = 1;
    test1(a);
    printf("%d\n", test2(2));//结果为1
    return 0;
}

两个test虽然都没有声明形参,但是仍然可以传参,只不过在函数内取不到参数。
调用test1,传入的是个变量,所以此时eax中的值为a的值1,之后调用test2,传入的是个直接量2,不会用到eax,所以eax还是1,由于test2声明了返回类型,但是又不写return,eax的值还是老样子,所以整个test2的结果就是eax的值1。

4. 思考

  尽量不要这么玩,很危险!!!

### 回答1: 在某些编程语言中,如果一个类有定义有参构造函数,那么默认的无参构造函数就不被自动生成。因此,在你调用无参构造函数,编译器找不到对应的构造函数,就报错。 如果你想同使用有参构造函数无参构造函数,可以在类中显式地定义一个无参构造函数,或者在调用无参构造函数传入一个空的参数列表。例如,在C++中,你可以这样写: ```c++ class MyClass { public: MyClass(int arg) { // 构造函数代码 } MyClass() { // 无参构造函数代码 } }; int main() { MyClass obj1(123); // 调用有参构造函数 MyClass obj2{}; // 调用无参构造函数 return 0; } ``` 在上面的例子中,`MyClass`类中定义了一个有参构造函数和一个无参构造函数。在`main`函数中,我们分别创建了一个使用有参构造函数的对象`obj1`和一个使用无参构造函数的对象`obj2`。注意,为了调用无参构造函数,我们使用了花括号表示法,并传入了一个空的参数列表。 ### 回答2: 在调用一个类的构造函数,如果类定义中同提供了有参构造函数无参构造函数,那么可以根据需要选择使用哪一个构造函数进行调用。 然而,问题出现在先调用有参构造函数,再调用无参构造函数。在Java语言中,一旦在一个类中定义了有参构造函数,编译器就不再自动生成无参构造函数。因此,如果先调用有参构造函数,编译器在执行无参构造函数发现它并不存在,进而报错。 解决这个错误的常见方法是在使用无参构造函数的地方提供相应的参数,或者通过重载的方式增加一个无参构造函数。 另外,本题涉及的报错信息没有提供具体细节,这也可能导致错误判断。请在提问提供相关详细信息,以便能够更好地回答和定位问题。 ### 回答3: 当一个类中定义了有参构造函数无参构造函数,创建对象根据传入的参数选择调用有参构造函数无参构造函数。如果你先调用了有参构造函数,那么对象已经被初始化为有参构造函数的状态,再调用无参构造函数就相当于重新初始化对象。在大多数编程语言中,一个对象只能被初始化一次,所以再次调用无参构造函数引发错误。 这种错误通常被称为"重复构造"错误。它发生在编译器在初始化一个对象发现对象已经被构造,又试图调用构造函数进行二次构造。编译器认为这是非法操作并报错。因此,在编写代码,应该避免出现重复调用构造函数的情况。 解决这个问题的方法有两种: 1. 只调用有参构造函数:如果你已经调用了有参构造函数并成功初始化了对象,那么就没有必要再调用无参构造函数了。只需构造一个对象,然后使用该对象即可。 2. 使用函数重载:如果你希望在同一个类中既可以调用有参构造函数又可以调用无参构造函数,可以使用函数重载的特性。在类中同定义有参构造函数无参构造函数,通过参数的个数或类型的不同来区分它们,这样就可以根据需要选择调用特定的构造函数。 总之,当一个对象已经通过有参构造函数进行了初始化,就无法再通过调用无参构造函数重新初始化同一个对象,导致编译错误。应根据实际需求选择合适的构造方式,避免重复调用构造函数的错误。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值