简体   繁体   中英

Do C functions generally have more arguments than OOP languages' methods?

I had to write a C program with more than 600 lines and about 25 functions. This is the longest C code that I've written.

I noticed that some of the functions have more than 5 arguments. The ones that are directly called from main() have more arguments. The further away it goes from main(), the fewer.

I also noticed that I frequently had to pass an argument to a function, not because that function directly uses that argument, but the function calls another function that needs that argument.

So it would look something like

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

I tried to minimize the use of global variables, but I had to declare some global variable because some arguments became way too redundant. Basically I had to pass those arguments to every function.

I'm not an experienced programmer but when I programmed in Java, I don't think I ever needed to write a method with more than 5 arguments.

Is it normal in C to pass way more arguments than in other languages? Is it just the nature of Procedural Programming vs OOP? Or am I just writing bad C code?

Your concerns about avoiding too many global variables are correct, because with them programs tend to become unmaintainable, especially when they grow in size. So let's pass data to functions through parameters.

Using parameters to provide your functions with the information they need to execute is a good idea for many reasons. It offers first of all the readability of the code, but also make it easier writing thread safe functions (functions that can be called safely from different threads).

Anyway, generally speaking, defining a function with too many parameters sometimes may indeed cause inefficiency in terms of stack consumption (especially in embedded systems, where only the first 3 or 4 parameters use the processor registers, with all the others parameters copied to the stack).

The solution is using data structures. With struct s (not so different from what, in OOP languages such as Java, you would call objects ) you can group together your global data in logical entities . This makes possible to define of all your data together, to change its fields, and to pass it to your functions. And passing it by pointer makes possible modifying it in its original location.

So your example functions would become

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;
}

You need to change f2() passing it more parameters? Well, forward the pointer to MyData_t to it and you'll access all the variables you need.


In conclusion, to answer your question , probably a statistical analysis would result in less parameters passed in OOP languages rather than procedural languages: just because in most of them the calling object would be a parameter in a procedural language. But with well designed structured programming, this difference would be very small.

Is it normal in C to pass way more arguments than in other languages? Is it just the nature of Procedural Programming vs OOP? Or am I just writing bad C codes?

It's a very common thing. It's because in C, we don't have objects (yes, we do, but it's something completely different than what Java people would call objects) but instead just variables (objects in C).

So you're passing the equivalent of a class to C functions by just passing every single attribute in that class to the function. A function inverting matricies would have this signature:

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

In Java or C++, it would look like something like this:

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

(I'm not a good C++ coder so forgive me for mistakes)

The point is that the Matrix object contains the dimensional inside them member variables. Something that is frowned upon in OOP-languages is dataclasses, which is classes without methods and public member variables.

There is an equivalent for that in C, and that is a struct. No support for member functions, unless you're using function pointers (You can do OOP in C, but it's very messy). What a struct basically is, is just a class without encapsulation and support for private members. So they suit the purpose.

Unlike arrays, you don't have to pass them as pointers. This is perfectly fine:

struct myStruct {
    int a;
    char b;
    double c[2];
    void **;
};

bool intIsFortyTwo(struct myStruct args) {
    return args.a == 42;
}

You can also return structs:

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

In general, pointers are advisable, for performance reasons. If you don't use pointers, a whole copy of the struct will be created. The first function could then be

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

Passing structs to functions is not extremely common, but it's not strange either. Use it you find it useful.

To expand on the point made in comments, efficiency of passing a single pointer to struct when the alternative is a large number individual of arguments is improved simply because the sizeof a single pointer is passed for as many members as you like (as long as it is less than 1023) is small when compared to passing a number of pointers, or values representing individual arguments. It is also much easier to read one argument as opposed to anything with more than 3 or 4 arguments.

So, even with your example of a reletively small prototype: void f1(int a, int b, int bar) (having removed the ellipsis.) and given 32 bit target, with 4bytes/ int

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

Compared to the size of a pointer to a struct with over 1000 members

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM