C++ way to explore https:https://cdn.v2ex.com/navatar/6c34/0f25/1063_normal.png?m=1645243654 https:https://cdn.v2ex.com/navatar/6c34/0f25/1063_large.png?m=1645243654 2025-10-03T12:07:45Z Copyright © 2010-2018, V2EX 有没有什么工具可以统计 C++项目里标识符的使用情况? tag:www.v2ex.com,2025-10-03:/t/1163273 2025-10-03T12:09:45Z 2025-10-03T12:07:45Z gfbts member/gfbts 比如统计使用频率并排名

]]>
看到一些 C++ 或者 C#项目 驼峰和下划线一块用,为啥泥? tag:www.v2ex.com,2025-09-17:/t/1159892 2025-09-17T04:06:54Z 2025-09-17T19:18:47Z ksc010 member/ksc010 [求助] Linux 系统下动态库卸载后全局变量未重置的问题 tag:www.v2ex.com,2025-09-05:/t/1157377 2025-09-05T10:31:04Z 2025-09-06T20:10:33Z Ainokiseki member/Ainokiseki 我把代码封装成了.so
动态库给他们使用。他们会写很多测试 case ,每个 case 依次运行,运行时首先使用 dlopen 装载我的库,运行完毕后使用 dlclose 卸载。下一个 case 重新使用 dlopen 装载。

目前遇到的问题是,在第二次 dlopen 之后,我的库里的全局变量的值仍然是上一次运行之后剩下的。而我期望在 dlclose 之后,全局变量们应该被析构掉,在 dlopen 之后重新构造以及初始化。

我询问 AI 得到的信息是,dlclose 之后如果引用计数为 0 ,那么会进行我期望的析构过程。但是没有直接手段能查看引用计数。可能导致引用计数不为 0 的原因包括:多次 dlopen 只有一次 dlclose ;引用的其他动态库依赖了我的库。其中第一条我认为不可能,我通过断点和日志能确信只有一次 dlopen 和一次 dlclose 。第二条也不可能,我查看了所有动态库的依赖库,没有任何一个依赖我的库。

我在 dlclose 和 dlopen 的时候均进行了检查,两次 dlopen 和一次 dlclose 都是成功的,没有错误信息。

求问有没有大佬遇到过类似的情况,要被搞疯了。。。 ]]> 交叉编译 asop android adb 最新版的问题 tag:www.v2ex.com,2025-09-05:/t/1157237 2025-09-05T01:56:10Z 2025-09-06T00:03:50Z ChainLock member/ChainLock 目标:交叉编译 android adb,放到嵌入式板子上面执行

android 源码已经下载好

mkdir -p ~/.bin PATH="${HOME}/.bin:${PATH}" curl https://storage.googleapis.com/git-repo-downloads/repo > ~/.bin/repo chmod a+rx ~/.bin/repo repo init --partial-clone -b android-latest-release -u https://android.googlesource.com/platform/manifest repo sync -c -j8 

packages/modules/adb 目录下面新版的 asop 已经没有 Android.mk,只有 Android.bp

已经跟 chatgpt 对线了 3 天,依旧没有搞出来,望搞过来的大佬指点一下,必须得用新版来编译,我在 csdn 参考了这编文章 aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2Rpc2FwcGVhcnNfbmljay9hcnRpY2xlL2RldGFpbHMvMTE3MDMxNzQz

可以交叉编译成功,版本是 1.0.31,最新版本已经是 1.0.41,将编译好 adb 放到板子上面运行时

adb connect 128.0.12.109:5555 connected to 128.0.12.109:5555 adb devices List of devices attached 128.0.12.109:5555 offline 一直是离线状态,导致不可用 
]]>
[有偿] 小白, Windows UI Automation TextPattern 检测问题求助 tag:www.v2ex.com,2025-09-04:/t/1157005 2025-09-04T02:40:17Z 2025-09-04T06:46:15Z ck125s member/ck125s 各位 V 友,最近在用 UI Automation (UIA) 时遇到了一个很奇怪的问题,卡了好几天了。

若方法有效感谢🙏200RMB

目标: 获取记事本( Notepad )编辑框的 TextPattern 。

现象:

我用 Accessibility Insights for Windows 去看,明明确确显示记事本的编辑框是支持 TextPattern 的。

Accessibility Insights for windows

问题:

我自己的代码,无论用哪种方式,都检测不到 TextPattern 。

我试过的两种方法:

C++ 原生 COM 接口:

通过 GetFocusedElement 拿到元素,然后 GetCurrentPattern(TextPattern.Pattern),结果是拿不到。

C# + Axe.Windows (Accessibility Insights 核心库):

我以为是我的姿势不对,[找到源码]( GitHub - microsoft/accessibility-insights-windows: Accessibility Insights for Windows),引用 Axe.Windows 库,完全模拟 AI 的工作流程,调用 PopulateAllPropertiesWithLiveData() 等方法,结果依然检测不到 TextPattern 。

已排除的常规问题:

UIAccess 权限、COM 线程模型( STA )、元素句柄有效性等都检查过了,没问题。其他 Pattern 比如 ValuePattern 是可以正常获取的。

核心疑问:

Accessibility Insights 到底用了什么魔法? 为什么它能看到 TextPattern ,而我直接调用 UIA API 或者用它的核心库都复现不了?是不是需要什么特殊的初始化步骤,或者 Windows 对记事本这个“亲儿子”有什么特殊的处理? 有大佬了解其中机制吗?或者有其他调试思路也行。


如果能提供解决方案或关键思路,可有偿指导,感谢!

微信:Delightpl

]]>
小白问个 vcpkg 相关的问题 tag:www.v2ex.com,2025-09-01:/t/1156174 2025-09-01T02:08:22Z 2025-09-01T04:34:08Z xlpxx member/xlpxx 我用 vcpkg 的清单模式管理项目依赖的三方库(主要是 opencv ),当我配置好后,项目也能编过。但是运行的时候总是报缺 cv 的 dll ,但是之前是没有这个问题的,cmakelist 文件也没有改过,想知道这个坑到底在哪里

]]>
记录一次踩坑过程(clion + cmake + vcpkg) tag:www.v2ex.com,2025-08-14:/t/1152503 2025-08-14T22:50:15Z 2025-08-15T02:02:26Z zcion member/zcion 首先结论放这里:编写 cmake 文件时,project(xxx) 放在越后边越好,避免在它之后定义和构建相关的宏变量

好的,下边是踩坑经历: 楼主在写一个程序时,突发奇想的想分别使用 vs 工具链和 mingw 工具链跑下代码,所需要的库文件都是用 vcpkg 下载的。

CMAKE_TOOLCHAIN_FILE 举例,使用 vcpkg + cmake,就需要定义这个值(指明你的 vcpkg.cmake 放在哪个路径下,通常是 xxx/vcpkg/scripts/buildsystems/vcpkg.cmake)。要定义这个值,要么就是在执行 cmake 构建命令时加上 -DCMAKE_TOOLCHAIN_FILE 参数,要么就是直接在 cmake 文件中指定。第二种方法很好理解,直接在 cmake 文件定义就行( clion 在构建时会将其添加进 cache variable),而第一种,如果是在 clion 中,你就需要在如下图位置指定:

那么问题就来了,由于楼主需要分别使用 msvcgcc 编译,所以需要定义 VCPKG_TARGET_TRIPLET 来选用 vcpkg 中库文件的 triplet ,第一次用 msvc 编译项目,没有任何问题,但换成 mingw 后就出现莫名其妙的问题(例如 cmake 构建不成功,构建成功但链接时找不到对应的 lib )。在进行了一系列的排查发现,虽然我在 cmake 中指定了 set(VCPKG_TARGET_TRIPLET x64-mingw-dynamic),但 clion 的 cache variable 中的 VCPKG_TARGET_TRIPLET 的值雷打不动的为 x64-windows(因为先用的是 vs 工具链的,所以 clion 一直用的是缓存的值)。在经过很长一段时间的折磨后,我突发奇想的将所有设计 vcpkg 的宏定义提到了 cmake 文件的最前边,然后问题就解决了。

# 从原先的这样 cmake_minimum_required(VERSION 3.30) project(myproject) set(CMAKE_TOOLCHAIN_FILE "D:/development-tool/vcpkg/scripts/buildsystems/vcpkg.cmake") set(VCPKG_TARGET_TRIPLET x64-mingw-dynamic) # ... # 变成这样 cmake_minimum_required(VERSION 3.30) set(CMAKE_TOOLCHAIN_FILE "D:/development-tool/vcpkg/scripts/buildsystems/vcpkg.cmake") set(VCPKG_TARGET_TRIPLET x64-mingw-dynamic) # ... project(myproject) # ... 

最后想通了,在 project() 前定义宏,这些宏就能够在项目在构建前使用,这样 clion 就能够先写入 cache variable,这样就确保项目构建的行为是根据 cmake 文件中来的。反之在 project() 后定义,这些宏就变为在项目构建过程中才能使用,这就导致了 clion 需要在构建前指定 vcpkg 某些宏找不到,所以 clion 用的是缓存的值。

相信有一部分人和我一样,在开始写 cmake 时,喜欢用默认的模板来写,而默认模板的 project() 又是最先写的,等到项目逐渐的开发,需要往 cmake 中假如越来越多东西,这些东西很容易就加到 project() 后,然后一些在构建前需要用到的宏无法被识别,从而引发一系列问题。

这个点可能是 cmake 很常规的一个点,但如果忽略了,就可能像我一样,在 google->ai 后陷入“明明都是按照语法来的,怎么死活就跑不起来”,然后无能狂怒数个小时的情况。

最后再分享点心得,如果什么都看着正常,但项目就是跑不起来,可以看看 cache variable 中的值是否有问题

]]>
用智能指针管理 ffmpeg 中的数据结构是有必要的吗? tag:www.v2ex.com,2025-07-22:/t/1146903 2025-07-22T07:51:47Z 2025-07-23T07:02:07Z zcion member/zcion ffmpeg 的 api 和 数据结构都是 c 风格,当我在 c++ 中使用它们时,很自然就想到用智能指针去管理(例如 AVFormatContext*AVCodecContext* 等),因为可以自定义删除器,将 ffmpeg 提供的 free 操作放进去;但 ffmpeg 中的一些 api 需要传入裸指针,一些 api 甚至会在内部直接分配空间,这样子用智能指针管理的想法会不会是没有必要的?

AVFormatContext 来举例,正常可以像这样得到一个被智能指针管理的 AVFormatContext 结构

auto deleter = [](AVFormatContext* f){ if(f) avformat_free_context(f); }; std::unique_ptr<AVFormatContext, decltype(deleter)> fmt(avformat_alloc_context(), deleter); 

但和它相关的一个 api 是 avformat_open_input,它的函数声明如下(以下贴出一部分实现)

int avformat_open_input(AVFormatContext **ps, const char *url, const AVInputFormat *fmt, AVDictionary **options); // demux.c 下 avformat_open_input 的一部分实现 int avformat_open_input(AVFormatContext **ps, const char *filename, const AVInputFormat *fmt, AVDictionary **options) { ... AVFormatContext *s = *ps; ... if (!s && !(s = avformat_alloc_context())) return AVERROR(ENOMEM); ... } 

可以看到 avformat_open_input 需要一个二级指针,所以需要直接传入裸指针。如果想要将一个初始化的 unique_ptr<AVFormatContext> 搭配 avformat_open_input 使用,就需要像这样(网上看到的做法)

auto deleter = [](AVFormatContext* f){ if(f) avformat_free_context(f); }; std::unique_ptr<AVFormatContext, decltype(deleter)> fmt(avformat_alloc_context(), deleter); auto tmp = fmt.get(); avformat_open_input(&tmp, ...); 

到这里我就开始怀疑用 unique_ptr 管理 AVFormatContext 的意义了,不过以上这个例子还好,只是观感上没那么优雅。但以下的例子让我质疑用智能指针做管理的必要。

AVFormatContext 还有一个相关的 api 是 avformat_alloc_output_context2,以下是函数声明和部分实现:

int avformat_alloc_output_context2(AVFormatContext **ctx, const AVOutputFormat *oformat, const char *format_name, const char *filename); int avformat_alloc_output_context2(AVFormatContext **avctx, const AVOutputFormat *oformat, const char *format, const char *filename) { AVFormatContext *s = avformat_alloc_context(); int ret = 0; *avctx = NULL; ... *avctx = s; } 

可以看到,avformat_alloc_output_context2 同样需要传入二级指针,但与 avformat_open_input 的区别在于,它内部直接将 *avctx = NULL,并没有判断其是否为空,同时还将分配了新的内存地址给 avctx,这也就意味着以下的操作会造成内存泄漏:

auto deleter = [](AVFormatContext* f){ if(f) avformat_free_context(f); }; std::unique_ptr<AVFormatContext, decltype(deleter)> fmt(avformat_alloc_context(), deleter); auto tmp = fmt.get(); avformat_alloc_output_context2(&tmp, ...); 

至此让我产生用智能指针管理 ffmpeg 数据结构的必要性,有没有大佬来解答一下。

]]>
定位重载的插件或者 IDE tag:www.v2ex.com,2025-07-09:/t/1144033 2025-07-09T08:16:27Z 2025-06-29T11:42:40Z BlackSnow member/BlackSnow 求助 V 友们,是否有那种能够过滤其他重载函数,直接定位到具体函数定义的工具或者技巧

只写过一点 C ,目前使用 VSCODE ( C++) + GCC ,每次查看函数定义用自带的 definition 会跳出所有重载,朋友推荐的是 source insight 或者 visual studio + VC

但是由于不是重度使用,只是跟做个小项目,倾向 vscode+插件,感谢指点

]]>
想系统的学习 Modern C++,麻烦大佬们推荐一些书籍 tag:www.v2ex.com,2025-07-07:/t/1143633 2025-07-07T23:59:06Z 2025-07-08T12:03:57Z liuguangxuan member/liuguangxuan 多年 C++开发经验,但是对一些新特性知之甚少,想系统的学习一下,麻烦推荐一些书籍。

最好是类似《 C++ Primer 》那样权威的书籍。

]]>
困扰几天的问题,这是被 gcc 优化了吗? tag:www.v2ex.com,2025-07-04:/t/1142912 2025-07-04T01:27:01Z 2025-07-05T10:41:08Z aqtata member/aqtata 一个动态库项目,支持 win32 和 arm64 ,编译器是 msvc 和 gcc ( gcc 是自己从源码编译的,版本 15.1.0 ) 对外暴露一个标准 C API ,其内部实现只有一行代码,调用一个内部名称空间内的方法

int my_foo() { return internal::bar(); } 

魔幻的事情是,这个 so 文件,我写一个控制台程序去调用它,能顺利进入到bar()中,放到实际项目中bar()根本就没有被调用,于是尝试打印

int my_foo() { std::cout << "111111111111111" << std::endl; std::cout << __FUNCTION__ << std::endl; std::cout << "internal::bar address: " << (long long)((void*)&internal::bar); return internal::bar(); } 

好家伙,在 linux 下只能打印前两行,然后函数返回 0 ,但这种情况只发生在项目引用时出现。写一个简单的命令行程序触发完全没问题,win32 下也都没问题。 我想 so 文件已经是二进制了,还能被链接它的程序优化不成?这里卡住了,不知道怎么办 项目均使用了-O2

]]>
好的 c++代码是什么样的 tag:www.v2ex.com,2025-06-29:/t/1141838 2025-06-29T17:46:59Z 2025-06-30T23:33:30Z daju233 member/daju233 如题,如何写出好的 c++代码

]]>
为什么 C/C++ 语言的标准库不做成 Java 那样可安装的运行时? tag:www.v2ex.com,2025-06-26:/t/1141180 2025-06-26T04:39:27Z 2025-06-26T14:02:18Z w568w member/w568w 如题。现在的平台/编程语言运行时,按兼容性大致可以分成几类:

  1. 几乎不变动,程序可以动态链接/调用:POSIX API ,Win32 API ;
  2. 经常变动,但可以自由安装:Python ,Java ,NodeJS ,C# .NET……;
  3. 经常变动,但直接嵌入到编译后的程序:Go ,Rust……。

唯独 C 和 C++,在 Linux 下不仅经常变动,并且不向前兼容(即旧版 libc(++) 不能运行新版 libc(++) 的程序)、不互相兼容( musl-libc 的程序不能用 glibc 运行),我在 Arch 上编译的程序几乎没法拿到 Ubuntu LTS 上运行,只能开个 Docker 容器来编译。

这就导致两个奇怪的现象:

  1. 在面向旧发行版开发 C/C++ 的时候,很多人宁愿自己搭古老开发环境来编译,也不愿/不能升级目标环境。而在 Python 、Java 之类的语言里,第一反应是直接给目标环境装个新版 Python/JRE 。
  2. 很多 C/C++ 软件不得不发布一堆变体来保证兼容性(此外,C++ 还有 CXX11ABI 的兼容性问题),或者干脆让用户自己编译(然而用户并不是何时都有空、有能力搭环境,尤其是一些编译依赖非常复杂的软件)。

但似乎很少有人会专门去下载标准库实现。除了 Conda ,好像也没人关心怎么打包标准库。

为什么 C/C++ 不像 JRE 那样,发布一个 C/C++ Runtime 呢,这样分发软件不是方便得多吗?

]]>
CLion 提供非商业免费使用了 tag:www.v2ex.com,2025-05-07:/t/1130269 2025-05-07T13:17:21Z 2025-05-17T00:00:25Z Noicdi member/Noicdi https://blog.jetbrains.com/clion/2025/05/clion-is-now-free-for-non-commercial-use/

当初年度订阅给的永久回退许可是 2023.3 版本的,这个版本没有并入 CLion Nova ,跑公司的项目确实感觉会有点吃力,不知道使用 Nova 的引擎会不会好一点,可惜公司项目已经用不上了。

]]>
MFC c++对话框项目使用 httplib 创建静态资源服务, Debug 时每次访问都会被断下是什么原因 tag:www.v2ex.com,2025-04-18:/t/1126446 2025-04-18T05:39:53Z 2025-04-18T06:39:53Z s609926202 member/s609926202 是在 OnInitDialog 中创建的线程:

UINT CMFCDlg::HttpServerThreadProc(LPVOID lpParam) { httplib::Server svr; svr.set_base_dir("./"); auto ret = svr.set_mount_point("/", "./images"); if (!ret) { std::cout << "The specified base directory doesn't exist..." << std::endl; } svr.listen("0.0.0.0", 5000); return 0; } BOOL CMFCDlg::OnInitDialog() { AfxBeginThread(HttpServerThreadProc, nullptr); } 

然后点击本地 windows 调试器启动后,在浏览器中访问 127.0.0.1:5000/img.jpg 就会在 vs2019 中 httplib.h 中被断下: https://imgur.com/w00YPbh

请问这个是什么原因?

]]>
c++调试遇到奇怪问题 tag:www.v2ex.com,2025-04-10:/t/1124436 2025-04-10T04:06:23Z 2025-04-11T14:51:26Z hwdq0012 member/hwdq0012 struct DV_COMMON_EXPORT product_config { int detect_delay_ms = 0; int reject_delay_ms = 0; int detect_count_Oneshot= 1; int detect_count = 0; int detect_count_interval = 100; std::string ref_image_path = "1"; int cam_x =2; int cam_y =3; // yuv420p",rgb888 std::string rpicam_pixel_type = "yuv420p"; int tmp =44; };

调试时发现从第一个字符串往后,字段都没有正常初始化

(gdb) info line Line 1021 of "/repos/dv_app_solution/prism_all/prism/include/prism/prismJson.hpp" starts at address 0x7fffeb60f470 <prism::json::fromJsonString<dv_common_config>(std::string const&&)+28> and ends at 0x7fffeb60f478 <prism::json::fromJsonString<dv_common_config>(std::string const&&)+36>. (gdb) list 1016 1017 template <class T> 1018 static inline std::unique_ptr<T> fromJsonString(const std::string&& str) 1019 { 1020 std::unique_ptr<T> model = std::make_unique<T>(); 1021 privates::jsonType<T>::type::from_jsonStr(std::move(*model), std::move(str), 0, static_cast<int>(str.length() - 1)); 1022 1023 return model; 1024 } 1025 template <class T> (gdb) print *model $9 = {detect_delay_ms = 0, reject_delay_ms = 0, detect_count_Oneshot= 1, detect_count = 0, detect_count_interval = 100, ref_image_path = "", cam_x = 0, cam_y = 0, rpicam_pixel_type = <error reading variable: Cannot create a lazy string with address 0x0, and a non-zero length.>, tmp = 796092265} (gdb) 

程序会在后面的逻辑中,崩溃在使用 rpicam_pixel_type 这个字段的时候,用 asan 看了是由于这个错误的字符串被认为超过 10 个 T 导致崩溃 随便把它赋值给其他变量就会崩溃

没有思路,有什么方式进一进定位吗

]]>
求推荐 C++ 高性能的 web 框架, curd 用 tag:www.v2ex.com,2025-04-10:/t/1124351 2025-04-10T00:36:35Z 2025-04-11T08:55:27Z ChainLock member/ChainLock 一个项目下有多个 cpp 程序的源文件以及多个程序共用的源文件与头文件, vscode 的 clangd 插件与 compile_commands.json 该如何配置 tag:www.v2ex.com,2025-03-31:/t/1122348 2025-03-31T09:06:15Z 2025-03-31T12:28:15Z zwyyy456 member/zwyyy456 例如在 source 目录下有 a b c common frame 五个文件夹,A B C 三个程序的主要源文件分别位于 a b c 三个目录,而 common 与 frame 下是一些通用的头文件与源文件,例如一些共用的函数、类的声明与定义;

A B C 三个程序分别有通过祖传工具生成的 makefile (不是 cmake ),我是利用 bear 根据这些 makefile 生成的 compile_commands.json 文件,分别记为 A.json 、B.json 、C.json ,我现在是把 A.json 放在 a 目录下,B.json 放在 b 目录下,C.json 放在 c 目录下;

但是这样的话,以 A 为例,在我印象里,vscode 的 clangd 无法跳转到位于 common 或者 frame 文件夹中的函数声明或者定义,只有声明以及定义在 a 文件夹中的函数可以直接跳转过去,我是 common 与 frame 文件夹中也放了一份 A.json ,这样才能跳转,但是印象里还是有不完善的地方。

求教一下万能的 v 友,有没有办法配置一下 clangd ,实现这些函数的正常跳转吗,尤其是跳转到 common 与 frame 中的函数。

这个文件夹分布是简化的,实际上进程不止 A B C 三个,共用的文件夹也不止两个。

]]>
C++库脚手架项目及思考 tag:www.v2ex.com,2025-03-14:/t/1118551 2025-03-14T14:23:25Z 2025-03-18T22:16:28Z RiverBWU member/RiverBWU 之前在考虑编写一些个人的开源项目,不奢求成为什么明星项目,只希望把已有的技能和知识进行总结。一方面将来遇到类似需求时可以直接拿去用,另一方面也给遇到相同问题的人一些帮助。

最开始的想法是不管三七二十一先写起来,之后再逐步测试、修改和完善。没想到功能还没堆多少,那些觉得不会有问题懒得测的模块,总是写出低级 bug ;等想要添加单元测试时,面对的是写成一团的构建脚本;之后适配跨平台,每次提交代码都得在虚拟机之间来回切换、拉取代码和编译测试。

在总结失败教训并参考开源项目后,我决定编写一个适合自己需求的脚手架项目KRCppLibraryTemplate

天下苦构建久矣

就我个人经历而言,当初入门学习 C++时确实遇到了很多困难,但好在有很多优秀的书籍和资料(根本看不完),大部分问题也可以通过搜索找到答案。

没想到跨过这座大山后,迎面而来的是另一座大山——构建:

当你觉得学有所成,打算写个稍微像样点的项目时,就一定会被这些问题深深困扰。

这些问题都来自于 C++编译模型,以及平台和编译器实现细节,没办法三言两语概括,当初学习时主要参考了如下资料:

如果想要新人消化这些内容,恐怕不太适合当今快节奏的职场环境,所以稍微划划重点,其他的就让 AI 来辅助吧:

构建系统

使用构建系统的目的,主要是避免重复的手动编写编译脚本,同时自动分析依赖变更,从而控制重新编译的范围,加速构建过程。实际上构建系统还用于处理安装和打包等工作,有的支持不同平台,从而简化跨平台开发的工作。

不过构建系统自身也会带来一些复杂性,比如 make ,它基于手写依赖规则,并根据文件时间戳判断是否发生变动,如果漏写了依赖(头文件尤其常见),或是修改的是编译器宏定义等不修改文件的选项,很可能会得到错误的结果。

我曾经尝试系统的学习 make ,但最终结论是,遇到老项目,要么重写,要么别动它,遇事不决全量重新编译。

类似的,CMake 也有问题:

但话又说回来,涉及跨平台 C++开发,CMake 自身确实有问题,但选择 CMake 没啥问题。

CMake

比较系统和完善的参考资料如下:

现在的共识应该是 Modern CMake ,但我猜本就不多的 C++程序员里,懂得写 CMake 的人就更少了,更别提推动构建系统脚本的规范化。上面的知识从吸收到能够编写规范的代码需要很久的积累,所以这些就交给脚手架来完成吧。

现存优秀的项目

经常关注 CMake 的人应该都了解过这几个项目:

最终我的选择是造轮子( C++程序员必经之路),从需求角度来说,是因为我希望脚手架应该尽可能封装平台差异,能够支持动态库和静态库,而不是在一开始就对用户强加限制。另一方面则是为了对 CMake 的工程实践有一个完整的了解。

动态库与静态库

从用户角度来说,根据需要选择动态库或静态库是很正常的需求。就算不考虑使用动态库实现平滑升级、功能插件等需求,对于被多个库或可执行程序依赖的情况,使用动态库也可以减少链接时间和空间占用(尤其是 FFmpeg )。真正应该避免的是在存在菱形依赖的情况下进行动态库和静态库的混编,windows 中经典的跨 DLL 内存问题便来源于此,详情可见Professional CMake: A Practical Guide的 Mixing Static And Shared Libraries 章节。

很多个人开发者不太乐于专门适配动态库(比如Catch2: issue 2895),主要原因应该是会增加额外的工作量。

同时支持两种库的话又产生了新的问题,文章Building a Dual Shared and Static Library with CMake中进行了一些讨论:

原文章中的解决方案不支持将动态库与静态库安装至同一个目录下,这里主要介绍我的解决方案。

指定库类型

用户可以通过 static 和 shared 两个别名目标显式链接至对应版本的库:

target_link_libraries(<app1> PRIVATE KRLibrary::static) target_link_libraries(<app2> PRIVATE KRLibrary::shared) 

也可以不显式链接,而是通过选项进行指定,当库依赖层次较深时,便于从外部进行控制:

# 不指定动态库和静态库,通过 BUILD_SHARED_LIBS 或 KRLibrary_USE_SHARED_LIBS 控制 # 后者优先级更高 set(KRLibrary_USE_SHARED_LIBS ON) # 比起硬编码,一般是通过命令行或 CMakeCache.txt 进行修改 find_package(KRLibrary REQUIRED) target_link_libraries(<app> PRIVATE KRLibrary::KRLibrary) 

库的编译

动态库和静态库总是独立编译,不使用-fPIC编译静态库,因为会对静态库用户造成不必要的性能损耗。

当库作为顶层项目进行构建时,认为用户是库本身的开发者或打包人员,此时默认对两种类型的库都进行编译。

当库作为子项目被引入时,认为用户可能只需要其中一种类型的库,此时为两种类型的库目标设置EXCLUDE_FROM_ALL属性,只有被使用时才会进行编译,避免用户产生不必要的构建开销。

windows 下还需要处理动态库和静态库的.lib同名的问题,如果使用的是 MSBuild ,同名库文件很可能就被静默覆盖掉了,使用 Ninja 才会提示错误。我的解决方案是为 windows 下的静态库基本名称添加_static后缀,如果有不同的需求可以按需自行调整。

符号导出

MSVC 默认不导出动态库符号,需要手动通过dllexport 和 dllimport进行控制。GCC 和 Clang 默认导出全局符号,但也提供了对应的控制选项。对于上述属性,CMake 提供了<LANG>_VISIBILITY_PRESETVISIBILITY_INLINES_HIDDEN进行控制。

从“让错误尽早被发现”的角度出发,我选择默认不导出符号:

CXX_VISIBILITY_PRESET "hidden" VISIBILITY_INLINES_HIDDEN ON 

而导出宏则交给GenerateExportHeader自动生成,开发过程中只需要引入生成的头文件,并为要导出的函数添加宏标记即可:

#pragma once #include <krlibrary/export.hpp> namespace krlibrary { KRLIBRARY_EXPORT void exported_hello(); } // namespace krlibrary 

动态库和静态库共用一份头文件,因此使用静态库时,自动设置宏选项禁用符号导出属性,不需要用户手动处理:

target_compile_definitions( "${static_target}" PUBLIC "${project_name_uppercase}_STATIC_DEFINE" ) 

安装

安装一般涉及三类文件:

从打包人员的角度出发,则可以分为两种场景:

这两个选项是通过 CMake 的install功能中的 Componet 提供的,安装时默认都安装,也可以指定安装:

$ cmake --install build/ --prefix install/ --component KRLibrary_Runtime -- Install configuration: "Release" -- Up-to-date: install/lib/libkrlibrary.so.1.0.0 -- Up-to-date: install/lib/libkrlibrary.so.1 

这里额外说明一下,install 中的 component 与 find_package 中的没有任何关系,完全是正交的概念。这里的可以理解为简单的打了个标签方便安装时进行选择,名字也可以按照自己的意图编写,例如干脆细分成*_Headers*_Static*_Runtime等,然后添加到对应组件的属性中即可。

另一种角度是从需求角度出发,例如只需要动态库或者静态库之一,那么可以在构建阶段进行设置:

cmake -S . -B build/ -DKRLibrary_ENABLE_INSTALL_STATIC=OFF 

同理可以通过选项KRLibrary_ENABLE_INSTALL_SHARED控制动态库的安装。这两个选项和前述 componets 也是正交的。

其他

提供了 Catch2 的集成,手动处理了它在构建中可能遇到的一些小问题。CI 方面则编写了比较通用的 Github Action 脚本,代码覆盖分析在 Linux 和 windows 平台分别使用gcovrOpenCppCoverage,编译器警告选项适配了 GCC 、Clang 和 MSVC ,应该足够应付大部分开发场景了。

实际上还处理了一些比较细节的问题,但一方面篇幅所限,另一方面光是要介绍其应用场景可能就要想半天,需要的人就直接阅读源代码吧(懒)。

]]>
有人遇到过 vs2022 c++代码高亮不生效的问题吗? tag:www.v2ex.com,2025-03-12:/t/1117947 2025-03-12T11:41:56Z 2025-03-13T02:45:53Z FanyFull member/FanyFull 突然有一天打开 vs2022 就变成了现在这个样子,怎么调也没用。比如,c++ 的注释,原来是渲染成绿色的,结果现在颜色全都消失了。如下图所示,

]]>
使用 C++20 协程与 ASIO 库写了个 Socks5 Server 的跨平台 Demo 程序,几乎全功能,单文件源码少于一千行 tag:www.v2ex.com,2025-03-09:/t/1117106 2025-03-09T15:51:59Z 2025-03-09T19:50:59Z cnbatch member/cnbatch 源码已经发布在 Github: https://github.com/cnbatch/cpp20-socks5demo

RFC 1928 要求的功能几乎都实现了。

支持的功能:

未实现的功能:

Socks5 标准 (RFC 1928) 写着必须实现这个功能,然而我做的只是个 Demo 程序,平时也用不到 GSSAPI ,为了简单起见就不实现了。

已在这些系统测试过:


用协程写代码的体验

用了协程之后,思路清晰多了,不像 callback 时那么头大,相对而言轻松多了。

Github 就有一大堆 Socks5 Server 程序,为什么又造了个新的?

两大原因:

  1. 我自己是 Windows + FreeBSD 用户,正好需要这样的 socks5 server 程序——可以同时在 Windows 与 FreeBSD 运行,能够支持 TCP + UDP, IPv4 + IPv6 ,使用相同的运行配置方式。
    虽然平时 socks5 server 主要在 FreeBSD 当中运行,但稳妥起见也要在 Windows 台式机运行同样的程序,用作 backup 方案。
    最重要的一点,两个平台都要采用 Native 编译方式,而不是单纯的“妥协”编译方式。直白点说就是:

    • Windows 可以用 MSVC 直接编译,不需要经过 Cygwin / MinGW 绕一层。
    • FreeBSD 可以用内置编译器 + BSD Make 直接编译(即使是 cmake 生成的),不需要 GNU Make ,不需要额外再安装编译器。
  2. 一直想试试 ASIO 库的协程模式,毕竟写起来流畅多了。我个人记忆力不太好,callback 数量一多就头大,实在记不过来。趁着有需求,正好拿来试一试。

小提示

由于这个程序只是个 Demo ,用是能用。只不过暂时不支持侦听到具体的地址,不提供日志记录,连接超时的时间判断是硬编码的。如果要其他额外功能都实现的话,就不能单靠一个源文件了,只能另开新 repo 把各部份拆开来重新梳理一遍。以后再在新 repo 内慢慢拆、慢慢补。

]]>
小众论坛问个好奇的问题关于 c++ tag:www.v2ex.com,2025-03-06:/t/1116327 2025-03-06T04:36:59Z 2025-03-05T20:36:59Z slideclick member/slideclick 深入浅出 mfc 的作者 我看在某站开了号讲 c++ 我没有看,看视频标题感觉是 c++98 的水平 看了的知道么?

这可是 22 年的视频

难道我错了,还是他不学习?

]]>
市面上大部分 c++程序员都在 c++98 水平吧? tag:www.v2ex.com,2025-03-06:/t/1116281 2025-03-06T02:53:19Z 2025-03-05T18:53:19Z slideclick member/slideclick 不是来踢馆的,我老 c++程序员,在学习 c++20

这话题贴别的论坛没人看

大部分人宣称会 c++,其实都是 C

c++98 是什么水平? 就是需要一大片 n 个对象的内存,使用 vector 而不是 new[n] 可是我猜很多面试官的提问都是 delete[]而不是 delete 才能和 new[]配对

这面试官自己都没有达到 98 水平

这烂问题就不该问了

]]>
cpp 一个隐式转换奇怪的现象 tag:www.v2ex.com,2025-02-11:/t/1110662 2025-02-11T07:22:24Z 2025-02-11T07:48:27Z jdz member/jdz std::map<std::string, std::string> a; std::string m = 2; //编译失败 a["hello"] = 1; //编译成功 为什么呢

]]>
C++入门书籍,我是不是被坑了? tag:www.v2ex.com,2025-02-07:/t/1109496 2025-02-07T01:04:26Z 2025-02-15T07:16:27Z Amose2024 member/Amose2024 在 B 站找 C++自学路线,有的 UP 主包括 01 星球等,推荐书籍《 C++ Primer Plus 》。我买回来上下两册,巨厚。 上册目前看了两百页。

我发现这书的槽点有两点: 第一点是书中明确说对于初学者不需要 C 语言基础,或者其它语言基础。但是它一再提及其它语言(有些是没有见过的语言),甚至大篇幅讲 C 语言语法,示例里 C 语言和 C++混用,看了之后合上书顿时分不清哪个是 C 的,哪个是 C++的。对于没 C 语言基础的人来说,尤其痛苦。

第二点是重点的地方不讲深,几句话带过去了,而不重要的地方废话真是多。

当时 B 站的人推荐理由是 C++ Primer 更深,不适合初学者,推荐 C++ Primer Plus 。

后悔当时没有在外网去收集这两本书的不同之处,外网骂后者是垃圾书籍的可多了。。。

这两本书完全不是同一级别,Primer 更好,Plus 是 shit!

就吐槽一下,看完还是要看完的。

]]>
mac clion 调试怎么才能看到 stl 容器的值 tag:www.v2ex.com,2025-02-01:/t/1108491 2025-02-01T02:40:47Z 2025-02-02T09:04:03Z rednose1037 member/rednose1037 image.png

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++ -I/opt/homebrew/Cellar/gcc/13.2.0/include/c++/13.2.0 -I/opt/homebrew/Cellar/gcc/13.2.0/include/c++/13.2.0/aarch64-apple-darwin23.4.0") 
]]>
有没有合适开源的 C++项目可以快速实现一些功能 tag:www.v2ex.com,2025-01-25:/t/1107860 2025-01-25T15:36:47Z 2025-01-25T17:35:47Z winskyme member/winskyme
1 ,通过 http 或者 tcp 接收客户端发过来的 json 格式的数据
2 ,支持解析、修改 json 格式的数据,根据 json 里某些字段的内容,去数据库再去查一些信息,补充进 json 数据中
3 ,将这些 json 格式的数据保存在任务队列中,支持根据 json 数据里的计算类型字段,划分多个任务队列,支持队列的查看、管理;将队列中的信息轮询发送给各个计算节点,节点计算完成后再发下一个
4 ,接收计算节点返回的 json 格式计算结果,并写入指定的数据库
5 ,支持和各个计算节点的心跳报文,以感知计算节点的状态、当前是否有计算任务
6 ,支持监听端口、数据库地址、客户端 IP 从配置文件中读取 ]]>
用 c++实现 bluez 对于 31 个字节蓝牙广播限制的问题 tag:www.v2ex.com,2025-01-24:/t/1107538 2025-01-24T03:27:22Z 2025-01-24T00:25:22Z dy416394356y78 member/dy416394356y78
我的需求:我的板子开机后会蓝牙广播,app 接收广播后可以直接识别该板子的型号,目前已经广播的数据有标志位,UUID 和蓝牙广播名字,已经占用了 29 字节,我查到蓝牙广播限制 31 个字节,我直接拼接在数据后面广播,nRF 会直接报 none ,即能扫描到但是没有数据

目前我的蓝牙模块是 4.1 的 hci ,不支持拓展数据
查到网上可以使用分包,或者加入扫描数据中,但是这样都无法在广播的时候,接收方就立刻收到数据进行识别,分包需要收到两个包,而加入扫描数据需要收到广播建立连接后才可以

还有没有什么别的办法?

感谢。 ]]>
寻找一个在线运行 c++的方案 tag:www.v2ex.com,2025-01-20:/t/1106524 2025-01-20T08:14:27Z 2025-01-20T16:20:54Z yuzhixin411416 member/yuzhixin411416 我想做个少儿编程网站

最基础的功能是能够做到在线运行 c++代码,输入输出能够动态持续的进行

这种都用什么方案呀

类似学而思的小猴编程: https://www.xiaohoucode.com/

]]>
这种情况如何消除几百个 if/else tag:www.v2ex.com,2025-01-16:/t/1105424 2025-01-16T00:43:29Z 2025-01-17T05:56:00Z aqtata member/aqtata 运行时从外部读取一个 16 进制数字,然后调用对应的函数,比如读取到1F3,那么就调用函数foo_1f3,函数参数也是有编号的,规律是这样:

void foo_1f0(myclass_1f0& val); void foo_1f1(myclass_1f1& val); void foo_1f2(myclass_1f2& val); 

之前 C#是用的反射,很容易实现。到 C++这不知道怎么搞比较优雅,目前有上百个 if/else 去判断然后调用。

C++这边可以用到 C++20 ,不知道有什么酷的解决方法?

]]>
cmake + googletest 的目录结构最佳实践是? tag:www.v2ex.com,2025-01-14:/t/1104863 2025-01-14T00:47:47Z 2025-01-14T06:59:31Z aqtata member/aqtata 目前看到有几种做法:

  1. 测试代码在源码中,通过宏区分编译。
  2. 测试代码在工程目录下的 test 文件夹中,引入被测的源文件编译测试。
  3. 把被测代码编译成静态库,在顶层目录下有个 tests 文件夹,链接静态库测试。

各位怎么组织的?

]]>
为什么打印模板元编程计算阶乘结果,比打印 for 循环计算阶乘结果更耗时 tag:www.v2ex.com,2024-12-09:/t/1096242 2024-12-09T13:22:23Z 2024-12-09T14:54:03Z zcion member/zcion 最近看了 effective c++ 这本书,书中有一种用模板元编程计算阶乘的骚操作,说是可以将计算从运行时转到编译期间,这样可以提高代码的执行效率。

但我尝试了下,发现并没有比使用 for 循环计算阶乘的方法快,反而花费了更多的时间,代码如下:

#include <chrono> #include <cstdlib> #include <iostream> #include <new> #include <vector> using std::size_t; template <unsigned x> struct fac { static const size_t value = x * fac<x - 1>::value; }; template <> struct fac<1> { static const size_t value = 1; }; // for 循环计算阶乘 size_t fori(size_t v) { size_t tmp = 1; for (size_t i = 1; i <= v; i++) { tmp = tmp * i; } return tmp; } // 利用模板元编程计算阶乘 constexpr size_t facc() { return fac<901>::value; } void func() { // 模板元编程计算耗时 auto start = std::chrono::high_resolution_clock::now(); constexpr auto tmp = facc(); std::cout << tmp << std::endl; auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start); std::cout << "Elapsed time: " << duration.count() << " ns" << std::endl; // 输出 57466 ns // for 循环计算耗时 auto start1 = std::chrono::high_resolution_clock::now(); size_t t = fori(901); std::cout << tmp << std::endl; auto end1 = std::chrono::high_resolution_clock::now(); auto duration1 = std::chrono::duration_cast<std::chrono::nanoseconds>(end1 - start1); std::cout << "Elapsed time: " << duration1.count() << " ns" << std::endl; // 输出 1647 ns } int main() { func(); } 

如果去掉打印,反而是利用模板元编程的更快,确实符合编译期计算提高效率的说法,但这里打印了其结果,反而花费了更多时间。

这是为什么,是编译器自个的优化策略问题还是什么?

编译器版本:gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0

]]>
Asio 异步模型 tag:www.v2ex.com,2024-12-09:/t/1095980 2024-12-09T00:28:37Z 2024-12-09T06:57:28Z zsxzy member/zsxzy 一份很不错的资料, 描叙 Asio 的异步模型

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2444r0.pdf

]]>
求教, mac 下 cmake c++工程编译后 elf 里面还有很多路径字符串 tag:www.v2ex.com,2024-11-29:/t/1093733 2024-11-29T07:13:29Z 2024-11-29T11:01:04Z wjx0912 member/wjx0912 windows 也有这样的问题,后来参考 visual studio 设置 cpp flags 后解决了。 但是 mac 找了一堆参数还是不行。

测试代码: https://github.com/PacktPublishing/Modern-CMake-for-Cpp/blob/main/examples/chapter06/05-dynamic/CMakeLists.txt 编译:

cmake . -G "Unix Makefiles" cmake --build . --config Release 

生成的文件导出的 string 有本地文件夹路径字符串(但实际项目里面并没有用到__path__)

下图是用 cutter (开源反编译工具 https://github.com/rizinorg/cutter ,类似 IDA pro )

添加了一些参数(-flto ,-g0 还是不行),求大佬指点迷津

]]>
C 怎么进阶学 C++呀 tag:www.v2ex.com,2024-11-27:/t/1093126 2024-11-27T08:07:45Z 2024-12-09T03:38:08Z zzzyk member/zzzyk 只会 C 语言想进阶学学 C++,要怎么学,那些简单的语法看了好像问题都不大(跟 C 基本一样),但是到了那些面向对象的那些,就完全懵逼了,看不太懂。有什么好的教程或者数据推荐吗。

]]>
用 C++ lambda 太爽了 tag:www.v2ex.com,2024-11-20:/t/1091206 2024-11-20T07:38:40Z 2024-12-01T11:07:46Z zhuyongqi9 member/zhuyongqi9 写 GUI 经常碰到需要使用 callback 来描述 event 发生时的 behavior ,在 callback 函数里面不可避免的要使用到某些变量,之前不用 lambda 需要把 callback 内引用的变量都作为全局变量,现在用了 lambda 之后可以直接变量捕捉,在 class method 内也能捕获 this 指针,用起来太爽了

]]>
如何保证一个成员函数在另一个成员函数之前获得 mutex? tag:www.v2ex.com,2024-11-19:/t/1090860 2024-11-19T08:03:38Z 2024-11-19T09:57:42Z LuckyPocketWatch member/LuckyPocketWatch 假设有个类的两个成员函数,需要在不同的线程里执行,这两个成员函数需要写入同一个文件,因此需要使用 mutex 确保这两个函数不会同时写,代码类似这样

class Widget{ public: void funA(); void funnB(); private: std::mutex mutex; }; void Widget::funA(){ { std::unique_lock(mutex); //operate A; } } void Widget::funB(){ { std::unique_lock(mutex); //operate B; } } 

然后设计两个函数来封装这两个成员函数,类似

void execA(Widget* w){ w->funcA(); }; 

最后程序里,生成一个 Widget 的对象,需要在两个线程里执行这两个函数,即

Widget* w{}; std::jthread threadA(execA, &w); //在一个线程里执行 A 函数 std::jthread threadB(execB, &w); //在另一个线程里执行 B 函数 

在这种情况下,大多数式成员函数 funcA()先执行,但多次尝试后,有几次式 funcB()先获得 mutex 。

在下列三个前置条件下

  1. 使用 c++20 标准,并可以使用 vs2022 最新版支持的 c++23 标准
  2. 不该用 std::thread
  3. 不使用 std::this_thread::sleep_for()对 B 进行睡眠

我向问下,有没有办法确保 A 一定在 B 之前获得 mutex ?

]]>
[求助] C++ std::move 问题 tag:www.v2ex.com,2024-11-15:/t/1089886 2024-11-15T08:47:24Z 2024-11-15T12:15:10Z yippee0539 member/yippee0539 为什么

std::fstream file_("path_to_file"); std::string content_ = std::move(std::string(std::istreambuf_iterator<char>(file_), std::istreambuf_iterator<char>()));

执行之后 file_为 null 了

这里构造的 string 临时变量应该跟 file_没有关系才对吧

]]>
C++中右值与右值引用在使用中的疑问 tag:www.v2ex.com,2024-11-12:/t/1089024 2024-11-12T15:02:11Z 2024-11-13T07:46:14Z Symbo1ic member/Symbo1ic 如标题。最近在看现代 cpp ,感觉右值和右值引用这两个概念非常重要,因此自己尝试构建一些例子来加深理解。例子如下:

#include <iostream> #include <ostream> #include <utility> using namespace std; struct C { int a = 1; C() { cout << "Ha ha" << endl; } C(C& c) : a(c.a) { cout << "Copy" << endl; } C(C&& c) : a(std::move(c.a)) { cout << "Move" << endl; } ~C() { cout << "Fucked" << endl; } }; C func() { C shit; cout << &shit << endl; return shit; } C f2() { C&& shit = func(); cout << &shit << endl; return shit; } C f3() { C&& shit = func(); cout << &shit << endl; return std::move(shit); } int main() { auto&& shit = f2(); // Ha ha // 0x5ffe24 // 0x5ffe24 // Copy // Fucked cout << &shit << endl; // 0x5ffe7c cout << "*************" << endl; auto shit2 = f3(); cout << &shit2 << endl; // Ha ha // 0x5ffe24 // 0x5ffe24 // Move // Fucked // 0x5ffe78 cout << "*************" << endl; auto&& shit3 = f3(); cout << &shit3 << endl; // Ha ha // 0x5ffe24 // 0x5ffe24 // Move // Fucked // 0x5ffe74 cout << "*************" << endl; // cout << shit.a; } 

对于这个例子所产生的结果,我不是很懂,我主要是不太懂以下几个问题:

  1. 为啥对于右值引用 shit ,在初始化之前会产生 copy ?而对于 shit2 则会在之前有 move ?
  2. 我尝试将 f3 的声明改成了'C&& f3()',这个时候 clangd 警告引用了一个栈空间上的变量。为啥会这样?正常来说右值引用应该怎么使用?
  3. f2 和 f3 都引用了位于 func 构建出来的函数栈上的 shit ,从地址可以看出他们引用后地址没有产生变化。则使用右值引用引用了一个位于栈上的值,从 cpp 内存模型的角度来讲是怎么做到的?这种做法会不会对在该值所在的函数之后运行的函数栈空间分配产生影响?
]]>
买了 mac mini 及 Linux 开发相关问题请教 tag:www.v2ex.com,2024-11-11:/t/1088454 2024-11-11T03:24:14Z 2024-11-11T08:32:47Z Noicdi member/Noicdi 手里有 iPhone 和 ipad ,但是还没有使用过 macos ,趁着国补买了一台 mac mini m4 24+512 ,放在家里当台式机用,用于上网和开发。

开发方面,只是用于个人项目和代码学习。我的方向是 Linux c++ 开发,平常玩 Linux 很多,会写一些 Linux 项目,不考虑跨平台,也打算摸一摸 kernel 的代码学习。

我的问题是,在 m 系列芯片的 macos 上,如何做 Linux 开发?不考虑远程 Linux 服务器和架构集的情况下,使用 clion 和 vscode remote ssh ,在 macos 本地可以有哪些方式? docker 和虚拟机吗?能不能正常的完成编译和调试?

]]>
请教一个 C++性能问题 tag:www.v2ex.com,2024-11-08:/t/1087884 2024-11-08T13:02:19Z 2024-11-27T15:25:17Z wisefree member/wisefree 对于两个转置运算,两种的性能明显不一样,是为什么呢?

我电脑的输出是:

0.0473308

0.0265206

 #include <iostream> #include <chrono> int main(void) { int I = 100; int J = 200; int K = 300; int idealI = 105; // i j k int* arr = new int[I * J * K]; for (int i = 0; i < I; i++) { for (int j = 0; j < J; j++) { for (int k = 0; k < K; k++) { arr[i * (K * J) + j * K + k] = k; } } } // k j i float* transArr = new float[idealI * J * K]; auto startTime = std::chrono::steady_clock::now(); for (int i = 0; i < I; i++) { for (int j = 0; j < J; j++) { for (int k = 0; k < K; k++) { transArr[k * (J * I) + j * I + i] = arr[i * (K * J) + j * K + k] * 0.1f; } } } auto endTime = std::chrono::steady_clock::now(); std::chrono::duration<double> diffTime = endTime - startTime; std::cout << diffTime.count() << std::endl; startTime = std::chrono::steady_clock::now(); for (int i = 0; i < I; i++) { for (int j = 0; j < J; j++) { for (int k = 0; k < K; k++) { transArr[k * (J * idealI) + j * idealI + i] = arr[i * (K * J) + j * K + k] * 0.1f; } } } endTime = std::chrono::steady_clock::now(); diffTime = endTime - startTime; std::cout << diffTime.count() << std::endl; delete[] arr; delete[] transArr; return 0; } 
]]>
CLion 界面字体大小调节问题 tag:www.v2ex.com,2024-10-31:/t/1085485 2024-10-31T13:29:15Z 2024-11-02T12:51:42Z A1st0n member/A1st0n 双非研二在读,求 C++嵌入式方向学习经验以便找工作 tag:www.v2ex.com,2024-10-22:/t/1082599 2024-10-22T07:45:21Z 2024-10-16T03:03:06Z Incarna member/Incarna 26 年双非硕应届毕业生,目前一篇小论文在写,准备年底之前投出去,组内无项目但是把论文投出去后大概率导师放实习。之前本科有一点 C++基础,目前打算再学几个月往嵌入式开发方向走,然后明年找个实习,以后想留成都工作。各位 V 友有好的学习路线么,或者可以介绍一下成都嵌入式开发找工作怎么样。

]]>
C++ 新手问下有没有办法链式定义一个类 tag:www.v2ex.com,2024-10-21:/t/1082201 2024-10-21T06:38:15Z 2024-10-21T11:15:03Z BRS5672023 member/BRS5672023 比如说我先定义一个单项式类为这种形式:

a * pow(p, n) * pow(q, m) 

其中 a, m, n 都是整数,p 和 q 是两个字符,然后现在我想定义操作一个更复杂的类,就是一般所说的多项式,但是它要满足我添加一个单项式进来之后仍然还是一个多项式的要求。。

]]>
atomic<shared_ptr<T>>在 GCC 和 Clang 的受支持程度真是一言难尽 tag:www.v2ex.com,2024-10-20:/t/1081936 2024-10-20T08:50:17Z 2024-10-20T22:39:14Z cnbatch member/cnbatch Clang 到现在都不支持atomic<shared_ptr<T>>,只能继续 atomic_load()atomic_store()。一旦要用 weak_ptr 则如同残废,不支持atomic_load()atomic_store()

GCC 12.2 及旧版本有“bug”( P0718R2 的疏忽),刚好 Debian 12 自带的 GCC 就是 12.2 ,直接完蛋。

这段代码在 Debian 12 (bookworm)无法编译,换成 Debian Testing (trixie)就可以成功编译:

#include <atomic> #include <memory> class A{ int a; }; int main() { std::atomic<std::shared_ptr<A>> a_ptr = std::make_shared<A>(); a_ptr = nullptr; return 0; } 

想要写跨编译器的代码很麻烦,只能加好几行#if #else #endif

Clang 原本已经有人在实现atomic<shared_ptr<T>>,准备到一半就放弃了:
[libc++] Implement P0718R2: atomic<shared_ptr<T>>
放弃的原因令人无语,因为 PR 内wait/notify_all的效率不太高,需要重写,作者直接不干了

]]>
C++ 新手想问下关于 Linux 下如何实现类似 Windows 的 Pause 功能的问题 tag:www.v2ex.com,2024-10-18:/t/1081614 2024-10-18T12:17:48Z 2024-10-18T15:38:07Z BRS5672023 member/BRS5672023 最近几天看了一点黑马程序员的视频(没什么基础),试着跟着写了一下实现通讯录管理的代码(暂时只完成了一部分功能),想要在 Linux 系统下实现类似 Windows 里 system("pause") 的功能,比如在通讯录中写完一个联系人的信息或者显示一个联系人的信息的时候能够 Pause 一下。。代码如下

#include <iostream> using namespace std; #include <string> #include <limits> // 定义 pause 函数以及 getValidInput 函数中使用 #define MAX 1000 // 通讯录最大人数 void showMenu (); void pause (); int getValidInput (); // 联系人结构体 struct Person { string m_Name; int m_Gender; int m_Age; long m_Phone; string m_Address; }; // 通讯录结构体 struct Addressbooks { struct Person personArray[MAX]; int m_Size; // 通讯录中人员个数 }; void addPerson (Addressbooks *abs); void showPerson (Addressbooks *abs); int main () { struct Addressbooks abs; abs.m_Size = 0; while (true) { showMenu(); // 菜单调用 // cin >> select; // 检查输入是否有效 // if (cin.fail()) { // cin.clear(); // 清除错误状态 // cin.ignore(numeric_limits<streamsize>::max(),'\n'); // 清空缓冲区 // cout << "请输入有效的数字!" << endl; // continue; // 重新进入循环 // } int select = getValidInput (); switch (select) { case 1: // 添加联系人 addPerson(&abs); // 利用地址传递,可以修饰实参 break; case 2: showPerson(&abs); break; case 3: break; case 4: break; case 5: break; case 6: break; case 0: cout << "欢迎下次使用" << endl; // pause(); return 0; // break; default: cout << "请输入数字 1-6 或 0" << endl; break; } } return 0; } void showMenu () { cout << "1 、添加联系人" << endl; cout << "2 、显示联系人" << endl; cout << "3 、删除联系人" << endl; cout << "4 、查找联系人" << endl; cout << "5 、修改联系人" << endl; cout << "6 、清空联系人" << endl; cout << "0 、退出通讯录" << endl; } // 实现类似 Windows 系统上的 system("pause") 功能 void pause () { cin.clear(); // if (cin.eof()) { cin.ignore(numeric_limits<streamsize>::max(), '\n'); // 忽略输入流中的内容直到换行符,但因为输入内容已经被清空,这里程序会等待输入一个回车(换行符) // } cout << "请按回车键继续" << endl; cin.get(); } // 检测输入数据是否为整数,是则返回该输入 int getValidInput () { int input; while (true) { cin >> input; if (cin.fail()) { cin.clear(); cin.ignore(numeric_limits<streamsize>::max(), '\n'); cout << "请输入有效的数字!" << endl; } else { if (cin.eof()) { cin.ignore(numeric_limits<streamsize>::max(), '\n'); } return input; } } } // 添加联系人 void addPerson (Addressbooks *abs) { // 判断通讯录是否已满 if (abs->m_Size == MAX) { cout << "通讯录已满,无法添加联系人!" << endl; return; } else { string name; cout << "请输入联系人姓名:" << endl; cin >> name; abs->personArray[abs->m_Size].m_Name = name; cout << "请输入联系人性别:" << endl; cout << "输入数字 1 为男性" << endl; cout << "输入数字 2 为女性" << endl; while (true) { // cin >> gender; // if (cin.fail()) { // cin.clear(); // cin.ignore(numeric_limits<streamsize>::max(), '\n'); // cout << "请输入有效的数字!" << endl; // continue; // } int gender = getValidInput (); if (gender == 1 || gender == 2) { abs->personArray[abs->m_Size].m_Gender = gender; break; } cout << "输入有误,请重新输入" << endl; } cout << "请输入联系人年龄:" << endl; int age = getValidInput (); abs->personArray[abs->m_Size].m_Age = age; cout << "请输入联系人电话号码:" << endl; long phone; cin >> phone; abs->personArray[abs->m_Size].m_PhOne= phone; cout << "请输入联系人家庭住址:" << endl; string address; cin >> address; abs->personArray[abs->m_Size].m_Address = address; cout << "已成功添加联系人 " << abs->personArray[abs->m_Size].m_Name << endl; abs->m_Size++; pause(); system("clear"); // 对于 Windows 系统,应该使用 system("cls") } } void showPerson (Addressbooks *abs) { if (abs->m_Size == 0) { cout << "当前记录为空" << endl; } else { for (int i=0;i<abs->m_Size;i++) { cout << "姓名:" << abs->personArray[i].m_Name << endl; cout << "性别:" << abs->personArray[i].m_Gender << endl; cout << "年龄:" << abs->personArray[i].m_Age << endl; cout << "电话:" << abs->personArray[i].m_Phone << endl; cout << "地址:" << abs->personArray[i].m_Address << endl; } } pause(); system("clear"); } 

然后我发现在我定义的函数 getValidInput 里面加入一个 cin.eof() 的判断就基本实现了我想要的效果,但其实我不太理解原因是什么,特别是如果我把 getValidInput 函数的这个判断给注释掉的话,那么在我输入 "2" 使用 "显示联系人" 这个功能时,需要再输入一个回车才会显示 "请按回车键继续" 的字符;而如果我仍然注释 getValidInput 中的这个判断,但取消 pause 函数定义中关于 cin.eof() 的注释(见上面的代码),那么在我输入 "1" 使用 "添加联系人" 的功能的时候,在我输入完联系人信息之后,pause() 似乎不会起作用,system("clear") 会直接清屏。。

]]>
C++项目分布式存储上的编译问题 tag:www.v2ex.com,2024-10-18:/t/1081515 2024-10-18T06:44:25Z 2024-10-18T08:58:12Z chen0520 member/chen0520 最近在做 webide 相关的开发,C++的开发人员反馈编译环节有问题,目前已出现的报错都是 can't write xxx bytes to section xxxxxx

然后物理机上 docker 跑的 ide 就没啥问题,我怀疑问题还是使用 nfs 上的问题,所以上诉的错误一般是由什么产生的?有没有进一步的排查方式

我的初步梳理:我目前了解到的是 nfs 会有一致性的问题,但同时在这个存储上跑的只会有这一个项目啊,单个环境下的一致性问题应该在系统层面就解决了把

]]>
如何增强自己的程序设计水平? tag:www.v2ex.com,2024-10-11:/t/1079123 2024-10-11T02:40:58Z 2024-10-12T15:34:18Z sbldehanhan member/sbldehanhan 在熟悉计算机基本原理、编程语言语法,也写过一些小程序的前提下,还是在收到一个功能时感觉无从下手,不知道如何设计这个程序。所以,如何提高自己的程序设计水平?在收到一个功能时就能大概知道怎么做,模块如何划分?虽然设计的可能不是最优,但至少能保证功能基本正常。该怎么做?或者看什么书?

]]>
cmake 交叉编译有大佬懂吗? tag:www.v2ex.com,2024-10-01:/t/1077285 2024-10-01T08:46:56Z 2024-10-03T23:21:16Z cohen121 member/cohen121 c++新手,之前写 java 和 go 的。目前使用 cmake + vcpkg 在 Linux 开发。我现在想在在 Linux 环境生产 Windows/mac/linux 等操作系统下的可执行文件。可以完成吗? 现在只考虑最简单一个程序 hello world, 没有第三方依赖。如何操作。。。

]]>
c++多线程如何配置环境看线程的调试信息 tag:www.v2ex.com,2024-09-29:/t/1076956 2024-09-29T16:18:39Z 2024-09-29T21:59:54Z zcion member/zcion 用的是 vscode+cmake,debug 的方式是配置 Launch.jsontasks.json 执行 cmake 构建命令并运行可执行文件。 现在遇到的问题是:不知道怎么查看多线程中多个线程的调试信息。 我在网上看见给命令加-pthread的,以下是我的CMakeLists.txt文件

cmake_minimum_required(VERSION 3.10) # 添加了 -pthread set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20 -pthread") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c17") project(thread-pool) set(HOME ${CMAKE_CURRENT_SOURCE_DIR}) set(EXECUTABLE_OUTPUT_PATH ${HOME}/bin) include_directories(${HOME}/include) link_directories(${HOME}/bin) aux_source_directory(${HOME}/src SRC_PATH) add_executable(app ${SRC_PATH}) target_link_libraries(app PUBLIC pthread) 

结果 vscode 中还是看不到多个线程的调试信息。 大手子都是怎么看多线程调试信息的?

]]>
ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86