Zhytou

Zhytou

May the force be with me.

01 Aug 2023

C/C++奇技淫巧

GCC魔法

Attribute

属性说明符用于描述函数,变量和类型的属性。GCC可以根据这些指定属性做出相应的优化。它的形式为__attribute__ ((attribute-list)),其中属性列表是一个可能为空的以逗号分隔的属性序列。最常见的属性包括:

  • packed:类内存紧凑排列。
  • aligned(n):所有类成员按n字节对齐。
  • constructor:函数先于main函数执行,一般用于共享库加载的初始化。

此外,C++11时推出了属性语法,来保证在不同的编译环境如:GNU GCC和Microsoft MSVC下效果统一。具体语法可以参考C++手册

Inline Assembly

GCC中提供了C语言和汇编混合编译的功能,具体可以参考手册

通过这个功能,结合着co_yield和co_wait可以实现一个简单的协程库,具体可以参考NJU-OS M2

SIMD

SIMD(Single Instruction Multiple Data)即单指令流多数据流,是一种采用一个控制器来控制多个处理器,同时对一组数据(又称“数据向量”)中的每一个分别执行相同的操作从而实现空间上的并行性的技术。简单来说就是一个指令能够同时处理多个数据。

处理器对SIMD的支持

使用SIMD

Intel Intrinsics

Intel Intrinsics是内置在Intel编译器中的特殊函数,它们可以直接调用处理器的SIMD指令集,比如AVX、SSE等。换句话说,它的主要目的就是简化SIMD编程,帮助开发者充分利用现代CPU的并行计算能力。

OpenMP

除了Intrinsics这种偏向底层的技术之外,我们还可以使用OpenMP这类库来更容易的实现并行,比如:

#include <omp.h>

int main() {
  #pragma omp parallel for
  for(int i=0; i<100; i++) {
    // parallel loop body
  }

  return 0;
}

编译期运算

模板

在我们的印象中,模板可能大部分时候都是用于函数或者类,保证一份代码可针对多种类型复用。复杂一点的可能配合萃取技术进行类型运算,实现SFINAE,比如:enable_if、is_same等等。

但实际上,模板还可以用于编译期计算,可以将运行时消耗转移到编译期消耗,比如:

template <size_t N> 
struct Fibonacci {  
    constexpr static size_t value = 
        Fibonacci<N - 1>::value +
        Fibonacci<N - 2>::value;
};

template <> struct Fibonacci<0> {   
    constexpr static size_t value = 0;
};

template <> struct Fibonacci<1> {   
    constexpr static size_t value = 1;
}

template<size_t N>
constexpr size_t Fibonacci_v = Fibonacci<N>::value; 

constexpr

constexpr作为新关键字在C++11引入,它的作用是修饰能在编译期确定或完成计算变量或函数。随着C++20的普及,constexpr的含义越来越丰富,引入了包括if constexpr、constexpr容器等新特性,“constexpr all the things!“也作为元编程的一种新流派出现。常见的constexpr用法包括:

  • 编译期计算常量;
template<size_t N>
constexpr size_t fibonacci = fibonacci<N - 1> + fibonacci<N - 2>;
template<>
constexpr size_t fibonacci<0> = 0;
template<>
constexpr size_t fibonacci<1> = 1;

static_assert(fibonacci<10> == 55);
  • if constexpr配合类型萃取或约束(C++20特性)实现类似SFINAE;
template<typename T, typename Tag>
void process(T t, Tag tag) {
  if constexpr(std::is_same_v<Tag, int>) {
    // 处理int标签版本
  } else {
    // 其他标签版本 
  }
}
  • C++17起,lambda默认为constexpr,比如:
// constexpr int fibonacci(int n);
auto fibonacci = [](int n) {
    int a = 0, b = 1;
    for (int c = 0; c < n; ++ c) {
        int t = a + b;
        a = b;
        b = t;
    }
    return a;
};

- constexpr容器

```c++
constexpr std::array<int, 5> array = {1, 2, 3, 4, 5}; 

constexpr int sum() {
  int total = 0;
  for (const auto& element : array) {
    total += element; 
  }
  return total;
}