typedef函数指针和extern关键字

Tug*_*.44 6 c typedef function-pointers extern

我在使用typedef理解指向函数的指针的语法时遇到了问题.我已经阅读了很多答案,但仍然无法理解.我会试着解释一下我是如何看待事物的,这样你才能理解我的想法.

因此我们使用typedef为现有类型提供别名,例如:

typedef int number;
Run Code Online (Sandbox Code Playgroud)

这样我们可以使用与整数相同的数字(类似于预处理器指令 - 我知道在制作指针的typedef时会有一些差异).另一个例子 :

typedef struct
{
    int num;
} MyStruct;
Run Code Online (Sandbox Code Playgroud)

将为未命名的结构提供名为MyStruct的别名.

所以这是函数typedef指针的语法:

typedef int (*pFunc)(int, int);
Run Code Online (Sandbox Code Playgroud)

也许我很难理解这一点,因为typedef就像它给TYPES赋予别名的名字而且函数不是完全类型但是无论如何,根据我的理解,这更像是指向某种函数签名的指针,所以第一个int是返回的类型,第二个括号用于指示传递给函数的参数是什么类型.现在我不太明白这一部分:

(*pFunc)
Run Code Online (Sandbox Code Playgroud)
  • 我认为是,我们创建一个名为pFunc的新类型(使用typedef),它是一个指针,它是*的作用.现在我们可以创建这种类型的变量,它将指向具有我们描述的签名的ANY函数.我对么 ?

好吧,说我是对的,通常指向一些内存的指针声明如下:

int *p;
double *p;
.
.
.
Run Code Online (Sandbox Code Playgroud)

因此,按照以下方式进行操作会更有意义:

(pFunc*)
Run Code Online (Sandbox Code Playgroud)

因为对我而言,如果星号位于名称之前,它看起来像pFunc是某种类型的类型指针的变量名,而不是实际的类型指针.

  • 我们能做到吗?如果是这样,它是否常用于将星号放在之后而不是之前?如果它之前更常见的那么为什么呢?正如我说的那样,当我们定义指针类型时,我们总是将星号放在名称本身之后,就像上面的例子那样,为什么会这样呢?
  • 关于这一点的另一个问题,我不太明白*pFunc周围括号的作用是什么. 我认为它们用于表示pFunc类型指针的某些东西,如果我们不做括号,那么签名的返回类型将是int*类型而不仅仅是int,我在这里是否正确?

好吧,另一件困扰我的事情就是语法的顺序.到目前为止,在所有typedef定义中,我们左边是类型,右边是别名.

typedef int number;

typedef struct
{
    int num;
} MyStruct;
Run Code Online (Sandbox Code Playgroud)

我们看到int和struct是左边的类型,我们给它们的别名是右边的.

现在,在指向函数typedef的指针中,它不遵循此约定.我们在右边的函数返回了类型,然后是括号中的typename,然后是括号中的参数类型,这个顺序让我在查看其他typedef如何处理相同的顺序后感到困惑.

  • 做这样的事情会不会更有意义?:

    typedef int (int,int) Func;所以我们首先得到一个typedef,我们想要给别名的类型,在这种情况下是一个函数签名,它取2个int并返回一个int,然后在右边我们有别名.它会更有意义吗?这跟随其他的typedef顺序,我只是没有得到那么多的函数指针顺序..

  • 我的另一个问题:当我们指向一个函数时,它实际意味着什么?我知道我们可以使用别名来调用这个函数,但像变量这样的指针存储在一个内存地址中?什么是存储功能?
  • 最后,我已经读过关键字extern与指向函数的指针有关但无法理解这个关键字的作用,有人可以向我解释它的作用吗?

pat*_*pat 6

typedef使用用于声明类型作为通常会被用于声明值的相同语法.

例如,如果我们声明一个int被叫myInt,我们做:

int myInt;
Run Code Online (Sandbox Code Playgroud)

如果我们要声明一个名为myIntTypeint 的类型,我们只需添加typedef:

typedef int myIntType;
Run Code Online (Sandbox Code Playgroud)

我们可以声明一个函数myFunc,如下所示:

int myFunc(int a, int b);
Run Code Online (Sandbox Code Playgroud)

这告诉编译器我们可以调用具有该名称和签名的实际函数.

我们还可以通过以下方式声明函数类型myFuncType:

typedef int myFuncType(int a, int b);
Run Code Online (Sandbox Code Playgroud)

我们可以这样做:

myFuncType myFunc;
Run Code Online (Sandbox Code Playgroud)

这相当于之前的声明myFunc(虽然很少使用这种形式).

功能不是传统值; 它表示带有入口点地址的代码块.像上面那样的函数声明是隐含的extern; 他们告诉编译器命名的东西存在于其他地方.但是,您可以获取函数的地址,该函数称为函数指针.函数指针可以指向具有正确签名的任何函数.通过在类型/值的名称前加上a来声明指针*,因此,我们可以尝试:

int *myFuncPtr(int a, int b);
Run Code Online (Sandbox Code Playgroud)

但这是不正确的,因为它*与the 绑定得更紧密int,所以我们声明这myFuncPtr是一个返回指针的函数int.我们必须在指针和名称周围放置parens以更改绑定顺序:

int (*myFuncPtr)(int a, int b);
Run Code Online (Sandbox Code Playgroud)

要声明一个类型,我们只需添加typedef到前面:

typedef int (*myFuncPtrType)(int a, int b);
Run Code Online (Sandbox Code Playgroud)

myInt上面的声明中,编译器为变量分配了一些内存.但是,如果我们在不同的编译单元中编写一些代码并想要引用myInt,我们需要将其声明为extern(在引用编译单元中),以便引用相同的内存.如果没有extern,编译器将分配第二个myInt,这将导致链接器错误(实际上这不是真的,因为C允许暂定定义,您不应该使用).

如上所述,函数不是正常值,并且总是隐式的extern.但是,函数指针正常值,extern如果您尝试从单独的编译单元引用全局函数指针,则需要该函数指针.

通常,您可以将extern全局变量(和函数)的s放入头文件中.然后,您可以将标头包含在包含这些变量和函数的定义的编译单元中,以便编译器可以确保类型匹配.