C++ 中文周刊 第93期

2022-12-31 16:05:09 浏览数 (2)

C 中文周刊 第93期

资讯

编译器信息最新动态推荐关注hellogcc公众号 2022-12-14 第180期

文章

  • Did you know that the layout of struct fields will affect its size/alignment?
代码语言:javascript复制
struct unpacked {
  char a;  // size: 1b => size: 4b
  int  b;  // size: 4b => size: 4b
  char c;  // size: 1b => size: 4b
           //             ---------
           //             size: 12b
};

struct packed {
  char a;  // size: 1b => size: 4b
  char b;  // size: 1b => size: 4b
  int  c;  // size: 4b => size: 8b
           //             --------
           //             size: 8b
};

static_assert(12 == sizeof(unpacked));
static_assert(8 == sizeof(packed));

struct simple {
  int a;   // size: 4b => align: 4b
};

struct empty {
           // size: 1b => align: 1b
};

这个我感觉都知道,问题是,如何检测是否对齐呢?

代码语言:javascript复制
template<auto Id>
struct alignment {
  std::size_t* alignments{};
  template<class T> constexpr operator T() const {
    alignments[Id] = alignof(T);
    return {};
  }
};

template<class T, class... TArgs>
using AggregateInitializable = decltype(T{std::declval<TArgs>()...});

template<class T, auto... Ns>
constexpr auto is_packed_layout(std::index_sequence<Ns...>) {
  if constexpr(std::experimental::is_detected_v<AggregateInitializable, T, alignment<Ns>...>) {
    std::size_t alignments[sizeof...(Ns)]{};
    void(T{alignment<Ns>{alignments}...});
    return (alignments[Ns] <= ... <= sizeof(T));
  } else {
    return is_packed_layout<T>(std::make_index_sequence<sizeof...(Ns) - 1>{});
  }
}

template<class T, class = std::enable_if_t<std::is_aggregate_v<T>>>
constexpr std::bool_constant<is_packed_layout<T>(
  std::make_index_sequence<sizeof(T)>{})> is_packed_layout_v{};

static_assert(12 == sizeof(unpacked));
static_assert(not is_packed_layout_v<unpacked>);

static_assert(8 == sizeof(packed));
static_assert(is_packed_layout_v<packed>);

static_assert(1 == sizeof(empty));
static_assert(is_packed_layout_v<empty>);

static_assert(4 == sizeof(simple));
static_assert(is_packed_layout_v<simple>);
  • C coroutine generator 实现笔记

学习一波

  • 如何理解 C 中的 定制点对象 这一概念?为什么要这样设计?

值得一看

  • MSVC AddressSanitizer中的bug

很精彩的抓bug,值得一看

  • C23 implications for C libraries

很详尽的记录了c23变了啥

  • Add moc includes to speed up Qt compilation

整了个脚本把moc开头的生成的头文件include一下

  • C Uniform Initialization - Benefits & Pitfalls

老生常谈了属于是,列表初始化这个玩意

  • Modern CMake Packaging: A Guide

一个cmake教程

  • Structured bindings in C 17, 5 years later

直接看代码

代码语言:javascript复制
auto [_, was_inserted] =
      done_events_.insert({device_ordinal, std::move(done_event)});



auto [installer_download_url, installer_filename] = extract_installer_asset_download_info(release_object);
co_return new_version_download_info{ extract_release_page_url(release_object),
                                                 std::move(github_version),
                                                 std::move(installer_download_url),
                                                 std::move(installer_filename) };



const auto [colorForeground, colorBackground] = renderSettings.GetAttributeColors(textAttributes);



const auto [first_nonmatching, error_condition] 
    = std::from_chars(val.data(), val.data()   val.size(), result);

其实就可以当作多个返回值解包来用

  • Does it inline?

简单题,以下四段代码会不会inline?

A

代码语言:javascript复制
inline int fn(int v) { return v; }
int main(int argc, char *argv[]) { return fn(0); }

B

代码语言:javascript复制
//remove inline
int fn(int v) { return v; }
int main(int argc, char *argv[]) { return fn(0); }

C

代码语言:javascript复制
//move function body
int fn(int v);
int main(int argc, char *argv[]) { return fn(0); }
int fn(int v) { return v; }

D

代码语言:javascript复制
//extern C and non zero param
extern "C" int fn(int v);
int main(int argc, char *argv[]) { return fn(123); }
int fn(int v) { return v*0; }

答案是全都会inline, gcc/clang无差别。这是简单题。继续, 下面几段代码,头文件分开,代码是

代码语言:javascript复制
#include "header.h"
int main(int argc, char *argv[]) { return fn(123); }

他们会不会inline?

A:

代码语言:javascript复制
//Using a header without inline keyword
int fn(int v) { return v*0; }

B:

代码语言:javascript复制
//using noinline
__attribute__ ((noinline))
int fn(int v) { return v*0; }

C:

代码语言:javascript复制
//add the inline keyword
__attribute__ ((noinline))
__inline int fn(int v) { return v*0; }

D:

代码语言:javascript复制
//Using both noinline and always_inline
__attribute__ ((noinline))
__attribute__((always_inline))
__inline int fn(int v) { return v*0; }

E:

代码语言:javascript复制
//Same but swap
__attribute__((always_inline))
__attribute__ ((noinline))
__inline int fn(int v) { return v*0; }

有点复杂了

A clang/gcc都inline,

B clang会忽视这个noinline设置,直接inline,gcc不会

C 都不inline,因为指定了__inline又修饰成noinline,编译器准确翻译

D 都不inline,gcc会告警两个修饰词冲突

E 都inline gcc会告警两个修饰词冲突

DE都是修饰符出现的早说了算。另外CD如果去掉__inline那就都会inline了,得有inline,修饰才有作用

上强度了是吧?再来!

A:

代码语言:javascript复制
#include <stdlib.h>
int main(int argc, char *argv[]) { return atoi("0"); }

B:

代码语言:javascript复制
//using strtol
#include <stdlib.h>
int main(int argc, char *argv[]) { return strtol("0", 0, 10); }

C:

代码语言:javascript复制
//using strtod which returns a double
#include <stdlib.h>
int main(int argc, char *argv[]) { return strtod("0", 0); }

谁会内联?这个涉及到这几个库接口的实现在那一层以及实现形式

atoi clang就能内联,而gcc是通过strtol来实现的

换个口味!库实现谁知道啊!下一题!

A:

代码语言:javascript复制
#include <vector>
int main(int argc, char *argv[]) { std::vector<int> v; v.push_back(1000); return 0; }

B:

代码语言:javascript复制
//Added an if
#include <vector>
int main(int argc, char *argv[]) { std::vector<int> v; v.push_back(1000); if (v.size() > 0) { return 0; } return 1; }

C:

代码语言:javascript复制
//Added a pop inside the if and returned the size
#include <vector>
int main(int argc, char *argv[]) { std::vector<int> v; v.push_back(1000); if (v.size() > 0) { v.pop_back(); return v.size(); } return 1; }

会不会内联? clang能完全优化掉,gcc不能 (O2)。原因没深究。clang收益有点明显了,来点复杂的!

A:

代码语言:javascript复制
class B { public: virtual int test() { return 0; }};
class D : public B { public: int test() override { return 1; }};
int main(int argc, char *argv[]) {
    D d;
    B*b = &d;
    auto p = dynamic_cast<D*>(b);
    return !p;
}

B:

代码语言:javascript复制
//Add final to D
class B { public: virtual int test() { return 0; }};
class D final : public B { public: int test() override { return 1; }};
int main(int argc, char *argv[]) {
	D d;
	B*b = &d;
	auto p = dynamic_cast<D*>(b);
	return !p;
}

C:

代码语言:javascript复制
//Both branches are 0
class B { public: virtual int test() { return 0; }};
class D final : public B { public: int test() override { return 1; }};
int main(int argc, char *argv[]) {
	D d;
	B*b = &d;
	auto p = dynamic_cast<D*>(b);
	if (p)
		return 0;
	return 0;
}

D:

代码语言:javascript复制
//replace the first return
class B { public: virtual int test() { return 0; }};
class D final : public B { public: int test() override { return 1; }};
int main(int argc, char *argv[]) {
	D d;
	B*b = &d;
	auto p = dynamic_cast<D*>(b);
	if (p)
		return ((D*)p)->test()-1;
	return 0;
}

E:

代码语言:javascript复制
//What happens if you change the cast to reinterpret_cast
class B { public: virtual int test() { return 0; }};
class D final : public B { public: int test() override { return 1; }};
int main(int argc, char *argv[]) {
	D d;
	B*b = &d;
	auto p = reinterpret_cast<D*>(b);
	if (p)
		return ((D*)p)->test()-1;
	return 0;
}

AB都内联不了。CD gcc能内联,E都能内联

已经有点折磨了,有啥差别?为啥E可以AB就不行?差别在哪里?为啥CD和AB差不多,但能内联?(坑爹的cast)

最后一轮! A:

代码语言:javascript复制
//main.cpp
inline int getzero();
int main(int argc, char *argv[]) { return getzero(); }

//getzero.cpp
int getzero() { return 0; }

B:

//A again but add in -flto

C:

代码语言:javascript复制
//Use -flto
#include <stdlib.h>
int main(int argc, char *argv[]) { return strtol("0", 0, 10); }

D:

代码语言:javascript复制
//For a laugh, recursive fibonacci
int fibonacci(int n) {
	if(n == 0)
		return 0;
	else if(n == 1)
		return 1;
	else {
		return (fibonacci(n-1)   fibonacci(n-2));
	}
}
int main() { return fibonacci(0); }

A 不内联,会告警,B会内联,LTO发威,C即使LTO gcc也不内联,这是和实现有关的。clang可以,D是搞笑的就不说了

  • Checking for the absence of a string, naive AVX-512 edition

博士实现了一个strstr avx版本,代码在这里 https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2022/12/15/check.cpp

  • C 23: attributes

介绍c 23的属性,assume,这玩意是__builtin_assume

代码语言:javascript复制
`void limiter(float* data, size_t size) {
    [[assume(size > 0)]];
    [[assume(size % 32 == 0)]];
    
    for (size_t i = 0; i < size;   i) {
        [[assume(std::isfinite(data[i])]];
        data[i] = std::clamp(data[i], -1.0f, 1.0f);
    }
}
  • How can I do the opposite of compare_exchange and exchange if the value is different?

直接贴代码

代码语言:javascript复制
bool exchange_unless(int value, int bad_value)
{
    int old_value = var.load(std::memory_order_acquire);
    do {
        if (old_value == bad_value) return false;
    while (!var.compare_exchange_weak(value, old_value,
                std::memory_order_release));
    return true;
}

另外,我不懂winrt Raymond chen的博客我就列下来,不多赘述了

  • [Inside C /WinRT: IReference](https://devblogs.microsoft.com/oldnewthing/20221215-00/?p=107595)
  • [In C /WinRT, how do I create or consume an IReference that wraps a particular value?](https://devblogs.microsoft.com/oldnewthing/20221214-00/?p=107589)

视频

  • C Weekly - Ep 355 - 3 Steps For Safer C
  1. 基本的单测/CICD
  2. clang-tidy配置
  3. sanitizer配置

开源项目需要人手

  • asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群384042845和作者对线
  • pika 一个nosql 存储, redis over rocksdb,非常需要人贡献代码胖友们, 感兴趣的欢迎加群294254078前来对线

开源项目介绍

  • emio 嵌入式使用io库
  • ser20 一个c 20序列化库,改的cereal

看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!

0 人点赞