C++ 中文周刊 2024-03-03 第150期

2024-07-30 15:01:20 浏览数 (2)

RSS https://github.com/wanghenshui/cppweeklynews/releases.atom

欢迎投稿,推荐或自荐文章/软件/资源等 评论区留言

本期文章由 黄亮Anthony Amnesia 赞助

最近沸沸扬扬的白宫发文,转向更安全的语言,明示c 不行

除了把NSA之前的观点重新提出来之外,没有任何新东西

就像个想离婚的在这里埋怨不想过了,死鬼你也不改你看人家xx语言

要我说这就是美帝不行的原因,从上到下都没有耐性我靠

最近很忙视频都没来得及看。后面慢慢补吧,视频可能单独发总结

资讯

标准委员会动态/ide/编译器信息放在这里

编译器信息最新动态推荐关注hellogcc公众号 本周更新 2024-02-21 第242期

本台记者 kenshin报道,visual studio最近更新了非常有用的功能,分析编译时间之类,分析字段内存布局,分析include等等

感兴趣 可以更新一下 What’s New for C Developers in Visual Studio 2022 17.9 https://devblogs.microsoft.com/cppblog/whats-new-for-cpp-developers-in-visual-studio-2022-17-9/?WT.mc_id=academic-0000-abartolo

另外clang gcc有单独的工具,比如ftime-trace,比如 这个 https://github.com/aras-p/ClangBuildAnalyzer

xmake 2.8.7发布

https://github.com/xmake-io/xmake/wiki/Xmake-v2.8.7-released,-Add-cosmocc-toolchain-support,-build‐once-run‐anywhere

boost新parser正在review中 https://lists.boost.org/Archives/boost/2024/02/255957.php

类似boost spirit,代码在这里 https://github.com/tzlaine/parser

think-cell出了个意见,他们在自己的库里维护了boost spirit,觉得重新造轮子不太合理,详情见 https://www.think-cell.com/en/career/devblog/parsers-vs-unicode

文章

Rage Against The Glue: Beyond Run-Time Media Frameworks with Modern C https://cnrs.hal.science/hal-04090584/document

音视频领域有个 M x N问题

不同的media processors 在N种平台上导致api复杂度上升不可维护

考虑一种接口设计方法,让代码更简练

琢磨半天结果是concept boost pfr之类的检测接口/策略模版

代码在这里 https://github.com/celtera/avendish

还有一些其他的想法 在这里 https://ossia.io/posts/reflection/

constexpr and consteval functions https://biowpn.github.io/bioweapon/2024/02/17/constexpr-consteval-function.html

记住这段代码就行了

代码语言:javascript复制
// This is a pure compile-time function.
// Any evaluation is fully done at compile-time;
// no runtime code will be generated by the compiler, just like `static_assert`.
consteval size_t strlen_ct(const char* s) {
    size_t n = 0;
    for (; s[n] != '';   n);
    return n;
}

// This is a pure runtime function, which can only be invoked at runtime.
size_t strlen(const char* s);

// This function can be invoked both at both compile-time and at runtime,
// depending on the context.
constexpr size_t strlen_dual(const char* s) {
    if consteval {
        return strlen_ct(s); // compile-time path
    } else {
        return strlen(s);    // runtime path
    }
}

constexpr最好两种分支都实现,避免意外的问题

How to debug C and C programs with rr https://developers.redhat.com/blog/2021/05/03/instant-replay-debugging-c-and-c-programs-with-rr#

其实rr和gdb record差不多,感觉可以用这个文档例子做个视频,这里标记一个TODO

https://github.com/rr-debugger/rr?tab=readme-ov-file

Undefined behavior in C and C https://lumagraph.ie/undefined-behavior

讲UB产生的场景,以及如何避免,给的方案编译flag ubsan以及换个语言,我谢谢你

Measuring energy usage: regular code vs. SIMD code https://lemire.me/blog/2024/02/19/measuring-energy-usage-regular-code-vs-simd-code/

lemire新活,只要你的代码足够快,即使是simd这种费电的指令相比而言整体费电也不多

代码在这里 https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/tree/master/2024/02/19

值得复现一下

My late discovery of std::filesystem - Part I https://www.sandordargo.com/blog/2024/02/28/std-filesystem-part1-paths-and-operations

介绍fs相关api,比如遍历之类的,我就不列出来了

How to write unit tests in C relying on non-code files? https://www.sandordargo.com/blog/2024/02/21/cpp-tests-with-resources

介绍非代码文件怎么和代码编译到一起的,bazel/cmake都有类似configfile的方法。embed赶紧来吧

Navigating Memory in C : A Guide to Using std::uintptr_t for Address Handling https://blog.feabhas.com/2024/02/navigating-memory-in-c-a-guide-to-using-stduintptr_t-for-address-handling/

为什么用它,用int32 int64之类的类型,reinterpret cast可能会有fpermissive报错,比如

代码语言:javascript复制

#include <cstdint>

namespace HAL {
class UART {
public:
 explicit UART(std::uint32_t base_address); 
 void write(std::byte byte);
 std::byte read() const;
 // ...
private:
 struct Registers* const registers;
};
}

constexpr std::uint32_t com1_based_address = 0x4002'0000U;

int main() {
 HAL::UART com1{com1_based_address}; 
 com1.write(std::byte{0x5A});
 auto val = com1.read();
 ...
}
namespace {
 struct Registers // layout of hardware UART
{ 
  std::uint32_t status;     // status register
  std::uint32_t data;      // data register
  std::uint32_t baud_rate;    // baud rate register
  ...
  std::uint32_t guard_prescaler; // Guard time and prescaler register
 };
 static_assert(sizeof(Registers) == 40, "Registers struct has padding");
 Registers Mock_registers{};
} 

// doctest
TEST_CASE("UART Construction") {
  constexpr std::uint32_t baud_115k = 0x8b;
  constexpr std::uint32_t b8_np_1stopbit = 0x200c;

  HAL::UART com3 {reinterpret_cast<std::uint32_t>(&Mock_registers)}; // 不行

  CHECK(Mock_registers.baud_rate == baud_115k);
  CHECK(Mock_registers.ctrl_1 == b8_np_1stopbit);
}

但如果把UART构造函数改成intptr就没问题

代码语言:javascript复制
#include <cstdint>

namespace HAL {
class UART {
public:
 explicit UART(std::uintptr_t base_addr); 
 ...
};
}

// doctest
TEST_CASE("UART Construction") {
  constexpr std::uint32_t baud_115k = 0x8b;
  constexpr std::uint32_t b8_np_1stopbit = 0x200c;

  HAL::UART com3 {reinterpret_cast<std::uintptr_t>(&Mock_registers)};

  CHECK(Mock_registers.baud_rate == baud_115k);
  CHECK(Mock_registers.ctrl_1 == b8_np_1stopbit);
}

为什么不用intptr? 如果涉及到负数移动,或者做差有负数之类的,可以用intptr,其他场景还是uintptr更合适

Introduction To Low Latency Programming: Minimize Branching And Jumping https://tech.davidgorski.ca/introduction-to-low-latency-programming-minimize-branching-and-jumping/

哥们出书了,120页卖10刀有点贵我靠,书在这里 https://a.co/d/0U6KOfb

这个文章是节选,大概思路就是降低跳转和分支

  • • 勤用 && || 利用短路特性
  • • 关注能生成cmov的写法,condition mov几乎和mov差不多,利用cmov替代jump test更好,什么能生成cmov? 冒号表达式
  • • 减少虚函数使用,你用variant模拟那也是虚函数,不要自欺欺人哈
  • • inline,可以用[[gnu::always_inline]]
  • • 善用 __builtin_expect
  • • 分支改switch

一个样例

代码语言:javascript复制
void processThisString(std::string_view input)
{
  if (input == "production") {
    processProd(input);
  } else if (input == "RC") {
    processRC(input);
  } else if (input == "beta")
    processBeta(input);
  }
}
void processThisString(std::string_view input)
{
  constexpr auto i = 0;
  switch (input[i]) {
    case "production"[i]: processProd(input); break;
    case "RC"[i]: processRC(input); break;
    case "beta"[i]: processBeta(input); break;
  }
}
1 << n vs. 1U << n and a cell phone autofocus problem https://rachelbythebay.com/w/2024/02/24/signext/
代码语言:javascript复制

#include <stdio.h>

static unsigned long set_bit_a(int bit) {
  return 1 << bit;
}

static unsigned long set_bit_b(int bit) {
  return 1U << bit;
}

int main() {
  printf("sizeof(unsigned long) here: %zdn", sizeof(unsigned long));

  for (int i = 0; i < 32;   i) {
    printf("1 << %d : 0x%lx | 0x%lxn", i, set_bit_a(i), set_bit_b(i));
  }

  return 0;
}

64位机器 31会打印什么?https://gcc.godbolt.org/z/qa3o34hrW

非常幽默

代码语言:javascript复制
1 << 0 : 0x1 | 0x1
1 << 1 : 0x2 | 0x2
1 << 2 : 0x4 | 0x4
1 << 3 : 0x8 | 0x8
1 << 4 : 0x10 | 0x10
1 << 5 : 0x20 | 0x20
...
1 << 29 : 0x20000000 | 0x20000000
1 << 30 : 0x40000000 | 0x40000000
1 << 31 : 0xffffffff80000000 | 0x80000000

m32并没有这个问题

自底向上理解memory_order https://zhuanlan.zhihu.com/p/682286231

理解理解

Using std::expected from C 23 https://www.cppstories.com/2024/expected-cpp23/

不会的拖出去

代码语言:javascript复制

#include <charconv>
#include <expected>
#include <string>
#include <system_error> 
#include <iostream>

std::expected<int, std::string> convertToInt(const std::string& input) {
    int value{};
    auto [ptr, ec] = std::from_chars(input.data(), input.data()   input.size(), value);
    
    if (ec == std::errc())
        return value;

    if (ec == std::errc::invalid_argument)
        return std::unexpected("Invalid number format");
    else if (ec == std::errc::result_out_of_range)
        return std::unexpected("Number out of range");

    return std::unexpected("Unknown conversion error");
}

int main() {
    std::string userInput = "111111111111111";

    auto result = convertToInt(userInput);
    if (result)
        std::cout << "Converted number: " << *result << 'n';
    else
        std::cout << "Error: " << result.error() << 'n';
}

c23有一种模拟的方法

代码语言:javascript复制
#include <stdio.h>

struct { bool success; int value; } parse(const char* s)
{
    if (s == NULL)
       return (typeof(parse(0))) { false, 1};

    return (typeof(parse(0))) { true, 1 };
};

int main()
{
   auto r = parse("1");
   if (r.success) {
     printf("%d", r.value);
   }
}

不建议使用

LLVM 中的一致性分析框架详解 之 发散源和指令一致性判断 https://zhuanlan.zhihu.com/p/684983035

学点llvm

A story of a very large loop with a long instruction dependency chain https://johnnysswlab.com/a-story-of-a-very-large-loop-with-a-long-instruction-dependency-chain/

简单来说就是拆循环 loop fission 降低数据buffur大小,小于l1 cacheline,提升性能

需要复现一下

如何发现是内存子系统的问题(buffer大于cacheline)? 使用likwid 查的。这个实验需要复现一下看看

When an instruction depends on the previous instruction depends on the previous instructions… : long instruction dependency chains and performance

简单来说就是通过 interleave 拆分任务,来加速,这个和loop fission还不太一样,loop fission就是单纯的拆循环,interleave又不同任务分发调度的感觉

Atomics And Concurrency

这个比较基础和cpprefence差不多 https://redixhumayun.github.io/systems/2024/01/03/atomics-and-concurrency.html

The Auto macro https://quuxplusone.github.io/blog/2018/08/11/the-auto-macro/
代码语言:javascript复制
#pragma once

template<class L>
class AtScopeExit {
    L& m_lambda;
public:
    AtScopeExit(L& action) : m_lambda(action) {}
    ~AtScopeExit() noexcept(false) { m_lambda(); }
};

#define TOKEN_PASTEx(x, y) x ## y
#define TOKEN_PASTE(x, y) TOKEN_PASTEx(x, y)

#define Auto_INTERNAL1(lname, aname, ...) 
    auto lname = [&]() { __VA_ARGS__; }; 
    AtScopeExit<decltype(lname)> aname(lname);

#define Auto_INTERNAL2(ctr, ...) 
    Auto_INTERNAL1(TOKEN_PASTE(Auto_func_, ctr), 
        TOKEN_PASTE(Auto_instance_, ctr), __VA_ARGS__)

#define Auto(...) 
    Auto_INTERNAL2(__COUNTER__, __VA_ARGS__)

// 使用

bool Mutate(State *state){
    state->DisableLogging();
    Auto(state->EnableLogging());

    if (!state->AttemptOperation1()) return false;
    if (!state->AttemptOperation2()) return false;
    return true;
}
// 还能递归
void Example()
{
    Auto(
        puts("starting the first Auto");
        Auto(puts("cleaning up in the second Auto"));
        puts("getting ready to clean up in the first Auto");
    );
    puts("doing the main operation");
}
libfork https://arxiv.org/pdf/2402.18480.pdf

这个完成度看起来比taro强很多,且融合了很多taskflow点子

比如 https://tsung-wei-huang.github.io/papers/icpads20.pdf

文档 https://conorwilliams.github.io/libfork/api/schedule.html

代码 https://github.com/ConorWilliams/libfork

另外就是性能要测试一下,这里标记TODO有空测一下

开源项目介绍

  • • 一个unique ptr SSO优化实现 https://github.com/KRM7/small_unique_ptr 代码很短,600行,感觉可以讲一讲,这里标记一个TODO
  • • https://github.com/google/gemma.cpp 这是啥啊最近挺火的
  • • https://github.com/pizlonator/llvm-project-deluge 这个哥们fork llvm整了个safe c。看一乐
  • • https://github.com/TerensTare/modern_bloom 一个bloom filter实现
  • • https://github.com/catchorg/Catch2/commit/dc51386b9fd61f99ea9c660d01867e6ad489b403 幽默MSVC兼容性问题一例

0 人点赞