-
Rust 相比 C/C++ 在内存安全方面的优势,以及大厂选择 Rust 替代 C/C++ 的原因,可以从技术特性、安全模型、生态发展和业务需求等角度深入分析:一、Rust 如何实现内存安全?Rust 通过以下核心机制从语言层面杜绝内存安全问题:1. 所有权(Ownership)系统核心规则:每个值有唯一所有者:所有权转移时,旧所有者失效(类似“移动语义”)。离开作用域时自动释放内存:无需手动调用 free 或 delete。示例:let s1 = String::from("hello"); let s2 = s1; // 所有权从 s1 转移到 s2,s1 失效 // println!("{}", s1); // 编译错误:s1 已失效 优势:避免悬垂指针(Dangling Pointer)和重复释放(Double Free)。2. 借用(Borrowing)与生命周期(Lifetime)借用规则:可变借用与不可变借用互斥:同一时间只能有一个可变借用或多个不可变借用。生命周期标注:编译器强制检查引用的有效性,确保引用不会超出数据的作用域。示例:fn print_str(s: &str) { println!("{}", s); } let s = String::from("world"); print_str(&s); // 不可变借用,s 仍可用 优势:避免空指针解引用(Null Pointer Dereference)和数据竞争(Data Race)。3. 类型系统与模式匹配枚举(Enum)与模式匹配:强制处理所有可能状态,避免未定义行为。enum Option<T> { Some(T), None, } let x: Option<i32> = Some(5); match x { Some(v) => println!("Value: {}", v), None => println!("No value"), // 必须处理 None 情况 } 优势:杜绝空指针异常(类似 C++ 的 std::optional,但更严格)。4. 无垃圾回收(GC)的内存安全Rust 通过所有权和借用规则在编译时管理内存,无需运行时 GC,兼顾性能和安全性。二、大厂为何选择 Rust 替代 C/C++?1. 降低安全漏洞风险C/C++ 的痛点:内存错误(如缓冲区溢出、空指针解引用)是安全漏洞的主要来源(如 Heartbleed、Log4j 等)。Rust 的优势:从语言层面消除内存安全问题,减少安全审计成本。案例:Mozilla Firefox:用 Rust 重写部分关键组件(如 CSS 引擎),减少崩溃和漏洞。Microsoft:在 Windows 内核和安全组件中引入 Rust,降低攻击面。2. 提升开发效率与可维护性C/C++ 的痛点:手动内存管理、复杂指针操作和头文件依赖导致开发效率低。Rust 的优势:现代工具链:Cargo 包管理器、内置测试框架、文档生成工具。清晰的错误处理:通过 Result 和 Option 强制处理错误,避免未捕获异常。案例:Dropbox:用 Rust 重写文件同步核心模块,减少 30% 的代码量。Discord:用 Rust 重写后端服务,提升性能并降低资源占用。3. 性能与安全兼顾C/C++ 的优势:直接内存操作和低级控制,适合高性能场景。Rust 的优势:零成本抽象:高级特性(如迭代器、闭包)编译后与 C 性能相当。无 GC 停顿:适合实时系统(如游戏引擎、嵌入式设备)。案例:Figma:用 Rust 重写渲染引擎,性能提升 10 倍。AWS Lambda:用 Rust 实现高性能运行时,冷启动时间缩短。4. 生态与社区支持Rust 的生态:WebAssembly:Rust 是 WebAssembly 的首选语言之一,用于高性能前端开发。区块链:Solana、Polkadot 等区块链项目用 Rust 实现。操作系统:Redox OS、Tock OS 等系统级项目。大厂投入:Google:探索 Rust 替代 Android 系统中的 C/C++。Amazon:在 AWS 中广泛使用 Rust,并开源工具链。三、Rust 与 C/C++ 的对比总结维度RustC/C++内存安全编译时强制检查,杜绝内存错误依赖开发者手动管理,易出错性能零成本抽象,与 C 相当直接内存操作,高性能开发效率现代工具链、清晰错误处理手动内存管理、复杂构建系统生态WebAssembly、区块链、系统级开发游戏引擎、操作系统、嵌入式学习曲线较陡峭(所有权、生命周期)较陡峭(指针、内存管理)四、结论Rust 通过所有权系统、借用规则和生命周期检查,从语言层面解决了 C/C++ 的内存安全问题,同时保持高性能和低级控制能力。大厂选择 Rust 的核心原因包括:降低安全风险:减少内存错误导致的漏洞。提升开发效率:现代工具链和清晰的错误处理。性能与安全兼顾:适合高性能场景(如系统级开发、区块链)。生态与社区支持:广泛用于新兴领域(如 WebAssembly、区块链)。尽管 Rust 的学习曲线较陡峭,但其长期收益(如安全性、可维护性)使其成为 C/C++ 的有力替代者,尤其在安全敏感和高性能要求的场景中。
-
产品名称:MDC 610软件版本:MDC 610 1.99.102-0000000 问题现象(问题描述):摄像头程序在编译机上编译通过但是在MDC上显示Segmentation fault故障后已采取的措施:/示例代码:如下这是.c文件#include <iostream>#include <vector>#include <cstdint>#include <cstring>#include "camera.h" // 声明 CameraInit、CameraWaitEvents、CameraGetData、CameraData#include "ascend_hal.h" // 声明全局 halMbufFreeusing mdc::camera::CameraInit;using mdc::camera::CameraWaitEvents;using mdc::camera::CameraGetData;using mdc::camera::CameraData;int main(int argc, char* argv[]){ // 默认参数 uint32_t camId = 21; int32_t timeoutWait = 1000; int32_t timeoutGet = 1000; // 简单命令行解析 for (int i = 1; i < argc; ++i) { if (std::strcmp(argv[i], "--camera") == 0 && i+1 < argc) { camId = static_cast<uint32_t>(std::stoi(argv[++i])); } else if (std::strcmp(argv[i], "--wait-timeout") == 0 && i+1 < argc) { timeoutWait = std::stoi(argv[++i]); } else if (std::strcmp(argv[i], "--get-timeout") == 0 && i+1 < argc) { timeoutGet = std::stoi(argv[++i]); } else { std::cerr << "Usage: " << argv[0] << " [--camera ID] [--wait-timeout ms] [--get-timeout ms]\n"; return -1; } } // 1. 初始化摄像头 std::vector<uint32_t> initList = { camId }; int32_t ret = CameraInit(initList); if (ret != 0) { std::cerr << "CameraInit failed: " << ret << "\n"; return -1; } // 2. 等待事件 auto ready = CameraWaitEvents(timeoutWait); if (ready.empty()) { std::cerr << "No camera event\n"; return -1; } // 3. 获取数据 std::vector<CameraData> frames; ret = CameraGetData(camId, frames, timeoutGet); if (ret != 0 || frames.empty()) { std::cerr << "CameraGetData failed: " << ret << "\n"; return -1; } // 4. 打印第一帧信息 —— 替换下列字段为实际名称 CameraData &f = frames[0]; std::cout << "Camera ID: " << /* f.realCameraIdField */ 0 << "\n"; std::cout << "Timestamp: " << /* f.realTimestampField */ 0 << "\n"; std::cout << "Image size: " << /* f.realImgSizeField */ 0 << "\n"; std::cout << "Meta size: " << /* f.realMetaSizeField */ 0 << "\n"; // 5. (可选)解析 metaBuf // const uint8_t* meta = f.realMetaBufPtr; // TODO // size_t msize = f.realMetaSizeField; // TODO // for (size_t off = 0; off + 1 < msize; off += 2) { // uint16_t word = (uint16_t(meta[off]) << 8) | uint16_t(meta[off+1]); // std::cout << "0x" << std::hex << word << " "; // } // std::cout << std::dec << "\n"; // 6. 释放缓冲 for (auto &d : frames) { // TODO: 替换为实际 buf 指针成员 // ::halMbufFree(d.realImgBufPtr); // ::halMbufFree(d.realMetaBufPtr); } return 0;}这是CMakeLists.txtcmake_minimum_required(VERSION 3.10)project(camera_example CXX)# 读取交叉编译环境变量if(DEFINED ENV{CC}) set(CMAKE_C_COMPILER $ENV{CC})endif()if(DEFINED ENV{CXX}) set(CMAKE_CXX_COMPILER $ENV{CXX})endif()if(DEFINED ENV{SYSROOT}) set(CMAKE_SYSROOT $ENV{SYSROOT})endif()# 计算交叉编译器自带 include 路径get_filename_component(CLANG_BIN_DIR ${CMAKE_CXX_COMPILER} DIRECTORY)get_filename_component(CROSS_ROOT ${CLANG_BIN_DIR} DIRECTORY)set(CROSS_INCLUDE_DIR ${CROSS_ROOT}/include)# 通用编译/链接选项set(COMMON_FLAGS -O2 --target=aarch64-linux-gnu --sysroot=${CMAKE_SYSROOT})add_compile_options(${COMMON_FLAGS})add_link_options (${COMMON_FLAGS})# 生成可执行add_executable(camera_example camera_example.cpp)# 包含头文件路径target_include_directories(camera_example PRIVATE ${CROSS_INCLUDE_DIR} ${CMAKE_SYSROOT}/usr/include ${CMAKE_SYSROOT}/usr/include/driver)# 链接库路径target_link_directories(camera_example PRIVATE ${CMAKE_SYSROOT}/usr/lib64)# 链接 SDK 库(根据实际库名调整)find_library(LIB_CAMERA NAMES mdc_camera camera PATHS ${CMAKE_SYSROOT}/usr/lib64)find_library(LIB_MBUF NAMES mdc_mbuf PATHS ${CMAKE_SYSROOT}/usr/lib64)if(NOT LIB_CAMERA OR NOT LIB_MBUF) message(FATAL_ERROR "找不到 SDK 库 (libcamera.so / libmdc_camera.so 或 libmdc_mbuf.so)")endif()target_link_libraries(camera_example PRIVATE ${LIB_CAMERA} ${LIB_MBUF})这是Makefile文件# Makefile —— 读取环境变量:CC, CXX, SYSROOTSRC := camera_example.cppTARGET := camera_example# 交叉编译器根目录CROSS_ROOT := $(shell dirname $(shell dirname $(CXX)))CXXFLAGS := -O2 \ --target=aarch64-linux-gnu \ --sysroot=$(SYSROOT) \ -I$(SYSROOT)/usr/include \ -I$(SYSROOT)/usr/include/driver \ -I$(CROSS_ROOT)/includeLDFLAGS := --target=aarch64-linux-gnu \ --sysroot=$(SYSROOT) \ -L$(SYSROOT)/usr/lib64 \ -lmdc_camera \ -lmdc_mbufall: $(TARGET)$(TARGET): $(SRC)$(CXX) $(CXXFLAGS) $< -o $@ $(LDFLAGS)clean:rm -f $(TARGET).PHONY: all clean
yd_251998187
发表于2025-06-03 11:35:33
2025-06-03 11:35:33
最后回复
yd_251998187
2025-06-16 22:14:57
331 17 -
请问官方组委会能提供一份参赛获奖证明吗,我们这边在申请奖学金,谢谢
-
[2025/5/20 20:17:41] Unable to get configuration for editor.editContextMenu, please check if it's valid configuration[2025/5/20 20:17:43] WeCode-DB stopping error occurred, exit code: 1[2025/5/20 20:17:48] WeCode-DB starting error: Cannot read properties of null (reading 'pid')[2025/5/20 20:17:48] Huawei C/C++ Error:TypeError: Cannot read properties of null (reading 'pid')
-
不是很清楚提交文件的目录结构,所以想参考一下提交样例
-
CodeArts的Java版本和C/C++和ShellRemote是一个安装包吗, 为啥我下载这三个的安装包,安装下来都是一个软件呢?
-
在安装 VS Code时老是说有错误,主要有:一是下载的code.deb文件图标上老是有个锁,二是安装时提示:“code.deb 并非 Debian 格式的包文件”。不知道这是什么原因,有哪位高手能指点一下吗?
-
一 C中的类型转换在C语语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不⼀致时等场景,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型转换和显式强制类型转换。隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败显式强制类型转化:需要用户自己去显示在变量前用括号指定要转换的类型并不是任意类型之前都支持转换,两个类型支持转换需要有⼀定关联性,也就是说转换后要有⼀定的意义,两个毫无关联的类型是不支持转换的。#include<stdio.h>#include<stdlib.h>int main(){int i = 1;// 隐式类型转换// 隐式类型转换主要发⽣在整形和整形之间,整形和浮点数之间,浮点数和浮点数之间double d = i;printf("%d, %.2f\n", i, d);int* p = &i;// 显⽰的强制类型转换// 强制类型转换主要发⽣在指针和整形之间,指针和指针之间int address = (int)p;printf("%p, %d\n", p, address);// malloc返回值是void*,被强转成int*int* ptr = (int*)malloc(8);// 编译报错:类型强制转换:⽆法从“int* ”转换为“double”// 指针是地址的编号,也是⼀种整数,所以可以和整形互相转换 // 但是指针和浮点数毫⽆关联,强转也是不⽀持的 // d = (double)p;return 0;}二. C++中的类型转换C++兼容C,所以C支持的隐式类型转换和显式强制类型转换C++都支持。C++还支持内置类型到自定义类型之间的转换,内置类型转成自定义类型需要构造函数的支持,自定义类型转成内置类型,需要一个operator类型()的函数去支持。C++还支持自定义类型到自定义类型之间的转换,需要对应类型的构造函数支持即可,比如A类型对象想转成B类型,则支持一个形参为A类型的B构造函数即可支持。三. C++显示强制类型转换3.1类型安全类型安全是指编程语言在编译和运行时提供保护机制,避免非法的类型转换和操作,导致出现一个内存访问错误等,从而减少程序运行时的错误。C语言不是类型安全的语言,C语言允许隐式类型转换,一些特殊情况下就会导致越界访问的内存错误,其次不合理的使用强制类型转换也会导致问题,比如一个int的指针强转成double访问就会出现越界。C++兼容C语言,支持隐式类型转换和强制类型转换,C++也不是类型安全的语言,C++提出4个显示的命名强制类型转换static_cast/reinterpret_cast/const_cast/dynamic_cast就是为了让类型转换相对而言更安全。void insert(size_t pos, char ch){// 这⾥当pos == 0时,就会引发由于隐式类型转换// end跟pos⽐较时,提升为size_t导致判断结束逻辑出现问题 // 在数组中访问挪动数据就会出现越界,经典的类型安全问题 int end = 10;while (end >= pos){// ...cout << end << endl; --end;}}int main(){insert(5, 'x');//insert(0, 'x');// 这⾥会本质已经出现了越界访问,只是越界不⼀定能被检查出来int x = 100;double* p1 = (double*)&x;cout << *p1 << endl;const int y = 0;int* p2 = (int*)&y;(*p2) = 1;// 这⾥打印的结果是1和0,也是因为我们类型转换去掉了const属性// 但是编译器认为y是const的,不会被改变,所以会优化编译时放到 // 寄存器或者直接替换y为0导致的cout << *p2 << endl;cout << y << endl;return 0;}3.2 C++中4个显示强制类型转换运算符static_cast用于两个类型意义相近的转换,这个转换是具有明确定义的,只要底层不包含const,都可以使用static_cast。reinterpret_cast用于两个类型意义不相近的转换,reinterpret是重新解释的意思,通常为运算对象的位模式提供较低层次上的重新解释,也就是说转换后对原有内存的访问解释已经完全改变了,非常的大胆。所以我们要谨慎使用,清楚知道这样转换是没有内存访问安全问题的。const_cast用于const类型到非const类型的转换,去掉了const属性,也是一样的我们要谨慎使用,否则可能会出现意想不到的结果。dynamic_cast用于将基类的指针或者引用安全的转换成派生类的指针或者引用。如果基类的指针或者引用时指向派生类对象的,则转换回派生类指针或者引用时可以成功的,如果基类的指针指向基类对象,则转换失败返回nullptr,如果基类引用指向基类对象,则转换失败,抛出bad_cast异常。其次dynamic_cast要求基类必须是多态类型,也就是基类中必须有虚函数。因为dynamic_cast是运行时通过虚表中存储的type_info判断基类指针指向的是基类对象还是派生类对象。int main(){//对应隐式类型转换--数据的解释意义没有改变double d = 12.34;int a = static_cast<int>(d);cout <<a << endl;int&& ref = static_cast<int&&>(a);//对应强制类型转换-—数据的解释意义已经发生改变int* pl = reinterpret_cast<int*>(a);//对应强制类型转换中有风险的去掉const属性//所以要注意加volatilevolatile const int b = 0;int* p2 = const_cast<int*>(&b);*p2² = 1;cout << b << endl;cout << *p2 << endl;return 0;}class A{public:virtual void f() {}int _a = 1;};class B :public A{public:int _b = 2;};void funl(A* pa){//指向父类转换时有风险的,后续访问存在越界访问的风险//指向子类转换时安全B* pbl = (B*)pa;cout << "pbl:"<< pb1 <<endl;cout << pbl->_a << endl;cout << pbl->_b << endl;pb1->_a++;pbl->_b++;cout << pbl->_a << endl;cout << pbl->_b << endl;}void fun2(A* pa){//dynamic_cast会先检查是否能转换成功(指向子类对象),能成功则转换,//(指向父类对象)转换失败则返回nullptrB* pbl = dynamic_cast<B*>(pa);if (pb1){cout << "pbl:" << pbl << endl;cout << pbl->_a << endl;cout << pbl->_b << endl;pb1->_a++;pb1->_b++;cout << pbl->_a << endl;cout << pbl->_b << endl;}else{cout <<"转换失败" <<endl;}}void fun3(A& pa){//转换失败,则抛出bad_cast异常try{B& pb1 = dynamic_cast<B&>(pa);cout << "转换成功" << endl;}catch (const exception& e){cout << e.what() << endl;}}int main(){A a;B b;//fun1(&a) ;//funl(&b) ;fun2(&a);fun2(&b);fun3(a);fun3(b);return 0;}四. RTTIRTTI的英文全称是"RuntimeTypeIdentification",中文称为"运行时类型识别",它指的是程序在运行的时候才确定需要用到的对象是什么类型的。用于在运行时(而不是编译时)获取有关对象的信息。RTTI主要由两个运算符实现,typeid和dynamic_cast;typeid主要用于返回表达式的类型,dynamic_cast前面已经讲过了,主要用于将基类的指针或者引用安全的转换成派生类的指针或者引用。typeid(e)中e可以是任意表达式或类型的名字,typeid(e)的返回值是typeinfo或typeinfo派生类对象的引用,typeinfo可以只支持比较等于和不等于,name成员函数可以返回c风格字符串表示对象类型名字,typeinfo的精确定义随着编译器的不同而略有差异,也就以为着同一个e表达式,不同编译器下,typeid(e).name()返回的名字可能是不一样的。typeinfo的文档如下:https://legacy.cplusplus.com/reference/typeinfo/kw=typeinfotypeid(e)时,当运算对象不属于类类型或者是一个不包含任何虚函数的类时,typeid返回的是运算对象的静态类型,当运算对象是定义了至少一个虚函数的类的左值时,typeid的返回结果直到运行时才会求得。#include<iostream>#include<string>#include<vector>#include<list>using namespace std;int main(){int a[10];int* ptr = nullptr;cout << typeid(10).name() << endl;cout << typeid(a).name() << endl;cout << typeid(ptr).name() << endl;cout << typeid(string).name() << endl;cout << typeid(string::iterator).name() << endl;cout << typeid(vector<int>).name() << endl;cout << typeid(vector<int>::iterator).name() << endl;return 0;// vs2019下的运⾏结果intint[10]int*class std::basic_string<char, struct std::char_traits<char>, classstd::allocator<char> >class std::_String_iterator<class std::_String_val<structstd::_Simple_types<char> > >class std::vector<int, class std::allocator<int> >class std::_Vector_iterator<class std::_Vector_val<structstd::_Simple_types<int> > >//gcc9。4下运行结果iA10_iPiNSt7__cxxll12basic_stringIcStllchar_traitsIcESaIcEEEN9__gnu_cxx17__normal_iteratorIPcNSt7__cxxll12basic_stringIcStllchar_traitsIcESaIcEEEEESt6vectorIiSaIiEEN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEE#include<iostream>using namespace std;class A{public:virtual void func() {}protected:int _a1 = 1;};class B : public A{protected:int _b1 = 2;};int main(){try{B* pb = new B;A* pa = (A*)pb;if (typeid(*pb) == typeid(B)){cout << "typeid(*pb) == typeid(B)" << endl;}// 如果A和B不是继承关系,则会抛bad_typeid异常if (typeid(*pa) == typeid(B)){cout << "typeid(*pa) == typeid(B)" << endl;}// 这⾥pa和pb是A*和B*,不是类类型对象,他会被当做编译是求值的静态类型运算// 所以这⾥始终是不相等的if (typeid(pa) == typeid(pb)){cout << "typeid(pa) == typeid(B)" << endl;}}catch (const std::exception& e){cout << e.what() << endl;}return 0;}后言这就是 C++类型转换。大家自己好好消化!今天就分享到这!感谢各位的耐心垂阅!咱们下期见!拜拜~———————————————— 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:https://blog.csdn.net/2301_81670477/article/details/146606784
-
将地面点进行栅格化处理,以Haf3dDetectionOut格式存储,并将其赋值为可视化对象for (auto obj : out->detectionOut3d) {mdc::visual::Object object3d;object3d.header.frameId = "lidar_front_node";object3d.objectId = obj.objectID;object3d.objectBoxCenter.x = obj.rect.center.x;object3d.objectBoxCenter.y = obj.rect.center.y;object3d.objectBoxCenter.z = obj.rect.center.z;object3d.objectBoxSize.x = obj.rect.size.x;object3d.objectBoxSize.y = obj.rect.size.y;object3d.objectBoxSize.z = obj.rect.size.z;object3d.classification = obj.cls;object3d.objectBoxOrientation = obj.rect.orientation;//航向角// object3d.textDisplay = "grid_points = ";// object3d.textDisplay += std::to_string(obj.contourPoints.size());objectArray3d.objectList.push_back(object3d);outputFile << obj.rect.center.x << " " << obj.rect.center.y << " " << obj.rect.center.z << std::endl;}终端打印有1800个障碍物,但可视化只能看到几十个,如何显示所有的障碍物?
-
1概述1.1案例介绍在云原生与远程协作成为主流的软件开发趋势下,开发环境的快速构建、一致性维护及跨团队共享已成为提升效率的关键挑战。C/C++开发因其对系统工具链(如编译器、调试器、第三方库)的高度依赖,环境配置复杂且易出错,传统的手动配置模式难以满足敏捷开发需求。此外,跨地域团队或开源协作场景中,环境差异常导致“本地正常、云端报错”等问题,严重影响交付效率。通过将C/C++开发环境预置为云主机镜像,开发者可一键获取标准化的开发环境,减少重复配置成本,同时为团队协作、CI/CD流水线提供底层支持,显著提升开发流程的可靠性与可复现性。本案例聚焦于利用华为云开发者空间功能(云主机),结合VS Code的IDE工具,定制包含C/C++全工具链(如GCC/Clang、CMake、Conan包管理器)、调试工具(GDB/LLDB)及常用依赖库的云主机镜像。该镜像可直接部署为云主机实例,开发者通过一键部署即可获得开箱即用的编程环境,无需手动安装配置。云主机的弹性资源特性(按需购买开发者专业会员)进一步支持高性能编译与测试场景,而镜像的版本化管理则确保环境更新可追溯、可回滚,与云平台的计算、存储服务无缝集成。1.2适用对象个人开发者高校学生1.3案例时间本案例总时长预计60分钟。1.4案例流程说明:登录云主机,终端Terminal命令安装编译工具链和调试工具,安装VS Code;在VS Code上编写实验代码,并运行测试实验结果;在开发者空间-工作台-我的镜像制作镜像,重置云主机,配置云主机自定义镜像,登录验证实验程序。1.5资源总览本案例预计花费总计0元。资源名称规格单价(元)时长(分钟)开发者空间(云主机)4vCPUs | 8GB RAM ARM UbuntuUbuntu 24.04 Server 定制版免费60VS Code1.97.2免费60实验环境搭建2 实验环境搭建2.1配置云主机登录开发者空间,参考“10分钟玩转云主机” 案例的2.2小节内容完成华为开发者空间云主机申请与配置,云主机配置参数如下:2.2安装编译工具链C/C++运行时环境需要依赖编译器(GCC/G++)和调试工具GDB。因此,在任务开始前我们首先需要确认云主机是否已经安装GCC/G++和GDB。云主机桌面右键,点击Open Terminal Here打开Terminal Emulator窗口。在窗口中输入如下命令进行验证:gcc --versiong++ --versiongdb --version如果云主机中未安装gdb,可通过如下命令进行部署:sudo apt update #更新软件包列表sudo apt install build-essential gdb -yVS Code安装部署3 VS Code安装部署3.1VS Code安装下载.deb在云主机Terminal Emulator窗口,可以通过命令行下载.deb安装Visual Studio Code:sudo wget -O code.deb https://vscode.download.prss.microsoft.com/dbazure/download/stable/e54c774e0add60467559eb0d1e229c6452cf8447/code_1.97.2-1739406006_arm64.deb注:这里使用wget命令下载的deb包会默认下载到当前目录,并且默认命名为code.deb。如果云主机类型是X86,可以通过以下命令下载:sudo wget -O code.deb https://vscode.download.prss.microsoft.com/dbazure/download/stable/e54c774e0add60467559eb0d1e229c6452cf8447/code_1.97.2-1739406807_amd64.deb安装VS Code下载完成后,使用 dpkg 命令来安装下载好的 .deb 包:sudo dpkg -i code.deb注:若在安装过程中遇到依赖问题,可使用以下命令修复依赖:sudo apt-get install -f运行VS Code安装完成后,可以在云桌面左下角所有应用程序 – 开发 – Visual Studio Code点击启动,也可以通过以下命令打开VS Code:code3.2 安装VS Code插件VS Code作为一个款强大的跨平台编辑器,为开发者提供了非常丰富的拓展插件。开发者可以打开VS Code扩展商店,点击插件管理图标,输入插件名称,点击install安装。插件介绍如下:C/C++:语法高亮、智能补全、代码跳转、调试支持(支持跨平台编译和多环境配置),所有 C/C++ 项目的开发基础,无需额外配置即可直接使用。C/C++ Extension Pack:代码编辑、调试、构建和格式化的核心功能,覆盖从代码编写到编译调试的全流程,尤其适合需要跨平台或依赖 CMake 的中大型项目。CMake Tools:集成 CMake 构建系统,支持自动化编译、调试和项目配置,简化跨平台项目管理,适用于复杂工程依赖的构建。Code Runner:一键运行代码片段或文件,支持快速测试和调试,无需手动配置编译命令,实时输出结果到终端。GitLens:增强 Git 功能,支持代码历史追溯、差异对比、作者信息查看,协作开发时快速定位代码变更和提交记录。C/C++ Snippets:快速插入常用代码模板(如循环、条件语句),减少重复编码。3.3 配置开发环境在云主机左下角打开File Manager。在File Manager左上角文件 – 新建文件夹,编辑名称创建所需要的工程目录。点击VS Code左上角File – OpenFolder,选择上一步新建的工程目录cpp_project。在VS Code中,新建 main.cpp 文件,编写示例代码:#include <iostream>using namespace std;int main() {printf("欢迎来到华为云开发者空间!");return 0;}配置构建任务在VS Code中,按 Ctrl+Shift+P 输入 Tasks: Configure Task,选择 Create tasks.json from template → Others。完成上述步骤后,工程目录中自动增加了配置文件tasks.json。双击打开并修改tasks.json:{// See https://go.microsoft.com/fwlink/?LinkId=733558// for the documentation about the tasks.json format"version": "2.0.0","tasks": [{"label": "build","type": "shell","command": "g++","args": ["-g", "-o", "main", "main.cpp"],"group": {"kind": "build","isDefault": true}}]}配置launch.json点击左侧调试图标(或按 Ctrl+Shift+D),选择 Create a launch.json file → C++ (GDB/LLDB)。修改 launch.json:{// Use IntelliSense to learn about possible attributes.// Hover to view descriptions of existing attributes.// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387"version": "0.2.0","configurations": [{"name": "C++ Debug","type": "cppdbg","request": "launch","program": "${workspaceFolder}/main","args": [],"stopAtEntry": false,"cwd": "${workspaceFolder}","environment": [],"externalConsole": false,"MIMode": "gdb","preLaunchTask": "build"}]}修改完成后,左侧工具栏会发生变化如下:编译与调试开发者可以通过左上角的C++ Debug按钮启动编译调试。也可以通过如下方式进行编译调试:编译:按 Ctrl+Shift+B 或运行终端命令: g++ -g -o main main.cpp调试:按 F5 启动调试,支持断点、变量监视等功能。3.4 常见问题解决问题 1:编译器未找到确保已安装 build-essential,检查 PATH 环境变量:echo $PATH问题 2:调试器无法启动确保已安装 gdb:sudo apt install gdb -y问题 3:VS Code 插件安装失败尝试更换网络环境,或手动下载 .vsix 文件安装。4 镜像制作与使用4.1 制作镜像在制作镜像前,我们首先要确认云主机已处于关机状态。在开发者空间,工作台 – 我的云空间模块,点击我的镜像,进入镜像编辑页面。点击制作镜像,设置镜像名称、镜像描述、选择镜像源。点击确定,开发者空间将自动开始制作镜像,制作镜像需要30分钟,请耐心等待。镜像制作完成后,状态变为“就绪”状态。4.2 使用镜像在加载镜像前,需要先确认云主机当前是可配置状态。点击配置云主机,选择私有镜像,下拉选项中选择之前已经制作好的镜像,点击安装按钮。进入桌面,自定义镜像开始加载。等待镜像加载(约3-5分钟),进入云桌面,Terminal Emulator窗口通过code命令启动VS Code,点击运行程序,这里显示程序运行成功。至此,基于开发者空间,定制C/C++开发环境云主机镜像案例内容全部完成。更多案例,点击案例中心查看~
-
请问最终代码会人工审查吗,之前出现过用到未来报文但没有报错的情况。
-
在使用 snprintf 函数时,不需要手动添加 \0,因为 snprintf 会自动在生成的字符串末尾添加空字符 \0,前提是缓冲区大小足够容纳字符串内容以及终止符。具体说明:函数行为:snprintf 的作用是将格式化的字符串写入指定的缓冲区,并确保字符串以 \0 结尾(只要缓冲区大小允许)。如果缓冲区大小不足以容纳整个格式化字符串(包括终止符 \0),snprintf 会截断字符串,但仍会确保在截断后的字符串末尾添加 \0。返回值:snprintf 返回的是理论上需要的缓冲区大小(不包括终止符 \0)。如果返回值大于或等于指定的缓冲区大小(n),说明缓冲区不足以容纳整个字符串,此时生成的字符串会被截断。例子:#include <stdio.h> int main() { char buffer[10]; int len = snprintf(buffer, sizeof(buffer), "Hello, World!"); printf("Buffer: '%s'\n", buffer); // 输出: Buffer: 'Hello, Wo' printf("Returned length: %d\n", len); // 输出: Returned length: 13 return 0; } 在这个例子中,缓冲区大小为 10,snprintf 只会写入前 9 个字符(Hello, Wo),并在末尾添加 \0。返回值 13 表示如果缓冲区足够大,完整字符串的长度(不包括 \0)是 13。注意事项:如果缓冲区大小过小,snprintf 会截断字符串,但依然会保证字符串以 \0 结尾。如果需要完整存储字符串,应根据返回值调整缓冲区大小。总结:使用 snprintf 时,不需要手动添加 \0,函数会自动处理。但需要确保缓冲区大小足够,或者根据返回值动态调整缓冲区大小以避免截断。
-
1.硬件平台:MDC 6102.软件版本:MDC_Development_Studio-3.0.002-0000000-Ubuntu203.问题描述:已按照产品文档进行交叉编译环境、SCFI环境等配置(SCFI例程已成功在计算平台上运行),当使用MDS软件或直接使用scfirepo showrpm时,均提示找不到RPM库4.一点疑问:产品文档中描述“确认当前工程所关联SDK中的交叉编译环境已配置lyum源”,但仅有计算平台的第三方库安装方式之一涉及到lyum,而交叉编译环境的第三方库完全不涉及lyum,该如何配置
-
1.产品名称:MDC 6102.软件版本:MDC_Development_Studio-3.0.002-0000000-Ubuntu203.问题现象:已按照产品文档完成交叉编译环境、第三方库、SCFI等相关配置,使用MDS软件创建SCFI工程,右键该工程打开属性配置窗口后,在“Build & Execution > RPM Management”中输入当前开发机的root密码,提示无法找到rpm库。 4.已采取的措施:交叉编译、SCFI的环境变量已加载,交叉编译环境的第三方库已安装,计算平台的第三方库也已安装。5.主要疑问:文档中提到“确认当前工程关联SDK中的交叉编译环境已配置lyum源”,但在产品文档中,仅计算平台的第三方库安装有一种安装方式是采用lyum_install.sh脚本的,而交叉编译环境的第三方库安装并未涉及lyum,请问如何解决当前问题。
-
上合赛区复赛个人信息收集问卷短信上写的是4月3日下午两点前进行填写,但是目前(4月3日中午12点)发现问卷已经无法进行填写了,想询问一下如何解决。
上滑加载中
推荐直播
-
用码道,让你的AI作品三步上朋友圈2026/08/04 周二 19:00-20:00
林华鼎-华为云AI开发者运营负责人
从入门 · 到做AI应用 · 到企业级开发。不教编程,只教用AI · 零代码、有产出、能带走、可炫耀 · 每课人人动手实操
回顾中 -
华为云码道Agent集成与鸿蒙实战2026/08/11 周二 19:00-21:00
王一男-华为云码道产品规划专家;李炎-华为云码道产品专家;彭江敏-华为云鸿蒙端云一体化开发专家
本次直播带你解读华为云码道7月份产品新特性、新功能。更有专家演示码道Agent Space × 钉钉机器集成实战,从0到1打通消息通道;码道鸿蒙端云一体化实战,快速搭建员工签到系统。
回顾中 -
基于华为云码道,构建你的定制化AI搭子2026/08/14 周五 09:00-11:30
明亮-华为云开发者发展与支持部部长
本期直播将向您全面介绍华为云码道产品,并基于码道手把手教你部署自己的定制化AI陪伴搭子。
回顾中
热门标签