0%

前情提要

長久以來寫C/C++的Code時,配置環境是很麻煩的一件事,通常會遇到以下的事情

  • 下載第三方Library
  • 設定Include Path
  • 設定Linking library
  • Cross Platform的設置
  • Makefile的編寫

雖然有了CMake幫助解決塊平台的問題。不過還是不夠。有時我們想要Rust的Cargo或是Go Build這樣的東西,而Biicode給了我們一點光明。

Read more »

這篇是How to get started with the LLVM C API的讀後感,不過用我自己的方式表達。

先講結論

我重寫了程式碼,放在整篇文章的最後面,先看輸出結果。再回頭看程式碼。

1
2
3
4
5
6
7
8
9
10
11
12
13
$ cc `llvm-config --cflags` -c sum.c
$ c++ `llvm-config --cxxflags --ldflags --libs core executionengine jit interpreter analysis native bitwriter --system-libs` sum.o -o sum
$ ./sum 42 99
141
$ llvm-dis sum.bc
$ cat sum.ll
; ModuleID = 'sum.bc'

define i32 @sum(i32, i32) {
entry:
%tmp = add i32 %0, %1
ret i32 %tmp
}

這邊可以看兩個部份, Bitcode內容,以及JIT技術。之前介紹過LLVM的Bitcode,利用LLVM API可以生成Bitcode

建立Module

這邊就不特別提了,原來的連結寫得比較清楚。

1
LLVMModuleRef mod = LLVMModuleCreateWithName("my_module");
Read more »

看到這篇Type safe handles in C++覺得很有意思。原來可以這樣用。兩個同樣type,不過代表不同意義的Handle,要怎麼區別才安全。

Tag solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
template<class Tag, class impl, impl default_value>
class ID
{
public:
static ID invalid() { return ID(); }

// Defaults to ID::invalid()
ID() : m_val(default_value) { }

// Explicit constructor:
explicit ID(impl val) : m_val(val) { }

// Explicit conversion to get back the impl:
explicit operator impl() const { return m_val; }

friend bool operator==(ID a, ID b) { return a.m_val == b.m_val; }
friend bool operator!=(ID a, ID b) { return a.m_val != b.m_val; }

private:
impl m_val;
};
struct sound_tag{};
typedef ID<sound_tag, int, -1> sound_id;
struct sprite_tag{};
typedef ID<sprite_tag, int, -1> sprite_id;

Strong typedef

根據未來的C++ Proposal Toward Opaque Typedefs for C++1Y,用Boost_StrongTypedef可以達到類似的效果

1
2
3
4
5
#include <boost/serialization/strong_typedef.hpp>
BOOST_STRONG_TYPEDEF(int, sound_id);
BOOST_STRONG_TYPEDEF(int, sprite_id);
sprite_id gfx = create_sprite();
destroy_sound(gfx); // ERRROR!

其實是看了The C++ Memory Model之後,對於之前懵懂的點有點茅塞頓開,寫下來記錄。

Pre-C/C++11

先來看以下這段Code

1
2
3
4
5
6
7
8
9
10
11
12
int count = 0;
bool flag = false;
void thread1()
{
count = 1; // (1)
flag = true; // (2)
}
void thread2()
{
while(!flag);
r0 = count;
}

就直覺上來說,r0拿到的值會是1,而事實往往不會這麼簡單。Compiler有可能把(1)和(2)的指令重排,因為對Single thread來說,如此重排不匯兌結果產生任何影響,如果我們就算強迫Compiler禁止指令重排,CPU也會有機會做這件事

Read more »

Singleton這個題目酸燃被出到爛了,不過變化實在千變萬化。列出幾種不錯的解決方式。

Meyers version

1
2
3
4
5
6
7
8
9
class Singleton {
private:
Singleton() {}
public:
static Singleton& getInstance() {
static Singleton instance;
return instance;
}
};

非常有名的實作方式,在C++11的環境下是Thread-safe的,而C++98沒有這種保證。可以參考Is Meyers implementation of Singleton pattern thread safe?這個討論串。
GCC預設編譯時開啟static threadsafe的選項,所以C++11的程式碼可以正確運行,可以強制使用-fno-threadsafe-statics關閉這功能。可以參考Are function static variables thread-safe in GCC?

Read more »

為了很多因素(降低Playform depdent / Optimization等。 GCC 跟 CLANG 都引進了一層中間層,這曾的目的是定義一個平台無關的指令集, 以老朋友hello來示範如何輸出中間產物。

1
2
3
4
5
6
#include <stdio.h>
int main()
{
printf("Hello world\n");
return 0;
}
Read more »

看到濟濟篇文章的總結,寫起來,免得忘了。

do-while & continue

以下這段Code應該一堆人猜錯

1
2
3
4
5
int i = 0;
do {
std::cout << i << std::endl;
if (i < 5) continue;
} while (i++);

continue會跳到邏輯判斷的地方,而不是Block的最前端。

sizeof

sizeof是compile-time的operator,所以以下這段code的結果會是4 0

1
2
3
int i = 0;
std::cout << sizeof(i++) << std::endl;
std::cout << i << std::endl;

另外sizeof在不同的地方會有不同的表現

1
2
3
4
5
6
7
8
9
int arr[SIZE][SIZE][SIZE];
void print_sizeof(int a[SIZE][SIZE][SIZE])
{
std::cout << sizeof(a) << std::endl; // 4
std::cout << sizeof(a[0]) << std::endl; // 400
std::cout << sizeof(a[0][0]) << std::endl; // 40
}
std::cout << sizeof(arr) << std::endl; // 4000
print_sizeof(arr);

裡面最令人驚奇的是print_sizeof中的第一個輸出值是4,因為第一維的index是pointer。

Static class variable in class

1
2
3
4
5
6
7
8
9
class A {
public:
A() { cout << "A::A" << endl; }
};
class B {
static A a;
public:
B() { cout << "B::B" << endl; }
};

這邊的輸出結果沒有呼叫A的Constructor,因為a只宣告沒定義。
需要加上

1
A B::a;

如果我們沒有加上定義,這樣子是沒有問題的。

1
2
3
4
5
6
7
8
class B {
static A a;
public:
B() { cout << "B::B" << endl; }
static A getA() { return a; }
};
B b;
A a = b.getA();

因為A是個empty class所以就算沒定義也沒問題,如果不是的話就會出現編譯錯誤。

NULL pointer to an object

這段Code沒有問題

1
2
3
4
5
6
7
class A {
int x;
public:
void print() { cout << "A" << endl; }
};
A *pA = nullptr;
pA->print();

因為member function不涉及這物件的屬性任何操作,因此什麼都沒發生。

參考docker-gitlab這個網頁,實際餐作一次。

1
2
3
$ docker pull sameersbn/gitlab:latest
$ docker pull sameersbn/mysql:latest
$ docker pull sameersbn/redis:latest
1
$ 

紀錄一下STL裡面常用的幾種iterator

reverse_iterator

顧名思義就是將容器從後面往前的順序訪問。

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iterator>
#include <iostream>
using namespace std;
int main()
{
char array[] = "abcde";
using backword_iterator = reverse_iterator < char * > ;
backword_iterator it = backword_iterator(array + 5);
backword_iterator itend = backword_iterator(array);
while (it != itend)
cout << *it++;
cout << endl;
}

insert_iterator

共分三種

  • back_inserter 插入在容器最尾端,需要Container有push_back功能,所以只支援vector deque list
  • front_inserter 插入在容器最前端,需要Container有push_front功能,所以之支援deque list
  • insert_iterator 可插入在任何容器的任何位置,需要Contaner有insert功能,所有Container都支援。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iterator>
#include <iostream>
#include <list>
using namespace std;
template <typename T>
void printContainer(const list<T>& lists)
{
for (auto iter = begin(lists); iter != end(lists); ++iter)
cout << *iter;
cout << endl;
}
template <typename T>
insert_iterator<T> make_insert_iterater(T& lists, typename T::iterator iter)
{
return insert_iterator<T>(lists, iter);
}
int main()
{
int array[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
list<int> integers;
copy(array + 5, array + 10, back_inserter(integers));
printContainer(integers);
using backword_iterator = reverse_iterator < int * >;
copy(backword_iterator(array + 5), backword_iterator(array), front_inserter(integers));
printContainer(integers);
list<int>::iterator iter = integers.begin();
iter++; iter++;
copy(array + 1, array + 3, make_insert_iterater(integers, iter));
printContainer(integers);
}

move_iterator

C++11之後新增的,顧名思義就是加上move semantics,給個範例就很明顯了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>     // std::cout
#include <iterator> // std::move_iterator
#include <vector> // std::vector
#include <string> // std::string
#include <algorithm> // std::copy

int main() {
std::vector<std::string> foo(3);
std::vector<std::string> bar{ "one", "two", "three" };

typedef std::vector<std::string>::iterator Iter;

std::copy(std::move_iterator<Iter>(bar.begin()),
std::move_iterator<Iter>(bar.end()),
foo.begin());

// bar now contains unspecified values; clear it:
bar.clear();

std::cout << "foo:";
for (std::string& x : foo) std::cout << ' ' << x;
std::cout << '\n';

return 0;
}