0%

雖然這題目很簡單,不過看到How to zero a buffer我嚇到了,原來我之前的觀念不一定正確。
假設我們在程式中有些敏感資料(金鑰/密碼等),希望能夠在使用之後清除掉。通常我們會這麼作。

1
2
3
4
5
6
7
8
9
void dosomethingsensitive(void)
{
uint8_t key[32];

...

/* Zero sensitive information. */
memset(key, 0, sizeof(key));
}

不過這段程式碼經過最佳化之後,最後的memset被省略不做。

Read more »

最近碰到一個困難的問題,好不容易找到解答,因此紀錄起來。
當一個Socket讀寫速度不對稱的時候,該怎麼處理。
假設Socket讀取的資料室100M/S,而寫入的速度是10M/S。
如果是Blocking I/O,OS會自動幫你處理這種狀況,難怪上網找範例程式碼都沒特別處理。
由於libuv/libevent等都是Non-blocking I/O framework,,因此無法得到有用的資訊。
翻到Linux多線程服務端編程:使用muduo C++網絡庫裡面有個地方觸動了我的靈感。利用Watermark來管理讀寫動作。
後來找到Libevent的BuffereventsPython asys IO都有類似Watermark的觀念,我想這應該是可行解。

以讀取比寫入快為例

  • 當寫入的資料量大於Hih water mark時,暫停讀取動作
  • 當剩餘的寫入資料量小於Low water mark時,重新開始讀取
    反之亦然。
    Read more »

Aspect oriented programming的技術基礎可以看這裡
我想這篇已經寫得很清楚了,有興趣的話繼續Google。
接著試著用C++來實做一些Complie time的AOP方式。

Decorator Pattern

可以試著在關新的函數前面,加上Before跟After。

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
31
32
33
34
35
36
37
template <typename WrappedType>
class BaseAspect
{
protected:
WrappedType* m_wrappedPtr;

struct AfterWrapper
{
BaseAspect* m_derived;
AfterWrapper(BaseAspect* derived) : m_derived(derived) {};
void operator()(WrappedType* p)
{
m_derived->After(p);
}
};
public:
explicit BaseAspect(WrappedType* p) : m_wrappedPtr(p) {};

virtual void Before(WrappedType* p) {
// Default does nothing
};

virtual void After(WrappedType* p) {
// Default does nothing
}

std::shared_ptr<WrappedType> operator->()
{
Before(m_wrappedPtr);
return std::shared_ptr<WrappedType>(m_wrappedPtr, AfterWrapper(this));
}
};
template <template <typename> class Aspect, typename WrappedType>
Aspect<WrappedType> MakeAspect(WrappedType* p)
{
return Aspect<WrappedType>(p);
}
Read more »

這題目雖然不怎麼困難,不過解法還蠻多的,雖然原理相同,不過根據編譯氣得能力,得到的結果也不同。
題目要求: 把讀到的內容當作一個string傳回來。
不考慮OS Level API(open/CreateFile)的方式,直接用C/C++的API來做。

fopen版

大家都很熟了,用fopen/fseek/fread/fclose來達成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <cstdio>
using namespace std;
string get_file_content(const char *filename)
{
FILE *fp = fopen(filename, "rb");
if (fp)
{
string content;
fseek(fp, 0, SEEK_END);
content.resize(ftell(fp));
rewind(fp);
fread(&content[0], 1, content.size(), fp);
fclose(fp);
return content;
}
else return string();
}
Read more »

最近時常使用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];
} ;