extern 关键字

news2024/10/5 1:15:19

参考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.coloradmin.cn/o/421661.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

k8s调度器扩展(Scheduler Framework)、源码编译及部署

因为研究的需要&#xff0c;需要对K8S的调度器进行扩展&#xff0c;本文主要讲解了k8s调度器扩展的一个流程&#xff0c;其中包含源码修改、源码编译、调度器配置以及部署和本人所踩的一些坑&#xff0c;使用的k8s的版本为1.23.1 1.下载源码&#xff0c;在此选择v1.23.1版本&a…

大数据之Spark部署模式

文章目录前言一、Spark的部署模式&#xff08;一&#xff09;Client模式1. Standalone集群下的Client模式2. Spark On Yarn集群下的Client模式&#xff08;二&#xff09;Cluster模式1. Standalone集群下的Cluster模式2. Spark On Yarn集群下的Cluster模式总结前言 #博学谷IT学…

c++头文件、namespace 的理解、#include、 编译模式

namespace C 命名空间 | 菜鸟教程 C命名空间&#xff08;名字空间&#xff09;详解 作用&#xff1a;多写在头文件中&#xff0c;用于多个头文件的变量函数出现重命名。 namespace中可以定义变量&#xff0c;函数&#xff0c;类等等&#xff0c;也可以写声明&#xff0c;来…

牛客网 HJ28 素数伴侣【二分图匹配,匈牙利算法】困难

描述 若两个正整数的和为素数&#xff0c;则这两个正整数称之为“素数伴侣”&#xff0c;如2和5、6和13&#xff0c;它们能应用于通信加密。现在密码学会请你设计一个程序&#xff0c;从已有的 N &#xff08; N 为偶数&#xff09;个正整数中挑选出若干对组成“素数伴侣”&am…

一种用于水位量测的浮子水位计

简介 浮子式水位传感器&#xff08;带水位显示&#xff09;是集机、电技术于一体的数字化传感器。通过输出轴的角度位移量转换成相应的数字量&#xff0c;可以高精度测量被测液位高度&#xff0c;能确认准确位置。具有断电记忆功能。 其工作原理就是&#xff1a;水位传感器测轮…

二叉搜索树(BSTree)

目录 一、二叉搜索树 二、二叉搜索树的接口及实现 1、二叉搜索树的查找 2、二叉搜索树的插入 3、二叉搜索树的删除 三、二叉搜索树的递归版本 本期博客主要分享二叉搜索树的底层实现。(主要是笔记&#xff0c;供自己复习使用&#x1f602;) 一、二叉搜索树 二叉搜索树(B…

Github创建组织(organization)

目录 前言 Github上创建组织的详细步骤 前言 创建 Github 组织&#xff08;Organization&#xff09;可以让你和你的团队共享代码&#xff0c;更好地管理和协作开发项目。Github 组织&#xff08;Organization&#xff09;是一个非常有用的工具&#xff0c;可以让开发者协同…

stm32cubemx IAP升级(一)

stm32cubemx IAP升级- Bootloader的制作 板卡&#xff1a;Nucleo-L412 平台&#xff1a;macbook pro 工具&#xff1a;vscode stm32cubemx stm32cubeProgramer cmake toolchain 分区 L412 自带128K的flash&#xff0c;所以我们可以这样分区&#xff0c; printf(“| flash pr…

crypto-js AES-CTR 实现密文前缀式局部解密细节 踩坑点

项目有需求&#xff0c;长明文经过AES-CTR模式加密后&#xff0c;在解密的时候&#xff0c;密文不能直接得到&#xff0c;每次通过某些方法尝试后&#xff0c;只能得到一块密文&#xff08;按顺序&#xff09;&#xff0c;所以只能一块一块的拼接解密。在使用crypto-js这个库的…

WooCommerce可扩展性:如何扩大您的WooCommerce商店

有了合适的人和技术&#xff0c;WooCommerce可扩展性绝对是很大的&#xff01; 事实上&#xff0c;使用WooCommerce作为您的电子商务平台&#xff0c;您的在线商店的规模可以与您的目标和愿望一样大&#xff01; 根据自定义模板开发高性能品牌电子商务网站 全球超500万个电商…

高效办公——Excel表格-02篇(if函数常见用法 + 条件格式的使用)

高效办公——Excel表格-02篇&#xff08;if函数常见用法 条件格式的使用&#xff09;1. if单条件简单用法1.1 简单需求1.2 实现方法2. if多条件使用(if-else的情况)3. if多条件使用(if(A && B)的情况)3.1 简单需求3.2 实现需求4. if多条件使用(if(A || B)的情况)5. 条…

亚马逊云科技“三步走”,实现区块链应用的快速开发

作为数字技术的代表之一&#xff0c;区块链技术正在被越来越多的企业所重视&#xff0c;并被引入到各行业的数字化转型中。根据中国通信院数据显示&#xff0c;目前中国区块链应用场景主要以金融和互联网为主&#xff0c;但应用范围呈现不断拓展的态势&#xff0c;政务数据共享…

day10_oop

今日内容 零、 复习昨日 一、面向对象的概念 二、面向对象编程 三、内存图 零、 复习昨日 晨考复习… 一、作业 package com.qf.homework;import java.util.Arrays;/*** --- 天道酬勤 ---** author QiuShiju* desc* ----------------* 引用数据类型的默认初始值null*/ public …

Nginx 正向代理、方向代理、端口转发

正向代理就是客户端代理&#xff0c;代理客户端&#xff0c;服务端不知道实际发起请求的客户端 正向代理中&#xff0c;proxy和client一般同一个lan或者网络可达&#xff0c;server与client一般不可达&#xff08;缓存场景除外&#xff09; 正向代理类似一个跳板机&#xff0c…

下一个“AI王炸”,别只盯着OpenAI,DeepMind也在憋大招

过去几个月&#xff0c;OpenAI风头无两&#xff0c;各大科技公司争先恐后地跟进大语言模型&#xff08;LLM&#xff09;这一技术路线。 对比之下&#xff0c;OpenAI的老对手DeepMind&#xff0c;显得有些低调和沉默。微软靠OpenAI打了一场胜仗&#xff0c;而谷歌推出的Bard翻了…

【c++初阶】命名空间的定义

命名空间的定义一.缺陷二.namespace和::三.访问namespace四.一些注意1.工程里标准库的展开2.命名域的小技巧一.缺陷 在c语言中&#xff0c;如果我们同时定义一个全局变量和一个局部变量并且使用同一个名称的话&#xff0c;是可以编过的&#xff08;因为全局和局部是属于两个不同…

云原生_kubernetes(k8s)_pod介绍以及配置信息说明

目录 一、Pod介绍 1、Pod结构 2、Pod定义 二、Pod配置 1、基本配置 2、镜像拉取 3、启动命令 4、环境变量 5、端口设置 6、资源配额 一、Pod介绍 1、Pod结构 每个Pod中都可以包含一个或者多个容器&#xff0c;这些容器可以分为两类&#xff1a; 用户程序所在的容器&…

网络编程(第二章: TCPUDP基础模型)

TCP/UDP&#xff08;服务器、客户端源码&#xff09; [(12条消息) 网络编程(4.7作业)(TCP/UDP源代码)_m0_37565374的博客-CSDN博客]: 一. 套接字 socket 1.概念 最早的socket和消息队列、共享内存&#xff0c;管道一致只能实现一台主机中的多个进程间通信。后期加入了TCP/I…

云日记个人中心项目思路

验证昵称的唯一性 前台&#xff1a; 昵称文本框的失焦事件 blur 1. 获取昵称文本框的值 2. 判断值是否为空 如果为空&#xff0c;提示用户&#xff0c;禁用按钮&#xff0c;并return 3. 判断昵称是否做了修改…

一文详解:linux部署jenkins,一键构建并部署springboot至第三方服务器

目录 1、下载jenkins 2、 启动jenkins 3、访问jenkins 4、在当前Linux上安装maven 4.1、更新wget命令&#xff0c;支持https请求 4.2、下载maven 4.3、解压安装maven 4.4、配置maven环境变量 4.5、maven配置阿里云镜像 4.6、配置maven依赖下载的位置 5、Linux安装Gi…