# C Family Programming Languages Relevant Resource Collection **Repository Path**: zenny-chen/c-family-programming-languages-relevant-resource-collection ## Basic Information - **Project Name**: C Family Programming Languages Relevant Resource Collection - **Description**: 类C语言编程相关 - **Primary Language**: Unknown - **License**: GPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2020-08-30 - **Last Updated**: 2022-06-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # C Family Programming Languages Relevant Resource Collection 类C语言编程相关
- [ISO C Working Group's official website](http://www.open-std.org/jtc1/sc22/wg14/www/wg14_document_log.htm) - [Objective-C Runtime](https://developer.apple.com/documentation/objectivec?language=objc) - [Objective-C Runtime Programming Guide](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Introduction/Introduction.html?language=objc#//apple_ref/doc/uid/TP40008048) - [http://www.cplusplus.com/reference/](http://www.cplusplus.com/reference/) - [https://en.cppreference.com](https://en.cppreference.com/w/) - [Clang Contents](https://clang.llvm.org/docs/index.html) - [Attributes in Clang](https://clang.llvm.org/docs/AttributeReference.html) - [Clang Language Extensions](https://clang.llvm.org/docs/LanguageExtensions.html) - [GCC Extensions to the C Language Family](https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html#C-Extensions) - [P1467R5 Extended floating-point types and standard names](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1467r5.html) - [Eclipse官方帮助文档](https://help.eclipse.org/latest/) - Eclipse下设置程序运行的环境变量:`${env_var:MY_ENVIRONMENT_VARIABLE_HERE}`。 - Eclipse下对汇编文件的使用:Eclipse下汇编文件后缀名必须用 **.S** (即大写的S)。在项目工程中选中一个汇编源文件,然后鼠标右键,选择Properties。在C/C++ Build下先点击Tool Chain Editor,确认Select Tool所选的工具已经是GCC Assembler。要调试该汇编文件的话则随后点击Settings,点击General,在Assembler flags一栏中添加 **`-g`** 即可调试。 - Eclipse在CUDA工程下添加GAS工具:鼠标右键项目工程,选择properties,点击C/C++ Build,再点击Tool Chain Editor。在下方used tools一栏点击右侧的Select Tools,然后在左侧列表中选中GCC Assembler,最后点击Add tool。 - CLion下常用快捷键——`点两次shift`:调出文件搜索工具栏;`ctrl+shift+f`:调出在当前工程搜索关键词的工具栏。 - [Clion中单行注释、多行注释及取消注释快捷键示例](https://blog.csdn.net/pan66rui/article/details/107841452) - [CLion Hexadecimal view](https://www.jetbrains.com/help/clion/using-hexadecimal-view.html) - [值得我们学习的C语言开源项目汇总](https://www.toutiao.com/a6816559091704398339/) - [C编译器剖析_1.5 结合C语言来学汇编_浮点数运算(比较大小)](https://blog.csdn.net/sheisc/article/details/43017909) - [详解C语言中的stdin,stdout,stderr](http://blog.csdn.net/Crazy_Tengt/article/details/72717144) - [\中的 **c16rtomb** ](https://cloud.tencent.com/developer/section/1009566) - [C语言压缩文件和用MD5算法校验文件完整性的实例教程_C 语言](https://yq.aliyun.com/ziliao/119635) - [C/C++下scanf的%匹配以及过滤字符串问题](https://www.toutiao.com/a6659550631625228808) - [(有用的C++ proposal)Familiar template syntax for generic lambdas](http://open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0428r2.pdf) - [C++ vector清空元素的三种方法](https://blog.csdn.net/weixin_30897079/article/details/97119054) - [如何在C++ 11中创建线程对象数组?](http://cn.voidcc.com/question/p-vgibagru-zc.html) - [std::jthread与std::thread的区别](https://blog.csdn.net/danshiming/article/details/117648806) - [C++11 并发指南五(std::condition_variable 详解)](https://www.cnblogs.com/haippy/p/3252041.html) - [C++11中获取当前线程的ID](https://en.cppreference.com/w/cpp/thread/get_id):使用 **`std::this_thread::get_id()`** - [一文读懂C++右值引用和std::move](https://zhuanlan.zhihu.com/p/335994370) - [优先使用using,而非typedef](https://zhuanlan.zhihu.com/p/266140466) - [std::initializer_list](https://en.cppreference.com/w/cpp/utility/initializer_list) - [std::isnan](https://en.cppreference.com/w/cpp/numeric/math/isnan) - [std::to_string](https://en.cppreference.com/w/cpp/string/basic_string/to_string) - [C++/C++11中std::transform的使用](https://blog.csdn.net/fengbingchun/article/details/63252470) - [c++ ostringstream的用法(c语言的sprintf)](https://blog.csdn.net/zhenguo26/article/details/80716075) - [C++中输出/输入十六进制数](https://blog.csdn.net/woaijssss/article/details/93190865) - C++中将std::string十六进制字符串转为整数:`std::strtoull`;整数转字符串:`std::to_string()` - [C++20不定参数个数的宏](https://en.cppreference.com/w/cpp/preprocessor/replace#Function-like_macros) - [c++11-17 模板核心知识(四)—— 可变参数模板 Variadic Template](https://www.cnblogs.com/zhangyachen/p/13946450.html) - [C++20新特性—consteval与constinit](https://blog.csdn.net/guxch/article/details/113641104) - [c++中的 constexpr lambda 表达式](https://docs.microsoft.com/zh-cn/cpp/cpp/lambda-expressions-constexpr) - [C++20 Coroutine实例教学](https://zhuanlan.zhihu.com/p/414506528) - [C++20协程原理和应用](https://csdnnews.blog.csdn.net/article/details/124123024) - [C语言的JSON库Jansson](https://www.toutiao.com/a6751005440798114315/) - [链接过程中的符号重定位_C底层](http://blog.csdn.net/darkfaker/article/details/79370796) - [类Unix系统中如何获取另一个程序的输出内容](https://baike.baidu.com/item/popen) - [使用popen执行shell命令并获取返回结果](https://www.cnblogs.com/hiawind/p/9089288.html) - [C语言中的系统库system函数](https://baike.baidu.com/item/system/15078602?fr=aladdin) - C语言将控制台输出内容转存到指定文件:`freopen(filePath, "w", stdout);`。用完之后再用`fclose`关闭文件即可。在转存过程中,控制台内容仍然会输出。 - GCC可直接使用`#pragma unroll`或是`_Pragma("unroll")`对循环做展开。 - [pragma gcc optimize](https://blog.csdn.net/u010796610/article/details/69352484)(另参考此文:[GCC 设置部分代码的优化级别](http://blog.chinaunix.net/uid-26334045-id-4743500.html)) - [gcc在代码中禁止某些warning](https://www.cnblogs.com/jhj117/p/6639111.html) - [gcc 编译 gcc warning 'variable tracking size limit exceeded' 原因及解决办法](https://blog.csdn.net/photon222/article/details/89217737) - [严格别名规则“-fstrict-aliasing”和“-fno-strict-aliasing”及类型双关](https://www.cnblogs.com/aquester/p/10299471.html) - GCC对某一函数启用`-O2`编译选项并禁用`strict-aliasing`:`__attribute__((optimize("-O2"), optimize("-fno-strict-aliasing")))` - GCC/Clang编译器下要使用,则需要包含:`#include `。 - GCC默认连接静态库使用此连接选项:`-static`。 - GCC编译器指定结构体对齐:`-fpack-struct=n`。 - 用GCC编译C++代码时最好使用 `g++`,否则会导致一些特定的C++函数符号找不到。如果遇到某些引用STL库的函数而引发符号找不到错误,则可尝试添加 `-lstdc++` 来解决。 - [gcc, g++编译时消除特定警告的方法](https://blog.csdn.net/li_wen01/article/details/71171413) - GCC上对于静态库或动态库文件名不以`lib`作为前缀的情况下可在连接时直接用该文件名去连。比如我们要连接一个`libtest.so`和`testlib.so`,我们可以用:`gcc -ltest testlib.so -o target`。 - GCC上对于用 **`-D`** 定义的预处理符号,如果其值包含双引号 **`"`**,则需要使用转义符 **` \ `**。比如:`-DMY_NAME=\"Smith\"`。 - [gcc命令objdump用法----反汇编](https://blog.csdn.net/cwcwj3069/article/details/8273129) - [linux 强制32位编译,使用CMake强制进行32位编译的正确方法](https://blog.csdn.net/weixin_34952628/article/details/116756981) - [C Programming/complex.h/carg](https://en.wikibooks.org/wiki/C_Programming/complex.h/carg) - [《高级语言内的单指令多数据流计算(SIMD)》整理](https://www.cnblogs.com/zenny-chen/archive/2012/05/06/2486030.html) - 获取当前进程ID: ```c // Windows #include DWORD GetCurrentProcessId(); // Unix #include pid_t getpid(void); ``` - [linux下生成core dump方法与gdb解析core dump文件](https://blog.csdn.net/weixin_39249306/article/details/94554782) - [GDB调试教程:1小时玩转Linux gdb命令](http://c.biancheng.net/gdb/) - GDB查看寄存器 ```bash info registers info all-registers info registers reggroup info registers regname ``` - Linux下在GDB调试模式下忽略 **`SIGSEGV`** 信号,而直接让程序继续执行: ```bash handle SIGSEGV nostop noprint ``` - [GDB and LLDB Command Examples](https://developer.apple.com/library/archive/documentation/IDEs/Conceptual/gdb_to_lldb_transition_guide/document/lldb-command-examples.html) - [gdb到底是怎样实现的?](https://www.toutiao.com/a6699652803918299655) - [调试程序时,设置断点的原理是什么?](https://www.toutiao.com/a6651660887507599886/) - [gdb(debugger)加入软件断点的本质原理分析](https://www.toutiao.com/a6828945264800170504/)
## GCC内联汇编相关技巧(Clang编译器亦与之兼容) - [gcc 内联汇编](https://blog.csdn.net/yanzhongqian/article/details/124482833) - [ARM64基础11:GCC内嵌汇编补充](https://blog.csdn.net/luteresa/article/details/120140887) - [如何在ARM aarch64中使用32位w寄存器进行GCC内联汇编?](https://cloud.tencent.com/developer/ask/sof/815815) 以下为几个常用例子: ```c #include // 常见的内联汇编方式 static inline int MyARM64Sub(int a, int b) { int result; asm volatile ("sub %w[dst], %w[src1], %w[src2]" : [dst] "=r" (result) : [src1] "r" (a), [src2] "r" (b)); return result; } // 只有一个输出操作数 static inline unsigned MyGetFPCR(void) { unsigned long long result; asm volatile ("mrs %[result], fpcr" : [result] "=r" (result)); return (unsigned)result; } // 只有一个输入操作数 static inline void MySetFPCR(unsigned fpcrValue) { asm volatile ("msr fpcr, %[fpcrValue]" : : [fpcrValue] "r" ((unsigned long long)fpcrValue)); } // 参数expected在内联汇编中既作为输入操作数又作为输出操作数 static inline unsigned MyAtomicCAS_LSE(volatile void *dst, unsigned expected, unsigned newValue) { asm volatile ("cas %w[expected], %w[newValue], [%[dst]]" : [expected] "+r" (expected) : [newValue] "r" (newValue), [dst] "r" (dst)); return expected; } static inline unsigned MyLDXR(const volatile void *ptr) { unsigned result; asm volatile ("ldxr %w[result], [%[ptr]]" : [result] "=r" (result) : [ptr] "r" (ptr)); return result; } // 这里为了避免对不同变量使用相同的寄存器名,而特意指定相应的寄存器 static inline bool MySTXR(volatile void *dst, unsigned value) { register volatile void *pDst asm("x2") = dst; register unsigned srcValue asm ("w1") = value; register bool result asm ("w0"); asm volatile ("stxr %w[result], %w[src], [%[dst]]" : [result] "=r" (result) : [src] "r" (srcValue), [dst] "r" (pDst)); return result; } // 以上内联汇编的C函数在Android NDK平台下的测试: const int result = MyARM64Sub(7, 3); syslog(LOG_INFO, "The subtraction result: %d\n", result); volatile unsigned data = 100; unsigned expected = data; expected = MyAtomicCAS_LSE(&data, expected, expected + 10); syslog(LOG_INFO, "expected = %u\n", expected); syslog(LOG_INFO, "now data = %u\n", data); expected = MyLDXR(&data); expected += 1000U; const bool bRes = MySTXR(&data, expected); syslog(LOG_INFO, "bRes = %d, expected = %u\n", bRes, expected); syslog(LOG_INFO, "now data = %u\n", data); MySetFPCR(0x07000000U); expected = MyGetFPCR(); syslog(LOG_INFO, "Current FPCR: 0x%08X\n", expected); ```
## C11与C++11中的 **alignas** 在C++11中与C11中的 **`alignas`** 的摆放位置会因编译器而各有不同。而且C++11与C11中的摆放位置也是有所区别。其中,Clang编译器对 **`alignas`** 位置要求更为苛刻,而MSVC则对其位置要求比较宽松。 下面我们先举Clang编译器下C11和C++11中 **`alignas`** 用于修饰变量或结构体的摆放位置 ```cpp // 首先是C++11中alignas能够摆放的位置 static char s_dummy_chars alignas(64) [2] = "a"; static int s_dummy_int alignas(64) = 100; alignas(64) static char s_dummy_chars2[2] = "a"; alignas(64) static int s_dummy_int2 = 100; ``` ```c // 然后这里是C11中alignas能够摆放的位置 #include static char alignas(64) s_dummy_chars[2] = "a"; static int alignas(64) s_dummy_int = 100; alignas(64) static char s_dummy_chars2[2] = "a"; alignas(64) static int s_dummy_int2 = 100; static alignas(64) char s_dummy_chars3[2] = "a"; static alignas(64) int s_dummy_int3 = 100; // Warning: Attribute '_Alignas' is ignored, // place it after "struct" to apply attribute to type declaration // 这里对alignas(64)的修饰会被Clang编译器忽略 alignas(64) struct DummyS1 { char s; }; // 在Clang中可以这么对结构体类型做对齐要求设置 struct __attribute__((aligned(64))) DummyS2 { char s; }; ``` 下面是MSVC编译器下,C11和C++11中 **`alignas`** 用于修饰变量或结构体的摆放位置: ```cpp // 这里首先是C++源文件 static char s_dummy_chars alignas(64)[2] = "a"; static int s_dummy_int alignas(64) = 100; alignas(64) static char s_dummy_chars2[2] = "a"; alignas(64) static int s_dummy_int2 = 100; static alignas(64) char s_dummy_chars3[2] = "a"; static alignas(64) int s_dummy_int3 = 100; static char alignas(64) s_dummy_chars4[2] = "a"; static int alignas(64) s_dummy_int4 = 100; struct alignas(64) DummyS { char s; }; ``` ```c // 然后这个是C语言源文件 #include static char alignas(64) s_dummy_chars[2] = "a"; static int alignas(64) s_dummy_int = 100; alignas(64) static char s_dummy_chars2[2] = "a"; alignas(64) static int s_dummy_int2 = 100; static alignas(64) char s_dummy_chars3[2] = "a"; static alignas(64) int s_dummy_int3 = 100; // 在MSVC中,直接用alignas(64)修饰结构体类型将会直接编译报错 //alignas(64) struct DummyS1 { char s; }; // MSVC中可以用以下方式修饰C语言的结构体对齐方式 struct __declspec(align(64)) DummyS2 { char s; }; ``` 综上所述,无论是哪种编译器,无论是C还是C++,对一个变量指定用 **`alignas`** 进行修饰时,将它摆放在变量声明语句的最前面才是最通用的形式。 而C++中,**`alignas`** 用于修饰结构体的摆放位置在编译器中都是一样的;而C11中则暂不支持对结构体的修饰。
## C++与C语言标准库头文件的对应 ```cpp #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // // The follwing C headers are deprecated since C++17 #include // #include // #include // // The header behaves as if it simply includes the headers and #include // #include // ``` **这里要注意的是**:由于``标准库各大编译器表现不太一致,而且都实现得比较简陋,因此C++要使用数学库最好同时包含``、``以及``。
## CMake的常用用法集合 - [cmake 简介](https://www.cnblogs.com/lidabo/p/7359422.html) - [CMAKE最全实战(1)](https://www.toutiao.com/i6858063275733713416/) - [CMAKE最全实战(2)](https://www.toutiao.com/a6859561394904236547/) - [If value not equal in cmake 2.8](https://stackoverflow.com/questions/11741325/if-value-not-equal-in-cmake-2-8)(使用`if(NOT )`时,里面的 **`NOT`** 必须是全大写) - [cmake构建时指定编译器架构(x86 or x64)](https://www.cnblogs.com/lidabo/p/12017014.html) - [CMake平台判断](https://blog.csdn.net/bianchengjingling22/article/details/88810593) - [Android NDK 开发之 CMake 必知必会](https://blog.csdn.net/zhying719/article/details/82657519) - [CMAKE添加编译选项](https://blog.csdn.net/qinglongzhan/article/details/80743731)(汇编语言的编译选项的环境变量:`CMAKE_ASM_FLAGS`) - [如何使用CMake为单个目标编译具有不同选项的不同源文件?](https://www.javaroad.cn/questions/90941) - [cmake 中使用环境变量](https://www.cnblogs.com/stdpain/p/13467203.html) - CMake同时指定当前项目支持C、C++和CUDA: ```cmake PROJECT(project_name C CXX CUDA) ``` - CMake给Visual Studio设置环境变量,使用`VS_DEBUGGER_ENVIRONMENT`。具体可参考:[Correct use of VS_DEBUGGER_WORKING_DIRECTORY etc.](http://cmake.3232098.n2.nabble.com/Correct-use-of-VS-DEBUGGER-WORKING-DIRECTORY-etc-td7599386.html)(其中,正确地设置`VS_DEBUGGER_ENVIRONMENT`变量的方式如下所示) ```cmake set_target_properties(appName PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "PATH=${CMAKE_INSTALL_PREFIX}/bin;%PATH% \$(LocalDebuggerEnvironment)" ``` - CMake为MSVC安装pdb调试文件: ```cmake install(FILES $ DESTINATION bin) ``` - 在项目安装时,将指定文件重命名然后复制到指定目标路径: ```cmake install(FILES ${MY_SRC_LIB}/file.txt RENAME file.log DESTINATION dst_dir) ``` - 用CMake来拷贝文件: ```cmake file(COPY "${CMAKE_SOURCE_DIR}/some_dir/header.h" "${CMAKE_SOURCE_DIR}/another_dir/resource.res" DESTINATION "${CMAKE_BINARY_DIR}/dir") ``` - [In CMake, how can I test if the compiler is Clang?](https://stackoverflow.com/questions/10046114/in-cmake-how-can-i-test-if-the-compiler-is-clang) - [switching between gcc and clang-llvm using cmake](https://stackoverflow.com/questions/7031126/switching-between-gcc-and-clang-llvm-using-cmake) - CMake添加带有字符串的宏定义: ```cmake ADD_COMPILE_DEFINITIONS(SOME_DIR="${CMAKE_INSTALL_PREFIX}") ``` 或是 ```cmake ADD_COMPILE_DEFINITIONS(SOME_DIR=\"${CMAKE_INSTALL_PREFIX}\") ``` - [cmake:设置编译选项的讲究(add_compile_options和CMAKE_CXX_FLAGS的区别)](https://blog.csdn.net/10km/article/details/51731959) - CMake修改项目最终生成文件名的前缀和后缀:`set_target_properties(project_name PROPERTIES PREFIX "prefix")`;`set_target_properties(project_name PROPERTIES SUFFIX "suffix")`。比如,要把输出文件扩展名改为 **.suf**:`set_target_properties(project_name PROPERTIES SUFFIX ".suf")`。如果当前CMake项目是一个Linux上的动态链接库,并且我们想让生成 .so 文件不带有“lib”前缀,则可以:`set_target_properties(MySharedLib PROPERTIES PREFIX "")`,那么最后将会生成“MySharedLib.so”文件。 - 用CMake生成Eclipse C/C++项目工程:`cmake -G"Eclipse CDT4 - Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug ...`。 - [Using NASM with CMake and Clang](https://metricpanda.com/using-nasm-with-cmake-and-clang/) - CMake中开启汇编文件的编译:类Unix下使用GAS为 `ENABLE_LANGUAGE(ASM)`;Visual Studio下使用MASM为 `ENABLE_LANGUAGE(ASM_MASM)`;在Android Studio中使用为x86架构NASM,为:`enable_language(ASM_NASM)`。 - CMake中设置CUDA额外编译选项:`TARGET_COMPILE_OPTIONS(project_name PRIVATE $<$: --use_fast_math --gpu-architecture=sm35>)` - CMake中启用CUDA单独编译(即relocatable device code,-rdc=true): ```cmake SET_TARGET_PROPERTIES(project_name PROPERTIES INTERFACE_LINK_LIBRARIES "" CUDA_SEPARABLE_COMPILATION ON) ``` - CMake中调用其他进程获取相应字符串值: ```cmake # This module determines which compute capability / SM version # we should be compiling our CUDA code for, and adds the appropriate # switch to the NVCC compiler flags - so that you don't have to worry # about it. # # TODO: Be willing to take CUDA_CC, CUDA_TARGET_COMPUTE_CAPABILITY, # CUDA_TARGET_COMPUTE or CUDA_TARGET_COMPUTE_CAP and maybe even # those without the CUDA_ prefix if (NOT CUDA_TARGET_COMPUTE_CAPABILITY) if("$ENV{CUDA_SM}" STREQUAL "") set(ENV{CUDA_INCLUDE_DIRS} "${CUDA_INCLUDE_DIRS}") set(ENV{CUDA_CUDART_LIBRARY} "${CUDA_CUDART_LIBRARY}") set(ENV{CMAKE_CXX_COMPILER} "${CMAKE_CXX_COMPILER}") execute_process(COMMAND bash -c "${CMAKE_CURRENT_SOURCE_DIR}/scripts/get_cuda_sm.sh" OUTPUT_VARIABLE CUDA_TARGET_COMPUTE_CAPABILITY_) else() set(CUDA_TARGET_COMPUTE_CAPABILITY_ $ENV{CUDA_SM}) endif() set(CUDA_TARGET_COMPUTE_CAPABILITY "${CUDA_TARGET_COMPUTE_CAPABILITY_}" CACHE STRING "CUDA compute capability of the (first) CUDA device on the system, in XY format (like the X.Y format but no dot); see table of features and capabilities by capability X.Y value at https://en.wikipedia.org/wiki/CUDA#Version_features_and_specifications") execute_process(COMMAND bash -c "echo -n $(echo ${CUDA_TARGET_COMPUTE_CAPABILITY})" OUTPUT_VARIABLE CUDA_TARGET_COMPUTE_CAPABILITY) execute_process(COMMAND bash -c "echo ${CUDA_TARGET_COMPUTE_CAPABILITY} | sed 's/^\\([0-9]\\)\\([0-9]\\)/\\1.\\2/;' | xargs echo -n" OUTPUT_VARIABLE FORMATTED_COMPUTE_CAPABILITY) message(STATUS "CUDA device-side code will assume compute capability ${FORMATTED_COMPUTE_CAPABILITY}") endif() set(CUDA_GENCODE "arch=compute_${CUDA_TARGET_COMPUTE_CAPABILITY},code=compu ```
## makefile的常用用法集合 - [GNU Make in Detail for Beginners](https://opensourceforu.com/2012/06/gnu-make-in-detail-for-beginners/) - [linux下的C语言开发(makefile编写详解)](https://www.toutiao.com/i6763898618379239950/) - [全网最牛Linux内核Makefile文件详解](https://www.toutiao.com/i7034387758751678988/) - [Makefile编译选项](http://blog.chinaunix.net/uid-24612247-id-176517.html) - [Makefile编译时怎么打印出变量值](https://blog.csdn.net/zygblock/article/details/53330643)
## 我的一些C语言有趣函数库 - 通过系统控制台输入命令并获得命令执行的结果: ```c #ifndef _WIN32 #include #endif // !_WIN32 #include #include #include #include #ifdef _WIN32 bool ExecuteSystemCommand(char resultBuffer[], size_t bufferSize, const char* command) { if (resultBuffer == NULL || command == NULL) return false; char lineBuffer[256] = { '\0' }; FILE* hPipe = _popen(command, "r"); if (hPipe == NULL) { puts("Pipe cannot be opened!"); return false; } size_t const resultBufferCapacity = bufferSize - 1; size_t const lineBufferCapacity = sizeof(lineBuffer) - 1; size_t remainAvailBytes = resultBufferCapacity; size_t index = 0; while (feof(hPipe) == 0) { size_t const maxLineSize = remainAvailBytes < lineBufferCapacity ? remainAvailBytes : lineBufferCapacity; if (fgets(lineBuffer, maxLineSize, hPipe) != NULL) { if (strcpy_s(&resultBuffer[index], remainAvailBytes, lineBuffer) != 0) break; size_t const nReadBytes = strlen(lineBuffer); remainAvailBytes -= nReadBytes; index += nReadBytes; } } _pclose(hPipe); if (index > 0) { if (resultBuffer[index - 1] == '\n') resultBuffer[index - 1] = '\0'; } return true; } #else bool ExecuteSystemCommand(char resultBuffer[], size_t bufferSize, const char* command) { int fd[2]; int back_fd; if (pipe(fd) != 0) { puts("pipe establish failed!"); return false; } // Backup standard I/O back_fd = dup(STDOUT_FILENO); // Redirect standard I/O to fd[1] dup2(fd[1], STDOUT_FILENO); close(fd[1]); system(command); read(fd[0], resultBuffer, bufferSize); // Restore standard I/O dup2(back_fd, STDOUT_FILENO); close(fd[0]); close(back_fd); size_t const resultLen = strlen(resultBuffer); if (resultLen > 0 && resultBuffer[resultLen - 1] == '\n') resultBuffer[resultLen - 1] = '\0'; return true; } #endif // _WIN32 int main(void) { char buffer[2048] = { '\0' }; ExecuteSystemCommand(buffer, sizeof(buffer), "echo %USERPROFILE%"); printf("command result is: %s\n", buffer); } ``` - 在控制台中读取一行输入命令字符串 ```c // Linux char *contents = NULL; size_t initLen = 0; // contents最后会包含一个换行符,这也就是意味着如果用户仅输入一个回车, // 那么contents中就一个换行符,长度为1。 ssize_t contentLength = getline(&contents, &initLen, stdin); printf("Content length is: %zd, content is: %s", contentLength, contents); // Windows char commandBuffer[256] = { '\0' }; gets_s(commandBuffer, sizeof(commandBuffer)); // 这里commandBuffer不包含最后的换行符 printf("The length is: %zu, content is: %s\n", strlen(commandBuffer), commandBuffer); ``` 以上代码只需要包含``头文件即可。这里需要注意的是,getline的第二个参数不能为空。 - 获取当前执行程序所在的文件目录 ```c #include #define ZF_MAX_PATH_CHARACTERS 512 /// Store the current executable directory static char sCurrentExecPath[ZF_MAX_PATH_CHARACTERS]; #ifdef __APPLE__ const char* zf_get_current_exec_path(void) { if(sCurrentExecPath[0] == '\0') { const int maxSize = ZF_MAX_PATH_CHARACTERS - 1; uint32_t size = 0; _NSGetExecutablePath(NULL, &size); if(size > maxSize) size = maxSize; _NSGetExecutablePath(sCurrentExecPath, &size); sCurrentExecPath[size] = '\0'; } return sCurrentExecPath; } #elif defined(_WIN32) #include const char* zf_get_current_exec_path(void) { if(sCurrentExecPath[0] == '\0') { WCHAR path[ZF_MAX_PATH_CHARACTERS]; const int maxSize = ZF_MAX_PATH_CHARACTERS - 1; GetModuleFileNameW(NULL, path, maxSize); int len = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL); if(len > maxSize) len = maxSize; WideCharToMultiByte(CP_UTF8, 0, path, -1, sCurrentExecPath, len, NULL, NULL); } return sCurrentExecPath; } #else // Unix-like platforms #include const char* zf_get_current_exec_path(void) { if(sCurrentExecPath[0] == '\0') { const int maxSize = ZF_MAX_PATH_CHARACTERS - 1; int size = readlink("/proc/self/exe", sCurrentExecPath, sizeof(sCurrentExecPath)); if(size > maxSize) size = maxSize; sCurrentExecPath[size] = '\0'; } return sCurrentExecPath; } #endif ``` - 获得时间戳函数: ```c #ifdef _WIN32 #include #include int main(void) { DWORD tBegin = GetTickCount(); _mm_mfence(); volatile int count = 0; for (int i = 0; i < 1000 * 1000; i++) { count += i; } DWORD tEnd = GetTickCount(); _mm_mfence(); printf("Time spent: %u ms\n", tEnd - tBegin); } #else #include #include int main(void) { struct timeval tBegin, tEnd; gettimeofday(&tBegin, NULL); _mm_mfence(); volatile int count = 0; for(int i = 0; i < 1000 * 1000; i++) { count += i; } gettimeofday(&tEnd, NULL); _mm_mfence(); long long deltaTime = 1000000LL * (tEnd.tv_sec - tBegin.tv_sec ) + (tEnd.tv_usec - tBegin.tv_usec); printf("Time spent: %lldus", deltaTime); } #endif ``` - 三大操作系统获取当前系统主存大小: ```c #ifdef _WIN32 #include #elif defined(__APPLE__) #include #include #else #include #endif size_t system_physical_ram() { #ifdef _WIN32 MEMORYSTATUSEX ram; ram.dwLength = sizeof (ram); GlobalMemoryStatusEx(&ram); return ram.ullTotalPhys * 1024; #elif defined(__APPLE__) uint64_t ram = 0; size_t len = sizeof(ram); if (sysctlbyname("hw.memsize", &ram, &len, NULL, 0) == 0) { return ram; } return 0; #else size_t ps = sysconf(_SC_PAGESIZE); size_t pn = sysconf(_SC_PHYS_PAGES); return ps * pn; #endif } ``` - 统计一个无符号32位整型有多少个比特为1: ```c static unsigned PopulateOnes(unsigned n) { unsigned tmp = 0x55555555 & (n >> 1); n -= tmp; tmp = 0x33333333 & (n >> 2); n &= 0x33333333; n += tmp; n += n >> 4; n &= 0x0f0f0f0f; n *= 0x01010101; return n >> 24; } ``` - 对一个32位带符号整数取饱和,将其值裁剪到\[-32768, +32767\]的范围内: ```c static inline int ZennySat16(int src) { const int mask = src >> 31; src ^= mask; if (src > 0x7fff) { src = 0x7fff; } src ^= mask; return src; } ```
## 我的一些C++函数库 - 在编译时统计一个无符号32位整数有多少比特1: ```cpp template struct GetOnes { enum { ONES = ((N & 1) == 0 ? 0 : 1) + GetOnes < (N >> 1) >::ONES }; }; template <> struct GetOnes<0> { enum { ONES = 0 }; }; ``` - 使用指定整数常量的数值对齐 ```cpp template static inline unsigned GetAlignedValue(unsigned n) { static_assert(GetOnes::ONES == 1, "Invalid ALIGNMENT!!"); return (n + (ALIGNMENT - 1U)) & ~(ALIGNMENT - 1U); } ``` - 编译时获取一个整数至少需要用多少比特来表示: ```cpp template struct GetBitCountValueStruct { enum { BIT_COUNT = (GetBitCountValueStruct<(VALUE >> 1), pos + 1>::BIT_COUNT > (pos + 1)) ? GetBitCountValueStruct<(VALUE >> 1), pos + 1>::BIT_COUNT : ((VALUE & 1) != 0 ? (pos + 1) : 1) }; }; template struct GetBitCountValueStruct<0, pos> { enum { BIT_COUNT = 1 }; }; template static inline constexpr int GetBitCountInValue(void) { return GetBitCountValueStruct::BIT_COUNT; } ``` - C++11标准:UTF-8字符串与UTF-16字符串互转 ```cpp #include #include #include #include extern "C" void CPPTest(void) { std::string u8str = u8"你好,世界!"; // UTF-8转UTF-16 std::u16string u16str = std::wstring_convert< std::codecvt_utf8_utf16, char16_t >{}.from_bytes(u8str); // UTF-16转UTF-8 std::string str = std::wstring_convert< std::codecvt_utf8_utf16, char16_t >{}.to_bytes(u16str); printf("UTF-8 string is: %s\n", str.c_str()); } ``` - 对某一类型做cv限定符的移除并声明一个对象 ```cpp const int c = 100; std::decay::type a = c; // a为int类型 ``` - 如果一个函数参数为一个结构体类型,那么可以对它传递一个匿名结构体对象;同样,如果返回类型是一个结构体类型,则也可以使用匿名结构体的初始化器进行构造: ```cpp struct { int a, b, c; } s2{ .a = 10, .c = -20 }; std::cout << "s2 value = " << s2.a + s2.b + s2.c << std::endl; auto strucLam = [](const decltype(s2)& s) -> decltype(s2) { printf("The value is: %d\n", s.a + s.b + s.c); return { .a = 10, .b = 20, .c = 30 }; }; strucLam({ .a = 1, .b = 2, .c = 3 }); ``` - 某个类型的对象指针直接显式地调用该类型的构造方法(仅针对Visual C++可用): ```cpp struct MyStruct { int value; int data[]; inline MyStruct(int i) : value(i) { } }; constexpr int dataCount = 4; MyStruct* myData = (MyStruct*)malloc(sizeof(MyStruct) + dataCount * sizeof(myData->data[0])); // 显式调用构造方法对成员进行初始化 (仅针对Visual C++可用) myData->MyStruct::MyStruct(10); // 对data成员进行初始化 for (int i = 0; i < dataCount; ++i) { myData->data[i] = i + 1; } int sum = myData->value; for (int i = 0; i < dataCount; ++i) { sum += myData->data[i]; } free(myData); printf("sum = %d\n", sum); // 这里将输出:sum = 20 ``` - C++原生字符串字面量(Raw string literal) ```cpp const char16_t* raw_u16string = uR"(你好,世界!)"; std::u16string u16str(raw_u16string); printf(R"(The raw string length is: %zu )", u16str.length()); ``` - C++显式调用构造方法来创建一个指定内存位置的对象 ```cpp struct MyObject { int value; MyObject(void) : value(1) { } ~MyObject(void) { puts("MyObject is destroyed!"); } }; uint8_t objBuffer[64] = { }; MyObject* p = (MyObject*)objBuffer; // 注意!以下方法仅针对Visual C++可用 // p->MyObject::MyObject(); // 使用placement new对所有平台有效 new(p) MyObject(); printf("value in p is: %d\n", p->value); // 最后需要显式调用析构方法来释放对象,如果需要做额外内存释放的话 p->~MyObject(); ``` - C++20中泛型模板lambda表达式 ```cpp // Generic template lambda in C++20 auto const genericLambda = [](const T& a) -> T { if constexpr (size < 0) { puts("Illegal size!!"); } printf("size is: %d\n", size); return a + T(1); }; // Use the generic lambda auto const lamRet = genericLambda.template operator() (100); printf("Generic lambda result: %d\n", lamRet); ``` - C++17/20中将lambda表达式转换为函数指针的形式进行调用,并能存放其参数(这里的lambda表达式中不允许捕获任何变量) ```cpp #include // PARAM_TYPES必须与LAMBDA类型的参数类型完全等价 template static inline void CallLambda(LAMBDA lambda, PARAM_TYPES... params) { decltype(lambda(params...)) (* const fptr)(PARAM_TYPES...) = lambda; constexpr size_t maxParamCount = 64; unsigned long long paramBuffer[maxParamCount] = { static_cast(params)... }; constexpr size_t nParams = sizeof...(params); static_assert(nParams <= maxParamCount, "parameter count exceeds the max count"); printf("There are %zu parameters in this function\n", nParams); for (size_t i = 0; i < nParams; ++i) { printf("param i = %llu\n", paramBuffer[i]); paramBuffer[i] = 0; } int i = 0; (... , [](int i, unsigned long long *pBuffer, auto param) { pBuffer[i] = static_cast(param); }(i++, paramBuffer, params)); if constexpr (nParams > 0) { printf("Verify fold expression to take the parameters...\n"); } for(size_t i = 0; i < nParams; ++i) { printf("param i = %llu\n", paramBuffer[i]); } fptr(params...); } int main(void) { CallLambda([](void) { printf("This is a lambda expression with no parameters...\n"); }); CallLambda([](int a, int b) -> int { const int result = a + b; printf("This is a lambda expression: %d\n", result); return result; }, 100, 20); } ``` - 将Lambda表达式直接转换为其对应的函数指针类型(这里的lambda仍然不允许捕获任何变量) ```cpp template struct function_info : function_info { }; template struct function_info { enum : size_t { PARAM_COUNT = sizeof...(Args) }; using return_type = RET_TYPE; using function_type = RET_TYPE(Args...); }; template struct function_info : function_info { }; template struct function_info : function_info { using class_type = C; using function_type_with_class = R(C*, As...); }; template struct function_info : function_info { using class_type = C; using function_type_with_class = R(C*, As...); }; template static constexpr size_t parameter_count_v = function_info::PARAM_COUNT; template using function_type = typename function_info::function_type; template using function_type_with_class = typename function_info::function_type_with_class; template using return_type = typename function_info::return_type; template using class_type = typename function_info::class_type; template static inline auto FptrCast(LAMBDA lambda) noexcept { return static_cast*>(lambda); } template static void PrintLambdaParamCount(LAMBDA lambda) { printf("Paramter count: %zu\n", parameter_count_v); } int main(void) { auto const lam = [](int a, int b) { printf("a - b = %d\n", a - b); }; auto const fptr = FptrCast(lam); fptr(5, 3); PrintLambdaParamCount(lam); } ```