C 函数通常比 OOP 语言的方法有更多的参数吗?



我不得不写一个有600多行和约25个函数的C程序。这是我写过的最长的C代码。

我注意到有些函数有5个以上的参数。那些直接从main()调用的函数有更多的参数。它离main()越远,就越少。

我还注意到,我经常不得不将一个参数传递给一个函数,这并不是因为该函数直接使用该参数,而是该函数调用另一个需要该参数的函数。

所以它看起来像

void f1(int a, int b,..., int bar){
int foo = f2(bar); // the only time 'bar' is used in f1
.
.
.
}

我试图尽量减少全局变量的使用,但我不得不声明一些全局变量,因为有些参数变得太多余了。基本上,我必须将这些参数传递给每个函数。

我不是一个经验丰富的程序员,但当我用Java编程时,我不认为我需要编写一个超过5个参数的方法。

在C语言中,传递的参数比其他语言中多,这正常吗?这只是过程编程与面向对象编程的本质吗?还是我只是在写糟糕的C代码?

您对避免过多全局变量的担忧是正确的,因为有了它们,程序往往变得无法维护,尤其是当它们的大小增加时。因此,让我们通过参数将数据传递给函数。

使用参数为函数提供执行所需的信息是一个好主意,原因有很多。它首先提供了代码的可读性,但也使编写线程安全函数(可以从不同线程安全调用的函数)变得更容易。

无论如何,一般来说,定义一个参数过多的函数有时确实会导致堆栈消耗效率低下(尤其是在嵌入式系统中,只有前3或4个参数使用处理器寄存器,所有其他参数都复制到堆栈中)。

解决方案是使用数据结构。使用structs(不是,所以与Java等OOP语言中的对象不同),您可以在逻辑实体中将全局数据分组在一起。这使得可以一起定义所有数据,更改其字段,并将其传递给函数。通过指针传递它可以在其原始位置对其进行修改。

因此,您的示例函数将变成

typedef struct
{
int a;
int b;
int bar;
} MyData_t;
void f1( MyData_t *data )
{
int foo = f2( data->bar );
/* ... */
}
int main( void )
{
MyData_t d = { 5, 7, 9 };
f1( &d );
return 0;
}

你需要更改f2()传递更多参数吗?好吧,将指向MyData_t的指针转发给它,您将访问所需的所有变量。


总之,为了回答您的问题,统计分析可能会导致OOP语言而不是过程语言中传递的参数更少:因为在大多数OOP语言中,调用对象将是过程语言中的参数。但是,对于设计良好的结构化编程,这种差异将非常小。

在C语言中传递比其他语言更多的参数是正常的吗?这只是过程编程与面向对象编程的本质吗?还是我只是在写糟糕的C代码?

这是一件很常见的事情。这是因为在C中,我们没有对象(是的,我们有,但这与Java人所称的对象完全不同),而是只有变量(C中的对象)。

因此,只需将类中的每个属性都传递给函数,就可以将类的等价物传递给C函数。反转矩阵的函数会有这样的签名:

void inverse (const double *input, size_t ix, size iy, 
double *output, size_t ox, size_t oy);

在Java或C++中,它看起来像这样:

void inverse(const Matrix &input, Matrix &output);

(我不是一个好的C++程序员,所以请原谅我的错误)

关键是Matrix对象包含其内部的维度成员变量。OOP语言中不受欢迎的是数据类,它是没有方法和公共成员变量的类。

在C中有一个等价物,那就是一个结构。不支持成员函数,除非您使用函数指针(您可以在C中执行OOP,但它非常混乱)。结构基本上就是一个没有封装和支持私有成员的类。所以它们符合目的。

与数组不同,您不必将它们作为指针进行传递。这非常好:

struct myStruct {
int a;
char b;
double c[2];
void **;
};
bool intIsFortyTwo(struct myStruct args) {
return args.a == 42;
}

您也可以返回structs:

struct myStruct initStruct() {
struct myStruct ret = {.a=22, .b='a'};
return ret;
}

通常,出于性能原因,建议使用指针。如果不使用指针,将创建结构的完整副本。第一个功能可能是

bool intIsFortyTwo(struct myStruct *args) {
return args->a == 42;
}

将structs传递给函数并不常见,但也并不奇怪。使用它,你会发现它很有用。

为了扩展注释中的观点,当备选方案是大量单个参数时,将单个指针传递到结构的效率得到了提高,因为与传递多个指针相比,单个指针传递给任意多个成员的sizeof(只要小于1023)很小,或表示单个自变量的值。阅读一个论点也比阅读任何超过3或4个论点的论点容易得多。

因此,即使是一个相对较小的原型示例:void f1(int a, int b, int bar)(去掉省略号),给定32位目标,4字节/int

sizeof a + sizeof b + sizeof bar == 12bytes

与成员超过1000的结构的指针大小相比

typedef struct {
int a;
int b;
... say 1000 more ints
int bar;
}data_t;
data_t *pData 
pData = &data_t;//point pointer back to location t_data.
sizeof pData == 8 bytes

最新更新