参考https://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777431.html
extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。此外extern也可用来进行链接指定。
也就是说extern有两个作用,第一个,当它与"C"一起连用时,如: extern "C" void fun(int a, int b);则告诉编译器在编译fun这个函数名时按着C的规则去翻译相应的函数名而不是C++的,C++的规则在翻译这个函数名时会把fun这个名字变得面目全非,可能是fun@aBc_int_int#%$也可能是别的,这要看编译器的"脾气"了(不同的编译器采用的方法不一样),为什么这么做呢,因为C++支持函数的重载啊,在这里不去过多的论述这个问题,如果你有兴趣可以去网上搜索,相信你可以得到满意的解释!
第二,当extern不与"C"在一起修饰变量或函数时,如在头文件中: extern int g_Int; 它的作用就是声明全局变量的作用范围的关键字,用法和声明函数一模一样,也就是这个变量他是从别人那里过来的,要通过链接找到。记住它是一个声明不是定义!也就是说B.cpp要引用A.cpp中定义的全局变量或函数时,它只要包含A.h即可,在编译阶段,模块B虽然找不到该函数或变量,但它不会报错,它会在连接时从模块A生成的目标代码中找到此函数。
示例:
参考关于“#ifdef __cplusplus” 和 " extern "C" 的问题_extern c cplusplus_踏莎行hyx的博客-CSDN博客
写的非常好!
总结一下:
原因在于:c编译和c++编译后得到的相同函数的起名规则是不一样的,导致链接的时候找不到人。
比如一个函数名叫f是用c编译的,那么生成的库文件中他的名字叫做 _f,如果使用c++编译那么得到编译后它叫做__Z1fv
如果该函数(或者说是源码文件)是c编译的,在编译好的.o文件中叫 _f,该函数在file1.c文件中,但如果我file2.cpp想要引用这个函数,我#include"file1.c" 这样行不通的,因为我file2.cpp使用c++编译,他找f()的时候是按__Z1fv去找,但在.o文件中他叫做 _f,所以是找不到的,此时我们要指定他按c的名字规则去找,这样才能找到。
注意:nvcc编译是按c的命名规则进行编译的,所以他的函数一定要使用c的命名规则进行查找!
记住一句话就行,如果该c文件是由c编译,那么对应头文件中函数声明也应该要用c编译,如果是cpp编译,那么对应函数声明也要用cpp编译
#ifndef _ATTENTION_CUDA_KERNEL
#define _ATTENTION_CUDA_KERNEL
#include
#include
#include
void attention_step1_forward_cuda(int N_q, int N_k, int M, int h, int hdim, const unsigned int n_max, at::Tensor q_tensor, at::Tensor k_tensor, at::Tensor index0_tensor, at::Tensor index1_tensor, at::Tensor attn_tensor);
void attention_step1_backward_cuda(int N, int M, int h, int hdim, const unsigned int n_max, at::Tensor grad_out_tensor, at::Tensor index0_tensor, at::Tensor index0_tensor_offsets, at::Tensor index1_tensor, at::Tensor index1_tensor_offsets, at::Tensor q_tensor, at::Tensor k_tensor, at::Tensor grad_q_tensor, at::Tensor grad_k_tensor);
void attention_step2_forward_cuda(int N, int M, int h, int hdim, int n_max, at::Tensor attn_tensor, at::Tensor v_tensor, at::Tensor index0_offsets_tensor, at::Tensor index1_tensor, at::Tensor output_tensor);
void attention_step2_backward_cuda(int N, int M, int h, int hdim, int n_max, at::Tensor grad_out_tensor, at::Tensor index0_tensor, at::Tensor index0_offsets_tensor, at::Tensor index1_tensor, at::Tensor index1_offsets_tensor, at::Tensor attn_tensor, at::Tensor v_tensor, at::Tensor grad_attn_tensor, at::Tensor grad_v_tensor);
#ifdef __cplusplus
extern "C" {
#endif
void attention_step1_forward_cuda_launcher(int N_q, int N_k, int M, int h, int hdim, const unsigned int n_max, const float *q, const float *k, const int *index0, const int *index1, float *attn);
void attention_step1_backward_cuda_launcher(int N, int M, int h, int hdim, const unsigned int n_max, const float *grad_out, const int *index0, const int *index0_offsets, const int *index1, const int *index1_offsets, const float *q, const float *k, float *grad_q, float *grad_k);
void attention_step2_forward_cuda_launcher(int N, int M, const int h, int hdim, int n_max, const float *attn, const float *v, const int *index0_offsets, const int *index1, float *output);
void attention_step2_backward_cuda_launcher(int N, int M, int h, int hdim, int n_max, const float *grad_out, const int *index0, const int *index0_offsets, const int *index1, const int *index1_offsets, const float *attn, const float *v, float *grad_attn, float *grad_v);
#ifdef __cplusplus
}
#endif
#endif
在一个源文件里定义了一个数组:char a[6];
在另外一个文件里用下列语句进行了声明:extern char *a;
请问,这样可以吗?
答案与分析:
1)、不可以,程序运行时会告诉你非法访问。原因在于,指向类型T的指针并不等价于类型T的数组。extern char *a声明的是一个指针变量而不是字符数组,因此与实际的定义不同,从而造成运行时非法访问。应该将声明改为extern char a[ ]。
2)、例子分析如下,如果a[] = "abcd",则外部变量a=0x61626364 (abcd的ASCII码值),*a显然没有意义
显然a指向的空间(0x61626364)没有意义,易出现非法内存访问。
3)、这提示我们,在使用extern时候要严格对应声明时的格式,在实际编程中,这样的错误屡见不鲜。
4)、extern用在变量声明中常常有这样一个作用,你在*.c文件中声明了一个全局的变量,这个全局的变量如果要被引用,就放在*.h中并用extern来声明。