如何将条件作为参数传递给C中的函数?

时间:2017-04-27 14:42:08

标签: c function pointers function-pointers function-parameter

我创建了一个函数指针数组来交换两个变量。 指向这些函数的指针即:swap1,swap2。 swap3和swap4。 swap2使用作为参数传递的指针进行交换。 但在声明函数指针时,只将int和int作为参数传递。编译后会导致许多警告。 所以我们有一个更好的传递参数的方法,我们把条件放在函数调用本身。 代码如下。

                 at line 36 in file '9e748221\script.c'
        WARNING: found pointer to int where int is expected
                 at line 47 in file '9e748221\script.c'
        WARNING: found pointer to int where int is expected
                 at line 47 in file '9e748221\script.c'

一些警告如下。

{{1}}

3 个答案:

答案 0 :(得分:2)

是的。您的代码存在许多问题,但我会关注您提供的警告所涉及的问题。您将swap声明为四个指向函数的数组,这些函数接受两个int参数并返回int

int (*swap[4])(int, int)

您的函数swap2()不是这样的函数,因此指向它的指针不是数组成员的正确类型。你的编译器可以通过完全拒绝代码而不仅仅是发出警告来帮助你。

无论如何,在编译器的警告中输入了指向swap2()的指针,你怎么想程序可以通过指针正确调用该函数?指针的类型要求函数参数为int s;你的编译器再次执行可疑服务,只接受警告而不是拒绝它。

由于事实上提供的参数是正确的类型,它实际上可能工作在系统上以及intint *的表示兼容的条件下。但是,这不是编写此类代码的借口。

因为默认参数提升没有改变指针和int,所以一种替代方法是从数组声明中省略原型:

int (*swap[4])() = {swap1,swap2,swap3,swap4};

这表示每个指针指向一个返回int的函数,并接受未指定类型的固定但未指定数量的参数。在调用时,实际参数将受默认参数提升的约束,但在这种情况下这不是问题。此选项确实阻止编译器对参数执行类型检查,但实际上您无法正确执行此操作。

您的编译器可能仍会对此发出警告,或者可能会使用正确的选项引发警告,但是生成的代码仍然符合并做正确的事情,因为它使用正确的函数调用指向的函数参数。

答案 1 :(得分:1)

首先处理警告:声明一个带int个参数的函数数组。这意味着swap2与您放入的数组的元素类型不兼容。这将生成诊断。

此外,当您调用数组中的一个函数时,相同的数组声明告诉编译器参数需要int不是指向int的指针。这里有两个诊断,每个参数一个。

要修复上述所有功能,需要使用与数组元素类型兼容的原型。它应该是int还是int*?这将我们带到另一个问题。

C函数参数始终按值传递。这意味着参数从变量复制到堆栈(或根据调用约定和参数计数进入参数寄存器 - 对于本文的其余部分,为了简单起见,我假设参数放在堆栈中)。如果它是文字,则将文字值放在堆栈上。如果被调用者更改了堆栈上的值调用者没有尝试,则在函数返回后,将新值放回变量。这些论点被简单地抛弃了。

因此,在C中,如果要进行相当于引用的调用,则需要将指针传递给用作swap2参数的变量。因此,您的所有函数和数组都应使用int*。显然,这会使swap1swap2中的一个变得多余。

正确的数组定义是

int (*swap[4])(int*, int*) = {swap1, swap2, swap3, swap4};

并且应修改每个函数的定义以获取int*个参数。我抵制使用int (*swap[4])()的诱惑只是因为它绕过了类型安全。当被调用的函数期望一个可能是灾难性的指针时,你可以很容易地忘记int参数前面的& - 当你这样做时最好的情况就是seg错误。

答案 2 :(得分:1)

其他人已经做了很多工作来解释问题所在。 你一定要先阅读它们。

我想向你展示一个解决这类问题的工作方案。

考虑以下(工作)简单程序:

// main.c

#include <stdio.h>

void swap1(int* aPtr, int* bPtr) {
    printf("swap1 has been called.\n");
    int tmp = *aPtr;
      *aPtr = *bPtr;
      *bPtr = tmp;
}

void swap2(int* aPtr, int* bPtr) {
    printf("swap2 has been called.\n");
    *aPtr += *bPtr;
    *bPtr  = *aPtr - *bPtr;
    *aPtr -= *bPtr;
}


int main() {
    int a = 1, b = 2;
    printf("a is now %d, and b is %d\n\n", a, b);

    // Declare and set the function table
    void (*swapTbl[2])(int*, int*) = {&swap1, &swap2};

    // Ask for a choice
    int choice;
    printf("Which swap algorithm to use? (specify '1' or '2')\n>>> ");
    scanf("%d", &choice);
    printf("\n");

    // Swap a and b using the right function
    swapTbl[choice - 1](&a, &b);

    // Print the values of a and b
    printf("a is now %d, and b is %d\n\n", a, b);

    return 0;
}

首先,如果我们尝试编译并执行它:

$ gcc main.c && ./a.out

a is now 1, and b is 2

Which swap algorithm to use? (specify '1' or '2')
>>> 2

swap2 has been called.
a is now 2, and b is 1

正如我和其他人在答案和评论中提到的那样,你的功能应该都有相同的原型。这意味着,他们必须采用相同的参数并返回相同的类型。我假设您确实希望更改ab,因此我选择了int*, int*个参数。请参阅@JeremyP的答案,了解原因。