色婷婷狠狠18禁久久YY,CHINESE性内射高清国产,国产女人18毛片水真多1,国产AV在线观看

c語言可以泛型編程嗎

林國瑞2年前18瀏覽0評論

c語言可以泛型https://www.52fb.cn嗎?

泛型https://www.52fb.cn是一個非常常見的https://www.52fb.cn方式。主要目的是實現靜態聯編,使得函數可以接受不同類型的參數,并且在編譯的時候確定正確的類型。

很多語言都對泛型https://www.52fb.cn提供了支持,比如在C++中可以使用函數模版和類模版來實現泛型https://www.52fb.cn;在Java、Objective-C或者C#等單根繼承的語言中,也可以使用類似java.lang.Object、NSObject等類型進行https://www.52fb.cn。在具有類型推斷功能(比如Swift)的https://www.52fb.cn語言中,更是可以直接使用泛型https://www.52fb.cn。

不過C語言是高級語言https://www.52fb.cn的基礎語言,那如何在C語言中實現泛型https://www.52fb.cn,確實是一個問題。首先C語言不支持函數重載,不支持模版類型,所以實現起來確實比較困難。

0x01 泛型指針(void *)簡介

void *是C語言中的一種類型,大家都知道在大多數https://www.52fb.cn語言中,void類型都代表所謂的空類型,比如一個函數的返回一個空類型void ,這是很常見的用法。

注意:返回值為void 并不是沒有返回值,而是代表返回空類型,這就是你仍然可以在這些函數中使用return語句的原因。只有一些語言的構造函數和析構函數才沒有返回值,在這些函數中,不可以使用return語句,他們是有顯著的不同的,Objective-C是一門獨特的語言,它的類的初始化方法是一個普通方法,返回值是instancetype(當前類的指針類型)類型。

而void *可能就稍微鮮為人知一些,void *在C語言中可以表示人任意類型的指針。畢竟對于內存單元的地址而言,所謂它存儲的數據類型,只是每次取出的字節數不同而已,這些內存單元的地址本身并沒有什么不同。下面會更好的體現這句話的含義。

void *的大小和普通類型的指針一樣,總是一個字,具體的大小因機器的字長而異,例如對于32位機器是4個字節,對于64位機器是8個字節。

我沒有考證過16位的8086機器上指針的大小,因為8086的地址是20位的,這個有興趣的話可以回去試一試。

個人認為指針的大小仍然是16位,因為20位是物理地址,而物理地址是由段地址和偏移地址計算出的,在匯編之后C語言的指針可能只是變成相對于段地址的偏移地址,畢竟對于8086而言數據一般總是在DS段中,而代碼一般總是在CS段中。(斜體字代表尚未考證的說法)

在C語言中,其他普通類型的指針可以自動轉換為void *類型,而void *類型一般只能強制轉換為其他普通類型的指針,否則會出現警告或錯誤。

有一個特別大的坑就是關于所謂void *指向數組的情況,這里直接上代碼解釋了。

void Swap(void *array, int x, int y, int mallocsize) {

void *temp = malloc(mallocsize);

memcpy(temp, array+mallocsize*x, mallocsize);

memcpy(array+mallocsize*x, array+mallocsize*y, mallocsize);

memcpy(array+mallocsize*y, temp, mallocsize);

free(temp);

}

這是一個比較經典的交換函數,借助的是臨時變量temp,但是這個函數是泛型的,對于memcpy的使用稍后會介紹。需要注意的是,array指向一個數組的話,不能直接用&array[x]或者array+x獲得指向第x個元素的地址,因為void *類型默認的指針偏移量是1,和char *是相同的,這對于絕大多數類型來說都會出現錯誤。所以在使用的時候必須知道該泛型類型原來所占的長度,我們需要一個名為mallocsize的int類型形參來告訴我們這個值,在計算指針偏移的時候乘以它。這就相當于C++https://www.52fb.cn中的模版類型定義或者Java中的泛型參數了。

同時要注意對于void *類型的指針,任何時候都不可以對其進行解引用運算(或者在課堂上老師習慣叫做“取內容”?),原因是顯然的:void類型的變量并不合法。所以如果想進行解引用運算,必須先將其轉換為普通類型的指針。用于數組的時候還需要注意解引用運算符的優先級是高于加法的,所以要加括號,比如這樣:

int a = *(array + mallocsize * x);

這句代碼完美的體現了C語言https://www.52fb.cn的丑陋。

0x02 sizeof運算符簡介

sizeof運算符相信學過C語言的朋友都不會陌生,但是sizeof是一個運算符估計就沒多少人知道了,返回的類型是size_t類型。sizeof運算符返回某個類型所占用的空間大小。這里只說一點就是,如果對一個指針類型或者數組名(實際上數組名就是指針常量嘛)求sizeof的話,返回結果總是一個字(見上面所述)。而對一個結構體類型求sizeof,并不是簡單的將結構體中各個類型的sizeof求和得到,而是要涉及到內存對齊問題,這里不多做介紹了,詳細了解可以訪問:如何理解 struct 的內存對齊? - 知乎。

0x03 memcpy函數簡介

memcpy是一個經常和void *配合使用的函數,其函數原型為:

void * memcpy(void *, const void *, size_t);

所屬的頭文件為string.h,大家也看出來了,這個函數本身就是以void *類型作為參數和返回值,其實也很好理解,就是一個賦值的過程,進行內存拷貝。把第二形參指向的內存拷貝到第一形參,拷貝的字節數由第三形參指定。當然了第三個參數一般通過sizeof運算符求出,這里就不舉例子了。返回值我沒有研究過,也沒用過,如果有知道的朋友可以評論區交流。

0x04 C語言中實現泛型https://www.52fb.cn

說了這么多,還沒提到泛型https://www.52fb.cn。不過前面也提的差不多了,總體思想就是使用void *類型當作泛型指針,然后再輔以類似于mallocsize的參數指定所占內存大小,所占內存大小通過sizeof運算符求得,如果需要進行賦值的話,利用memcpy函數完成,下面就直接給一個例子出來,是泛型的快速排序算法,說明這些問題:

#ifndef Compare_h

#define Compare_h

#include <stdio.h>

#include "JCB.h"

int IsGreater(void *x, void *y);

int IsGreaterOrEqual(void *x, void *y);

int IsSmaller(void *x, void *y);

int IsSmallerOrEqual(void *x, void *y);

#endif /* Compare_h */

//

// Compare.c

// Job-Dispatcher

//

// Created by 路偉饒 on 2017/11/16.

// Copyright ? 2017年 路偉饒. All rights reserved.

//

#include "Compare.h"

int IsGreater(void *x, void *y) {

return *(int *)x > *(int *)y;

}

int IsGreaterOrEqual(void *x, void *y) {

return *(int *)x >= *(int *)y;

}

int IsSmaller(void *x, void *y) {

return *(int *)x < *(int *)y;

}

int IsSmallerOrEqual(void *x, void *y) {

return *(int *)x <= *(int *)y;

}

//

// QuickSort.h

// Job-Dispatcher

//

// Created by 路偉饒 on 2017/11/16.

// Copyright ? 2017年 路偉饒. All rights reserved.

//

#ifndef QuickSort_h

#define QuickSort_h

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include "Compare.h"

void QuickSort(void *array, int left, int right, int mallocsize);

#endif /* QuickSort_h */

//

// QuickSort.c

// Job-Dispatcher

//

// Created by 路偉饒 on 2017/11/16.

// Copyright ? 2017年 路偉饒. All rights reserved.

//

#include "QuickSort.h"

void Swap(void *array, int x, int y, int mallocsize) {

void *temp = malloc(mallocsize);

memcpy(temp, array+mallocsize*x, mallocsize);

memcpy(array+mallocsize*x, array+mallocsize*y, mallocsize);

memcpy(array+mallocsize*y, temp, mallocsize);

free(temp);

}

int QuickSortSelectCenter(int l, int r) {

return (l+r)/2;

}

int QuickSortPartition(void *array, int l, int r, int mallocsize) {

int left = l;

int right = r;

void *temp = malloc(mallocsize);

memcpy(temp, array+mallocsize*right, mallocsize);

while (left < right) {

while ( IsSmallerOrEqual(array+mallocsize*left, temp) && left < right) {

left ++;

}

if (left < right) {

memcpy(array+mallocsize*right, array+mallocsize*left, mallocsize);

right--;

}

while ( IsGreaterOrEqual(array+mallocsize*right, temp) && left < right) {

right--;

}

if (left < right) {

memcpy(array+mallocsize*left, array+mallocsize*right, mallocsize);

left ++;

}

}

memcpy(array+mallocsize*left, temp, mallocsize);

return left;

}

void QuickSort(void *array, int left, int right, int mallocsize) {

if (left>=right) {

return;

}

int center = QuickSortSelectCenter(left, right);

Swap(array, center, right, mallocsize);

center = QuickSortPartition(array, left, right, mallocsize);

QuickSort(array, left, center-1, mallocsize);

QuickSort(array, center+1, right, mallocsize);

}

這里留了一個懸念,明明可以直接比較的,為什么還要這么麻煩使用好多函數完成,也就是關于Compare.h的用處的問題,下面會揭曉答案。

0x05 泛型的協議問題

剛剛那個問題就涉及到了一個泛型的協議問題,我這里是借用了Objective-C 中的一個概念去闡述。就像剛剛那個問題,既然我的快速排序是泛型的,那么怎么保證實際傳入泛型參數一定是可比較的呢?舉個例子,顯然int、float、double是可以進行比較的,char使用ASCII編碼方案的比較我們也理解,String類型甚至也是可以比較的。但是如果在其他語言中,對象之間如何進行比較呢?這就是個問題了。在C++中我們可以進行運算符重載,這樣就仍舊可以使用比較運算符,借助運算符重載函數來完成。不過對于Java、Objective-C這種語言該怎么辦?而且如果傳入的泛型參數沒有實現對應的運算符重載函數怎么辦?這時候就要引入一個協議的概念,簡單來說就是,如果某個類型想要作為排序泛型函數的泛型參數,那你必須實現可比較的協議。這個協議在Swift語言中就稱為Comparable,這樣的話在編譯的時候,編譯器才知道這個泛型參數是可以進行比較的,這樣才能完成我們的操作,否則的話就會出現錯誤。這就是泛型中的協議問題。

0x06 總結

C語言的泛型https://www.52fb.cn以void *作為泛型類型,本質上是泛型指針。

C語言的泛型https://www.52fb.cn需要知道一個泛型類型變量所占的內存大小,這個可以通過sizeof求得并傳入泛型函數。

C語言的泛型https://www.52fb.cn中要注意數組的偏移問題,void *的默認偏移是1,對于絕大多數類型來說都是錯誤的,需要自行https://www.52fb.cn轉換。

C語言的泛型https://www.52fb.cn中使用memcpy函數進行泛型變量的拷貝和賦值。

C語言的泛型https://www.52fb.cn中也需要注意協議問題,但是C中就只能自行編寫函數進行定義了,在其他語言中可以使用現成的接口或者協議。

java 獲取 泛型類型,c語言可以泛型https://www.52fb.cn嗎