对于拥有其他语言经验、但初次接触 C/C++ 并准备开始 CUDA 编程的开发者来说,理解一些关键的 C/C++ 语法和编程模型将大有裨益。CUDA 实际上是在 C++ 基础上扩展而来的并行编程接口,因此在编写 CUDA 程序之前掌握这些要点能帮助我们更顺利地过渡到 GPU 编程。

C/C++ 在 CUDA 编程中的作用

CUDA 使用 C/C++ 作为编程基础语言。CUDA 源代码(通常使用 .cu 扩展名)会由 NVIDIA 提供的编译器 nvcc 按照 C++ 语法规则进行编译[](https://developer.nvidia.com/zh-cn/blog/cuda-programming-model-interface-cn/#:~:text=编译器前端根据 C%2B%2B 语法规则处理 CUDA 源文件。,C%2B%2B。 但是,设备代码仅完全支持 C%2B%2B 的一个子集,如 C%2B%2B 语言支持中所述。)。这意味着主机(Host)端代码可以使用完整的 C++ 功能,而设备(Device)端代码(内核函数等)则受到一定限制,只支持 C++ 的一个子集[](https://developer.nvidia.com/zh-cn/blog/cuda-programming-model-interface-cn/#:~:text=编译器前端根据 C%2B%2B 语法规则处理 CUDA 源文件。,C%2B%2B。 但是,设备代码仅完全支持 C%2B%2B 的一个子集,如 C%2B%2B 语言支持中所述。)。在实际编程中:

  • 内核函数定义: CUDA 内核(__global__ 函数)本质上是特殊标记的 C++ 函数,使用<<<>>>语法启动。这些函数运行在 GPU 上,但由 C++ 编写和调用。
  • 指针操作: CUDA 编程经常需要使用指针来管理内存,例如通过指针传递主机和设备的数据地址,以及在内核中通过指针访问数组元素。
  • 头文件组织: 和常规 C/C++ 项目一样,CUDA 工程通常使用头文件 (.h) 声明函数、内核和数据结构,在 .cu 源文件中实现它们。良好的头文件组织有助于将 CUDA 相关代码与其他 C/C++ 代码混合编译。

简而言之,CUDA 开发离不开 C/C++ 基础:你需要用 C/C++ 来编写 CPU 端控制逻辑,用扩展的 C++ 来编写 GPU 内核代码 [*](https://developer.nvidia.com/zh-cn/blog/cuda-programming-model-interface-cn/#:~:text=编译器前端根据 C%2B%2B 语法规则处理 CUDA 源文件。,C%2B%2B。 但是,设备代码仅完全支持 C%2B%2B 的一个子集,如 C%2B%2B 语言支持中所述。)。下面我们来梳理一些 CUDA 编程前必须掌握的 C/C++ 核心语法。

数据类型与变量

C/C++ 提供了丰富的基本数据类型用于声明变量。常见的数据类型及用途包括:

  • int 整型,一般占用32位,用于循环计数、数组索引等。
  • float 单精度浮点数(32位),CUDA 中常用来表示GPU上的实数计算。
  • double 双精度浮点数(64位),在需要更高精度的计算时使用(注意某些GPU对其计算性能较低)。
  • char 字符类型(1字节),可用于存储字符或小整数。
  • bool 布尔类型,取值为truefalse

在 C/C++ 中声明变量需要指定类型,例如:

int a = 10;
float b = 3.14f;
double c = 3.14159;
char d = 'A';
bool flag = true;

上述代码定义了不同类型的变量并赋初值。在 CUDA 编程中,我们会经常看到诸如 int N; float *x; 等变量声明,用于设置数组大小 (N) 或定义指向数据的指针 (x) 等。例如,在编写内核函数参数时,需要指明类型(如 int n, float a),以让编译器知道数据的大小和含义。

指针与数组的关系,指针算术

指针 是 C/C++ 中的独特概念,用于保存内存地址。数组与指针关系密切:在大多数表达式中,数组名为指向其第一个元素的指针。这意味着我们可以用指针来遍历或操作数组。

Ge Yuxu • AI & Engineering

脱敏说明:本文所有出现的表名、字段名、接口地址、变量名、IP地址及示例数据等均非真实,仅用于阐述技术思路与实现步骤,示例代码亦非公司真实代码。示例方案亦非公司真实完整方案,仅为本人记忆总结,用于技术学习探讨。
    • 文中所示任何标识符并不对应实际生产环境中的名称或编号。
    • 示例 SQL、脚本、代码及数据等均为演示用途,不含真实业务数据,也不具备直接运行或复现的完整上下文。
    • 读者若需在实际项目中参考本文方案,请结合自身业务场景及数据安全规范,使用符合内部命名和权限控制的配置。

Data Desensitization Notice: All table names, field names, API endpoints, variable names, IP addresses, and sample data appearing in this article are fictitious and intended solely to illustrate technical concepts and implementation steps. The sample code is not actual company code. The proposed solutions are not complete or actual company solutions but are summarized from the author's memory for technical learning and discussion.
    • Any identifiers shown in the text do not correspond to names or numbers in any actual production environment.
    • Sample SQL, scripts, code, and data are for demonstration purposes only, do not contain real business data, and lack the full context required for direct execution or reproduction.
    • Readers who wish to reference the solutions in this article for actual projects should adapt them to their own business scenarios and data security standards, using configurations that comply with internal naming and access control policies.

版权声明:本文版权归原作者所有,未经作者事先书面许可,任何单位或个人不得以任何方式复制、转载、摘编或用于商业用途。
    • 若需非商业性引用或转载本文内容,请务必注明出处并保持内容完整。
    • 对因商业使用、篡改或不当引用本文内容所产生的法律纠纷,作者保留追究法律责任的权利。

Copyright Notice: The copyright of this article belongs to the original author. Without prior written permission from the author, no entity or individual may copy, reproduce, excerpt, or use it for commercial purposes in any way.
    • For non-commercial citation or reproduction of this content, attribution must be given, and the integrity of the content must be maintained.
    • The author reserves the right to pursue legal action against any legal disputes arising from the commercial use, alteration, or improper citation of this article's content.

Copyright © 1989–Present Ge Yuxu. All Rights Reserved.