当前位置: 首页 > article >正文

extern 关键字

参考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生成的目标代码中找到此函数。

示例:

 

extern “C”

参考关于“#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 <vector>
#include <torch/serialize/tensor.h>
#include <ATen/cuda/CUDAContext.h>

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

问题:extern 变量

在一个源文件里定义了一个数组: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来声明。


http://www.kler.cn/news/10652.html

相关文章:

  • 「Vue面试题」Vue项目中有封装过axios吗?主要是封装哪方面的?
  • 【分布式技术专题】「单点登录技术架构」一文带领你好好对接对应的Okta单点登录实现接口服务的实现落地
  • DHTMLX Gantt入门使用教程【引入】:如何开始使用 dhtmlxGantt
  • 51单片机和32单片机有什么区别?该从哪个开始入门学习?
  • 2023-03-18青少年软件编程(C语言)等级考试试卷(二级)解析
  • DStream是什么?怎样对DStream进行操作?
  • JS 正则匹配(RegExp)
  • UniverSeg:通用医学图像分割模型来了!
  • Python3 os.symlink() 方法、Python 质数判断
  • 常见面试题之MQ篇
  • 【 SpringBoot 配置⽂件 】
  • 在window上安装python
  • 迈入Java,一文告诉你学习Java的原因
  • 二、Java 并发编程(5)
  • 【算法】【数组与矩阵模块】求数组中从未出现的最小正整数(含拓展思路)
  • FFMPEG: [ API ] >打开/关闭一个输入文件
  • Shiro概述
  • 9.1 相关分析
  • 定点乘法器优化---华为杯
  • Python求矩阵的特征值和广义特征值
  • 认识C++《共、枚、指1》
  • 什么是雪花算法?啥原理?
  • GORM 基础 -- Associations
  • 这7种常见的JavaScript错误,你知道吗?
  • 规模化敏捷框架:Scrum@Scale
  • 他98年的,我真的玩不过他...
  • 请我为详细讲解C11的新增原子操作
  • Oracle-主备切换问题(BUG-31747989)
  • 论文阅读 - ANEMONE: Graph Anomaly Detection with Multi-Scale Contrastive Learning
  • 大数据 | 实验一:大数据系统基本实验 | MapReduce 初级编程