warning C4819的處理

warning C4819: The file contains a character that cannot be represented in the current code page (950). Save the file in Unicode format to prevent data loss

選擇 File>Advanced Save Options => Encoding: Unicode (UTF-8 with signature) – Codepage 65001

要選有BOM的 如果選到 UTF-8 without signature warning一樣會出現

或是改system locale => English
參考
https://stackoverflow.com/questions/10501634/warning-c4819-how-to-find-the-character-that-has-to-be-saved-in-unicode

Posted in Tips | Leave a comment

VC++ pragma link

在VC++中
#pragma comment(lib, “my.lib”)
在link階段會搜尋 my.lib
一般配合_DEBUG與_MSC_VER 等巨集使用 可以根據編譯的特性來動態決定要link哪一個lib
例如

#if _MSC_VER >= 1400
#pragma comment(lib, "my.lib")
#elif 
...
#endif


使用時建議放在單獨的cpp檔方便查找

MSVC++ 15.0 _MSC_VER == 1910 (Visual Studio 2017)
MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)
MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)
MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012)
MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010)
MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008)

參考:
https://msdn.microsoft.com/en-US/library/7f0aews7(v=vs.100).aspx

Posted in Tips | Leave a comment

boost build (visual studio 2015 winxp toolset)

for winxp support

set INCLUDE=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include;%INCLUDE%
set PATH=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin;%PATH%
set LIB=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Lib;%LIB%
REM (如果CL沒有定義則 set CL=/D_USING_V110_SDK71_ )
set CL=/D_USING_V110_SDK71_ %CL%
REM  (如果LINK沒有定義則 set LINK=/SUBSYSTEM:CONSOLE,5.01 )
set LINK=/SUBSYSTEM:CONSOLE,5.01 %LINK%

以上是設定compile需要的參數與搜尋順序 (SDK v7.1A first)
接下來build boost (這邊沒有使用icu or iconv)

bootstrap.bat

b2.exe -sBZIP2_SOURCE=D:\build\bzip2-1.0.6 -sZLIB_SOURCE=D:\build\zlib-1.2.11 toolset=msvc define=WINVER=0x0501 define=_WIN32_WINNT=0x0501 define=NTDDI_VERSION=0x05010000 define=PSAPI_VERSION=1

其他的選項
toolset=msvc
link=static,shared (.lib or .dll)
threading=multi
runtime-link=static,shared (/MT or /MD)
variant=debug,release
address-model=32 or 64

安裝路徑
install –prefix=

其他注意: 需要安裝SDK v7.1A 如果用VS2015自帶的win10 sdk 只能support Win7+

參考資訊:
http://www.boost.org/doc/libs/1_64_0/boost/detail/winapi/config.hpp (_WIN32_WINNT)
http://www.boost.org/build/tutorial.html
https://tedwvc.wordpress.com/2014/01/01/how-to-target-xp-with-vc2012-or-vc2013-and-continue-to-use-the-windows-8-x-sdk/

主要參考以下連結
https://stackoverflow.com/questions/18054640/building-boost-under-visual-studio-2012-with-v110-xp-platform-toolset

Posted in Library | Leave a comment

string::assign

#include 
#include 

int main()
{
  std::string x("0123456789");
  x.assign(x.data() + 3, 5);
  std::cout << x << std::endl; //34567
}

以上的string assign在src和dest即使有overlapped,在C++標準中,這樣是不會有問題的。
參考c++03

21.3.5.3 basic_string::assign
basic_string < charT , traits , Allocator >&
assign ( const charT * s , size_type n );
Returns: assign(basic_string(s ,n ))

在實作上 以gcc4.8.5為例,它的libstdc++-v3 分別判斷了src/dest有無overlap(_M_disjunct)再進行處理

//libstdc++-v3/include/bits/basic_string.tcc
template
    basic_string<_CharT, _Traits, _Alloc>&
    basic_string<_CharT, _Traits, _Alloc>::
    assign(const _CharT* __s, size_type __n)
    {
      __glibcxx_requires_string_len(__s, __n);
      _M_check_length(this->size(), __n, "basic_string::assign");
      if (_M_disjunct(__s) || _M_rep()->_M_is_shared())
        return _M_replace_safe(size_type(0), this->size(), __s, __n);
      else
        {
          // Work in-place.
          const size_type __pos = __s - _M_data();
          if (__pos >= __n)
            _M_copy(_M_data(), __s, __n);
          else if (__pos)
            _M_move(_M_data(), __s, __n);
          _M_rep()->_M_set_length_and_sharable(__n);
          return *this;
        }
     }

儘管規範如此,在呼叫API時,碰到可能會有修改到自身的內部狀態時,要特別小心規範是否支援以及實作是否正確

以stlport 5.2.1為例,沒有特別處理overlap問題,而是直接_Traits::copy => memcpy(並不保證overlapped沒問題 要看memcpy實作, 如果要移動overlapped region, 應該用memmove, => _Traits::move),因此碰到overlapped的情況會有問題

// stl/stlport/_string.c
template 
basic_string<_CharT,_Traits,_Alloc>&
basic_string<_CharT,_Traits,_Alloc>::_M_assign(const _CharT* __f, const _CharT* __l) {
  ptrdiff_t __n = __l - __f;
  if (__STATIC_CAST(size_type, __n) <= size()) {
    _Traits::copy(this->_M_Start(), __f, __n);
    erase(begin() + __n, end());
  }
  else {
    _Traits::copy(this->_M_Start(), __f, size());
    _M_append(__f + size(), __l);
  }
  return *this;
}

// stl/stlport/char_traits.h
static char_type* _STLP_CALL copy(char_type* __s1, const char_type* __s2, size_t __n) {
    return (__n == 0 ? __s1 :
      (char_type*)memcpy(__s1, __s2, __n * sizeof(char_type)));
}
Posted in C++ Language | Leave a comment

return void type

在C++ void function()中,如果要提前返回的話,只要加上return;
那麼,是否可以return 一個void function呢? 答案是可以的,以下是C++03標準的摘錄

A return statement with an expression of type “cv void” can be used only in functions with a return type of cv void; the expression is evaluated just before the function returns to its caller.

C++03 6.6.3 The return statement

以下的程式碼皆為合法的C++

void g()
{
}
void h()
{
   return g(); // 這等同於 g(); return;
}
void f()
{
  return void();
}

以上的特性在template中可以如以下應用

class C
{
};

template 
T foo(void) {
  return T();
}

void f1()
{
  return foo();
}

int f2()
{
   return foo();
}

除了上面template的需要,一般是分開寫 f(); return;

return f(); 的作法可用作在API設計上提醒使用者做完某個function後就要返回,減少呼叫完忘記加return的機會。

但是因為C++回傳有型別的限制,這樣的技巧一般會在像javascript這類的語言中使用。

Posted in C++ Language | Leave a comment

Message 訊息(消息) – 介紹

message – 消息或是訊息,無處不在。Inter-process communication(IPC)中有用shared memory的方式,也有的使用message passing的方式,在物件導向的世界裡物件接收與發送訊息(對應程式語言中method的呼叫),event driven的程式開發模型更是把訊息當成主角。事實上,我們甚至可以用訊息的觀點(或是模型)來理解這個世界,一切的人事物交互作用都是通過訊息來完成。

message一般可以用header + body(payload)來理解,message header所帶的是與資料內容以外的資訊(如metadata, message property),而body帶的是資料本身。

Posted in MOM | Leave a comment

Message 訊息(消息) – 邊界判定

在程式語言與資訊系統的世界哩,談到消息免不了要處理序列化的問題,畢竟如果message無法往外傳,這樣的系統等同是處於isolation的狀態。而一封封的message傳輸時,在接收端一般需要另外處理將stream bytes分割,才能還原為一封封的message,因此這時候會需要有消息邊界判定的機制。

消息邊界的判定可分為兩類方式

  1. length prefix 描述消息的長度而知道邊界,下一封消息又往後再用同樣方式讀取,好處是可以預先知道整個消息的長度,缺點是需要知道消息的長度才能傳送(當然,這可由上層的application另外處理來傳送未知長度的消息),另外是如果因某些原因造成傳輸錯誤而未發現時(即使是TCP error rate也不是0),可能會造成訊息長度解析錯誤。這類型的作法在很多Message oriented middleware(MOM),也在DB的wire protocol也常見(如MySQL, MongoDB),主要原因是相對delimiter,不需要一直掃描內容,解析的效率較高。AMQP的作法也是採用這一種(參考amqp0-9-1)
  2. delimiter 分割字元 這種做法就是透過特殊的字元或byte組合來界定邊界,例如HTTP 透過\r\n\r\n 來區分 header, body。另外像H264 NAL也是利用特定的字元組合(start code eg. 00 00 00 01)來作為NAL unit的起始。這個方法的好處是,在設計的當的情況下,可以從消息流的中間開始解析,而不需要從一開始就一字不漏地接收。壞處是需要將整個內容掃過,因為要尋找delimiter並且內容中不能帶有與delimiter相同的位元組合。(若有則需要另外escape,接收時要將內容escaped的資料找出並且還原後再往application層傳)

當然﹐也可以利用delimiter + length prefix的組合來提高解析的效率。

Posted in MOM | Leave a comment

serialization 序列化

在C++程式語言中,語言本身所提供的資料表示可以用內建基礎型別(primitive type)如整型(integral type e.g. bool, char, int等)、浮點數(float, double),或是複合型別(array, class, pointer),但是當需要將程式語言理所表示的資料進行傳輸時,例如傳到磁碟上或是傳到另一個端點時,就會碰到要傳那些資料以及格式的問題,對於基礎型別來說,可以直接將整塊記憶體內容直接儲存傳送(但跨機器時可能會有其他問題,如byte ordering),對於牽涉到指標型別來說,就沒辦法指複製指標本身的值,而要考慮到所指的內容。物件的內容若牽涉到其他狀態(例如file handle)也沒辦法直接複製記憶體內容,因為這類資訊牽涉到當時的執行環境狀態。如果在重建端無法存取到所描述值的外部系統的狀態,這樣的重建是沒有意義的。

序列化有個最重要的原則: 序列化的資料足以重建回物件的狀態,跨越空間與時間。序列化的內容也可與外部系統相關,但前提是重建時要能夠存取的到,例如儲存DB table的row id,重建端要有辦法存取相關系統,才能還原。

這邊講物件重建回來原來狀態並非指結構上(structural)的值嚴格地完全相同,而是行為上(behavioral)要能夠一致。
舉例來說,假如我有一個檔案讀寫的物件,那麼需要重建回物件的狀態使得接下來的操作行為可以與原來相同,這樣序列化至少就需要檔案路徑、開檔模式、讀寫的position offset等,而依照這樣資訊重建回來的物件,物件內部檔案handle的值一般來說不會相同,但對物件的操作結果應該會一致。

對於單純儲存值的物件,可以想成這些值本身就是狀態,我們去get/set value時,在序列化前和還原後行為應該一致。

常見的序列化格式 XML, JSON, Avro, Apache Thrift, Google ProtoBuf 等
在設計上從schema的自我描述、傳輸的效率、版本控制等各有特色。

Posted in MOM | Leave a comment

C/C++ comments

註解主要的目的是讓其他人可以快速的理解程式碼,或是原始作者在後來修改自己的程式碼,不至於深陷混亂的程式碼泥沼當中。
但必須要注意註解過多過冗長不宜,因為註解本身不能取代程式碼,而程式碼才是主體。所以在註解上基本的原則是:

  • 要說明function/class的目的,在function內部不易閱讀的地方註記使用的演算法或是方法的目的(rationale),讓閱讀者可以抓住開發者當時的思路。
  • workaround的部分也必須註記,因為通常workaround不是在原來的正常思路當中,如果不加以註記,有很大的機會在後來會完全摸不著頭緒

另外是如果整合了文件產生工具或是IDE整合,為了要讓工具提取重要的metadata,註解的格式就會有所規範,可以參考
https://www.stack.nl/~dimitri/doxygen/manual/docblocks.html,
XML Documentation (Visual C++)

在C/C++裡註解分兩種: 單行註解(single-line comments, C style)多行註解(multi-line comments, C++ style)
C89不支援單行註解,但C99標準加上了

/* 
這是多行註解, 來自C語言的註解方式 
*/
/*也可以單行*/
//這是單行註解 
/* // 多行註解裡可以有單行註解 */
//註解原來已有多行註解符號的區塊,使用預處理指令
#if 0 
/* test function */
void test()
{
}
#endif
// or use 單行註解
///*
// test function
//*/ 
//void test() 
//{ 
//}
//or use if(0){ } //使用語言本身的語法
if(0) //這會讓區塊內的程式碼不執行
{
/* test function */
void test()
{
}
}

將整段程式碼註解時一般可用多行註解的方式,
但是多行註解不可nested,
故若碰到段落內已有多行註解時則要
改用全部單行或是用preprocessor裡的#if 0的方式處理,
或是語言本身的 if(0)。

comment style
有時候為了使註解醒目,會用一些排列方式呈現

/**
 *
 *
 */
/////////////////////////////////////////////////
///
/////////////////////////////////////////////////
/*-----------------------
|
+-----------------------
|
*------------------------*/

一般來說,程式原始檔的註解會標記 檔案 作者 變更紀錄
function, class 等的註解

/***********************************************************************
 * FILENAME : example.c
 *
 * DESCRIPTION :
 *       This is an example. 
 *
 * PUBLIC FUNCTIONS :
 *       void test()
 *
 * AUTHOR :    Enrico        START DATE :    1 Jan 2000
 *
 * CHANGE HISTORY :
 *
 * VERSION DATE         DETAIL     
 * 1.0     2000/01/01   fix ....       
 *
 */

相關參考資料:
https://google.github.io/styleguide/cppguide.html#Comments
http://en.cppreference.com/w/c/comment
http://en.cppreference.com/w/cpp/comment
http://www.oracle.com/technetwork/java/javase/documentation/index-137868.html
also
ISO/IEC 9899:1999 6.4.9
ISO/IEC 9899:1990 6.1.9

Posted in Tips | Leave a comment