diff --git a/cpp/C++_MJ.txt b/cpp/C++_MJ.txt new file mode 100644 index 0000000..9d5f54b --- /dev/null +++ b/cpp/C++_MJ.txt @@ -0,0 +1,44 @@ +1.sizeof 不是函数,是运算符。 +2.c++没有写构造函数,C++编译器不一定自动写一个默认构造函数。 +3.c++会对函数名符号进行改编,可以支持函数重载(name mangling)。 +4.被extern "C" { 修饰的代码会按照C语言的规则编译、声明被exeter "C"包含,CPP实现可以不要。 +5.函数调用要开辟会回收栈空间。 +6.incline 建议编译器 incline。 +[什么时候使用inline?] +(1)函数体积不大 +(2)频繁调用 +7.汇编 +从上往下是向下兼容,实际比如影响AX也是会影响x64中的RAX +x64 +RAX\RBX\RCX\RDX : 通用寄存器 +x86 +EAX\EBX\ECX\EDX : 通用寄存器 +16位 +AX\BX\CX\DX : 通用寄存器 +8位 +AH H High +AL L Low +8.C++中使用内联汇编 +汇编中没有; +__asm { + +} +word 2字节. +move dest, src +[地址值]([]里面一定是地址值) +call 调用 +字节占用都是低位=>高位占用, +已经占用的内存,内部采集大小端方式: + +int a = 3; + (高 ----> 低) +00000000 00000000 00000000 00000011 +[大小端] 一般来讲,大多数都是小端模式(低字节放低地址)。 + +lea dest, [地址值] (复制地址值)(load effect address) +mov dest, [地址值] (复制地址值内容) +xor a, b (a,b的异或结果复制给a) +add 加, sub 减, inc 自增, dec 自减, jmp 跳转 +xor 异或 + + diff --git a/cpp/clangd.txt b/cpp/clangd.txt new file mode 100644 index 0000000..d66f47f --- /dev/null +++ b/cpp/clangd.txt @@ -0,0 +1,52 @@ + "C_Cpp.intelliSenseEngine": "Disabled", // 禁用微软 Cpptools 插件的提示功能 + "C_Cpp.codeAnalysis.runAutomatically": false, + "C_Cpp.formatting": "Disabled", + // clangd + "clangd.path": "c:\\Users\\Sirius\\AppData\\Roaming\\Code\\User\\globalStorage\\llvm-vs-code-extensions.vscode-clangd\\install\\15.0.3\\clangd_15.0.3\\bin\\clangd.exe", // clangd 安装路径 + // Clangd 运行参数(在终端/命令行输入 clangd --help-list-hidden 可查看更多) + "clangd.arguments": [ + "--all-scopes-completion", // 全局补全(补全建议会给出在当前作用域不可见的索引,插入后自动补充作用域标识符),例如在main()中直接写cout,即使没有`#include `,也会给出`std::cout`的建议,配合"--header-insertion=iwyu",还可自动插入缺失的头文件 + "--background-index", // 后台分析并保存索引文件 + "--clang-tidy", // 启用 Clang-Tidy 以提供「静态检查」,下面设置 clang tidy 规则 + "--clang-tidy-checks=performance-*, bugprone-*, misc-*, google-*, modernize-*, readability-*, portability-*", + "--compile-commands-dir=${workspaceFolder}/.vscode", // 编译数据库(例如 compile_commands.json 文件)的目录位置 + "--completion-parse=auto", // 当 clangd 准备就绪时,用它来分析建议 + "--completion-style=detailed", // 建议风格:打包(重载函数只会给出一个建议);还可以设置为 detailed + // "--query-driver=/usr/bin/clang++", // MacOS 上需要设定 clang 编译器的路径,homebrew 安装的clang 是 /usr/local/opt/llvm/bin/clang++ + // 启用配置文件(YAML格式)项目配置文件是在项目文件夹里的“.clangd”,用户配置文件是“clangd/config.yaml”,该文件来自:Windows: %USERPROFILE%\AppData\Local || MacOS: ~/Library/Preferences/ || Others: $XDG_CONFIG_HOME, usually ~/.config + "--enable-config", + "--fallback-style=Webkit", // 默认格式化风格: 在没找到 .clang-format 文件时采用,可用的有 LLVM, Google, Chromium, Mozilla, Webkit, Microsoft, GNU + "--function-arg-placeholders=true", // 补全函数时,将会给参数提供占位符,键入后按 Tab 可以切换到下一占位符,乃至函数末 + "--header-insertion-decorators", // 输入建议中,已包含头文件的项与还未包含头文件的项会以圆点加以区分 + "--header-insertion=iwyu", // 插入建议时自动引入头文件 iwyu + "--include-cleaner-stdlib", // 为标准库头文件启用清理功能(不成熟!!!) + "--log=verbose", // 让 Clangd 生成更详细的日志 + "--pch-storage=memory", // pch 优化的位置(Memory 或 Disk,前者会增加内存开销,但会提升性能) + "--pretty", // 输出的 JSON 文件更美观 + "--ranking-model=decision_forest", // 建议的排序方案:hueristics (启发式), decision_forest (决策树) + "-j=12" // 同时开启的任务数量 + ], + // Clangd 找不到编译数据库(例如 compile_flags.json 文件)时采用的设置,缺陷是不能直接索引同一项目的不同文件,只能分析系统头文件、当前文件和include的文件 + "clangd.fallbackFlags": [ + "-pedantic", + "-Wall", + "-Wextra", + "-Wcast-align", + "-Wdouble-promotion", + "-Wformat=2", + "-Wimplicit-fallthrough", + "-Wmisleading-indentation", + "-Wnon-virtual-dtor", + "-Wnull-dereference", + "-Wold-style-cast", + "-Woverloaded-virtual", + "-Wpedantic", + "-Wshadow", + "-Wunused", + "-pthread", + "-fuse-ld=lld", + "-fsanitize=address", + "-fsanitize=undefined", + "-stdlib=libc++", + "-std=c++20" + ], \ No newline at end of file diff --git a/cpp/cmake.txt b/cpp/cmake.txt new file mode 100644 index 0000000..21ecad0 --- /dev/null +++ b/cpp/cmake.txt @@ -0,0 +1,285 @@ +下面先介绍一些CMake项目通常都需要进行的配置。下面介绍的内容以make作为构建工具作为示例。 + +下面的示例代码可以在开源项目cmake-template(发布在Gitee平台)中查看(当前commit id:c7c6b15)。把仓库克隆下来结合源码阅读本文效果更佳,如果有帮助,请点下Star哟。 + +1 设置项目版本和生成version.h +一般来说,项目一般需要设置一个版本号,方便进行版本的发布,也可以根据版本对问题或者特性进行追溯和记录。 + +通过project命令配置项目信息,如下: + +project(CMakeTemplate VERSION 1.0.0 LANGUAGES C CXX) +第一个字段是项目名称;通过VERSION指定版本号,格式为main.minor.patch.tweak,并且CMake会将对应的值分别赋值给以下变量(如果没有设置,则为空字符串): + +PROJECT_VERSION, _VERSION +PROJECT_VERSION_MAJOR, _VERSION_MAJOR +PROJECT_VERSION_MINOR, _VERSION_MINOR +PROJECT_VERSION_PATCH, _VERSION_PATCH +PROJECT_VERSION_TWEAK, _VERSION_TWEAK +因此,结合前一篇文章提到的configure_file命令,可以配置自动生成版本头文件,将头文件版本号定义成对应的宏,或者定义成接口,方便在代码运行的时候了解当前的版本号。 + +比如: + +configure_file(src/c/cmake_template_version.h.in "${PROJECT_SOURCE_DIR}/src/c/cmake_template_version.h") +假如cmake_template_version.h.in内容如下: + +#define CMAKE_TEMPLATE_VERSION_MAJOR @CMakeTemplate_VERSION_MAJOR@ +#define CMAKE_TEMPLATE_VERSION_MINOR @CMakeTemplate_VERSION_MINOR@ +#define CMAKE_TEMPLATE_VERSION_PATCH @CMakeTemplate_VERSION_PATCH@ +执行cmake配置构建系统后,将会自动生成文件:cmake_template_version.h,其中@@将会被替换为对应的值: + +#define CMAKE_TEMPLATE_VERSION_MAJOR 1 +#define CMAKE_TEMPLATE_VERSION_MINOR 0 +#define CMAKE_TEMPLATE_VERSION_PATCH 0 + +2 指定编程语言版本 +为了在不同机器上编译更加统一,最好指定语言的版本,比如声明C使用c99标准,C++使用c++11标准: + +set(CMAKE_C_STANDARD 99) +set(CMAKE_CXX_STANDARD 11) +这里设置的变量都是CMAKE_开头(包括project命令自动设置的变量),这类变量都是CMake的内置变量,正是通过修改这些变量的值来配置CMake构建的行为。 + +CMAKE_、_CMAKE或者以下划线开头后面加上任意CMake命令的变量名都是CMake保留的。 + +3 配置编译选项 +通过命令add_compile_options命令可以为所有编译器配置编译选项(同时对多个编译器生效);通过设置变量CMAKE_C_FLAGS可以配置c编译器的编译选项;而设置变量CMAKE_CXX_FLAGS可配置针对c++编译器的编译选项。比如: + +add_compile_options(-Wall -Wextra -pedantic -Werror) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pipe -std=c99") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pipe -std=c++11") +4 配置编译类型 +通过设置变量CMAKE_BUILD_TYPE来配置编译类型,可设置为:Debug、Release、RelWithDebInfo、MinSizeRel等,比如: + +set(CMAKE_BUILD_TYPE Debug) +当然,更好的方式应该是在执行cmake命令的时候通过参数-D指定: + +cmake -B build -DCMAKE_BUILD_TYPE=Debug +如果设置编译类型为Debug,那么对于c编译器,CMake会检查是否有针对此编译类型的编译选项CMAKE_C_FLAGS_DEBUG,如果有,则将它的配置内容加到CMAKE_C_FLAGS中。 + +可以针对不同的编译类型设置不同的编译选项,比如对于Debug版本,开启调试信息,不进行代码优化: + +set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -O0") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0") +对于Release版本,不包含调试信息,优化等级设置为2: + +set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O2") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2") +5 添加全局宏定义 +通过命令add_definitions可以添加全局的宏定义,在源码中就可以通过判断不同的宏定义实现相应的代码逻辑。用法如下: + +add_definitions(-DDEBUG -DREAL_COOL_ENGINEER) +6 添加include目录 +通过命令include_directories来设置头文件的搜索目录,比如: + +include_directories(src/c) +二 编译目标文件 +一般来说,编译目标(target)的类型一般有静态库、动态库和可执行文件。这时编写CMakeLists.txt主要包括两步: + +编译:确定编译目标所需要的源文件 + +链接:确定链接的时候需要依赖的额外的库 + +下面以开源项目(cmake-template)来演示。项目的目录结构如下: + +./cmake-template +├── CMakeLists.txt +├── src +│ └── c +│ ├── cmake_template_version.h +│ ├── cmake_template_version.h.in +│ ├── main.c +│ └── math +│ ├── add.c +│ ├── add.h +│ ├── minus.c +│ └── minus.h +└── test + └── c + ├── test_add.c + └── test_minus.c +项目的构建任务为: + +将math目录编译成静态库,命名为math + +编译main.c为可执行文件demo,依赖math静态库 + +编译test目录下的测试程序,可以通过命令执行所有的测试 + +支持通过命令将编译产物安装及打包 + +1 编译静态库 +这一步需要将项目目录路径src/c/math下的源文件编译为静态库,那么需要获取编译此静态库需要的文件列表,可以使用set命令,或者file命令来进行设置。比如: + +file(GLOB_RECURSE MATH_LIB_SRC src/c/math/*.c) +add_library(math STATIC ${MATH_LIB_SRC}) +使用file命令获取src/c/math目录下所有的*.c文件,然后通过add_library命令编译名为math的静态库,库的类型是第二个参数STATIC指定的。 + +如果指定为SHARED则编译的就是动态链接库。 + +2 编译可执行文件 +通过add_executable命令来往构建系统中添加一个可执行构建目标,同样需要指定编译需要的源文件。但是对于可执行文件来说,有时候还会依赖其他的库,则需要使用target_link_libraries命令来声明构建此可执行文件需要链接的库。 + +在示例项目中,main.c就使用了src/c/math下实现的一些函数接口,所以依赖于前面构建的math库。所以在CMakeLists.txt中添加以下内容: + +add_executable(demo src/c/main.c) +target_link_libraries(demo math) +第一行说明编译可执行文件demo需要的源文件(可以指定多个源文件,此处只是以单个文件作为示例);第二行表明对math库存在依赖。 + +此时可以在项目的根目录下执行构建和编译命令,并执行demo: + +➜ # cmake -B cmake-build +➜ # cmake --build cmake-build +➜ # ./cmake-build/demo +Hello CMake! +10 + 24 = 34 +40 - 96 = -56 +三 安装和打包 +1 安装 +对于安装来说,其实就是要指定当前项目在执行安装时,需要安装什么内容: + +通过install命令来说明需要安装的内容及目标路径; + +通过设置CMAKE_INSTALL_PREFIX变量说明安装的路径; + +3.15往后的版本可以使用cmake --install --prefix 覆盖指定安装路径。 + +比如,在示例项目中,把math和demo两个目标按文件类型安装: + +install(TARGETS math demo + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib) +这里通过TARGETS参数指定需要安装的目标列表;参数RUNTIME DESTINATION、LIBRARY DESTINATION、ARCHIVE DESTINATION分别指定可执行文件、库文件、归档文件分别应该安装到安装目录下个哪个子目录。 + +如果指定CMAKE_INSTALL_PREFIX为/usr/local,那么math库将会被安装到路径/usr/local/lib/目录下;而demo可执行文件则在/usr/local/bin目录下。 + +CMAKE_INSTALL_PREFIX在不同的系统上有不同的默认值,使用的时候最好显式指定路径。 + +同时,还可以使用install命令安装头文件: + +file(GLOB_RECURSE MATH_LIB_HEADERS src/c/math/*.h) +install(FILES ${MATH_LIB_HEADERS} DESTINATION include/math) +假如将安装到当前项目的output文件夹下,可以执行: + +➜ # cmake -B cmake-build -DCMAKE_INSTALL_PREFIX=./output +➜ # cmake --build cmake-build +➜ # cd cmake-build && make install && cd - +Install the project... +-- Install configuration: "" +-- Installing: .../cmake-template/output/lib/libmath.a +-- Installing: .../gitee/cmake-template/output/bin/demo +-- Installing: .../gitee/cmake-template/output/include/math/add.h +-- Installing: .../gitee/cmake-template/output/include/math/minus.h +可以看到安装了前面install命令指定要安装的文件,并且不同类型的目标文件安装到不同子目录。 + +2 打包 +要使用打包功能,需要执行include(CPack)启用相关的功能,在执行构建编译之后使用cpack命令行工具进行打包安装;对于make工具,也可以使用命令make package。 + +打包的内容就是install命令安装的内容,关键需要设置的变量有: + +变量 含义 +CPACK_GENERATOR 打包使用的压缩工具,比如"ZIP" +CPACK_OUTPUT_FILE_PREFIX 打包安装的路径前缀 +CPACK_INSTALL_PREFIX 打包压缩包的内部目录前缀 +CPACK_PACKAGE_FILE_NAME 打包压缩包的名称,由CPACK_PACKAGE_NAME、CPACK_PACKAGE_VERSION、CPACK_SYSTEM_NAME三部分构成 +比如: + +include(CPack) +set(CPACK_GENERATOR "ZIP") +set(CPACK_PACKAGE_NAME "CMakeTemplate") +set(CPACK_SET_DESTDIR ON) +set(CPACK_INSTALL_PREFIX "") +set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION}) +假如:CPACK_OUTPUT_FILE_PREFIX设置为/usr/local/package;CPACK_INSTALL_PREFIX设置为real/cool/engineer;CPACK_PACKAGE_FILE_NAME设置为CMakeTemplate-1.0.0;那么执行打包文件的生成路径为: + +/usr/local/package/CMakeTemplate-1.0.0.zip +解压这个包得到的目标文件则会位于路径下: + +/usr/local/package/real/cool/engineer/ +此时重新执行构建,使用cpack命令执行打包: + +➜ # cmake -B cmake-build -DCPACK_OUTPUT_FILE_PREFIX=`pwd`/output +➜ # cmake --build cmake-build +➜ # cd cmake-build && cpack && cd - +CPack: Create package using ZIP +CPack: Install projects +CPack: - Run preinstall target for: CMakeTemplate +CPack: - Install project: CMakeTemplate +CPack: Create package +CPack: - package: /Users/Farmer/gitee/cmake-template/output/CMakeTemplate-1.0.0-Darwin.zip generated. +cpack有一些参数是可以覆盖CMakeLists.txt设置的参数的,比如这里的-G参数就会覆盖变量CPACK_GENERATOR,具体细节可使用cpack --help查看。 + +四 测试 +CMake的测试功能使用起来有几个步骤: + +CMakeLists.txt中通过命令enable_testing()或者include(CTest)来启用测试功能; + +使用add_test命令添加测试样例,指定测试的名称和测试命令、参数; + +构建编译完成后使用ctest命令行工具运行测试。 + +为了控制是否开启测试,可使用option命令设置一个开关,在开关打开时才进行测试,比如: + +option(CMAKE_TEMPLATE_ENABLE_TEST "Whether to enable unit tests" ON) +if (CMAKE_TEMPLATE_ENABLE_TEST) + message(STATUS "Unit tests enabled") + enable_testing() +endif() +这里为了方便后续演示,暂时是默认开启的。 + +1 编写测试程序 +在此文的示例代码中,针对add.c和minus.c实现了两个测试程序,它们的功能是类似的,接受三个参数,用第一和第二个计算两个参数的和或者差,判断是否和第三个参数相等,如test_add.c的代码为: + +// @Author: Farmer Li, 公众号: 很酷的程序员/RealCoolEngineer +// @Date: 2021-05-10 + +#include +#include + +#include "math/add.h" + +int main(int argc, char* argv[]) { + if (argc != 4) { + printf("Usage: test_add v1 v2 expected\n"); + return 1; + } + + int x = atoi(argv[1]); + int y = atoi(argv[2]); + int expected = atoi(argv[3]); + int res = add_int(x, y); + + if (res != expected) { + return 1; + } else { + return 0; + } +} +这里需要注意的是,对于测试程序来说,如果返回值非零,则表示测试失败。 + +2 添加测试 +接下来先使用add_executable命令生成测试程序,然后使用add_test命令添加单元测试: + +add_executable(test_add test/c/test_add.c) +add_executable(test_minus test/c/test_minus.c) +target_link_libraries(test_add math) +target_link_libraries(test_minus math) +add_test(NAME test_add COMMAND test_add 10 24 34) +add_test(NAME test_minus COMMAND test_minus 40 96 -56) +3 执行测试 +现在重新执行cmake命令更新构建系统,执行构建,再执行测试: + +➜ # cmake -B cmake-build +➜ # cmake --build cmake-build +➜ # cd cmake-build && ctest && cd - +Test project /Users/Farmer/gitee/cmake-template/cmake-build + Start 1: test_add +1/2 Test #1: test_add ......................... Passed 0.00 sec + Start 2: test_minus +2/2 Test #2: test_minus ....................... Passed 0.01 sec + +100% tests passed, 0 tests failed out of 2 +使用ctest -VV则可以看到更加详细的测试流程和结果。 + +在CMake 3.20往后的版本中,ctest可以使用--test-dir指定测试执行目录。 + +至此,一个较为完备的CMakeLists.txt就开发完成了。 diff --git a/cpp/common/box_sleep.hpp b/cpp/common/box_sleep.hpp new file mode 100644 index 0000000..c498f74 --- /dev/null +++ b/cpp/common/box_sleep.hpp @@ -0,0 +1,86 @@ +#ifndef SLEEP_THREAD_HPP_ +#define SLEEP_THREAD_HPP_ + +/* +* 跟 Sleep 的功能相同,其不同点是可以 随时终止正在进行的 Sleep。 +*/ + +#include +#include + +namespace cpppub { + +typedef class CThreadSleep +{ +public: + CThreadSleep(); + ~CThreadSleep() = default; +public: + // 进入睡眠,不传入值使用默认值,传入则使用传入值。 + void Sleep(int nMilliseconds = 0); + // 停止所有的 Sleep 睡眠,继续向下。 + void Contiune(); + // 设置默认的睡眠时长,不填写时其默认值为 10 ms, 如果传入 <= 0 值将使用默认的 10 ms。 + void SetTimeOut(int nMilliseconds); + +private: + bool getStatus() const; + +private: + // 同步原语,能用于阻塞一个线程,或同时阻塞多个线程,直至另一线程修改共享变量(条件)并通知 condition_variable + std::condition_variable m_Cv; + int m_nTimeOut; // 睡眠时间 + const int m_nDefaultTimeOut = 10; // 默认睡眠时间 + std::mutex m_Mutex; // 锁 + bool m_bStopSleep; // 睡眠标志位 +}ThreadSleep; + +CThreadSleep::CThreadSleep() +{ + m_bStopSleep = false; + m_nTimeOut = 10; +} + +inline void CThreadSleep::Sleep(int nMilliseconds) +{ + int nSleepTime = m_nTimeOut; + if (nMilliseconds > 0) + nSleepTime = nMilliseconds; + + m_bStopSleep = false; + std::unique_lock lock(m_Mutex); + std::chrono::system_clock::time_point nowtime = std::chrono::system_clock::now(); + + // 度过 timeout 时限后 函数求值为 false 则为 false,否则为 true。 + // 若已度过时限,则求值并返回求值结果。 + if (m_Cv.wait_until(lock, nowtime + (std::chrono::milliseconds(nSleepTime)), + [this] { return getStatus(); })) { + // 这里触发手动关闭 + } + else { + // 这里触发超时 + } +} + +inline void CThreadSleep::Contiune() +{ + m_bStopSleep = true; + m_Cv.notify_all(); +} + +inline void CThreadSleep::SetTimeOut(int nMilliseconds) +{ + if (nMilliseconds <= 0) + m_nTimeOut = m_nDefaultTimeOut; + else + m_nTimeOut = nMilliseconds; +} + +inline bool CThreadSleep::getStatus() const +{ + return m_bStopSleep; +} + +} +#endif // !SLEEP_THREAD_HPP_ + diff --git a/cpp/common/box_threadpool.hpp b/cpp/common/box_threadpool.hpp new file mode 100644 index 0000000..5e6eb3d --- /dev/null +++ b/cpp/common/box_threadpool.hpp @@ -0,0 +1,209 @@ +#ifndef THREAD_POOL_HEADER +#define THREAD_POOL_HEADER + +#include +#include +#include +#include +#include +#include +#include + +namespace cppbox { + +// 线程安全队列 +template class CQueueMt +{ +public: + CQueueMt() = default; + CQueueMt(CQueueMt&& rh) noexcept {} + ~CQueueMt() = default; + +public: + // 返回队列是否为空 + bool IsEmpty() + { + std::unique_lock lock(m_mutex); + return m_queue.empty(); + } + // 返回队列数量 + size_t Size() + { + std::unique_lock lock(m_mutex); + return m_queue.size(); + } + // 添加元素 + void Push(T& t) + { + std::unique_lock lock(m_mutex); + m_queue.emplace(t); + } + // 取出元素 + bool Pop(T& t) + { + std::unique_lock lock(m_mutex); + if (m_queue.empty()) + return false; + t = std::move(m_queue.front()); + m_queue.pop(); + return true; + } + // 清除 + void clear() + { + std::unique_lock lock(m_mutex); + std::queue queue; + std::swap(m_queue, queue); + } + +private: + std::mutex m_mutex; + std::queue m_queue; +}; + +class CBoxThreadPool +{ +private: + class CWorker + { + public: + CWorker(CBoxThreadPool* pThreadPool, const size_t nID) + : m_nID(nID), m_pThreadPool(pThreadPool) + { + is_run_ = false; + } + // 重载操作 + void operator()() + { + // 1.定义基础函数类 func + std::function func; + // 2.是否成功取出队列中的元素 + bool have = false; + while (m_pThreadPool->is_start_ || !is_run_ || isContinue()) { + // 进入 while 后,标志位置成已进入。 + is_run_ = true; + { + // 2.1 为线程环境加锁,互斥访问线程的休眠与唤醒 + std::unique_lock lock(m_pThreadPool->mutex_); + // 2.2 如果队列为空则阻塞并等待条件变量的通知 + if (m_pThreadPool->m_queue.IsEmpty()) + m_pThreadPool->cv_.wait(lock); + // 2.3 取出任务队列中的元素 + have = m_pThreadPool->m_queue.Pop(func); + } + + if (have) + func(); + } + } + // 检查是否需要继续完成未完成的任务 + bool isContinue() + { + if (!m_pThreadPool->is_wait_) + return false; + if (m_pThreadPool->m_queue.IsEmpty()) + return false; + return true; + } + + private: + size_t m_nID; // 工作ID + CBoxThreadPool* m_pThreadPool; // 所属线程池 + bool is_run_; // 是否进入工作了 + }; + +public: + explicit CBoxThreadPool(const int nThreadNum = 4) + : th_cnt_(nThreadNum), + is_start_(false), + is_wait_(false), + threads_(std::vector(nThreadNum)) + { + } + ~CBoxThreadPool() { ShutDownWaitCurrent(); } + CBoxThreadPool(const CBoxThreadPool&) = delete; + CBoxThreadPool(CBoxThreadPool&&) = delete; + CBoxThreadPool& operator=(const CBoxThreadPool&) = delete; + CBoxThreadPool& operator=(CBoxThreadPool&&) = delete; + +public: + // 初始化线程池 + void Init() + { + if (!is_start_) { + threads_.resize(th_cnt_); + for (size_t i = 0; i < threads_.size(); ++i) { + threads_.at(i) = std::thread(CWorker(this, i)); + } + is_start_ = true; + is_wait_ = false; + return; + } + } + // 等待各线程当前任务完成然后关闭线程池 + void ShutDownWaitCurrent() + { + if (!is_start_) + return; + is_wait_ = false; + is_start_ = false; + Close(); + m_queue.clear(); + } + + // 等待所有已提交的任务完成然后关闭线程池 + void ShutDownWaitAll() + { + if (!is_start_) + return; + is_wait_ = true; + is_start_ = false; + Close(); + m_queue.clear(); + } + // 向池子中提交一个待执行函数 + template + auto Submit(F&& f, Args&&... args) -> std::future + { + // 1. 创建一个绑定参数的函数, + // 连接函数和参数定义,特殊函数类型,避免左右值错误 + std::function func = + std::bind(std::forward(f), std::forward(args)...); + // 2. 使用智能指针以便调用拷贝构造 + auto pTask = + std::make_shared>(func); + // 3. 包装进一个无参数函数 + std::function rf = [pTask]() { (*pTask)(); }; + // 4. 入队 + m_queue.Push(rf); + // 5. 唤醒一个等待中的线程 + cv_.notify_one(); + // 6. 返回先前注册的任务指针 + return pTask->get_future(); + } + +private: + void Close() + { + cv_.notify_all(); + + for (auto& m_thread : threads_) { + if (m_thread.joinable()) + m_thread.join(); + } + threads_.clear(); + } + +private: + int th_cnt_; // 线程数 + bool is_start_; // 线程池是否启动 + bool is_wait_; // 是否等待所有线程结束 + std::mutex mutex_; // 线程休眠锁互斥 + + CQueueMt> m_queue; + std::vector threads_; + std::condition_variable cv_; // 环境锁,用于休眠或者唤醒 +}; + +} // namespace cppbox +#endif \ No newline at end of file diff --git a/cpp/common/change_net_state.hpp b/cpp/common/change_net_state.hpp new file mode 100644 index 0000000..9b6bd90 --- /dev/null +++ b/cpp/common/change_net_state.hpp @@ -0,0 +1,147 @@ +#include +#include +#include +#include +#include +#pragma comment(lib,"ws2_32.lib") +#pragma comment(lib,"setupapi.lib") + +//wchar_t * char2wchar(const char* cchar) +//{ +// wchar_t *m_wchar; +// int len = MultiByteToWideChar(CP_ACP, 0, cchar, strlen(cchar), NULL, 0); +// m_wchar = new wchar_t[len + 1]; +// MultiByteToWideChar(CP_ACP, 0, cchar, strlen(cchar), m_wchar, len); +// m_wchar[len] = '\0'; +// return m_wchar; +//} +// +//char * wchar2char(const wchar_t* wchar) +//{ +// char * m_char; +// int len = WideCharToMultiByte(CP_ACP, 0, wchar, wcslen(wchar), NULL, 0, NULL, NULL); +// m_char = new char[len + 1]; +// WideCharToMultiByte(CP_ACP, 0, wchar, wcslen(wchar), m_char, len, NULL, NULL); +// m_char[len] = '\0'; +// return m_char; +//} + +BOOL DisableNetInterface(const std::string& szHardWareId, bool bStatus) +{ + IN LPTSTR HardwareId; + //硬件ComponentId,注册表地址:system\currentcontrolset\class\{4D36E972-E325-11CE-BFC1-08002BE10318}\0000 + // HardwareId = L"PCI\\VEN_8086&DEV_0085&SUBSYS_13118086&REV_34"; + HardwareId = (LPTSTR)szHardWareId.c_str(); + DWORD NewState; + if (bStatus) + { + NewState = DICS_DISABLE; + //禁用 + } + else + { + NewState = DICS_ENABLE; + //启用 + } + //调用ddk函数,来禁用网卡 + DWORD i, err; + BOOL Found = false; + HDEVINFO hDevInfo; + SP_DEVINFO_DATA spDevInfoData; + //访问系统的硬件库 + hDevInfo = SetupDiGetClassDevs(NULL, "PCI", NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT); + if (hDevInfo == INVALID_HANDLE_VALUE) + { + //printf("访问系统硬件出错!"); + return false; + } + //枚举硬件,获得需要的接口 + spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &spDevInfoData); i++) + { + DWORD DataT; + LPTSTR p, buffer = NULL; + DWORD buffersize = 0; + //获得硬件的属性值 + while (!SetupDiGetDeviceRegistryProperty( + hDevInfo, + &spDevInfoData, + SPDRP_HARDWAREID, + &DataT, + (PBYTE)buffer, + buffersize, + &buffersize)) + { + if (GetLastError() == ERROR_INVALID_DATA) + { + //不存在HardwareID. Continue. + break; + } + else if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + //buffer size不对. + if (buffer) + LocalFree(buffer); + buffer = (LPTSTR)LocalAlloc(LPTR, buffersize); + } + else + { + //未知错误 + goto cleanup_DeviceInfo; + } + } + if (GetLastError() == ERROR_INVALID_DATA) + continue; + //比较,找到和网卡ID相同的项 + for (p = buffer; *p && (p < &buffer[buffersize]); p += lstrlen(p) + sizeof(TCHAR)) + { + if (!_tcscmp(HardwareId, p)) + { + //找到网卡 + Found = TRUE; + break; + } + } + if (buffer) + LocalFree(buffer); + //如果相等 + if (Found) + { + //禁用该设备 + SP_PROPCHANGE_PARAMS spPropChangeParams; + spPropChangeParams.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); + spPropChangeParams.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE; + spPropChangeParams.Scope = DICS_FLAG_GLOBAL; + spPropChangeParams.StateChange = NewState; + //禁用:DICS_DISABLE,DICS_ENABLE启用 + // + if (!SetupDiSetClassInstallParams(hDevInfo, &spDevInfoData, (SP_CLASSINSTALL_HEADER*)&spPropChangeParams, sizeof(spPropChangeParams))) + { + DWORD errorcode = GetLastError(); + } + if (!SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, hDevInfo, &spDevInfoData)) + { + DWORD errorcode = GetLastError(); + } + switch (NewState) + { + case DICS_DISABLE: + printf("成功禁用网络!"); + break; + case DICS_ENABLE: + printf("成功启用网络!"); + break; + } + break; + } + } + //delete[] HardwareId; + //HardwareId = nullptr; + + //退出时,清理工作环境 + cleanup_DeviceInfo: + err = GetLastError(); + SetupDiDestroyDeviceInfoList(hDevInfo); + SetLastError(err); + return true; +} \ No newline at end of file diff --git a/cpp/common/closeprocess.hpp b/cpp/common/closeprocess.hpp new file mode 100644 index 0000000..2966562 --- /dev/null +++ b/cpp/common/closeprocess.hpp @@ -0,0 +1,64 @@ +#ifndef CLOSE_PROCESS_HPP +#define CLOSE_PROCESS_HPP + +/* +* 杀掉所有名字等于指定的名称的进程。 +*/ + +#include +#include +#include +#include + +char* Wchar2Char(const wchar_t* wp) +{ + int len = WideCharToMultiByte(CP_ACP, 0, wp, wcslen(wp), NULL, 0, NULL, NULL); + char* m_char = new char[len + 1]; + WideCharToMultiByte(CP_ACP, 0, wp, wcslen(wp), m_char, len, NULL, NULL); + m_char[len] = '\0'; + return m_char; +} + +BOOL KillProcessFromName(std::string strProcessName) +{ + //创建进程快照(TH32CS_SNAPPROCESS表示创建所有进程的快照) + HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + //PROCESSENTRY32进程快照的结构体 + PROCESSENTRY32 pe; + //实例化后使用Process32First获取第一个快照的进程前必做的初始化操作 + pe.dwSize = sizeof(PROCESSENTRY32); + //下面的IF效果同: + //if(hProcessSnap == INVALID_HANDLE_VALUE) 无效的句柄 + if (!Process32First(hSnapShot, &pe)) + { + return FALSE; + } + //将字符串转换为小写 + std::transform(strProcessName.begin(), strProcessName.end(), strProcessName.begin(), ::tolower); + //如果句柄有效 则一直获取下一个句柄循环下去 + while (Process32Next(hSnapShot, &pe)) + { + char* pszTem = Wchar2Char(pe.szExeFile); + //pe.szExeFile获取当前进程的可执行文件名称 + std::string scTmp = std::string(pszTem); + delete[] pszTem; + //将可执行文件名称所有英文字母修改为小写 + std::transform(scTmp.begin(), scTmp.end(), scTmp.begin(), ::tolower); + //scTmp.MakeLower(); + //比较当前进程的可执行文件名称和传递进来的文件名称是否相同 + //相同的话Compare返回0 + if (scTmp == strProcessName) + { + //从快照进程中获取该进程的PID(即任务管理器中的PID) + DWORD dwProcessID = pe.th32ProcessID; + HANDLE hProcess = ::OpenProcess(PROCESS_TERMINATE, FALSE, dwProcessID); + ::TerminateProcess(hProcess, 0); + CloseHandle(hProcess); + return TRUE; + } + //scTmp.ReleaseBuffer(); + } + //strProcessName.ReleaseBuffer(); + return FALSE; +} +#endif \ No newline at end of file diff --git a/cpp/common/judge_ip.hpp b/cpp/common/judge_ip.hpp new file mode 100644 index 0000000..ee347c6 --- /dev/null +++ b/cpp/common/judge_ip.hpp @@ -0,0 +1,133 @@ +#ifndef W_PUBLIC_H_ +#define W_PUBLIC_H_ + +#include +#include +#include +#include +#include +#include + +#pragma comment(lib,"Iphlpapi.lib") //需要添加Iphlpapi.lib库 + +// 工程是否是 Unicode 编码 +//#define CHARSET_UNICODE_DEFINE +namespace cpppub { + +bool IsLocalIPExist(const char* pszIP) +{ + bool isHave = false; + //PIP_ADAPTER_INFO结构体指针存储本机网卡信息 + auto pIpAdapterInfo = new IP_ADAPTER_INFO(); + //得到结构体大小,用于GetAdaptersInfo参数 + unsigned long stSize = sizeof(IP_ADAPTER_INFO); + //调用GetAdaptersInfo函数,填充pIpAdapterInfo指针变量;其中stSize参数既是一个输入量也是一个输出量 + ULONG nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize); + delete pIpAdapterInfo; + // 这里的操作:重新分配是为了保证有足够的空间来进行存储。 + pIpAdapterInfo = (IP_ADAPTER_INFO*)(new BYTE[stSize]); + nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize); + //记录网卡数量 + int netCardNum = 0; + //记录每张网卡上的IP地址数量 + int IPnumPerNetCard = 0; + PIP_ADAPTER_INFO header = pIpAdapterInfo; + if (ERROR_SUCCESS == nRel) + { + //输出网卡信息 + //可能有多网卡,因此通过循环去判断 + while (pIpAdapterInfo) + { + IP_ADDR_STRING *pIpAddrString = &(pIpAdapterInfo->IpAddressList); + do + { + if (strcmp(pIpAddrString->IpAddress.String, pszIP) == 0) + { + isHave = true; + break; + } + pIpAddrString = pIpAddrString->Next; + } while (pIpAddrString); + + if (isHave) + break; + + pIpAdapterInfo = pIpAdapterInfo->Next; + } + } + //释放内存空间 + delete[] header; + return isHave; +} + + +char* Wchar2Char(const wchar_t* wp) +{ + int len = WideCharToMultiByte(CP_ACP, 0, wp, + static_cast(wcslen(wp)), nullptr, 0, nullptr, nullptr); + char* m_char = new char[len + 1]; + WideCharToMultiByte(CP_ACP, 0, wp, static_cast(wcslen(wp)), m_char, len, nullptr, nullptr); + m_char[len] = '\0'; + return m_char; +} + +void Wchar2CharFree(const char* pszChar) +{ + delete[] pszChar; +} + +BOOL KillProcessFromName(const std::string& strProcessName) +{ + std::string szTemProcessName = strProcessName; + //创建进程快照(TH32CS_SNAPPROCESS表示创建所有进程的快照) + HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + //PROCESSENTRY32进程快照的结构体 + PROCESSENTRY32 pe; + //实例化后使用Process32First获取第一个快照的进程前必做的初始化操作 + pe.dwSize = sizeof(PROCESSENTRY32); + //下面的IF效果同: + //if(hProcessSnap == INVALID_HANDLE_VALUE) 无效的句柄 + if (!Process32First(hSnapShot, &pe)) + { + return FALSE; + } + //将字符串转换为小写 + std::transform(szTemProcessName.begin(), szTemProcessName.end(), szTemProcessName.begin(), ::tolower); + //如果句柄有效 则一直获取下一个句柄循环下去 + while (Process32Next(hSnapShot, &pe)) + { + std::string scTmp; + + // Unicode 编码时 + // pe.szExeFile获取当前进程的可执行文件名称 +#ifdef CHARSET_UNICODE_DEFINE + char* pszTem = Wchar2Char(pe.szExeFile); + scTmp = std::string(pszTem); + Wchar2CharFree(pszTem); + pszTem = nullptr; +#else + scTmp = std::string(pe.szExeFile); +#endif // CHARSET_UNICODE_DEFINE + + //将可执行文件名称所有英文字母修改为小写 + std::transform(scTmp.begin(), scTmp.end(), scTmp.begin(), ::tolower); + //scTmp.MakeLower(); + //比较当前进程的可执行文件名称和传递进来的文件名称是否相同 + //相同的话Compare返回0 + if (scTmp == strProcessName) + { + //从快照进程中获取该进程的PID(即任务管理器中的PID) + DWORD dwProcessID = pe.th32ProcessID; + HANDLE hProcess = ::OpenProcess(PROCESS_TERMINATE, FALSE, dwProcessID); + ::TerminateProcess(hProcess, 0); + CloseHandle(hProcess); + return TRUE; + } + //scTmp.ReleaseBuffer(); + } + //strProcessName.ReleaseBuffer(); + return FALSE; +} + +} +#endif \ No newline at end of file diff --git a/cpp/common/msvc_complier_info.cpp b/cpp/common/msvc_complier_info.cpp new file mode 100644 index 0000000..37da681 --- /dev/null +++ b/cpp/common/msvc_complier_info.cpp @@ -0,0 +1,86 @@ +#include +#include + +int main() { + int mscVersion = _MSC_VER; + + mscVersion = mscVersion - mscVersion % 10; + std::string vcVersion; + std::string releaseDate; + std::string toolsetVersion; + std::string ideInfo; + + if (mscVersion == 1200) { + vcVersion = "VC6.0 (Visual C++ 6.0)"; + releaseDate = "1998"; + toolsetVersion = "V60"; + ideInfo = "MSVC++ 6.0"; + } else if (mscVersion == 1300) { + vcVersion = "VC7.0 (Visual Studio 2002)"; + releaseDate = "2002"; + toolsetVersion = "V70"; + ideInfo = "7.0"; + } else if (mscVersion == 1310) { + vcVersion = "VC7.1 (Visual Studio 2003)"; + releaseDate = "2003"; + toolsetVersion = "V71"; + ideInfo = "7.1"; + } else if (mscVersion == 1400) { + vcVersion = "VC8.0 (Visual Studio 2005)"; + releaseDate = "2005"; + toolsetVersion = "V80"; + ideInfo = "8.0"; + } else if (mscVersion == 1500) { + vcVersion = "VC9.0 (Visual Studio 2008)"; + releaseDate = "2008"; + toolsetVersion = "V90"; + ideInfo = "9.0"; + } else if (mscVersion == 1600) { + vcVersion = "VC10.0 (Visual Studio 2010)"; + releaseDate = "2010"; + toolsetVersion = "V100"; + ideInfo = "10.0"; + } else if (mscVersion == 1700) { + vcVersion = "VC11.0 (Visual Studio 2012)"; + releaseDate = "2012"; + toolsetVersion = "V110"; + ideInfo = "11.0"; + } else if (mscVersion == 1800) { + vcVersion = "VC12.0 (Visual Studio 2013)"; + releaseDate = "2013"; + toolsetVersion = "V120"; + ideInfo = "12.0"; + } else if (mscVersion == 1900) { + vcVersion = "VC14.0 (Visual Studio 2015)"; + releaseDate = "2015"; + toolsetVersion = "V140"; + ideInfo = "14.0"; + } else if (mscVersion == 1910) { + vcVersion = "VC14.1 (Visual Studio 2017)"; + releaseDate = "2017"; + toolsetVersion = "V141"; + ideInfo = "14.1"; + } else if (mscVersion == 1920) { + vcVersion = "VC14.2 (Visual Studio 2019)"; + releaseDate = "2019"; + toolsetVersion = "V142"; + ideInfo = "14.2"; + } else if (mscVersion == 1930) { + vcVersion = "VC14.3 (Visual Studio 2022)"; + releaseDate = "2022"; + toolsetVersion = "V143"; + ideInfo = "14.3"; + } else { + vcVersion = "未知版本"; + releaseDate = "未知"; + toolsetVersion = "未知"; + ideInfo = "未知"; + } + + std::cout << "VC版本: " << vcVersion << std::endl; + std::cout << "发布时间: " << releaseDate << std::endl; + std::cout << "工具集版本: " << toolsetVersion << std::endl; + std::cout << "IDE信息: " << ideInfo << std::endl; + + return 0; +} diff --git a/cpp/common/network_card.hpp b/cpp/common/network_card.hpp new file mode 100644 index 0000000..592fb04 --- /dev/null +++ b/cpp/common/network_card.hpp @@ -0,0 +1,99 @@ +// 这里是其他函数实现的源Demo +#include +#include +#include + +int NetWorkInter() +{ + //PIP_ADAPTER_INFO结构体指针存储本机网卡信息 + PIP_ADAPTER_INFO pIpAdapterInfo = new IP_ADAPTER_INFO(); + //得到结构体大小,用于GetAdaptersInfo参数 + unsigned long stSize = sizeof(IP_ADAPTER_INFO); + //调用GetAdaptersInfo函数,填充pIpAdapterInfo指针变量;其中stSize参数既是一个输入量也是一个输出量 + int nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize); + //记录网卡数量 + int netCardNum = 0; + //记录每张网卡上的IP地址数量 + int IPnumPerNetCard = 0; + if (ERROR_BUFFER_OVERFLOW == nRel) + { + //如果函数返回的是ERROR_BUFFER_OVERFLOW + //则说明GetAdaptersInfo参数传递的内存空间不够,同时其传出stSize,表示需要的空间大小 + //这也是说明为什么stSize既是一个输入量也是一个输出量 + //释放原来的内存空间 + delete pIpAdapterInfo; + //重新申请内存空间用来存储所有网卡信息 + pIpAdapterInfo = (PIP_ADAPTER_INFO)new BYTE[stSize]; + //再次调用GetAdaptersInfo函数,填充pIpAdapterInfo指针变量 + nRel = GetAdaptersInfo(pIpAdapterInfo, &stSize); + } + if (ERROR_SUCCESS == nRel) + { + //输出网卡信息 + //可能有多网卡,因此通过循环去判断 + while (pIpAdapterInfo) + { + std::cout << "网卡数量:" << ++netCardNum << std::endl; + std::cout << "网卡名称:" << pIpAdapterInfo->AdapterName << std::endl; + std::cout << "网卡描述:" << pIpAdapterInfo->Description << std::endl; + switch (pIpAdapterInfo->Type) + { + case MIB_IF_TYPE_OTHER: + std::cout << "网卡类型:" << "OTHER" << std::endl; + break; + case MIB_IF_TYPE_ETHERNET: + std::cout << "网卡类型:" << "ETHERNET" << std::endl; + break; + case MIB_IF_TYPE_TOKENRING: + std::cout << "网卡类型:" << "TOKENRING" << std::endl; + break; + case MIB_IF_TYPE_FDDI: + std::cout << "网卡类型:" << "FDDI" << std::endl; + break; + case MIB_IF_TYPE_PPP: + printf("PP\n"); + std::cout << "网卡类型:" << "PPP" << std::endl; + break; + case MIB_IF_TYPE_LOOPBACK: + std::cout << "网卡类型:" << "LOOPBACK" << std::endl; + break; + case MIB_IF_TYPE_SLIP: + std::cout << "网卡类型:" << "SLIP" << std::endl; + break; + default: + + break; + } + std::cout << "网卡MAC地址:"; + for (DWORD i = 0; i < pIpAdapterInfo->AddressLength; i++) + if (i < pIpAdapterInfo->AddressLength - 1) + { + printf("%02X-", pIpAdapterInfo->Address[i]); + } + else + { + printf("%02X\n", pIpAdapterInfo->Address[i]); + } + std::cout << "网卡IP地址如下:" << std::endl; + //可能网卡有多IP,因此通过循环去判断 + IP_ADDR_STRING *pIpAddrString = &(pIpAdapterInfo->IpAddressList); + do + { + std::cout << "该网卡上的IP数量:" << ++IPnumPerNetCard << std::endl; + std::cout << "IP 地址:" << pIpAddrString->IpAddress.String << std::endl; + std::cout << "子网地址:" << pIpAddrString->IpMask.String << std::endl; + std::cout << "网关地址:" << pIpAdapterInfo->GatewayList.IpAddress.String << std::endl; + pIpAddrString = pIpAddrString->Next; + } while (pIpAddrString); + pIpAdapterInfo = pIpAdapterInfo->Next; + std::cout << "--------------------------------------------------------------------" << std::endl; + } + + } + //释放内存空间 + if (pIpAdapterInfo) + { + delete pIpAdapterInfo; + } + return 0; +} \ No newline at end of file diff --git a/cpp/error/cpp_err.cpp b/cpp/error/cpp_err.cpp new file mode 100644 index 0000000..4c48126 --- /dev/null +++ b/cpp/error/cpp_err.cpp @@ -0,0 +1,93 @@ +#include "cpp_err.h" +#include + +#ifdef _MSC_VER +#include "windows.h" +#include "DbgHelp.h" +#endif + +void stackoverflow() +{ + // 1.线程栈空间有上限: windows 默认:1MB,Linux默认 2MB。 + // 2.当前线程占用栈空间大小:线程函数调用堆栈中各个函数占用的栈空间总和。 + // 3.哪些对象占用了栈空间: + // (1)函数局部变量 + // (2)调用函数的参数 + // 4.常见引发栈溢出的原因: + // (1)递归太深 + // (2)局部变量占用太大 + // (3)switch-case case分支过多。 + // (4)死循环调用 + // 5.发生线程栈溢出时,VS可能直接退出,无法看到调用堆栈,可以使用WinDBG查看。 +} + +#ifdef _MSC_VER +int GenerateMiniDump(PEXCEPTION_POINTERS pExceptionPointers, const std::string& dump_dir) +{ + // 定义函数指针 + typedef BOOL(WINAPI * MiniDumpWriteDumpT)( + HANDLE, + DWORD, + HANDLE, + MINIDUMP_TYPE, + PMINIDUMP_EXCEPTION_INFORMATION, + PMINIDUMP_USER_STREAM_INFORMATION, + PMINIDUMP_CALLBACK_INFORMATION + ); + // 从 "DbgHelp.dll" 库中获取 "MiniDumpWriteDump" 函数 + MiniDumpWriteDumpT pfnMiniDumpWriteDump = NULL; + HMODULE hDbgHelp = LoadLibrary("DbgHelp.dll"); + if (NULL == hDbgHelp) + { + return EXCEPTION_CONTINUE_EXECUTION; + } + pfnMiniDumpWriteDump = (MiniDumpWriteDumpT)GetProcAddress(hDbgHelp, "MiniDumpWriteDump"); + + if (NULL == pfnMiniDumpWriteDump) + { + FreeLibrary(hDbgHelp); + return EXCEPTION_CONTINUE_EXECUTION; + } + // 创建 dmp 文件 + char path_buffer[512]{}; + char szVersion[] = "DumpDemo_v1.0"; + SYSTEMTIME stLocalTime; + GetLocalTime(&stLocalTime); + std::snprintf(path_buffer, sizeof(path_buffer), "%s\\%s-%04d%02d%02d-%02d%02d%02d.dmp", dump_dir.c_str(), + szVersion, stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, + stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond); + HANDLE hDumpFile = CreateFile(path_buffer, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE | FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0); + if (INVALID_HANDLE_VALUE == hDumpFile) + { + FreeLibrary(hDbgHelp); + return EXCEPTION_CONTINUE_EXECUTION; + } + // 写入 dmp 文件 + MINIDUMP_EXCEPTION_INFORMATION expParam; + expParam.ThreadId = GetCurrentThreadId(); + expParam.ExceptionPointers = pExceptionPointers; + expParam.ClientPointers = FALSE; + pfnMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), + hDumpFile, MiniDumpWithDataSegs, (pExceptionPointers ? &expParam : NULL), NULL, NULL); + // 释放文件 + CloseHandle(hDumpFile); + FreeLibrary(hDbgHelp); + return EXCEPTION_EXECUTE_HANDLER; +} + +LONG WINAPI ExceptionFilter(LPEXCEPTION_POINTERS lpExceptionInfo) +{ + // 这里做一些异常的过滤或提示 + if (IsDebuggerPresent()) + { + return EXCEPTION_CONTINUE_SEARCH; + } + return GenerateMiniDump(lpExceptionInfo, "D:\\"); +} +// windows cpp 崩溃使用 windbg 调试 +void use_windbg() +{ + SetUnhandledExceptionFilter(ExceptionFilter); +} +#endif \ No newline at end of file diff --git a/cpp/error/cpp_err.h b/cpp/error/cpp_err.h new file mode 100644 index 0000000..db84bea --- /dev/null +++ b/cpp/error/cpp_err.h @@ -0,0 +1,9 @@ +#pragma once + +// 线程栈溢出 +void stackoverflow(); + +#ifdef _MSC_VER +// windows cpp 崩溃使用 windbg 调试 +void use_windbg(); +#endif \ No newline at end of file diff --git a/cpp/export_c/ex_lib.cpp b/cpp/export_c/ex_lib.cpp new file mode 100644 index 0000000..f901828 --- /dev/null +++ b/cpp/export_c/ex_lib.cpp @@ -0,0 +1,29 @@ +#include "ex_lib.h" +#include "my_math.h" +#include + +struct math_struct { + my_math impl; +}; + +extern "C" +math_struct* create() +{ + return new(std::nothrow) math_struct; +} + +extern "C" +int get_sum(struct math_struct* ms, int a, int b) +{ + if (!ms) + return -1; + return ms->impl.GetSum(a, b); +} + +extern "C" +void free_math(struct math_struct* ms) +{ + if (!ms) + return; + delete ms; +} diff --git a/cpp/export_c/ex_lib.h b/cpp/export_c/ex_lib.h new file mode 100644 index 0000000..d0b73f8 --- /dev/null +++ b/cpp/export_c/ex_lib.h @@ -0,0 +1,19 @@ +#ifndef EX_LIB_H_ +#define EX_LIB_H_ + +#if __cplusplus +extern "C" { +#endif + +struct math_struct; + +math_struct* create(); + +int get_sum(struct math_struct* ms, int a, int b); + +void free_math(struct math_struct* ms); + +#if __cplusplus +} +#endif +#endif // !_EX_LIB_H_ diff --git a/cpp/export_c/main.cpp b/cpp/export_c/main.cpp new file mode 100644 index 0000000..7243cf2 --- /dev/null +++ b/cpp/export_c/main.cpp @@ -0,0 +1,10 @@ +#include +#include "ex_lib.h" + +int main() +{ + math_struct* pMath = create(); + printf("23 + 56 = %d\n", get_sum(pMath, 23, 56)); + free_math(pMath); + return 0; +} \ No newline at end of file diff --git a/cpp/export_c/my_math.cpp b/cpp/export_c/my_math.cpp new file mode 100644 index 0000000..53a95af --- /dev/null +++ b/cpp/export_c/my_math.cpp @@ -0,0 +1,6 @@ +#include "my_math.h" + +int my_math::GetSum(int a, int b) const +{ + return a + b + m_nBase; +} diff --git a/cpp/export_c/my_math.h b/cpp/export_c/my_math.h new file mode 100644 index 0000000..b81bc98 --- /dev/null +++ b/cpp/export_c/my_math.h @@ -0,0 +1,13 @@ +#pragma once + +class my_math +{ +private: + int m_nBase {6}; +public: + my_math() = default; + ~my_math() = default; +public: + int GetSum(int a, int b) const; +}; + diff --git a/linux.txt b/linux.txt deleted file mode 100644 index de9c1c7..0000000 --- a/linux.txt +++ /dev/null @@ -1,22 +0,0 @@ -1.ssh配置免访问文件:authorized_keys -2.apt设置临时代理: -sudo apt-get -o Acquire::http::proxy="socks5h://192.168.0.102:7890/" install mariadb-server -3.CentOS7 升级GCC -(3.1) rpm -q gcc -(3.2) rpm -e [第二步查到的版本号] -如果 -error: Failed dependencies: - gcc = 4.4.7-23.el6 is needed by (installed) gcc-c++-4.4.7-23.el6.x86_64 - gcc = 4.4.4 is needed by (installed) libtool-2.2.6-15.5.el6.x86_64 -rpm -e gcc-c++-4.4.7-23.el6.x86_64 -rpm -e libtool-2.2.6-15.5.el6.x86_64 -验证卸载: -[root@123 /]# gcc -v --bash: /usr/bin/gcc: No such file or directory -[root@123 /]# g++ -v --bash: /usr/bin/g++: No such file or directory -yum install centos-release-scl -yum install -y devtoolset-11-gcc devtoolset-11-gcc-c++ -scl enable devtoolset-11 bash -vim /etc/profile -PATH=$PATH::/opt/rh/devtoolset-11/root/usr/bin \ No newline at end of file diff --git a/linux/Linux-base.txt b/linux/Linux-base.txt new file mode 100644 index 0000000..ff163c7 --- /dev/null +++ b/linux/Linux-base.txt @@ -0,0 +1,147 @@ +1.ssh配置免访问文件:authorized_keys +2.apt设置临时代理: +sudo apt-get -o Acquire::http::proxy="socks5h://192.168.0.102:7890/" install mariadb-server +3.CentOS7 升级GCC +(3.1) rpm -q gcc +(3.2) rpm -e [第二步查到的版本号] +如果 +error: Failed dependencies: + gcc = 4.4.7-23.el6 is needed by (installed) gcc-c++-4.4.7-23.el6.x86_64 + gcc = 4.4.4 is needed by (installed) libtool-2.2.6-15.5.el6.x86_64 +rpm -e gcc-c++-4.4.7-23.el6.x86_64 +rpm -e libtool-2.2.6-15.5.el6.x86_64 +验证卸载: +[root@123 /]# gcc -v +-bash: /usr/bin/gcc: No such file or directory +[root@123 /]# g++ -v +-bash: /usr/bin/g++: No such file or directory +yum install centos-release-scl +yum install -y devtoolset-11-gcc devtoolset-11-gcc-c++ +scl enable devtoolset-11 bash +vim /etc/profile +PATH=$PATH::/opt/rh/devtoolset-11/root/usr/bin + +==>Debian系列安装后的网卡配置: + +1.U盘安装一个无线网卡驱动包。 +2.然后需要链接有线安装两个组件:net-tools wireless-tools +sudo apt install xxx +3.安装完毕之后查看无线网卡的信息,例如名称为: wlan0 +4.配置netplan,(之前网上讲的是/etc/network/interface,在这里不是) +在/etc/netplan/目录下有yaml文件,可以查看是哪个里面配置了网卡信息。 +默认内容是: +network: + ethernets: + ehth0: + dhcp4: true + optional: true + version 2 +在这里添加(最外层跟ethernets对齐): + renderer: networkd + wifis: + wlan0: + dhcp4: true + access-points: + "xxxwifiname": + password: "xxxxwifipasswd" +5.使用sudo netplan apply启用。 + +配置文件 +/etc/systemd/logind.conf + +配置说明 +HandlePowerKey: 按下电源键后的行为,默认power off +HandleSleepKey: 按下挂起键后的行为,默认suspend +HandleHibernateKey: 按下休眠键后的行为,默认hibernate +HandleLidSwitch: 合上笔记本盖后的行为,默认suspend + +只监视带有 “power-switch” 标签的 输入设备的 key(按下按钮)/lid(合上盖子) 事件。 + +如果主机插入了一个扩展坞(docking station) 或者连接了多个显示器, 那么"合上盖子"将执行 HandleLidSwitchDocked= 动作; +如果主机使用外部电源, 并且 HandleLidSwitchExternalPower= 不是默认值(“ignore”), 那么"合上盖子"将执行 HandleLidSwitchExternalPower= 动作; 否则将执行 HandleLidSwitch= 动作。 + +参数说明 +ignore(无操作), +poweroff(关闭系统并切断电源), +reboot(重新启动), +halt(关闭系统但不切断电源), +kexec(调用内核"kexec"函数), +suspend(休眠到内存), +hibernate(休眠到硬盘), +hybrid-sleep(同时休眠到内存与硬盘), +suspend-then-hibernate(先休眠到内存超时后再休眠到硬盘), +lock(锁屏) + +设置笔记本合并盖子不休眠 +编辑文件/etc/systemd/logind.conf + +将 + +#HandleLidSwitch=suspend +1 +注意前面的 # 也要去掉 + +修改为(无操作) + +HandleLidSwitch=ignore +1 +或(锁屏) + +HandleLidSwitch=lock +1 +重启服务 + +service systemd-logind restart +1 +文章知识点与官方知识档 +———————————————— +版权声明:本文为CSDN博主「猫巳」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 +原文链接:https://blog.csdn.net/qq_31635851/article/details/124627990 + +Q1: Qt5 安装之后无法打开,那么就在cmd命令行中,设置 export QT_DEBUG_PLUGINS=1 +然后启动应用程序,会报相信的错误信息,一般是缺少各种库,比如libqxcb依赖的库有的没有,则使用 +ldd libqxcb.so +查看具体哪些没有,然后使用 apt search xxxx 这些没有的库,最后安装。 + +Q2: 设置iBus中文输入法 + +为什么使用iBus输入法,因为fcitx有很多兼容性问题。 + +# 彻底卸载sogou和fcitx +sudo apt purge sogoupinyin +sudo apt purge fcitx +sudo apt autoremove +sudo apt remove fcitx* +sudo apt purge fcitx* +sudo apt autoremove + +# 删除配置文件 +cd .config/ +rm -rf sogoupinyin/ +rm -rf ibus + +# 安装ibus +sudo apt install ibus ibus-sunpinyin + +Q3: 键盘功能键设置失效问题 +echo options hid_apple fnmode=2 | sudo tee -a /etc/modprobe.d/hid_apple.conf +sudo update-initramfs -u -k all +sudo reboot + +# Debian/Ubuntu/Mint +sudo apt install initramfs-tools +# the "-k all" part is not always needed, but it's better to do that for all kernels anyway +sudo update-initramfs -u -k all + +# RedHat/Fedora/CentOS +sudo dracut --regenerate-all --force 作者:大敏鸽 https://www.bilibili.com/read/cv16950091 出处:bilibili + +R1: 使用 plank 作为 dock 坞 +sudo apt-get install pavucontrol + +安装远程桌面 +sudo apt-get install tightvncserver xrdp + +秘钥 +ssh-keygen +pub公钥>>authorized_keys \ No newline at end of file diff --git a/linux/Linux-knowledge.txt b/linux/Linux-knowledge.txt new file mode 100644 index 0000000..cfbdc5c --- /dev/null +++ b/linux/Linux-knowledge.txt @@ -0,0 +1,310 @@ +ctrl+p 上一个命令,ctrl+n 下一个命令 +ctrl+b 光标回移, ctrl+f 向后移动, ctrl+a 行首, ctrl+e 行尾 +ctrl+h 删除前, ctrl+d 删除后。Linux中光标盖住的是后一个字符。 +ctrl+u 删除光标前面所有。ctrl+l 清屏。 + +vim 基础操作: +j :下移一行 +k :上移一行 +h :左移一个字符 +l :右移一个字符 +gg :跳到第一行 +G :跳到最后一行 +0 :左移到行首 +$ :右移到行尾 +ctrl + f :向下翻页 +ctrl + b :向上翻页 +ctrl + d :向下翻半页( d 代表 down ) +ctrl + u :向上翻半页( u 代表 up ) +H :移动到屏幕最上面(页面本身不动)( H 代表 high ) +L :移动到屏幕最下面(页面本身不动)( L 代表 low ) +M :移动到屏幕中间行(页面本身不动)( M 代表 middle ) +zt :把当前行移动到屏幕最上面( t 代表 top ) +zb :把当前行移动到屏幕最下面( b 代表 bottom ) +z. :把当前行移动到屏幕中间 +: :跳到第 行(需要回车) + +ls 可传一个目录参数。 +Liunx的目录结构: +/bin: 常用命令 +/boot: 启动系统的核心文件 +/dev: Linux的外部设备,访问设备与访问文件的方式是一样的。 +/etc: 系统管理所需要的配置文件和子目录。 +/home: 用户目录。 +/lib: 库文件。 +/lost+found: 一般是空的,非法关机之后存放一些文件。 +/media: Linux会自动识别一些设备,如U盘,自动挂载到Media下面。 +/mnt: 让用户临时挂载别的文件系统时用。 +/opt: 给主机额外安装软件所摆放的目录, 默认为空。 +/proc: 虚拟的目录,内存的映射,可以直接访问这个目录来获取系统信息。 +这个目录的内容不在硬盘而是在内存中, 可以直接修改。 +/root: 超级用户目录。 +/sbin: 系统管理员的程序。 +/selinux: 是Redhat/Centos特有的一个安全机制,类似防火墙。 +/srv: 服务启动之后需要提取的数据。 +/sys: Liunx2.6内核的大变化 +/tmp: 存放临时文件。 +/usr: 很多用户程序和文件放在这里。 +/usr/bin: 系统用户程序。 +/usr/sbin: 超级用户使用的比较高级的管理程序和系统守护程序。 +/usr/src: 内核代码默认放置目录。 +/var: 存放不断扩充的东西,比如各种日志文件。 + + +cd -: 切换到临近目录。 +yun@debian: +yun是当前登录的用户名,debian是安装系统时设置的主机名。 +$: 普通用户 +#: 超级用户 +直接cd,回家目录。 + +创建软链接: +ln -s /home/yun/hello.c /home/yun/hello.soft +ln -s /home/yun/download xxx.soft +创建硬链接(并没有拷贝): +ln /home/yun/hello.c hello.hard + +wc: 获取文本文件的行数,单词数,字符数。 +od: 查看二进制文件,od -t 指定显示格式。 +du: 查看当前目录的大小。du -h + +-rw-rw-r--,-文件,rw-文件所有者权限,rw-所属组权限。r--其他人权限。 +chmod: +1.文字设定,[who]文件所有者u, 文件所属组g, 其他人o, 所有人a ++-= (增减覆盖) [mode]读r,w写,x执行。 +2.数字设定,r->4, w->2, x->1, chmod -001 xxx + +修改文件所属组所有者: +chown Lisi main.cpp 所有者变了,但是所有组没有变化。 +chown Zhangsan:group2 都变了。 +chgrp 仅修改所有组。chgrp group3 xxx.cpp + +mkfifo 创建管道 +所有的目录能查看和进入,必须有x,可执行权限。 +find [path] -name "xxx.cpp" +?: 通配一个字符 +*: 通配所有字符。 +find [path] -size +10k[-10 k,M,] +查找范围,多个-size即可。 +find [path] -type d +文件类型-所有者权限-同组用户权限-其他人权限-硬链接数-所有者-所属组-占用-时间 +Linux 文件类型: +-: 普通文件(f) +d: 目录 +l: 链接符 +b: 块设备 +c: 字符设备 +s: socket设备 +p: 管道 + +卸载硬盘:umount /media/user/xxx-usb +sudo fdisk -l 查看设备信息。比如U盘是/dev/sdb +挂载硬盘:mount devicename /mnt +sd->SCSI Device +hd->Hard Disk +fd->Floppy Disk +主分区最多有4个。sda4 + +压缩相关: +gzip 打包:g(un)zip *.txt ->xxx.gz 文件 +b(un)zip2 *.txt 都不会保留原文件,没有打包压缩。->bz2文件 + +tar: c-创建,x-解压缩, v-显示信息, f-指定名字, +z-使用gzip的方式压缩,j-使用bzip2的方式压缩,不添加zj只能打包。 + +压缩:tar zcvf xxx -> xxx.tar.gz tar jcvf xxx -> xxx.tar.bz2 +完整示例:tar zcvf result.tar.gz *.txt +解压到指定目录: +tar zxvf xxx.tar.gz -C /home/yun/test/ + +终端[文字终端][图形界面终端] +tty1->tty6 tty7 +who +pts: 设备终端 + +PID 进程的ID +ps [a 查看当前所有用户][u 显示用户的信息][x 查看没有终端的应用程序] +使用管道重定向(|){输出作为另外一个命令的输入} +ps aux | grep bash +kill -l 查看信号 +kill -SIGKILL 2351 或者 kill -9 8311 也可以 + +env 环境变量 + +网络相关命令: +ip addr, ping [-c 4 -i xx s], ifconfig, +nslookup www.baidu.com 查看IP地址。 + +用户的添加: +adduser (脚本) + Zhangsan +useradd (命令) +su Zhangsan 切换用户 +useradd [-s 什么解析器(/bin/bash)][-g 所属组(Robin)][-d 目录(/home/xxx)] +[-m 如果没有xxx目录就创建Robin] +groupadd xxxGroup 增加组 +passwd Zhangsan 修改密码 +删除用户:deluser, userdel -r +/etc/passwd下可以查看用户 + +vsftpd: FTP服务器的一个软件。 +service xxx restart +lftp: 可以上传和下载目录。 + +alias: 查看命令是否被封装 +ldd: 查看so文件依赖。 +Linux会优先搜索LD_LIBRARY_PATH,之后再去默认位置查找。 +也可以设置:/etc/ld.so.conf, ldconfig更新生效。 + +gdb xxx +l 查看源码,包含main函数的文件。 +否则 l qimen.c:20 查看这块代码 +l qimen.c:run 也可以。 +继续查看后面的继续输入l或者直接回车。 +break xxx行(b 行) 普通断点。 +特殊断点:b 20 if i==15 +i b: 查看断点信息。(info break) +start开始运行,执行一步。 +r 直接跑。[run] +单步调试:n, 直接到断点:c (continue) +进入函数:s (step) +p 打印值。 +ptype 查看变量类型。 +display i 追踪变量i的值。 +undisplay 变量编号取消追踪。 +u 跳出单次循环 +finish 跳出进入的函数体。取消里面的断点才可以退出。 +d 编号删除断点。[del] +set var i=10 设置变量的值。 +quit 退出。 + +Makefile的编写: +三要素:目标,依赖,命令。 --> 一条规则 +result: sub.h sub.cpp + g++ main.cpp sub.h sub.cpp -o result +分开编译,防止每次全部编译。 +math.o: sub.cpp + g++ -c sub.cpp +main.o: main.cpp + g++ -c main.cpp +result: main.o math.o + g++ -o result main.o math.o + +Makefile中的变量。 +obj=main.o math.o +result: $(obj) + g++ -o result $(obj) + +vim 替换:3,4s/prestr/afterstr +makefile语法一样的情况: +{模式规则} +%.o:%.c + g++ -c $< -o $@ +原理: +1.例如依赖sub.o,那么%.o中的%就对应成了sub, +即sub.o: sub.c +2.$<: 自动变量, 规则中的第一个依赖。 +$@: 规则中的目标。 +$^: 规则中的所有依赖。 +以上只能在命令模式中使用。 +一般:CPPFLAGS:预处理器需要的参数,例如: -I +CFLAGS:编译参数,例如: -Wall +LDFLAGS:链接库参数,例如: -L +makefile中的函数,所有的函数都有返回值。 +src=$(wildcard ./*.c) +obj=$(patsubst ./%.c, ./%.o, $(src)) + +.PHONY:clean 声明伪目标,不检查文件。 +-rm [-]如果当前命令失败,继续执行。 + +全局变量不初始化=0,局部的未知。 +FILE* 结构体:文件描述符,读写指针,I/O缓冲区(addr)de:8KB +Linux 启动一个进程后内存模型:{虚拟地址} +虚拟地址作用:1.空间隔离 2.访问不连续物理空间 3.物理内存分配。 +>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +Linux kernel[内存管理,进程管理,设备驱动管理,文件系统] +| 内核区32位是,3G~4G +环境变量 +命令行参数 +栈(向下增长) +共享库 +堆(向上增长) +>>>>>>>>> +.bss未初始化变量 +.data已初始化变量 +xxx 其他 +.text代码段 +>>>>>>>>> ELF段 +受保护的地址(0~4K)。 +>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +PCB进程控制块。文件描述符表[一个数组]。 +默认打开了三个,标准输入输出错误。 +打开一个文件占用一个描述符,最小占用原则。 +>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> +file xxx可以查看xxx信息。 + +C库函数与系统函数之间的关系: +例如[printf] +->系统API(应用层write) +->系统调用(sys_write) {用户空间到内核空间转换} +->内核层(驱动) +->硬件显示。 + +Linux系统IO函数:open, read, write, lseek 可使用man文档。 +man 章节号 open +errno 全局变量 +perror(const char* s)[stdio.h] +open系统函数中指定的权限与umask掩码取反做一个按位与的操作。 + +在vim中,可以直接使用K查看函数文档。 + +守护进程 +1.后台服务 +2.不受登录注册影响 +3.一般以d结尾。 +4.周期性执行任务 +5.独立于终端 + +简述秘钥使用方法: +非对称加密算法:加密使用的密钥和解密使用的密钥是不同的。 公钥密码体制就是一种非对称加密算法 +私钥,公钥。服务器持有公钥,本地私钥可以登录。 +加密解密过程如下: +加密:通过加密算法和公钥对内容(或者说明文)进行加密,得到密文。 +解密:通过解密算法和私钥对密文进行解密,得到明文。 +注意:由公钥加密的内容,只能由私钥进行解密。 + +服务:[debian] + +/etc/systemd/system/ +xxx.service +[Unit] +Description=EyeblueTank +Documentation=https://tank-doc.eyeblue.cn +Wants=network.target +After=network.target mariadb.service + +[Service] +Type=simple +ExecStart=/home/yun/program/tank/tank + +[Install] +WantedBy=multi-user.target + +# 装载tank服务 +systemctl daemon-reload +# 设置tank开机启动 +systemctl enable tank.service +# 查看tank状态 +systemctl status tank.service +# 启动tank +systemctl start tank.service +# 重启tank +systemctl restart tank.service +# 停止tank +systemctl stop tank.service + +1.安装mariadb 记录安装版本为10.5 +sudo apt-get install mariadb-server +sudo mysql_secure_installation设置密码即可。 +CREATE DATABASE boys CHARACTER SET = utf8 COLLATE = utf8_general_ci; + +neofetch diff --git a/qt/QtCompilerConfigure.txt b/qt/QtCompilerConfigure.txt new file mode 100644 index 0000000..4c0c39c --- /dev/null +++ b/qt/QtCompilerConfigure.txt @@ -0,0 +1,185 @@ +1.configure meta: +-help,-h ............显示此帮助屏幕 +-verbose,-v .........在配置期间输出详细消息 +-continue............尽管有错误仍然继续配置 +-redo ................用以前使用的选项重新配置。其他选项可能会通过,但不会保存以供-redo稍后使用。 +-recheck .............放弃缓存的负配置测试结果。安装缺失的依赖关系后使用它。 +-recheck-all .........放弃所有缓存的配置测试结果。 +-feature- <特征> ...启用<特征> +-no-feature- 禁用 [none] +-list-features .......列出可用功能。请注意一些功能也有专用的命令行选项。 +-list-libraries ......列出可能的外部依赖关系。 +2.Build options: +-opensource ..........构建Qt的开源版本 +-commercial ..........构建Qt的商业版 +-confirm-license .....自动确认许可证 +-release.............关闭调试版本的Qt [yes] +-debug ...............打开调试生成Qt [no] +-debug-and-release ...构建两个版本的Qt,包含和不包含打开调试[是](仅适用于Apple和Windows) +-optimize-debug ......在调试版本中启用调试友好的优化[自动](MSVC不支持) +-optimize-size .......优化发布版本的大小而不是速度[no] +-optimized-tools .....甚至在调试版本中构建优化的主机工具[no] +-force-debug-info ....为发布版本创建符号文件[no] +-separate-debug-info。分离调试信息以分离文件[no] +-strip ...............释放不需要的符号的二进制文件[是] +-force-asserts .......即使在发布版本中启用Q_ASSERT [no] +-developer-build .....编译并链接Qt以开发Qt本身(用于自动测试的出口,额外检查等)[no] +-shared..............建立共享的Qt库[是](不适用于UIKit) +-static ..............构建静态Qt库[no](对于UIKit是) +-framework ...........构建Qt框架包[是](仅限Apple) +-platform ...选择主机mkspec [检测到] +-xplatform ..交叉编译时选择target mkspec [PLATFORM] +-device .......交叉编译设备 +-device-option ...为设备mkspec添加选项 +-appstore-compliant ..禁用平台应用商店中不允许使用的代码。默认情况下,默认情况下,默认情况下,平台需要通过默认应用商店进行分发,特别是Android,iOS,tvOS,watchOS和Universal Windows Platform。 [汽车] +-qtnamespace ..将所有Qt库代码封装在'namespace {...}'中。 +-qtlibinfix 将所有libQt5 * .so重命名为libQt5 * .so。 +-testcocoon ..........带有TestCocoon代码覆盖工具的仪器[no] +-gcov ................具有GCov代码覆盖工具的仪器[no] +-sanitize {address | thread | memory | undefined}仪器与指定的编译器消毒剂。 +-c ++ std ....选择C ++标准 [c ++ 1z / c ++ 14 / c ++ 11](不支持MSVC) +-sse2 ................使用SSE2指令[自动] +-sse3 / -ssse3 / -sse4.1 / -sse4.2 / -avx / -avx2 / -avx512启用特定的x86指令[auto]启用的仍然受到运行时检测。 +-mips_dsp / -mips_dspr2使用MIPS DSP / rev2指令[auto] +-qreal ........ typedef qreal到指定的类型。 [双]注意:这会影响二进制兼容性。 +-R ..........为Qt添加一个显式的运行时库路径库。支持相对于LIBDIR的路径。 +-rpath ...............使用库链接Qt库和可执行文件将路径安装为运行时库路径。如同-R LIBDIR。在苹果平台上,禁用这意味着使用绝对安装名称(基于 LIBDIR)动态库和框架。 [汽车]减少输出......减少输出符号的数量[自动] +-reuce-relocations ..减少重定位量[auto](仅适用于Unix) +-plugin-manifests ....将清单嵌入插件[no](仅限Windows) +-static-runtime ......使用-static,使用静态运行时[no](仅限Windows) +-pch .................使用预编译头文件[auto] +-ltcg ................使用链接时间码生成[no] +-use-gold-linker .....使用GNU gold链接器[auto] +-incredibuild-xge ....使用IncrediBuild XGE [no](仅限Windows) +-ccache ..............使用ccache编译器缓存[no](仅适用于Unix) +-make-tool ....使用构建qmake [nmake](仅适用于Windows) +-mp ..................使用多个处理器进行编译(仅限MSVC) +-warnings-are-errors。将警告视为错误[no; yes如果-developer-build] +-silent ..............减少构建输出以便发出警告和错误可以更容易地看到 +3.Build environment: +-sysroot ....... 将设置为目标sysroot +-gcc-sysroot ......... 使用-sysroot,将编译器通过--sysroot [yes] +-pkg-config ..........使用pkg-config [auto](仅适用于Unix) +-D ..........传递附加的预处理器定义 +-I ..........传递额外的包含路径 +-L ..........传递额外的库路径 +-F ..........传递额外的框架路径(仅适用于Apple) +-sdk ...........使用Apple提供的SDK 构建Qt。争论应该是以下列出的可用SDK之一'xcodebuild -showsdks'。请注意,该参数仅适用于Qt库和使用目标mkspec构建的应用程序 - 不是主机工具,如qmake,moc,rcc等。 +-android-sdk path ....设置Android SDK根路径[$ ANDROID_SDK_ROOT] +-android-ndk路径....设置Android NDK根路径[$ ANDROID_NDK_ROOT] +-android-ndk-platform设置Android平台 +-android-ndk-host ....设置Android NDK主机(linux-x86,linux-x86_64等)[$ ANDROID_NDK_HOST] +-android-arch ........设置Android体系结构(armeabi,armeabi-v7a,arm64-v8a,x86,x86_64,mips,mips64) +-android-toolchain-version ...设置Android工具链版本 +-android-style-assets自动从设备中提取样式资产运行。此选项使Android样式表现良好正确的,但也使得Android平台插件与LGPL2.1不兼容。 [是] +4.Component selection: +-skip .........从构建中排除整个存储库。 +-make .........将添加到要构建的零件列表中。指定此选项将首先清除默认列表。[库和例子,如果不是交叉构建也是工具,还测试是否 - +开发人员构建] +-nomake .......从要构建的零件列表中排除。 +-compile-examples ....未设置时,只安装示例的源代码[是] +-gui .................构建Qt GUI模块和依赖[yes] +-widgets .............编译Qt Widgets模块和依赖[yes] +-no-dbus .............不要构建Qt D-Bus模块[Android和Windows默认] +-dbus-linked .........构建Qt D-Bus并链接到libdbus-1 [auto] +-dbus-runtime ........构建Qt D-Bus并动态加载libdbus-1 [no] +-accessibility.......启用可访问性支持[是]注意:不建议禁用可访问性。 +-qml-debug ...........启用QML调试支持[yes] +Qt附带一些第三方库的捆绑副本。这些被使用默认情况下,如果自动检测相应的系统库失败。 +5.Core options: +-doubleconversion ....选择使用的双转换库[system / qt / no]没有暗示使用sscanf_l和snprintf_l(不精确)。 +-glib ................启用Glib支持[no;在Unix上自动] +-eventfd .............启用eventfd支持 +-inotify .............启用inotify支持 +-iconv ...............启用iconv(3)支持[posix / sun / gnu / no](仅适用于Unix) +-icu .................启用ICU支持[自动] +-pcre ................选择使用的libpcre2 [system / qt] +-pps .................启用PPS支持[自动](仅限QNX) +-zlib ................选择用过的zlib [system / qt] +6.Logging backends: +-Journald ..........启用日志支持[no](仅限Unix) +-syslog ............启用syslog支持[no](仅适用于Unix) +-slog2 .............启用slog2支持[自动](仅限QNX) +7.Network options: +-ssl .................启用SSL支持方法[自动] +-no-openssl ..........不要使用OpenSSL [Apple和WinRT上的默认] +-openssl-linked ......使用OpenSSL并链接到libssl [no] +-openssl-runtime .....使用OpenSSL并动态加载libssl [auto] +-securetransport .....使用SecureTransport [auto](仅限Apple) +-sctp ................启用SCTP支持[no] +-libproxy ............启用libproxy的使用[no] +-system-proxies ......默认使用系统网络代理[yes] +8.Gui, printing, widget options: +-cups ................启用CUPS支持[自动](仅适用于Unix) +-fontconfig ..........启用Fontconfig支持[auto](仅适用于Unix) +-freetype ............选择使用的FreeType [system / qt / no] +-harfbuzz ............选择用过的HarfBuzz-NG [系统/ qt / no](不在Apple和Windows上自动检测) +-gtk .................启用GTK平台主题支持[auto] +-lgmon ...............启用lgmon支持[自动](仅限QNX) +-no-opengl ...........禁用OpenGL支持 +-opengl ........启用OpenGL支持。支持的API:es2(在Windows上默认),桌面(在Unix上默认),动态(仅限Windows) +-opengles3 ...........启用OpenGL ES 3.x支持而不是ES 2.x [自动] +-angle ...............使用捆绑的ANGLE支持OpenGL ES 2.0 [自动](仅限Windows) +-combined-angle-lib ..将LibEGL和LibGLESv2合并到LibANGLE(仅限Windows) +-qpa ..........选择默认的QPA后端(例如,xcb,cocoa,windows) +-xcb-xlib .............启用Xcb-Xlib支持[auto] +9.Platform backends: +-direct2d ..........启用Direct2D支持[自动](仅限Windows) +-directfb ..........启用DirectFB支持[no](仅适用于Unix) +-eglfs .............启用EGLFS支持[auto;没有在Android和Windows上] +-gbm ...............为GBM [auto]启用后端(仅限Linux) +-kms ...............启用KMS [auto]的后端(仅适用于Linux) +-linuxfb ...........启用Linux Framebuffer支持[auto](仅限Linux) +-mirclient .........启用Mir客户端支持[no](仅Linux) +-xcb ...............选择使用的xcb- *库[system / qt / no](-qt-xcb仍然使用libxcb本身的系统版本) +10.Input backends: +-evdev .............启用evdev支持[auto] +-imf ...............启用IMF支持[自动](仅限QNX) +-libinput ..........启用libinput支持[auto] +-mtdev .............启用mtdev支持[auto] +-tslib .............启用tslib支持[自动] +-xinput2 ...........启用XInput2支持[自动] +-xkbcommon-x11 .....选择与xcb结合使用的xkbcommon[系统/ QT / NO] +-xkb-config-root ...使用-qt-xkbcommon-x11,设置默认的XKB配置根目录 [检测] +-xkbcommon-evdev ...启用X-less xkbcommon与libinput结合使用[汽车] +11.Image formats: +-gif ...............启用对GIF的读取支持[自动] +-ico ...............启用对ICO的支持[是] +-libpng ............选择用过的libpng [system / qt / no] +-libjpeg ...........选择使用的libjpeg [system / qt / no] +12.Database options: +-sql- ........启用SQL <驱动程序>插件。支持的驱动db2 ibase mysql oci odbc psql sqlite2 sqlite tds[全自动] +-sqlite ..............选择用过的sqlite3 [系统/ qt] +13.Qt3D options: +-assimp ..............选择使用的assimp库[system / qt / no] +-qt3d-profile-jobs ...启用作业分析[no] +-qt3d-profile-gl .....启用OpenGL分析[no] +-qt3d-simd ...........选择SIMD支持级别[no / sse2 / avx2] +-qt3d-render .........启用Qt3D渲染方面[是] +-qt3d-input ..........启用Qt3D输入方面[是] +-qt3d-logic ..........启用Qt3D逻辑方面[是] +-qt3d-extras .........启用Qt3D Extras方面[yes] +-qt3d-animation .......启用Qt3D动画方面[是] +14.Multimedia options: +-pulseaudio ..........启用PulseAudio支持[自动](仅适用于Unix) +-alsa ................启用ALSA支持[自动](仅适用于Unix) +-no-gstreamer ........禁用对GStreamer的支持 +-gstreamer [版本]。启用GStreamer支持[自动]在没有参数的情况下,首先尝试1.0,然后再尝试0.10。 +-mediaplayer-backend <名称> ...选择媒体播放器后端(仅限Windows)支持的后端:directshow(默认),wmf +15.Webengine options: +-webengine-alsa ................启用ALSA支持[自动](仅限Linux) +-webengine-pulseaudio ..........启用PulseAudio支持[自动](仅限Linux) +-webengine-embedded-build ......启用Linux嵌入式构建[auto](仅限Linux) +-webengine-icu .................使用系统ICU库[system / qt](仅限Linux) +-webengine -ffmpeg ..............使用系统FFmpeg库[system / qt](仅限Linux) +-webengine-opus ................使用系统Opus库[system / qt](仅限Linux) +-webengine-webp ................使用系统WebP库[system / qt](仅限Linux) +-webengine-pepper-plugins ......启用Pepper Flash和Widevine插件[自动] +-webengine-printing-and-pdf ....启用打印和输出到PDF[汽车] +-webengine-proprietary-codecs ..启用对专有编解码器的支持[no] +-webengine-spellchecker ........启用对拼写检查程序的支持[是] +-webengine-native-spellchecker。启用对原生拼写检查器的支持[否](仅限macOS) +-webengine-webrtc ..............启用对WebRTC的支持[自动] +———————————————— +版权声明:本文为CSDN博主「天空之城8020」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 +原文链接:https://blog.csdn.net/kongcheng253/article/details/129001104 \ No newline at end of file diff --git a/qt/Qt乱码问题.txt b/qt/Qt乱码问题.txt new file mode 100644 index 0000000..d2d749e --- /dev/null +++ b/qt/Qt乱码问题.txt @@ -0,0 +1,13 @@ +《在windows下解决乱码问题的一个比较完美的方法(纯UTF-8环境使用下)(不影响系统其他软件的使用)》 +一、Qt设置文件编码为: +(1) UTF-8 +(2) BOM 如果是UTF-8则添加 +二、Qt项目中运行的时候使用外部Terminal(也就是CMD)且做如下设定: +(1) 先在启动的外部 cmd 窗口属性中勾选使用旧版控制台,然后重新启动一次(Qt运行项目的cmd,不是运行cmd)。 +(2) 步骤一完成后在注册表(regedit)中的HKEY_CURRENT_USER\Console\下会有 +一个 qt_creator_process_stub 的一个项,将此项中的 CodePage 名称的值更改为 +十进制(65001)后保存。 +(3) 此时重新运行Qt项目,发现还是有乱码,此时,将步骤一中的勾选取消就可以了。 + +《此方法未测试》 +SetConsoleOutputCP(65001); \ No newline at end of file diff --git a/qtuse.txt b/qt/qtuse.txt similarity index 100% rename from qtuse.txt rename to qt/qtuse.txt