layout | title |
---|---|
post |
第93期 |
公众号
欢迎投稿,推荐或自荐文章/软件/资源等
编译器信息最新动态推荐关注hellogcc公众号 2022-12-14 第180期
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
};
这个我感觉都知道,问题是,如何检测是否对齐呢?
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>);
学习一波
值得一看
很精彩的抓bug,值得一看
很详尽的记录了c23变了啥
整了个脚本把moc开头的生成的头文件include一下
老生常谈了属于是,列表初始化这个玩意
一个cmake教程
直接看代码
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);
其实就可以当作多个返回值解包来用
简单题,以下四段代码会不会inline?
A
inline int fn(int v) { return v; }
int main(int argc, char *argv[]) { return fn(0); }
B
//remove inline
int fn(int v) { return v; }
int main(int argc, char *argv[]) { return fn(0); }
C
//move function body
int fn(int v);
int main(int argc, char *argv[]) { return fn(0); }
int fn(int v) { return v; }
D
//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无差别。这是简单题。继续, 下面几段代码,头文件分开,代码是
#include "header.h"
int main(int argc, char *argv[]) { return fn(123); }
他们会不会inline?
A:
//Using a header without inline keyword
int fn(int v) { return v*0; }
B:
//using noinline
__attribute__ ((noinline))
int fn(int v) { return v*0; }
C:
//add the inline keyword
__attribute__ ((noinline))
__inline int fn(int v) { return v*0; }
D:
//Using both noinline and always_inline
__attribute__ ((noinline))
__attribute__((always_inline))
__inline int fn(int v) { return v*0; }
E:
//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:
#include <stdlib.h>
int main(int argc, char *argv[]) { return atoi("0"); }
B:
//using strtol
#include <stdlib.h>
int main(int argc, char *argv[]) { return strtol("0", 0, 10); }
C:
//using strtod which returns a double
#include <stdlib.h>
int main(int argc, char *argv[]) { return strtod("0", 0); }
谁会内联?这个涉及到这几个库接口的实现在那一层以及实现形式
atoi clang就能内联,而gcc是通过strtol来实现的
换个口味!库实现谁知道啊!下一题!
A:
#include <vector>
int main(int argc, char *argv[]) { std::vector<int> v; v.push_back(1000); return 0; }
B:
//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:
//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:
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:
//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:
//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:
//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:
//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:
//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:
//Use -flto
#include <stdlib.h>
int main(int argc, char *argv[]) { return strtol("0", 0, 10); }
D:
//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是搞笑的就不说了
博士实现了一个strstr avx版本,代码在这里 https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/blob/master/2022/12/15/check.cpp
介绍c++23的属性,assume,这玩意是__builtin_assume
`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);
}
}
直接贴代码
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
- In C++/WinRT, how do I create or consume an IReference that wraps a particular value?
- 基本的单测/CICD
- clang-tidy配置
- sanitizer配置
- asteria 一个脚本语言,可嵌入,长期找人,希望胖友们帮帮忙,也可以加群753302367和作者对线