我创建了一个函数指针数组来交换两个变量。 指向这些函数的指针即: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}}
答案 0 :(得分:2)
是的。您的代码存在许多问题,但我会关注您提供的警告所涉及的问题。您将swap
声明为四个指向函数的数组,这些函数接受两个int
参数并返回int
:
int (*swap[4])(int, int)
您的函数swap2()
不是这样的函数,因此指向它的指针不是数组成员的正确类型。你的编译器可以通过完全拒绝代码而不仅仅是发出警告来帮助你。
无论如何,在编译器的警告中输入了指向swap2()
的指针,你怎么想程序可以通过指针正确调用该函数?指针的类型要求函数参数为int
s;你的编译器再次执行可疑服务,只接受警告而不是拒绝它。
由于事实上提供的参数是正确的类型,它实际上可能工作在系统上以及int
和int *
的表示兼容的条件下。但是,这不是编写此类代码的借口。
因为默认参数提升没有改变指针和int
,所以一种替代方法是从数组声明中省略原型:
int (*swap[4])() = {swap1,swap2,swap3,swap4};
这表示每个指针指向一个返回int
的函数,并接受未指定类型的固定但未指定数量的参数。在调用时,实际参数将受默认参数提升的约束,但在这种情况下这不是问题。此选项确实阻止编译器对参数执行类型检查,但实际上您无法正确执行此操作。
您的编译器可能仍会对此发出警告,或者可能会使用正确的选项引发警告,但是生成的代码仍然符合并做正确的事情,因为它使用正确的函数调用指向的函数参数。
答案 1 :(得分:1)
首先处理警告:声明一个带int
个参数的函数数组。这意味着swap2
与您放入的数组的元素类型不兼容。这将生成诊断。
此外,当您调用数组中的一个函数时,相同的数组声明告诉编译器参数需要int
不是指向int
的指针。这里有两个诊断,每个参数一个。
要修复上述所有功能,需要使用与数组元素类型兼容的原型。它应该是int
还是int*
?这将我们带到另一个问题。
C函数参数始终按值传递。这意味着参数从变量复制到堆栈(或根据调用约定和参数计数进入参数寄存器 - 对于本文的其余部分,为了简单起见,我假设参数放在堆栈中)。如果它是文字,则将文字值放在堆栈上。如果被调用者更改了堆栈上的值调用者没有尝试,则在函数返回后,将新值放回变量。这些论点被简单地抛弃了。
因此,在C中,如果要进行相当于引用的调用,则需要将指针传递给用作swap2
参数的变量。因此,您的所有函数和数组都应使用int*
。显然,这会使swap1
和swap2
中的一个变得多余。
正确的数组定义是
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
正如我和其他人在答案和评论中提到的那样,你的功能应该都有相同的原型。这意味着,他们必须采用相同的参数并返回相同的类型。我假设您确实希望更改a
和b
,因此我选择了int*, int*
个参数。请参阅@JeremyP的答案,了解原因。