發表文章

目前顯示的是有「LinuxC」標籤的文章

C/C++查閱引用(include)或使用巨集(macro)後編譯有問題的程式碼

圖片
為什麼需要查閱 C/C++引用(include)或使用巨集(macro)編譯出錯的程式碼,因為使用巨集編譯時發生的錯誤訊息提示的程式碼行數,往往不是原始碼(source code)中看到的行數。 在學習與除錯的時候總覺麻煩,下面就展示該如何查閱引用/使用巨集後的程式碼。

Get the large file size

#define _LARGEFILE64_SOURCE #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> int main(int argc, char** argv) {     int fd;     off64_t pos;     if (argc <= 1) return -1;     printf("%d %s\n", argc, argv[1]);     fd = open(argv[1], O_RDONLY);     if (-1 == fd) {         printf("open failed\n");         return -1;     }     pos = lseek64(fd, 0, SEEK_END);     printf("size = %ld\n", pos);     close(fd);     return 0; }

Linux System Log

Config files in Ubuntu:    /etc/rsyslog.conf    /etc/rsyslog.d/*.conf Restart system log service in Ubuntu:    sudo service rsyslog restart     sudo /etc/init.d/rsyslog restart  #Ubuntu上不建議使用這個重啟服務 Show system log in Ubuntu:   tail -15 /var/log/syslog C Sample Code for the system log #include <stdio.h> #include <syslog.h> int main() {     syslog(LOG_CRIT,"LOG_CRIT\n");     syslog(LOG_ERR,"LOG_ERR\n");     syslog(LOG_WARNING,"LOG_WARNING\n");     syslog(LOG_INFO,"LOG_INFO\n");     syslog(LOG_DEBUG,"LOG_DEBUG\n");     printf("done!\n");     return 0; } Show the result: $tail -5 /var/log/syslog Mar 21 11:57:52 yhchiu-workstation a.out: LOG_CRIT Mar 21 11:57:52 yhchiu-workstation a.out: LOG_ERR Mar 21 11:57:52 yhchiu-workstation a.out: LOG_WARNING Mar 21 11:57:52 yhchiu-workstation a.out: LOG_INFO Mar 21 11:57:52 yhchiu-workstati...

C程式編譯流程

圖片
我們平常用編譯總共會經過四個階段Preprocessing, Compilation, Assembly以及Linking,gcc可以將各階段產生的結果輸出,只要依照左側的指令就能獲得各階段的檔案內容。 右下角的指令則是linking用的,其中各個.so和.o的檔案路徑是隨著Linux發行版會有不同,這裡是用Ubuntu 14.04 64bit的環境作演示。如果想查看設定可以透過gcc編譯程式碼時加上-v查看你目前電腦中的設置。 C程式編譯的四個階段

改變Ubuntu時區以及實作ISO8601標準時間格式

圖片
ISO8601是一種國際標準時間表示格式,細節請參考Wiki條目 https://zh.wikipedia.org/wiki/ISO_8601 用date可以查看電腦上的時區 $ date +%z +0800 如果要設定時區,請將環境變數TZ設定成下面網站提供的城市時區字串 https://whatbox.ca/wiki/Changing_Your_Bash_Timezone 例如: 美國紐約(-4:00)是America/New_York $ export TZ=America/New_York 而台北(+8:00)是Asia/Taipei $ export TZ=Asia/Taipei 沒有用export的話不會改date的時區 如果也可以可以找/usr/share/zoneinfo/裡面有的時區資料來用 $ find /usr/share/zoneinfo/ -name Taipei /usr/share/zoneinfo/right/Asia/Taipei /usr/share/zoneinfo/Asia/Taipei /usr/share/zoneinfo/posix/Asia/Taipei 下面是我用C/C++的strftime實作ISO 8601標準時間格式,不過Windows和Ubuntu上有些不同,Windows上用dev C++開發時發現localtime回傳的結構是沒有gmtoff欄位的,所以回傳的時間資料可以直接使用,而Ubuntu上會有gmtoff,表示時區位移資料,需要額外處理時區資訊。 #include <time.h> #include <stdio.h> int main(void) {   struct tm *local;   time_t t; #ifndef _WIN32   struct tm s_tl, s_tgm;   time_t tl, tgm; #endif   char buff[64] = {0};   char buff2[64] = {0};   t = time(NULL); // get ...

Demangle C++ function name at runtime

C++的函數名稱都會mangle 靜態Demanlge只要使用c++filt指令就能處理 動態的Demangle需要使用libstdc++的功能或是libliberty提供的函數功能 #include <iostream> #include <stdlib.h> #include <typeinfo> #include <cxxabi.h> // libstdc++ #include <libiberty/demangle.h> // libliberty // Prerequirement for Ubuntu // sudo apt-get install libiberty-dev // Please compile with -liberty // example: gcc test.cpp -liberty using namespace std; int main(int argc, char** argv) {     char* demangled_name = NULL;     int status;     int options = DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES;     if (argc<=1) {         cerr << "Please assign a mangling C++ function name" << endl;         return -1;     }     cout << "Demangle the mangling string [" << argv[1] << "]" << endl;     // libstdc++     // https://gcc.gnu.org/onlinedocs/libstdc++/manual/...

signal和sleep函數混用的問題

圖片
#include <stdio.h > #include  < stdlib.h > #include  < signal.h > #include  < unistd.h > void proc_signal(int signal) {     if (SIGINT == signal) {         printf("got a signal(%d) is SIGINT\n", signal);         exit(1);     } else if (SIGALRM == signal) {         printf("got a signal(%d) is SIGALRM\n", signal);     } else {         printf("got a signal(%d) is not SIGINT and SIGALRM\n", signal);     } } int main(int argc, char** argv) {     printf("main start\n");     if (SIG_ERR == signal(SIGALRM, proc_signal)) {         printf("An error occurred while setting a SIGALRM handler.\n");         return 0;     }     if (SIG_ERR == signal(SIGINT, proc_signal)) {         printf("An error occurred while setting a...

接收Ctrl+C的訊號中斷程式的執行

#include <stdio.h > #include  < stdlib.h > #include  < signal.h > void proc_term_signal(int signal) {     if (SIGINT == signal) {         printf("signal(%d) is SIGINT\n", signal);     } else {         printf("signal(%d) is not SIGINT\n", signal);     }     printf("exit by signal\n");     exit(1); } int main(int argc, char** argv) {     printf("main start\n");     if (SIG_ERR == signal(SIGINT, proc_term_signal)) {         printf("An error occurred while setting a SIGINT handler.\n");         return 0;     }     printf("main wait 180 sec\n");     sleep(180);     printf("main end\n");     return 0; } 如果希望恢復預設訊號處理,signal的第二個參數要使用SIG_IGN,直接忽略訊號用 SIG_DFL。 在程式中發送指定訊號則是用 raise函數;透過指令做訊號發送則是用kill來處理, 例如測試發送SIGUSR1訊號給PID為4771的執行程序 $ k...

基本SOCKET操作範例

本週末在複習基本的socket操作,並在Ubuntu 14.04.4上編譯完成, 程式碼和執行檔都已經放在github上,有需要請自由取用! https://github.com/Mirochiu/socket_practice 包含三個部分 socket_file  用socket file為媒介傳送封包 socket_inet 用socket傳送網路TCP封包 socket_udp 用socket傳送網路UDP封包 file的部分 只是看範例寫寫看,參考就好。這個方法的socket系統會依照指定名稱建立一個socket file,藉此讓兩者溝通。不正常結束程式時,系統不會自動刪除該socket檔案,就會造成下次啟動程式的一些問題,所以一般會先刪除(unlink)掉之前使用的socket檔案。 在inet的部分 有client和server可以做連線傳封包,不過用法是有些錯誤的。這些錯誤在client2和server2把它修正了,修正的部分是endian在探討。 電腦記憶體的byte-order架構,在x86電腦上是用little,但是網路協定是用big-endian,如果ip/port設定不經過轉換,你就會發現程式無法跟網路上的其他電腦溝通。showlisten.sh就是用來顯示Ubuntu中實際程式有開了哪個port。(記得使用時要給它執行權限) 另外寫了getifaces, getifaceinfo, getipbyname則是顯示電腦上的全部網路卡、顯示網路卡目前的IP, MAC, Netmask資訊、網站名稱(例如:www.google.com)與實際上主機IP查詢功能。 在udp的部分 包含sender和reciver可以做UDP封包的傳接,這裡使用的是unconnect udp socket,sender是固定500毫秒送一些資料出去。這部分為了只關注UDP的封包,在socket建立時就指定protocol為UDP。不過得記得要接收資料還是需要用bind將socket綁訂在本機的特定port上,然後傳送資料要使用,並且傳送資料接收資料應該換成 recvfrom和sendto而不再是read和write。 udpp2p的部分,是將port獲得的upd封包內容,經由另一個port送出去,也就是...

C與C++:展開前置處理的內容

gcc的-E選項可以將前處理(pre-processing)過後的程式碼印在螢幕上, 就是說所有的巨集與引入(include)都會被展開, 練習寫巨集的時候,可以用這個選項看到處理過後的結果, 或是發現一些程式碼的錯誤訊息所指出的位置與程式碼的行數不一樣, 也可以用來查看為何會有產生錯誤的訊息。 另外,配合管線的使用就能夠將資訊寫入到檔案中 EX:gcc -E main.c > main.pp gcc(1): GNU project C/C++ compiler - Linux man page

為什麼有些主程式(main)有三個參數?

為什麼有些main主程式會有三個變數在參數列上? 這個問題在書上有時會被提及,但是通常都不作說明,或要求你去查閱其他資料或使用手冊。在GNU C library第25章Program Basics中有詳細的說明,許多剛踏入Linux作程式的新手們都應該詳細閱讀此章的基礎知識。 其實 第三個參數就是系統環境變數 ,執行程式時由系統直接傳遞給程式,我們可以利用這個變數客制化我們的程式本身,得到多數程式放置的位置、常用的分隔符號、主系統檔案位置等等。在Linux系統上,有工具是依照這些環境變數來工作的,並依此變化出許多特殊的使用方法。 以下為 GNU C Library 25.1 的原文說明: 25.1 Program Arguments The system starts a C program by calling the function main. It is up to you to write a function named main—otherwise, you won't even be able to link your program without errors. In ISO C you can define main either to take no arguments, or to take two arguments that represent the command line arguments to the program, like this:  int main (int argc, char *argv[]) The command line arguments are the whitespace-separated tokens given in the shell command used to invoke the program; thus, in `cat foo bar', the arguments are `foo' and `bar'. The only way a program can look at its command line arguments is via the arguments of main. If main doesn...

旗標O_NONBLOCK與O_NDELAY有何不同?

O_NONBLOCK和O_NDELAY所產生的結果都是使I/O變成非擱置模式(non-blocking),在讀取不到資料或是寫入緩衝區已滿會馬上return,而不會擱置程式動作,直到有資料或寫入完成。 它們的差別在於設立O_NDELAY會使I/O函式馬上回傳0,但是又衍生出一個問題,因為讀取到檔案結尾時所回傳的也是0,這樣無法得知是哪中情況;因此,O_NONBLOCK就產生出來,它在讀取不到資料時會回傳-1,並且設置errno為EAGAIN。 不過需要注意的是,在GNU C中O_NDELAY只是為了與BSD的程式相容,實際上是使用O_NONBLOCK作為巨集定義,而且O_NONBLOCK除了在ioctl中使用,還可以在open時設定。 參考資料 新洞悉UNIX系統程式設計篇 GNU C Library 13.14.3 I/O Operating Modes

Links for Linux Programmer

一些關於作為Linux Programmer該知曉的資料 學習使用 GNU C Learning GNU C Linux GCC起步 The Linux GCC HOWTO 靜態與動態函式庫 Program Library HOWTO Linux 核心模組 The Linux Kernel Module Programming Guide

抓主機資料的函數

gethostbyname函數原型: struct hostent* gethostbyname(  const char* name ); 這個函數的回傳值若為NULL的時候,代表錯誤發生;其他回傳值代表有找到主機的資料。 如果發生錯誤的時候可以利用查詢h_errno的值來取得錯誤資訊。 *註: 還有另一個兄弟函數gethostbyname2(arg1,arg2),arg2是可以要求分辨IPv4或是IPv6的網路網路位址。 在紅書上所用的函數 gethostbyaddr函數原型: struct hostent * gethostbyaddr (  const char *addr,  size_t length,  int format ); 辨析:  gethostbyname的參數是表示網路名稱的字串,字串可以是192.168.1.1這種形式、或是localhost這種網路名稱,它會透過NameServer去查詢我們所指定的網路主機名稱,由它所回傳hostent結構裡面的IP資料都是網路上的byte-ordering,並不見得是本機電腦上的byte-ording。  gethostbyaddr三個參數分別意義是,網路IP、網路IP的長度、網路IP的格式。第一個參數所需要的網路IP,並不是我們人在看的192.168.1.1這種形式,而是存的位元資料,這種位元資料需要以網路的byte-ording表示,不然一定會查詢不到所需的主機資料;第二個參數我就此略過了,這個大小相信大家自己會給;第三個參數則是需要指定輸入的IP為何種IP格式,是IPv4、或是IPv6。  所以查詢主機資料的這兩個函數,可以拿來作為查詢網路主機IP位置,或是反查某個IP位置的網路名稱,至於其他用法,就有待思考囉! 網路主機名稱(string) ----gethostbyname()----> 網路主機資料(hostent) ----汲取IP----> 主機IP 主機IP(byte data) ----gethostbyaddr()----> 網路主機資料(hostent) ----汲取主機名稱----> 網路主機名稱