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 一直是离线状态,导致不可用
]]>若方法有效感谢🙏200RMB
目标: 获取记事本( Notepad )编辑框的 TextPattern 。
我用 Accessibility Insights for Windows 去看,明明确确显示记事本的编辑框是支持 TextPattern 的。
我自己的代码,无论用哪种方式,都检测不到 TextPattern 。
我试过的两种方法:
通过 GetFocusedElement 拿到元素,然后 GetCurrentPattern(TextPattern.Pattern),结果是拿不到。
我以为是我的姿势不对,[找到源码]( 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
]]>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 中,你就需要在如下图位置指定:
那么问题就来了,由于楼主需要分别使用 msvc
和 gcc
编译,所以需要定义 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
中的值是否有问题
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 数据结构的必要性,有没有大佬来解答一下。
]]>只写过一点 C ,目前使用 VSCODE ( C++) + GCC ,每次查看函数定义用自带的 definition 会跳出所有重载,朋友推荐的是 source insight 或者 visual studio + VC
但是由于不是重度使用,只是跟做个小项目,倾向 vscode+插件,感谢指点
]]>最好是类似《 C++ Primer 》那样权威的书籍。
]]>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 和 C++,在 Linux 下不仅经常变动,并且不向前兼容(即旧版 libc(++) 不能运行新版 libc(++) 的程序)、不互相兼容( musl-libc 的程序不能用 glibc 运行),我在 Arch 上编译的程序几乎没法拿到 Ubuntu LTS 上运行,只能开个 Docker 容器来编译。
这就导致两个奇怪的现象:
但似乎很少有人会专门去下载标准库实现。除了 Conda ,好像也没人关心怎么打包标准库。
为什么 C/C++ 不像 JRE 那样,发布一个 C/C++ Runtime 呢,这样分发软件不是方便得多吗?
]]>当初年度订阅给的永久回退许可是 2023.3 版本的,这个版本没有并入 CLion Nova ,跑公司的项目确实感觉会有点吃力,不知道使用 Nova 的引擎会不会好一点,可惜公司项目已经用不上了。
]]>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
请问这个是什么原因?
]]>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 导致崩溃 随便把它赋值给其他变量就会崩溃
没有思路,有什么方式进一进定位吗
]]>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 三个,共用的文件夹也不止两个。
最开始的想法是不管三七二十一先写起来,之后再逐步测试、修改和完善。没想到功能还没堆多少,那些觉得不会有问题懒得测的模块,总是写出低级 bug ;等想要添加单元测试时,面对的是写成一团的构建脚本;之后适配跨平台,每次提交代码都得在虚拟机之间来回切换、拉取代码和编译测试。
在总结失败教训并参考开源项目后,我决定编写一个适合自己需求的脚手架项目KRCppLibraryTemplate :
就我个人经历而言,当初入门学习 C++时确实遇到了很多困难,但好在有很多优秀的书籍和资料(根本看不完),大部分问题也可以通过搜索找到答案。
没想到跨过这座大山后,迎面而来的是另一座大山——构建:
当你觉得学有所成,打算写个稍微像样点的项目时,就一定会被这些问题深深困扰。
这些问题都来自于 C++编译模型,以及平台和编译器实现细节,没办法三言两语概括,当初学习时主要参考了如下资料:
如果想要新人消化这些内容,恐怕不太适合当今快节奏的职场环境,所以稍微划划重点,其他的就让 AI 来辅助吧:
#include <...>
和#include "..."
导入头文件时搜索路径的差异,以及如何指定自己所需的搜索路径;extern "C"
;使用构建系统的目的,主要是避免重复的手动编写编译脚本,同时自动分析依赖变更,从而控制重新编译的范围,加速构建过程。实际上构建系统还用于处理安装和打包等工作,有的支持不同平台,从而简化跨平台开发的工作。
不过构建系统自身也会带来一些复杂性,比如 make ,它基于手写依赖规则,并根据文件时间戳判断是否发生变动,如果漏写了依赖(头文件尤其常见),或是修改的是编译器宏定义等不修改文件的选项,很可能会得到错误的结果。
我曾经尝试系统的学习 make ,但最终结论是,遇到老项目,要么重写,要么别动它,遇事不决全量重新编译。
类似的,CMake 也有问题:
但话又说回来,涉及跨平台 C++开发,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_PRESET和VISIBILITY_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" )
安装一般涉及三类文件:
*Config.cmake
和*Targets.cmake
文件。从打包人员的角度出发,则可以分为两种场景:
*.cmake
文件。这两个选项是通过 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 平台分别使用gcovr和OpenCppCoverage,编译器警告选项适配了 GCC 、Clang 和 MSVC ,应该足够应付大部分开发场景了。
实际上还处理了一些比较细节的问题,但一方面篇幅所限,另一方面光是要介绍其应用场景可能就要想半天,需要的人就直接阅读源代码吧(懒)。
]]>RFC 1928 要求的功能几乎都实现了。
Connect
BIND
Associate
Socks5 标准 (RFC 1928) 写着必须实现这个功能,然而我做的只是个 Demo 程序,平时也用不到 GSSAPI ,为了简单起见就不实现了。
用了协程之后,思路清晰多了,不像 callback 时那么头大,相对而言轻松多了。
两大原因:
我自己是 Windows + FreeBSD 用户,正好需要这样的 socks5 server 程序——可以同时在 Windows 与 FreeBSD 运行,能够支持 TCP + UDP, IPv4 + IPv6 ,使用相同的运行配置方式。
虽然平时 socks5 server 主要在 FreeBSD 当中运行,但稳妥起见也要在 Windows 台式机运行同样的程序,用作 backup 方案。
最重要的一点,两个平台都要采用 Native 编译方式,而不是单纯的“妥协”编译方式。直白点说就是:
一直想试试 ASIO 库的协程模式,毕竟写起来流畅多了。我个人记忆力不太好,callback 数量一多就头大,实在记不过来。趁着有需求,正好拿来试一试。
由于这个程序只是个 Demo ,用是能用。只不过暂时不支持侦听到具体的地址,不提供日志记录,连接超时的时间判断是硬编码的。如果要其他额外功能都实现的话,就不能单靠一个源文件了,只能另开新 repo 把各部份拆开来重新梳理一遍。以后再在新 repo 内慢慢拆、慢慢补。
]]>这可是 22 年的视频
难道我错了,还是他不学习?
]]>这话题贴别的论坛没人看
大部分人宣称会 c++,其实都是 C
c++98 是什么水平? 就是需要一大片 n 个对象的内存,使用 vector 而不是 new[n] 可是我猜很多面试官的提问都是 delete[]而不是 delete 才能和 new[]配对
这面试官自己都没有达到 98 水平
这烂问题就不该问了
]]>我发现这书的槽点有两点: 第一点是书中明确说对于初学者不需要 C 语言基础,或者其它语言基础。但是它一再提及其它语言(有些是没有见过的语言),甚至大篇幅讲 C 语言语法,示例里 C 语言和 C++混用,看了之后合上书顿时分不清哪个是 C 的,哪个是 C++的。对于没 C 语言基础的人来说,尤其痛苦。
第二点是重点的地方不讲深,几句话带过去了,而不重要的地方废话真是多。
当时 B 站的人推荐理由是 C++ Primer 更深,不适合初学者,推荐 C++ Primer Plus 。
后悔当时没有在外网去收集这两本书的不同之处,外网骂后者是垃圾书籍的可多了。。。
这两本书完全不是同一级别,Primer 更好,Plus 是 shit!
就吐槽一下,看完还是要看完的。
]]>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++代码,输入输出能够动态持续的进行
这种都用什么方案呀
类似学而思的小猴编程: https://www.xiaohoucode.com/
]]>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 ,不知道有什么酷的解决方法?
]]>各位怎么组织的?
]]>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
]]>https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2444r0.pdf
]]>cmake . -G "Unix Makefiles" cmake --build . --config Release
生成的文件导出的 string 有本地文件夹路径字符串(但实际项目里面并没有用到__path__)
下图是用 cutter (开源反编译工具 https://github.com/rizinorg/cutter ,类似 IDA pro )
添加了一些参数(-flto ,-g0 还是不行),求大佬指点迷津
]]>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 。
在下列三个前置条件下
我向问下,有没有办法确保 A 一定在 B 之前获得 mutex ?
]]>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_没有关系才对吧
]]>#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; }
对于这个例子所产生的结果,我不是很懂,我主要是不太懂以下几个问题:
开发方面,只是用于个人项目和代码学习。我的方向是 Linux c++ 开发,平常玩 Linux 很多,会写一些 Linux 项目,不考虑跨平台,也打算摸一摸 kernel 的代码学习。
我的问题是,在 m 系列芯片的 macos 上,如何做 Linux 开发?不考虑远程 Linux 服务器和架构集的情况下,使用 clion 和 vscode remote ssh ,在 macos 本地可以有哪些方式? docker 和虚拟机吗?能不能正常的完成编译和调试?
]]>我电脑的输出是:
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; }
]]>a * pow(p, n) * pow(q, m)
其中 a, m, n 都是整数,p 和 q 是两个字符,然后现在我想定义操作一个更复杂的类,就是一般所说的多项式,但是它要满足我添加一个单项式进来之后仍然还是一个多项式的要求。。
]]>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
的效率不太高,需要重写,作者直接不干了
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")
会直接清屏。。
然后物理机上 docker 跑的 ide 就没啥问题,我怀疑问题还是使用 nfs 上的问题,所以上诉的错误一般是由什么产生的?有没有进一步的排查方式
我的初步梳理:我目前了解到的是 nfs 会有一致性的问题,但同时在这个存储上跑的只会有这一个项目啊,单个环境下的一致性问题应该在系统层面就解决了把
]]>vscode
+cmake
,debug 的方式是配置 Launch.json
和 tasks.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 中还是看不到多个线程的调试信息。 大手子都是怎么看多线程调试信息的?
]]>