0%

最近時常使用valgrind,紀錄一下分析使用心得。

從最簡單的範例開始

以下是一個很明顯的錯誤程式

1
2
3
4
5
6
#include <stdlib.h>
int main()
{
int *p = malloc(32768);
return 0;
}

編譯他並用valgrind檢查,可以看到類似的結果。

1
2
$ gcc leak.c -g -o leak
$ valgrind --leak-check=full ./leak
Read more »

這功能很有用,SVN的時代常常使用,不過在Git上就忘了怎麼用。
看到Stackoverflow的資料紀錄一下。

首先,先查詢某個檔案的Commit log。

1
$ git log -- [filename]

以下是一個示範

1
2
3
4
5
6
$ git log --pretty=oneline --abbrev-commit -- README.md
a442aa7 doc: small fixes to comments and syntax
acb9f89 doc: adding ARCHS flag to OS X build command
7d23c1d doc: add libuv-dox to the documentation section
2025341 doc: add readme link to all projects that use libuv.
8094ac2 doc: document how to run tests

接著就可以用git diff來比較兩個commit之間的差異。

1
$ git diff {version1} {version2} -- [filename]

如果我們要看README.md的前一個版本跟現在的版本差異,就能這樣操作

1
$ git diff acb9f89 HEAD -- README.md

有個好的GUI果然比較有用,這些技術以備不時之需。

這一組API雖然在Coding上不會直接用上,不過要實做Coroutine,模擬Exception的時候,總部會少了他。紀錄一下>
setjmp/longjmp很像Goto,不過比Goto更強,可以跳躍至任何地方,Goto不能跳躍至函數外層。直接看例子吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>  
#include <setjmp.h>
static jmp_buf buf;
void second(void) {
puts("second");
longjmp(buf, 1);
}
void first(void) {
second();
puts("first");
}
int main() {
if (!setjmp(buf)) {
first();
}
else {
puts("main");
}

return 0;
}

叢書出的結果我們可以猜到程式怎麼運作

1
2
second
main
Read more »

我對Rust也是初學者的狀態,以下是從A 30 minute introduction to Rust看來的,既然Rust被定位成System programming language,難免要拿來跟C++比一比。看看Ruat友什麼特別之處。

The power of ownership

在C/C++,很簡單可以寫出這樣的程式碼。

1
2
3
4
5
6
7
8
9
10
int* dangling(void)
{
int i = 1234;
return &i;
}
int add_one(void)
{
int* num = dangling();
return *num + 1;
}
Read more »

由於現在CPU對於Memory Byte Algined的處理較好,所以很多資料結構的擺法都會偏向於4 Byte Alginment的方式進行。例如

1
2
3
4
struct string_t {
int length;
char val[1];
} ;

string_t的大小為8,而非眾人想像中的5,如果要強制讓這個Structure大小為5的話,可以採用以下這種方式。

1
2
3
4
5
6
7
8
9
10
11
12
// GCC Style
struct string_t {
int length;
char val[1];
} __attribute__ ((packed));
// Visual C++ Style
#pragma pack(push,1)
struct string_t {
int length;
char val[1];
} ;
#pragma pack(pop)

如果不用這兩種方式的話,如何使用投機的方式來減少分配

1
2
3
4
5
6
7
8
#include <stddef.h>
struct string_t *allocstr(int len, char *str)
{
struct string_t *string = malloc(offsetof(struct string_t, str) + len + 1);
string->length = len;
memcpy(string->str, str, len);
return string;
}

其實上面那個char val[1]也是不需要的,在支援zero array之後,用這個方式更簡單

1
2
3
4
struct string_t {
int length;
char val[0];
} ;

這篇是Concurrency in C++11的部份筆記,先寫有關C++11標準的部份。
future, promise被加入C++11,大概等同於C#的Task或是Java8的Future

最簡單的情況

以讀寫一個檔案作為範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
vector<char> readFile(const string& inPath)
{
ifstream file(inPath, ios::binary | ios::ate);
size_t length = (size_t)file.tellg();
vector<char> buffer(length);
file.seekg(0, std::ios::beg);
file.read(&buffer[0], length);
return buffer;
}
size_t writeFile(const vector<char>& buffer, const string& outPath)
{
ofstream file(outPath, ios::binary);
file.write(&buffer[0], buffer.size());
return (size_t)file.tellp();
}

如果要拷貝一個檔案,可以這樣寫。

1
2
3
4
size_t sync_copyFile(const string& inFile, const string& outFile)
{
return writeFile(readFile(inFile), outFile);
}

這樣寫得問題在於,讀寫都是同步動作。如果檔案一大,就什麼事都不用做了。如何使用Multithread來感善動作。

Read more »

Partion Application

顧名思義,提供函數一部分的參數。變成一個新的函數。
最簡單的例子就像這樣

1
2
3
4
5
6
7
8
int sub(int a, int b)
{
return a - b;
}
int sub2(int v)
{
return sub(v, 2);
}

當然上面這種寫法復用度並不高,於是在C++11把bind跟function納入標準配備之後,可以寫成這樣。

1
std::function<int(int)> sub2 = std::bind(sub, std::placeholders::_1, 2);

有時間再來討論bind跟function。
不過就可讀性來說,Pyhton版的強多了

1
2
3
4
5
import functools
def sub(a, b):
return a - b

sub_two = functools.partial(sub, b = 2)

Currying

Currying是為了解決不一樣的問題
假設一個函數有多個參數,把他轉化成多個只有一個參數的函數組合。
用C++11的Lambda Expression來做示範。

1
2
3
4
5
6
7
std::function<int(int)> add2(int a)
{
return std::function<int(int)>([=](int b) -> int{
return a + b;
});
}
cout << add2(3)(5) << endl;

基本上PCurrying可以實現一部分Partion Application的應用。不過以上麵的sub2為例,Currying在這邊就不是用。
更清楚的描述可以看What is the difference between currying and partial application

不知道哪時候會用到,先做個筆記。需要的話再跟巨觀建字去搜尋。

測試工具