公众号
qq群 手机qq点击进入
RSS https://github.com/wanghenshui/cppweeklynews/releases.atom
欢迎投稿,推荐或自荐文章/软件/资源等
感谢 Amnesia 不语 高博 Yin YellyHornby 404 赞助
本周内容太少了,加点bug反馈,欢迎各位后台评论投稿遇到的奇怪bug,我发出来征集思路
新版本clang gcc thread local识别不出 fiber切换的场景,会优化,寄存器暂存,而不是从内存load同步一下
受害者很多,只要用boost context和tls,就可能遇到,比如 https://github.com/userver-framework/userver/issues/242
简单的规避手段
thread_local int* tls = nullptr;
[[gnu::noinline]] int* getTls() {
asm volatile("");
return tls;
}
[[gnu::noinline]] void setTls(int* val) {
asm volatile("");
tls = val;
}
难受
知乎网友@张威补充 brpc也有类似问题
标准委员会动态/ide/编译器信息放在这里
编译器信息最新动态推荐关注hellogcc公众号 OSDT Weekly 2023-09-27 第221期
riscv如火如荼啊
cppcon 2023 十一开始,我这几天在疯狂看去年的
int main() {
setlocale(LC_ALL, "C");
std::cout << std::to_string(42); // prints 42
std::cout << std::to_string(.42); // prints 0.42
std::cout << std::to_string(-1e7); // prints -1e+07
}
xmake确实好用
看个乐
看一乐
给forword查缺补漏的
靠tuple+ typeindex,设计的过于复杂了
感觉有点类似boost::ext:;di
剩下有意思的我攒一攒再发
https://github.com/boostcon/cppnow_presentations_2023
简单看一眼好玩的,视频太慢了,看不懂再看视频,感觉最近视频有点多看不过来
介绍carbon的好几个,介绍safety的好几个,介绍module的好几个,还有几个抽象的,我都不介绍了
介绍协程的有俩之前提过,视频链接就不贴了感兴趣的youtube搜标题就行
剩下的说实话有意思的也不多
设计思路,使用模板参数作为实现,不同实现拆分开
比如这种
namespace logging {
namespace null {
struct config {
struct {
template <level L, typename... Ts>
// NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward)
constexpr auto log(Ts &&...) const noexcept -> void {}
} logger;
};
} // namespace null
template <typename...> inline auto config = null::config{};
template <level L, typename... Ts, typename... TArgs>
static auto log(TArgs &&...args) -> void {
auto &cfg = config<Ts...>;
cfg.logger.template log<L>(std::forward<TArgs>(args)...);
}
}
实现放在config里,然后config有不同的初始化的值,其实就相当于CPO定制点
比如想用其他实现,就特化config初始值
namespace my_logger {
struct config {
struct {
template <logging::level L, typename... Ts>
auto log(Ts &&...ts) -> void {
// log the ts... according to my mechanism
}
} logger;
};
}
// use my logger
template <>
inline auto logging::config<> = my_logger::config{};
代码在这 https://github.com/intel/compile-time-init-build/tree/main/include/log
作者的意思是这种思路可以定制系统API,比如write之类的,然后测试使用不同的实现,方便mock
讲了一圈汇编基础知识 ELF VDSO知识,挺有意思的,可以看一乐
这个是讲fmap的。我不懂这个,说实话这玩意在16年那会很热闹
不过到现在我还是不太懂
介绍英伟达那个execution实现 std::exec的例子代码,建议直接看代码不用看视频
这个之前介绍过,就是switch case 或者 bit或模式太难看,想解决办法,比如这种
while (auto header = parse_header(reader)) {
switch (header.type)
{
case header_type::integer:
parse_integer(reader);
break;
case header_type::string:
parse_string(reader, header.length); break;
...
}
}
或者
while (*ip != bytecode::exit) {
switch (*ip)
{
case bytecode::add:
...
case bytecode::push:
... ...
}
}
case下面不同函数确实不好搞,作者一个函数尾递归调用搞定,期间各种优化benchmark调优
具体就不展开了,感觉这个我说了好几遍了
另外用到了https://github.com/sharkdp/hyperfine来测试命令行IO,挺有意思
介绍 编译期矩阵计算的
这个是介绍编译期hash string 来替换掉二进制中的特殊字符串,避免泄密
这个是llvm实现libc遇到的一些挑战和设计,还算有意思
string_view的妙用
LLVM_LIBC_FUNCTION(char *, getenv, (const char *name)) {
char **env_ptr = reinterpret_cast<char **>(__llvm_libc::app.envPtr);
if (name == nullptr || env_ptr == nullptr)
return nullptr;
__llvm_libc::cpp::string_view env_var_name(name);
if (env_var_name.size() == 0)
return nullptr;
for (char **env = env_ptr; *env != nullptr; env++) {
__llvm_libc::cpp::string_view cur(*env);
if (!cur.starts_with(env_var_name))
continue;
if (cur[env_var_name.size()] != '=')
continue;
// Remove the name and the equals sign.
cur.remove_prefix(env_var_name.size() + 1);
// We know that data is null terminated, so this is safe.
return const_cast<char *>(cur.data());
}
return nullptr;
}
再比如
LIBC_INLINE void write_to_stderr(cpp::string_view msg) {
__llvm_libc::syscall_impl(SYS_write, 2 /* stderr */,
msg.data(), msg.size());
}
使用 expect包装errno
template <class T>
using ErrorOr = cpp::expected<T, int>;
class Dir {
static ErrorOr<Dir *> open(const char *path);
ErrorOr<struct ::dirent *> read();
// Returns the error number to indicate the success or failure.
int close();
};
LLVM_LIBC_FUNCTION(::DIR *, opendir, (const char *name)) {
auto dir = Dir::open(name);
if (!dir) {
libc_errno = dir.error();
return nullptr;
}
return reinterpret_cast<DIR *>(dir.value());
}
使用bit_cast
template <typename T>
class FPBits {
UIntType bits;
LIBC_INLINE T get_val() const {
return cpp::bit_cast<T>(bits);
}
LIBC_INLINE void set_val(T value) {
bits = cpp::bit_cast<UIntType>(value);
}
…
};
考虑一下实现日历,有哪些可以优化的地方,开头还能看懂,比如
判断闰年
return Y % 4 == 0 && (Y % 100 != 0 || Y % 400 == 0);
就可以优化成
if (Y % 100 != 0)
return Y % 4 == 0;
return Y % 400 == 0;
最后一行可以优化成 Y%16
还可以继续优化成
int d = Y % 100 != 0 ? 4 : 16;
return (Y % d) == 0;
还可以优化成
int d = Y % 100 != 0 ? 4 : 16;
return (Y & (d - 1)) == 0;
判断最后一天
if (M == 2) return is_leap(Y) ? 29 : 28;
unsigned last[] = {
31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31
};
return last[M - 1];
由于天数大部分都是 30 31,重复度高,完全可以改成位运算
if (M == 2)
return is_leap(Y) ? 29 : 28;
return 30 | (M ^ (M >> 3));
//return 30 | (9 * M / 8);
后面就看不太懂了
介绍concept的
也是介绍日历的,chrono和date
介绍他们公司遇到的代码问题以及从维护角度如何复现,定位
这个之前也讲过,数据冷热,冷数据用指针指出去indirect_value封装,不需要的话甚至可以不创建,让数据集小点
如果有疑问评论最好在上面链接到评论区里评论,这样方便搜索,微信公众号有点封闭/知乎吞评论