pretty code

顯示具有 C++ 標籤的文章。 顯示所有文章
顯示具有 C++ 標籤的文章。 顯示所有文章

2025年2月26日 星期三

netlist_treeview

沒想到我的 netlist_treeview 還有隱藏版功能?

顧名思義,我這支 tcl 程式主要目的是用來瀏覽 netlist 用,但 module 或是 instance 的 regex 語法不管是 RTL code or netlist 其實都是一樣,故他其實也是可以開啟 RTL code 無誤XD

目前只有一個問題,我的 instance regex 語法本來就會避開單行註解,故這部分沒有問題,不過當 instance 是在多行註解中,之前 parser 為了快速處理,連我另一支用 Python 寫的 netlist parser 處理單行的機制都沒有,故我沒辦法避開這樣的情形。

查了一下 Standard 2005,還好他不允許巢狀註解,故要快速處理就很方便了。


順便查了一下 Standard C11,同樣也是不允許巢狀註解。


剛好想到為什麼之前買的 C11 這麼便宜?原來有這樣的疑問不只我一個,我們可以在這個討論串找到解答。

簡單來說,INCITS/ISO/IEC 9899-2012 是美國內部採用的標準,所以賣得比較便宜,當初不知標準險惡,以為台幣兩千是正常的(我以為這樣已經很貴了XD),直到最近買了兩份 IEEE Standard 噴了兩萬,我才知道以前的我還是太嫩了XD

2025/02/26 更新

看似簡單的東西,沒想到也會犯下低級錯誤,還好只花了幾分鐘就想到了XD

set is_multi_comment 0

if {[string first "*/" $line] != -1} {
    set is_multi_comment 0
} elseif {[string first "/*" $line] != -1} {
    set is_multi_comment 1
} elseif {$is_multi_comment == 1} {
    # do nothing
}

不小心把最後一個 elseif 放在第一行,故永遠不會脫離。

另外,下午也開始嘗試處理 clock tracing,果然跟我想的一樣麻煩。

不先規劃好遞迴中止條件,也沒先歸納出 clock path 的一些態樣,真的很難把程式寫好。

還好我不趕時間XD

2022年3月21日 星期一

error C2059: syntax error : 'string'

今天幫忙看一個 compiler error,第一個錯誤如標題所述,但因為 Visual C++ 還多顯示了其他很奇怪的錯誤,故一時還真看不出錯誤在哪,還好在半小時之內還是順利的解決了。

簡單把 Code 簡化一下,我們可以看到因為 structure Record 的成員變數 ID行數 7 的 define 相衝突,故在行數 14 的時候,會被前置處理器取代成 ptr->"id",故 VC 才會吐出這個錯誤,相較之下 GCC 的錯誤易懂多了,也算是學到一課了。

當然這是已經簡化 Code 後的結果,想像一下,如果 struct Record 與 define 分別位在不同的檔案,乍看之下,真的不容易發現問題,故在寫 C code 時,如果需要使用 define,最好是使用大寫(公司專案發生問題剛好是因為 define 用小寫,跟這邊的例子不一樣),比較不容易遇到這種鳥問題。

2020年5月21日 星期四

long long variable in C.

以前查資料發現,Windows 上的 gcc 底層還是呼叫 OS Runtime,故使用 "%ll" 會有問題。

最近無意間發現,這個限制已經是以前的事了,至少下列 2 種環境,測試起來都正常。

TDM-GCC-64 : 9.2.0
Visual Studio 2015

Google 雖然強大,但有時找到的都是過時資訊,畢竟時空背景都已經和當初不同。

故易經曰:若履虎尾,終之吉。

2020年5月16日 星期六

The format of xxprintf function in C99

前幾天為了打印一些數值在 Log,使用了 "%02.2f",不料結果卻不符預期,還是回到 Spec 一探究竟。

這個說明是在 7.21.6 Formatted input/output functions 的 7.21.6.1 The fprintf function

The description of format

% flags field-width precision length specifier(d, f, x ...)
(except specifier, all of them are optional)

其中在 0 flag 這一小段中有提到:
For d, i, o, u, x, and X conversions, if a precision is specified, the 0 flag is ignored. For other conversions, the behavior is undefined.

我原本以為是 0 不能與 precision 共用,但我記得我 10 幾年前剛學 C 語言時,有小數點的還是可以漂亮對齊的,難道是我記錯了?

後來嘗試幾種排列組合,終於可以對齊了,嘗試的結果 field-width 應該是有包含小數點及小數點位數?

明明有 Spec 還是看不懂,我的英文真的有待加強。


2020/05/17 更新

1. 今天再看了一次 Spec,field-width 提到如果轉換後的 values 有的 characters 比 field-width 少,則補 spaces on the left。
An optional minimum field width. If the converted value has fewer characters than the field width, it is padded with spaces (by default) on the left (or right, if the left adjustment flag, described later, has been given) to the field width. The field width takes the form of an asterisk * (described later) or a nonnegative decimal integer.

2. 我們一般習慣使用 field-width 去指定 int 個數,例如 "%04d",其實也可以用 precision,他就是用來指定最小位數,只是對 int 及 float 有不一樣的用法。
An optional precision that gives the minimum number of digits to appear for the d, i, o, u, x, and X conversions, the number of digits to appear after the decimal-point character for a, A, e, E, f, and F conversions.

2020年2月21日 星期五

Print integer string in the macro of GCC

前一篇文章提到的例子是 for VC。

既然平常都是用 GCC,還是查一下 GCC 要怎麼做。

底下是來自 stackoverflow rob05c 的解答。

#define STRINGIFY(s) XSTRINGIFY(s)
#define XSTRINGIFY(s) #s

#define XDEFINE __GNUC__
#define YDEFINE __GNUC_MINOR__
#define ZDEFINE __GNUC_PATCHLEVEL__

#pragma message "GCC = " STRINGIFY(XDEFINE)"."STRINGIFY(YDEFINE)"."STRINGIFY(ZDEFINE)
輸出結果

test.c:12:9: note: #pragma message: GCC = 4.9.2
 #pragma message "GCC = " STRINGIFY(XDEFINE)"."STRINGIFY(YDEFINE)"."STRINGIFY(ZDEFINE)

後記

這兩篇指的都是在編譯時期,需要做一些前置檢查,如果不符合某些條件,就停止編譯。如果是在執行時期就不需要那麼麻煩了。

2019年10月31日 星期四

rename function in C Spec

原本以為 rename function 是 UEFI 自己寫的非標準函數,沒想到我從 C11、C99,一路查回到 C90,這個 function 老早就存在了,其宣告如下:

Synopsis 
#include <stdio.h>
int rename(const char *old, const char *new)

Description
The rename function causes the file whose name is the string pointed to by old to be henceforth known by the name given by the string pointed to by new. The file named old is no longer accessible by that name It a tile named by the string pointed to by new exists prior to the call to the rename function, the behavior is implementation-defined.

Returns
The rename function returns zero if the operation succeeds. nonzero if it fails, in which case if the tile existed previously it is still known by its original name.

2019年10月22日 星期二

Use 64 bit offset in fseek function

fseek 的 offset 在 C Spec 中是 32 bit 的長度,由於現在的硬碟都很大,加上 GPT 有關 LBA 的欄位都是 8 個 Byte,當存取較後面的 Sector 時,勢必無法使用 fseek 這類的標準 C 函式庫,故我在撰寫 WinGPT 時,一開始使用的是 Win32 API。

後來查了一下資料,GCC 類的 compiler 有一個 fseeko 的函數可用,其宣告是在 stdio.h 裡,在 Windows 下不論是使用 TDM-GCC or MinGW 都可以直接使用,但在 Ubuntu 下,我們需定義一個 macro _LARGEFILE_SOURCE,記得要在 include 其他 header 時先定義。

https://github.com/tylpk1216/WinGPT/blob/master/WinGPT.c

另外在查資料時,發現到 2 件事:

1. printf%ll 在 TDM-GCC or MinGW 編譯時,如果有設 -Wall,會有 "warning: unknown conversion type character 'l' in format" 之類的錯誤訊息,那是因為這些 compiler 底層呼叫的仍是 Windows Runtime( msvcrt-DLL ),由於它不相容 C99 標準,故會有此 warning。

解決方式: 使用 %I64

2. 可以使用 "__linux__" 區分是 Ubuntu or Windows 環境,不需使用 -D 選項就可以寫出漂亮的 code。

2019年10月18日 星期五

GPT Table 解析小工具

由於 Windows 會隱藏某些分割區資訊,故使用磁碟管理工具無法看到全部的分割區。

在 Linux 下有好用的 GParted 可以用,或者也可以直接用 dd command 來 dump。

如果不想安裝額外的工具,可以使用這個小工具來觀看分割區資訊。

https://github.com/tylpk1216/WinGPT


unsigned long long 使用 printf 顯示不正常

一直以來都習慣 build 32bit 的執行檔

今天在印 GPT Table 時才發現
要 build 64bit 才會正確

有機會再來查一下 C Spec

2019年9月16日 星期一

列出 Linux 某目錄下所有檔案與目錄名稱

太久沒用,花了 10 幾分鐘才搞定,記錄一下。

#include <stdio.h>
#include <dirent.h>
#include <string.h>

void parseDir(char *dirPath) {
    struct dirent *de;
    DIR *dr = opendir(dirPath);

    if (dr == NULL) {
        printf("Can't open folder %s \n", dirPath);
        return;
    }

    while ((de = readdir(dr)) != NULL) {
        if (strcmp(de->d_name, ".") == 0 ||
            strcmp(de->d_name, "..") == 0) {
            // do nothing
        } else if (de->d_type == DT_DIR) {
            char path[256];
            sprintf(path, "%s/%s", dirPath, de->d_name);
            printf("folder - %s \n", path);

            parseDir(path);
        } else {
            printf("file - %s/%s \n", dirPath, de->d_name);
        }
    }

    closedir(dr);
    return;
}

int main(void)
{
    parseDir("/data/imagenet/raw_data/train");
    return 0;
}

2019年7月2日 星期二

人體 Compiler 果然很難

今天在測試 struct memory dump 時,無意間發現使用 gcc -S 轉出來的組語很不一樣,我只能說再給我 10 年我也不會想到可以這樣寫,組語其實也蠻有趣的XD


2019年6月11日 星期二

目前為止買過最貴的書 - ISO/IEC 9899:2011

人生到目前為止,買過最貴的書,就是 C11 規格書(約台幣 NT 1,884)。

沒辦法,最新標準 C18 要瑞士法郎 198﹝約台幣 NT 6,256﹞,實在是太貴買不下去。只好退而求其次,買前一個標準 C11,不管怎樣,也比我當初學的 C89 還要新。

2019年6月6日 星期四

UEFI - flexible array member

為了研究 Boot Variable,在 header file 看到一個很特別的宣告,依稀記得之前有看過討論,查了一下,這個東西叫做 flexible array member,是 C99 新增的語法,目的是讓動態新增資料更方便﹝語法上﹞,故寫了一個小程式來驗證。

2019/06/10 更新
1. 「C99 6.7.2.1 Structure and union specifiers」提到 flexible array member 只允許在 structure 的最後一個元素,故 UEFI 的 EFI_LOAD_OPTION 應該是用了某種方式達到一個以上的未定義長度的 array,故並不是 standard 裡的 flexible array member。
2. 原文如下:「As a special case, the last element of a structure with more than one named member may
have an incomplete array type; this is called a flexible array member.

#include <stdio.h>
#include <stdlib.h>

typedef struct Item {
    int length;
    // flexible array member
    int data[];
} Item;

int main(void)
{
    // this is decided dynamically.
    int realCount = 4;
    int realSize = realCount * sizeof(int);

    Item *p = (Item*)malloc(sizeof(Item) + realSize);
    p->length = realSize;

    // give values
    for (int i = 0; i < realCount; i++) {
        p->data[i] = i;
    }

    // check size
    printf("sizeof(Item) is %d \n", sizeof(Item));

    // check values
    for (int i = 0; i < realCount; i++) {
        printf("p->data[%d] = %d \n", i, p->data[i]);
    }

    free(p);
    system("pause");
    return 0;
}

執行結果

sizeof(Item) is 4
p->data[0] = 0
p->data[1] = 1
p->data[2] = 2
p->data[3] = 3

2019年5月24日 星期五

C code 冷知識 - argc and argv

程式寫久了,都會有一些感覺很理所當然的事,等到真正去寫,才會發現事情不是我們想的那樣!

最近在測試 C regex Library,為了方便 runtime 取得 pattern,故需要從 argv 取得想要的 pattern。原本以為我們需要自己去處理雙引號括起來的字串,故先寫支簡單的程式確認 argv 的字串是什麼?沒想到傳進去的 argv 已沒有雙引號。

原先以為這個是 C 的 implement,故先查了一下 C11 Draft Spec,發現裡面並沒有規定此原則。


後來才想到,這個應該是作業系統處理掉的,以我的環境來說就是 Windows cmd。

那如果我們真的需要前後的雙引號呢?可以使用 "\" 去 escape 雙引號,不過,因為雙引號已失去意義,故裡面的字串如果有空白,argv 的組成就不會跟原本的一樣了。


Windows 下有個 Win API - GetCommandLine,透過它就可以取得原始的一整個字串。


Test.exe "abc" def

GetCommandLine -> (Test.exe "abc" def)

2019年5月21日 星期二

Good Regex library written in C

https://github.com/monolifed/tiny-regex-c

supported syntax
^ $ . \s \S \d \D \w \W [^ABC0-9] [ABC0-9] * + ? *? +? ?? {m,n} {m,n}?

2019/06/03 更新
After doing simple test, it seems that it can support normal cases.



Good JSON library written in C

https://github.com/kgabis/parson

上面這個 Lib 只有 2 個檔案,可以 parsing 也可以組 JSON,似乎是個好選擇。

2019年5月17日 星期五

UEFI Application - Anonymous structures and unions

Anonymous structures and unions 是 C11 (ISO/IEC 9899:2011) 新增加的功能,當聯合和結構嵌套時很有用。

不過 UDK2018 的 StdLib 只支援到 C95 (ISO/IEC 9899/AMD1:1995),故不支援此功能。

我也是在改 https://github.com/kokke/tiny-regex-c 時,才知道這個東東。

像我習慣使用 VC build UEFI Application,故也可以 disable warning 解決此問題。

#pragma warning(disable : 4201)
typedef struct regex_t
{
  unsigned char  type;   /* CHAR, STAR, etc.                      */
  union
  {
    unsigned char  ch;   /*      the character itself             */
    unsigned char* ccl;  /*  OR  a pointer to characters in class */
  };
} regex_t;



2019年5月15日 星期三

UEFI Application - C Regex Library

https://github.com/kokke/tiny-regex-c

上面這個是我試過的,作者是為了 embedded ROM 開發的,特色就是輕巧,好 porting,但支援的 regex pattern 沒有那麼多。

另外,作者在 re_compile 回傳的變數是 1 個 static local variable,故無法同時宣告多個 pattern 來使用,在 github 中似乎有一些 bug,但我需要的都正常。

最後,如果要拿去 UEFI 下用,還是要稍微改一下,因為很簡單,這裡就不細述了。

----------------------------------------------------------------------------

https://github.com/ccxvii/minilibs/blob/master/regexp.c

上面這個是從 kokke issue 討論串看到的,有支援 {N,M} 語法,但是作者在 regcomp 回傳的變數是 1 個 global variable,故跟 tiny-regex-c 有同樣的問題。

心得
下次在找 library 時,還是要看一下 issue 討論,比較容易找到適當的。

2019年2月19日 星期二

QR Code in C

今天在網路上看到某篇文章
http://www.lab-z.com/step-to-uefi-167%EF%BC%89shell-%E4%B8%8B%E7%9A%84%E4%BA%8C%E7%BB%B4%E7%A0%81%E6%98%BE%E7%A4%BA/
提及到他在 UEFI 用 C 語言跑出 QR Code 的方式

下面是該作者使用到的 open source project
https://github.com/trezor/trezor-qrenc

覺得還蠻好玩的

下載後試了一下
只要使用以下指令將結果導向到 txt
test.exe > output.txt
就可以用手機掃瞄 QR Code 了

另外查了一下
這種 library 還不少
可以挑選一個喜歡的來用即可


2018年12月14日 星期五

UEFI Application - Stack overflow

最近在幫同事看一個問題
覺得很有趣,故記錄一下解題思路

同事在 build code 時,發現一個 link error
正在產生程式碼
已完成程式碼產生
UefiApplicationEntryPoint.lib(ApplicationEntryPoint.obj) : 
error LNK2001: 無法解析的外部符號 __chkstk

網路查了一下,是因為 VC compiler 檢查到某些 function  有 stack 問題時
便會在 code 中插入 __chkstk 這個 check function

網路看到的解法都是放大 stack size
可以在 INF 檔案編譯選項中加入 /GsXXXXX
但據實測的結果是一點用處都沒有
stack size 還是維持在 32K 左右

後來試著在 INF 檔案編譯選項中加入 /FAcs 選項
此選項會產生 assembly 檔案
副檔名為 .cod

接著在 UDK\Build\程式路徑中
用 grep 搜尋 __chkstk 關鍵字
便可以看到是那個 function 被插入了 __chkstk

底下是我模擬的結果
很明顯的看到 rsp register 被保留了 32776 這麼大的空間(char LocalVar[32768])
當然會造成 stack overflow