Python與C語言數據交互

       Python語言與C語言數據交互的場景還是比較常見的,例如在使用python優秀的數據處理可視化等優勢的同時,對於某些優秀的開源C/C++的軟件庫的調用就需要用到ctypes庫函數對動態庫進行API的靈活調用了,再例如在某些場景下,C語言的數據需要可視化,而C語言的可視化接口的支持是很薄弱的,這裏可以採用Python強大的可視化效果來驗證數據的正確性(也可以採用MATLAB完成可視化)。 再比如在某些Demo測試場景下,使用Python便捷部署的神經網絡框架在使用獲取內存圖像數據時也可能使用到Python和C之間數據交換的需求。

一、python與C交互的重要庫 ctypes

        ctypes庫作爲python與C之間的交互的重要庫,其定義了各類數據類型與C語言中的數據類型進行對應,其中包括了char,int,POINTER等等,具體可以參看數據手冊。ctypes還能夠通過CDLL接口應用C語言的動態庫.so,在調用接口過程中,應該要嚴格配置Python端調用動態庫函數接口的參數類型(不能有任何偏差),應該掌握如何定義數組緩衝區並操作地址變量,同時能夠使用接口獲取變量地址,從而傳給C-API使用,基礎如下所示:

1. 數組類型定義及使用

測試代碼:

1 # 特殊ctypes類型數組類型定義
2 ArrayTestType = ctypes.c_uint8 * 10 # 重定義數據類型
3 ArrayTest = ArrayTestType(11) # 定義數據並初始化數據賦值爲11
4 ArrayTest[5] = 20 # 對數據進行賦值處理
5 print('Line', sys._getframe().f_lineno, ':', ArrayTest, type(ArrayTest), ArrayTestType, type(ArrayTestType))
6 print('Line', sys._getframe().f_lineno, ':', ArrayTest[0], ArrayTest[5])

運行結果:

Line 20 : <__main__.c_ubyte_Array_10 object at 0x7fd1318e8ea0> <class '__main__.c_ubyte_Array_10'> <class '__main__.c_ubyte_Array_10'> <class '_ctypes.PyCArrayType'>
Line 21 : 11 20

這裏可以看到 ArrayTestType 的類型其實爲 PyCArrayType PythonC數組類型,因此 ArrayTestType 可以定義一個 unsigned char Array[10] 的數組。

注:數組類型的縮略定義方法(相當於上述步驟的兩步)

# 定義一個大小爲10指針實例作爲緩存, 等效爲 Step1:DataType = c_uint8 * LENGTH --> Step2:DataPoint = DataType()
DataPoint = (c_uint8 * LENGTH)() 

2. 動態庫的加載及接口調用

測試代碼:

1 # 從C語言或者C++的動態庫當中加載C函數以調用
2 p = os.getcwd() + '/libfunc.so' # 獲取當前的動態庫的絕對路徑位置
3 f = cdll.LoadLibrary(p) # 使用LoadLibrary接口加載C語言動態庫
4 
5 # Python Class類 到 C struct結構體 數據類型的傳輸轉換
6 Sfunction = f.py_struct_address # 從當前庫當中取得clib中的函數py_struct_address,並重命名爲Sfunction
7 Sfunction.argtypes = [POINTER(POINT), POINTER(ctypes.c_char)] # 設置當前函數的輸入參數

這裏使用了 os模塊獲取了動態庫的絕對路徑,並調用cdll.LoadLibrary(libpath),這裏使用 argtypes 定義了動態庫函數的輸入參數類型,分別爲結構體指針、char *指針。

3. 定義字符串類型(字符串string)

1 p = create_string_buffer(b"Hello World", 15) # create a 10 byte buffer
2 print('Line', sys._getframe().f_lineno, ':', p,sizeof(p), repr(p.raw))

創建一個string類型的緩衝空間,並返回一個字符串指針指向這串字符串,create_string_buffer 參數分別爲字符串、buffer總長度,這個長度不能小於前一個參數字符串的長度大小,否則會報錯,p.raw取字符串的內容。

4. Numpy數組的地址獲取及應用

測試代碼:

 1 # Numpy 數據類型等相互轉換測試(將內存數據轉換值Python當中)
 2 ImgW = 1669 # 圖像寬度
 3 ImgH = 21 # 圖像高度
 4 ImgC = 3 # 圖像通道數
 5 ImgL = ImgW*ImgH*ImgC # 圖像總長度
 6 
 7 ImgArray = np.zeros((ImgW,ImgH,ImgC), dtype=np.ubyte) # 申請圖像總空間爲多維 zeros 矩陣
 8 print(ImgArray.ctypes.data_as(ctypes.POINTER(ctypes.c_uint8))) # 將numpy數組轉換爲地址表示方式 data_as 並打印數據類型
 9 ImgArray_addr = ImgArray.ctypes.data_as(ctypes.POINTER(ctypes.c_uint8)) # 獲取的指針放置在ImgArray_addr變量當中
10 print('Line', sys._getframe().f_lineno, ':', ImgArray_addr[0],ImgArray_addr[1],ImgArray_addr[2],ImgArray_addr[3])
11 
12 Imgfunction = f.py_img_address # 從當前庫當中取得clib中的函數py_struct_address,並重命名爲Sfunction
13 Imgfunction.argtypes = [POINTER(ctypes.c_ubyte), ctypes.c_uint32] # 設置當前函數的輸入參數規劃 usigned char *pointer, unsigned int arg
14 Imgfunction.restype = ctypes.c_int # 設置當前函數返回值參數爲 int 類型
15 time_start = time.time()
16 Res = Imgfunction(ImgArray_addr, ImgL) # 調用Imgfunction函數
17 time_end = time.time()
18 print('Line', sys._getframe().f_lineno, ':', 'TimeCost:', (time_end - time_start)*1000, 'ms') # 記錄當前函數調用消耗的時間
19 
20 print('Line', sys._getframe().f_lineno, ':\n', ImgArray[:,:,0]) # 打印0通道的數據
21 print('Line', sys._getframe().f_lineno, ':\n', ImgArray[:,:,1]) # 打印1通道的數據
22 print('Line', sys._getframe().f_lineno, ':\n', ImgArray[:,:,2]) # 答應2通道的數據

通過numpy庫中數組的成員 ctypes.data_as 方法獲取指定類型的指針地址,並將此地址應用在函數庫的參數中。

5. 基本類型定義

測試代碼:

1 # 使用byref獲取ctypes類型數據的地址
2 data = ctypes.c_uint8(10) # 定義一個整數類型的變量,變量初始值爲 10,相當於C語言中的 char data=42;
3 data_addr = ctypes.byref(data, 0) # 通過使用byref接口獲取地址,相當於C語言中的 char *data_addr = &data; byref(obj, offset) 對應於這段 C 代碼:(((char *)&obj) + offset)
4 print('Line', sys._getframe().f_lineno, ':', type(data))
5 print('Line', sys._getframe().f_lineno, ':', type(data_addr))

這裏使用 ctypes.c_uint8(10) 定義一個 unsigned char 類型的數據並賦予初值爲10,byref函數接口用於獲取數據data的地址。

I) 完整的測試代碼:

MemoryTest.py

  1 import os
  2 import sys
  3 import time
  4 import ctypes
  5 from ctypes import *
  6 from ctypes import cdll
  7 import numpy as np
  8 
  9 BUFF_SIZE = 6*1024*1024 # 基本的緩衝區域尺寸大小定義
 10 LENGTH = 2*2*3 # 數據長度定義
 11 
 12 # 類定義
 13 class POINT(Structure): # 定義了一個類,類當中的基本成員變量包括了x、y, 相當於C語言中的 struct POINT{int x;inty};
 14     _fields_ = [("x", c_int),("y", c_int),("addr", POINTER(c_uint8)),("len", c_int)]
 15 
 16 # 特殊ctypes類型數組類型定義
 17 ArrayTestType = ctypes.c_uint8 * 10 # 重定義數據類型
 18 ArrayTest = ArrayTestType(11) # 定義數據並初始化數據賦值爲11
 19 ArrayTest[5] = 20 # 對數據進行賦值處理
 20 print('Line', sys._getframe().f_lineno, ':', ArrayTest, type(ArrayTest), ArrayTestType, type(ArrayTestType))
 21 print('Line', sys._getframe().f_lineno, ':', ArrayTest[0], ArrayTest[5])
 22 
 23 DataPoint = (c_uint8 * LENGTH)() # 定義一個大小爲10指針實例作爲緩存, 等效爲 Step1:DataType = c_uint8 * LENGTH --> Step2:DataPoint = DataType()
 24 DataPoint[3] = 22
 25 
 26 point = POINT(10, 20, DataPoint,LENGTH) # 定義個類對象Obj, 相當於 struct POINT point={10,20};
 27 print('Line', sys._getframe().f_lineno, ':', point.x, point.y, point.addr[3], point.len)
 28 
 29 point = POINT(y=5) # 定義個類對象Obj, 相當於 struct POINT point={,20};
 30 print('Line', sys._getframe().f_lineno, ':', point.x, point.y)
 31 
 32 # Class類數組定義
 33 addrTest = (POINT * 1)() # 定義一個POINT結構體緩衝地址
 34 addrTest[0].x = 10 # POINT緩衝地址的第一個變量的x成員值
 35 addrTest[0].y = 11 # POINT緩衝地址的第一個變量的y成員值
 36 addrTest[0].addr = DataPoint # POINT緩衝地址的第一個變量的addr成員賦值
 37 addrTest[0].len = LENGTH # POINT緩衝地址的第一個變量的len成員賦值
 38 print('Line', sys._getframe().f_lineno, ':', addrTest, addrTest[0].x,addrTest[0].y,addrTest[0].addr[3],addrTest[0].len)
 39 
 40 TenPointsArrayType = POINT * 3 # 重定義了一個POINT數組類型,相當於C語言中的 #define TenPointsArrayType POINT*3
 41 arr = TenPointsArrayType()
 42 for pt in arr:
 43     print(pt.x, pt.y, pt.addr)
 44 
 45 # 從C語言或者C++的動態庫當中加載C函數以調用
 46 p = os.getcwd() + '/libfunc.so' # 獲取當前的動態庫的絕對路徑位置
 47 f = cdll.LoadLibrary(p) # 使用LoadLibrary接口加載C語言動態庫
 48 function = f.py_point_address # 從當前庫當中取得clib中的函數py_point_address,並重命名爲function
 49 function.argtypes = [POINTER(c_byte)] # 設置當前函數的輸入參數
 50 
 51 # Python Class類 到 C struct結構體 數據類型的傳輸轉換
 52 Sfunction = f.py_struct_address # 從當前庫當中取得clib中的函數py_struct_address,並重命名爲Sfunction
 53 Sfunction.argtypes = [POINTER(POINT), POINTER(ctypes.c_char)] # 設置當前函數的輸入參數
 54 
 55 p = create_string_buffer(b"Hello World", 15) # create a 10 byte buffer
 56 print('Line', sys._getframe().f_lineno, ':', p,sizeof(p), repr(p.raw))
 57 
 58 time_start = time.time()
 59 Res = Sfunction(addrTest, p)
 60 time_end = time.time()
 61 for i in range(LENGTH):
 62     print(addrTest[0].addr[i])
 63 
 64 print('Line', sys._getframe().f_lineno, ':', addrTest[0].x, addrTest[0].y, addrTest[0].len, addrTest[0].addr)
 65 print('Line', sys._getframe().f_lineno, ':', 'TimeCost:', (time_end - time_start)*1000, 'ms') # 記錄當前函數調用消耗的時間
 66 
 67 # Numpy 數據類型等相互轉換測試(將內存數據轉換值Python當中)
 68 ImgW = 1669 # 圖像寬度
 69 ImgH = 21 # 圖像高度
 70 ImgC = 3 # 圖像通道數
 71 ImgL = ImgW*ImgH*ImgC # 圖像總長度
 72 # ImgArray = np.array([[0, 1], [2, 3]], dtype=np.uint8)
 73 ImgArray = np.zeros((ImgW,ImgH,ImgC), dtype=np.ubyte) # 申請圖像總空間爲多維 zeros 矩陣
 74 # ImgArray = np.array([1,2,3,4], dtype=np.int32)
 75 # print(ImgArray)
 76 # print(ImgArray.ctypes.data)
 77 print(ImgArray.ctypes.data_as(ctypes.POINTER(ctypes.c_uint8))) # 將numpy數組轉換爲地址表示方式 data_as 並打印數據類型
 78 ImgArray_addr = ImgArray.ctypes.data_as(ctypes.POINTER(ctypes.c_uint8)) # 獲取的指針放置在ImgArray_addr變量當中
 79 print('Line', sys._getframe().f_lineno, ':', ImgArray_addr[0],ImgArray_addr[1],ImgArray_addr[2],ImgArray_addr[3])
 80 # print(ImgArray.ctypes.data_as(ctypes.POINTER(ctypes.c_uint8)).contents)
 81 # print(ImgArray.ctypes.data_as(ctypes.POINTER(ctypes.c_uint16)).contents)
 82 # print(ImgArray.ctypes.shape)
 83 # print(ImgArray.ctypes.strides)
 84 
 85 Imgfunction = f.py_img_address # 從當前庫當中取得clib中的函數py_struct_address,並重命名爲Sfunction
 86 Imgfunction.argtypes = [POINTER(ctypes.c_ubyte), ctypes.c_uint32] # 設置當前函數的輸入參數規劃 usigned char *pointer, unsigned int arg
 87 Imgfunction.restype = ctypes.c_int # 設置當前函數返回值參數爲 int 類型
 88 time_start = time.time()
 89 Res = Imgfunction(ImgArray_addr, ImgL) # 調用Imgfunction函數
 90 time_end = time.time()
 91 print('Line', sys._getframe().f_lineno, ':', 'TimeCost:', (time_end - time_start)*1000, 'ms') # 記錄當前函數調用消耗的時間
 92 
 93 print('Line', sys._getframe().f_lineno, ':\n', ImgArray[:,:,0]) # 打印0通道的數據
 94 print('Line', sys._getframe().f_lineno, ':\n', ImgArray[:,:,1]) # 打印1通道的數據
 95 print('Line', sys._getframe().f_lineno, ':\n', ImgArray[:,:,2]) # 答應2通道的數據
 96 
 97 # 一般類型定義以及數據取地址方法 int *pi = &i;
 98 i = ctypes.c_int(42) # 定義一個整數類型的變量,變量初始值爲 42,相當於C語言中的 int i=42;
 99 pi = ctypes.pointer(i) # 通過使用pointer接口獲取,相當於C語言中的 int *pi = &i;
100 print('Line', sys._getframe().f_lineno, ':', pi.contents) # 查看指針變量的信息
101 print('Line', sys._getframe().f_lineno, ':', pi[0]) # 查看指針所指向的內容,相當於C語言中的 *pi;
102 
103 # ctypes.c_byte 類型的數組定義,等效於 byte a[BUFF_SIZE];
104 a = (c_byte * BUFF_SIZE)() # 定義一個大小爲BUFF_SIZE指針實例作爲緩存
105 # cast(a, POINTER(c_uint8)) # 函數可以將一個指針實例強制轉換爲另一種 ctypes 類型
106 print('Line', sys._getframe().f_lineno, ':', a)
107 print('Line', sys._getframe().f_lineno, ':', type(a))
108 time_start = time.time()
109 function(a) # 執行function函數並傳入a地址參數
110 time_end = time.time()
111 
112 for i in range(10):
113     print(a[i])
114 
115 print('Line', sys._getframe().f_lineno, ':', 'TimeCost:', (time_end - time_start)*1000, 'ms') # 記錄當前函數調用消耗的時間
116 
117 # 使用byref獲取ctypes類型數據的地址
118 data = ctypes.c_uint8(10) # 定義一個整數類型的變量,變量初始值爲 10,相當於C語言中的 char data=42;
119 data_addr = ctypes.byref(data, 0) # 通過使用byref接口獲取地址,相當於C語言中的 char *data_addr = &data; byref(obj, offset) 對應於這段 C 代碼:(((char *)&obj) + offset)
120 print('Line', sys._getframe().f_lineno, ':', type(data))
121 print('Line', sys._getframe().f_lineno, ':', type(data_addr))
122 
123 # 使用id獲取變量在python的地址
124 value = 'hello world'  # 定義一個字符串變量
125 address = id(value)  # 獲取value的地址,賦給address
126 get_value = ctypes.cast(address, ctypes.py_object).value  # 讀取地址中的變量
127 print('Line', sys._getframe().f_lineno, ':', address, get_value) # 
128 
129 # 一般Clib函數的調用
130 res = f.func(99) # 普通函數調用
131 print('Line', sys._getframe().f_lineno, ':', res)
View Code

function.c

  1 #include <stdio.h>
  2 #include <sys/shm.h>
  3 #include <string.h>
  4 #include <stdlib.h>
  5 #include <time.h>
  6 #include <sys/time.h>
  7 
  8 
  9 #define BUFF_SIZE 6*1024*1024
 10 
 11 typedef struct T_POINT{
 12     int x;
 13     int y;
 14     char * addr;
 15     int len;
 16 }POINT;
 17 
 18 time_t get_timestamp_us(void)
 19 {
 20   time_t timestamp_ms = 0;
 21   struct timeval tv;
 22   
 23   gettimeofday(&tv,NULL);
 24   timestamp_ms = tv.tv_sec * 1000 * 1000 + tv.tv_usec;
 25   return timestamp_ms;
 26 }
 27 
 28 char *file_read(unsigned long *file_bytes, char *file_name)
 29 {
 30   int file_size;
 31   FILE *fd = NULL;
 32   char *file_data = NULL;
 33   fd = fopen(file_name, "rw");
 34   if(fd < 0)
 35   {
 36     printf("File open failed...\n");
 37     return NULL;
 38   }
 39   fseek(fd, 0, SEEK_END);
 40   file_size = ftell (fd);
 41   file_data = malloc(sizeof(char)*file_size);
 42   if(file_data == NULL)
 43   {
 44     printf("Malloc failed...\n");
 45     return NULL;
 46   }
 47   fseek(fd, 0, SEEK_SET);
 48   *file_bytes = fread(file_data,sizeof(char),file_size,fd);
 49   fclose(fd);
 50   return file_data;
 51 }
 52 
 53 /* func.c */
 54 int func(int a)
 55 {
 56     return a*a;
 57 }
 58 
 59 void cycle_calc(int b)
 60 {
 61     int count = 100;
 62     while(count--){
 63         b*=2;
 64         printf("%d - %d\n", count, b);
 65     }
 66 }
 67 
 68 unsigned char * c_point_address(void)
 69 {
 70     unsigned char *Img = malloc(sizeof(unsigned char)*1000);
 71     printf("C-Address:%hhn\n", Img);
 72     memset(Img, 20, 1000);
 73     return Img;
 74 }
 75 
 76 int py_point_address(unsigned char * Addr)
 77 {
 78     unsigned char *Img = malloc(sizeof(unsigned char)*BUFF_SIZE);
 79     // printf("C-Address:%x\n", Img);
 80     // printf("Python-Address:%x\n", Addr);
 81     memset(Img, 20, BUFF_SIZE);
 82     memcpy((unsigned char * )Addr, Img, BUFF_SIZE);
 83     return 1;
 84 }
 85 
 86 int py_struct_address(POINT *pt_POINT, char *str)
 87 {
 88     int i = 0;
 89     for(i=0; i < pt_POINT->len; i++)
 90     {
 91         pt_POINT->addr[i] = i;
 92     }
 93     pt_POINT->x = 16;
 94     pt_POINT->y = 17;
 95     printf("FunctionPrint:%s\n",str);
 96     return 1;
 97 }
 98 
 99 int py_img_address(unsigned char *data, unsigned int lenght)
100 {
101     time_t st,et;
102     unsigned long count=0;
103     unsigned long i=0;
104     st = get_timestamp_us();
105     unsigned char *ImgData = file_read(&i, "./Test.PNG");
106     et = get_timestamp_us();
107     printf("C ### ReadFile time Cost:%ld\n", et - st);
108 
109     printf("Data[%ld]:%d\n", count, *(ImgData+i-1));
110 
111     st = get_timestamp_us();
112     memcpy(data, ImgData, sizeof(unsigned char)*lenght);
113     et = get_timestamp_us();
114     printf("C ### Memcpy time Cost:%ld\n", et - st);
115 
116     printf("py_img_address FunctionPrint:%ld\n", i);
117     return 1;
118 }
View Code

exe_shell.sh

1 #!/bin/bash
2 gcc -fPIC -shared function.c -o libfunc.so
3 python3 MemoryTest.py

II) 測試結果如下(測試平臺: Ubuntu 18.04.6 LTS + Intel(R) Core(TM) i5-10400F CPU @ 2.90GHz ):

Line 91 : TimeCost: 0.07772445678710938 ms  102KB  Speed=1.25GB/s

二、採用共享內存方式進行IPC通信

內存共享基本方法參考 《進程間通信原理》 ,共享內存的方式需要通過其他通信方式進行進程間數據同步,從而保證共享內存在使用的過程中不被其他進程修改。

main.py

 1 from ctypes import *  
 2 import numpy as np
 3 import codecs
 4 import datetime
 5 
 6 SHM_SIZE = 1024*1024*20 # 20MBytes
 7 SHM_KEY = 123559  
 8 
 9 OUTFILE="Shared.PNG"  
10 try:  
11     rt = CDLL('librt.so')  
12 except:  
13     rt = CDLL('librt.so.1')
14 
15 shmget = rt.shmget
16 shmget.argtypes = [c_int, c_size_t, c_int]  
17 shmget.restype = c_int  
18 shmat = rt.shmat  
19 shmat.argtypes = [c_int, POINTER(c_void_p), c_int]  
20 shmat.restype = c_void_p  
21 
22 shmid = shmget(SHM_KEY, SHM_SIZE, 0o666)
23 
24 if shmid < 0:  
25     print ("System not infected")  
26 else:
27     addr = shmat(shmid, None, 0)  
28     f=open(OUTFILE, 'wb')
29     begin_time = datetime.datetime.now()
30     DataLength = int.from_bytes(string_at(addr,4), byteorder='little', signed=True)   #這裏數據文件是小端int16類型
31     ImgData = string_at(addr+4,DataLength)
32     end_time = datetime.datetime.now()
33     print(DataLength, ' Bytes')
34     print('Type:',type(ImgData),' Bytes:', len(ImgData))
35     f.write(ImgData)
36     f.close()  
37 #print ("Dumped %d bytes in %s" % (SHM_SIZE, OUTFILE))
38 print("Success!",end_time-begin_time)
View Code

main.c

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <sys/shm.h>
  4 #include <string.h>
  5 #include <time.h>
  6 #include <sys/time.h>
  7 
  8 #define SHAERD_MEM_SIZE 20 * 1024 * 1024 // 20MBytes
  9 
 10 char mem_free(void *ptr);
 11 time_t get_timestamp_ms(void);
 12 char *file_read(unsigned int *file_bytes, char *file_name);
 13 
 14 int main(int argc, char *argv[])
 15 {
 16     int id = 0;
 17     size_t offset = 0;
 18     char *data = NULL;
 19     char *ImgData = NULL;
 20     unsigned int file_bytes = 0;
 21     time_t start_time, end_time;   
 22     if (argc < 2)
 23     {
 24         printf("args too less\n");
 25         return 0;
 26     }
 27     
 28     id = shmget(123559, SHAERD_MEM_SIZE, IPC_CREAT | 0777);
 29     if (id < 0)
 30     {
 31         printf("get id failed\n");
 32         return 0;
 33     }
 34     
 35     data = shmat(id, NULL, 0);
 36     if (data == NULL)
 37     {
 38         printf("shamt failed\n");
 39         return 0;
 40     }
 41 
 42     ImgData = file_read(&file_bytes, argv[1]);
 43     offset = sizeof(unsigned int);
 44     printf("Size of unsigned long:%d\n", offset);
 45     printf("Size of Image File:%d\n", file_bytes);
 46     start_time = get_timestamp_ms();
 47     memcpy(data, &file_bytes, sizeof(unsigned int));
 48     memcpy(data + offset, ImgData, file_bytes);
 49     end_time = get_timestamp_ms();
 50 
 51     printf("Time Cost:%d\n", end_time - start_time);
 52 
 53     mem_free(ImgData);
 54 
 55     return 0;
 56 }
 57 
 58 char *file_read(unsigned int *file_bytes, char *file_name)
 59 {
 60   int file_size;
 61   FILE *fd = NULL;
 62   char *file_data = NULL;
 63   fd = fopen(file_name, "rw");
 64   if(fd < 0)
 65   {
 66     printf("File open failed...\n");
 67     return NULL;
 68   }
 69   fseek(fd, 0, SEEK_END);
 70   file_size = ftell (fd);
 71   file_data = malloc(sizeof(char)*file_size);
 72   if(file_data == NULL)
 73   {
 74     printf("Malloc failed...\n");
 75     return NULL;
 76   }
 77   fseek(fd, 0, SEEK_SET);
 78   *file_bytes = fread(file_data,sizeof(char),file_size,fd);
 79   fclose(fd);
 80   return file_data;
 81 }
 82 
 83 time_t get_timestamp_ms(void)
 84 {
 85   time_t timestamp_ms = 0;
 86   struct timeval tv;
 87   
 88   gettimeofday(&tv,NULL);
 89   timestamp_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
 90   return timestamp_ms;
 91 }
 92 
 93 char mem_free(void *ptr)
 94 {
 95   if(NULL != ptr)
 96   {
 97     free(ptr);
 98     return 0;
 99   }
100   printf("Memory is Empty...\n");
101   return -1;
102 }
View Code

編譯執行即可

gcc -o main main.c
./main sdlinux.zip # 12MB
python3 main.py

測試結果如下(測試平臺:Ubuntu 18.04.6 LTS + Intel(R) Core(TM) i5-10400F CPU @ 2.90GHz ):

Success! 7.091045379638672 ms  12MB  Speed=1.67GB/s

Reference:

REF1:https://zhuanlan.zhihu.com/p/145165873

未完待續 ~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章