C에서의 템플릿 시뮬레이션(큐 데이터 타입의 경우)
지금 합니다.queue
다아다에는 '큐'만 수 .큐에 저장할 수 있는 것은int
다른 것은 없습니다.가 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★C++
, " "의C
)#define
으로써 나의 )는,queue
는 모든 데이터 유형을 포함할 수 있습니다.
주의: 사용하고 싶지 않습니다.void*
조금 위험하고 이상한 런타임 에러를 일으키기 쉽다고 생각합니다.
그런 종류의 템플릿을 만들기 위해 미묘하고 추한 트릭을 사용할 수 있습니다.제가 할 일은 다음과 같습니다.
템플릿 리스트 작성
목록을 정의할 매크로
. 이것을 다음과 같이 부릅니다.define_list(type)
- 특정 유형의 목록에 대한 모든 함수를 만듭니다.그런 다음 목록의 모든 함수에 대한 함수 포인터를 포함하는 글로벌 구조를 만들고 목록의 각 인스턴스에서 해당 글로벌 구조에 대한 포인터를 가집니다(가상 메서드 테이블과 얼마나 유사한지 주의).이런 종류의 것:
#define define_list(type) \
\
struct _list_##type; \
\
typedef struct \
{ \
int (*is_empty)(const struct _list_##type*); \
size_t (*size)(const struct _list_##type*); \
const type (*front)(const struct _list_##type*); \
void (*push_front)(struct _list_##type*, type); \
} _list_functions_##type; \
\
typedef struct _list_elem_##type \
{ \
type _data; \
struct _list_elem_##type* _next; \
} list_elem_##type; \
\
typedef struct _list_##type \
{ \
size_t _size; \
list_elem_##type* _first; \
list_elem_##type* _last; \
_list_functions_##type* _functions; \
} List_##type; \
\
List_##type* new_list_##type(); \
bool list_is_empty_##type(const List_##type* list); \
size_t list_size_##type(const List_##type* list); \
const type list_front_##type(const List_##type* list); \
void list_push_front_##type(List_##type* list, type elem); \
\
bool list_is_empty_##type(const List_##type* list) \
{ \
return list->_size == 0; \
} \
\
size_t list_size_##type(const List_##type* list) \
{ \
return list->_size; \
} \
\
const type list_front_##type(const List_##type* list) \
{ \
return list->_first->_data; \
} \
\
void list_push_front_##type(List_##type* list, type elem) \
{ \
... \
} \
\
_list_functions_##type _list_funcs_##type = { \
&list_is_empty_##type, \
&list_size_##type, \
&list_front_##type, \
&list_push_front_##type, \
}; \
\
List_##type* new_list_##type() \
{ \
List_##type* res = (List_##type*) malloc(sizeof(List_##type)); \
res->_size = 0; \
res->_first = NULL; \
res->_functions = &_list_funcs_##type; \
return res; \
}
#define List(type) \
List_##type
#define new_list(type) \
new_list_##type()
범용 인터페이스
다음은 단순히 저장된 함수 포인터를 통해 목록의 함수를 호출하는 매크로입니다.
#define is_empty(collection) \
collection->_functions->is_empty(collection)
#define size(collection) \
collection->_functions->size(collection)
#define front(collection) \
collection->_functions->front(collection)
#define push_front(collection, elem) \
collection->_functions->push_front(collection, elem)
같은 구조를 사용하여 리스트 이외의 컬렉션을 설계하면 좋은 포인터를 저장하는 컬렉션에 마지막 함수를 사용할 수 있습니다.
사용 예
마지막으로 새로운 리스트템플릿을 사용하는 방법의 간단한 예를 나타냅니다.
/* Define the data structures you need */
define_list(int)
define_list(float)
int main()
{
List(int)* a = new_list(int);
List(float)* b = new_list(float);
push_front(a, 5);
push_front(b, 5.2);
}
만약 당신이 정말로 C에 어떤 종류의 템플릿을 가지고 싶다면 당신은 그 정도의 트릭을 사용할 수 있지만, 그것은 다소 추하다(C++를 사용하면 더 간단하다). 않습니다.즉, 1개의 포인터를 저장할 void*
포인터, yeah \o/)다시는 그것을 사용하지 않기를 바랍니다.p
제한 사항
물론 실제 템플릿이 아닌 텍스트 대체 매크로를 사용하기 때문에 몇 가지 제한이 있습니다.
1회 정의
컴파일 유닛당 각 타입을 1회만 정의할 수 있습니다.그렇지 않으면 프로그램은 컴파일에 실패합니다.를 들어 되어 있는 경우 큰될 수 .define_
★★★★★★★★★★★★★★★★★★.
여러 단어 유형
「」를 List
되어 있다.signed char
,unsigned long
,const bar
,struct foo
(...)인 경우.char*
,void*
해야 .typedef
그런 타입부터.
define_list(int) /* OK */
define_list(char*) /* Error: pointer */
define_list(unsigned long) /* Error: several words */
typedef char* char_ptr;
typedef unsigned long ulong;
define_list(char_ptr) /* OK */
define_list(ulong) /* OK */
중첩 목록을 작성하려면 동일한 트릭을 사용해야 합니다.
건 #define
's'라고 할 수 있을 거예요
queue.h:
#define TYPE int
#define TYPED_NAME(x) int_##x
#include "queue_impl.h"
#undef TYPE
#undef TYPED_NAME
#define TYPE float
#define TYPED_NAME(x) float_##x
#include "queue_impl.h"
#undef TYPE
#undef TYPED_NAME
...
queue_module을 클릭합니다.h:
//no include guard, of course
typedef struct
{
TYPE *data;
...
} TYPED_NAME(queue);
void TYPED_NAME(queue_insert) (TYPED_NAME(queue) *queue, TYPE data)
{
...
}
전문가가 에 100%는 확실치 는, 구조(100%의 「」, 「전처리를 수 .int_queue
★★★★★★★★★★★★★★★★★」float_queue
과 함께, 「」라고 하는 것이 있습니다.
void int_queue_insert(int_queue *queue, int data);
void float_queue_insert(float_queue *queue, float data);
', 는 '템플릿'의 5행 과 같습니다.queue.h
실제 구현은 한 번만 작성하면 됩니다.물론 더 다듬을 수 있지만, 기본적인 생각은 분명해야 합니다.
이렇게 하면 인터페이스를 완전히 일치시킬 수 없지만 최소한 완벽한 타입 세이프 큐템플릿을 얻을 수 있습니다(C는 오버로드된 함수를 지원하지 않기 때문에 함수는 타입명을 전송해야 합니다).
void* 데이터를 포함하는 큐를 구현하고 이 void*를 모든 유형 또는 int와 같은 원시 유형에 대한 포인터로 해석합니다.
#define을 사용하는 것은 가능하지만, 디버깅에 대해 생각해 보십시오.무슨 문제가 있으면...
오랫동안 궁금했는데, 이제 누구나 이해할 수 있는 확답이 생겼으니 봐!
Data Structures 코스를 수강할 때 Standish의 "Data Structures, Algorithms in C"라는 책을 읽어야 했습니다.그것은 고통스러웠습니다.제너릭도 없고, 빈약한 표기법도 없고, 영장도 없는 글로벌 상태 돌연변이도 가득했습니다.하지만 저는 그의 코드 스타일을 채택하는 것이 미래의 모든 프로젝트를 망친다는 것을 알고 있었습니다.더 좋은 방법, 그러니까 더 좋은 방법:
만져보기 전의 모습입니다(사실 인간이 읽을 수 있는 포맷으로 만들기 위해 만진 것입니다). 정말 보기 흉하고 여러 가지 면에서 틀렸습니다만, 참고용으로 일람표시를 하겠습니다.
#include <stdio.h>
#define MaxIndex 100
int Find(int A[])
{
int j;
for (j = 0; j < MaxIndex; ++j) {
if (A[j] < 0) {
return j;
}
}
return -1;
}
int main(void)
{
// reminder: MaxIndex is 100.
int A[MaxIndex];
/**
* anonymous scope #1
* initialize our array to [0..99],
* then set 18th element to its negative value(-18)
* to make the search more interesting.
*/
{
// loop index, nothing interesting here.
int i;
// initialize our array to [0..99].
for (i = 0; i < MaxIndex; ++i) {
A[i] = i * i;
}
A[17]= -A[17];
}
/**
* anonymous scope #2
* find the index of the smallest number and print it.
*/
{
int result = Find(A);
printf(
"First negative integer in A found at index = %d.\n",
result
);
}
// wait for user input before closing.
getchar();
return 0;
}
이 프로그램은 여러 가지 작업을 끔찍할 정도로 나쁜 스타일로 수행합니다.특히 단일 범위 내에서만 사용되는 글로벌 매크로를 설정하지만 이후 모든 코드를 계속 오염시킵니다.매우 나쁨으로 인해 Windows API가 대규모로 글로벌 범위 오염을 일으킵니다.
또한 이 프로그램은 인수를 포함하는 구조가 없는 어레이로 전달합니다.즉, 어레이는 Find 함수에 도달하면 착하시 불능 상태가 됩니다.어레이의 크기를 알 수 없게 되어 메인 및 Find가 글로벌 매크로에 의존하게 되었습니다.매우 불량합니다.
이 문제를 해결하면서도 코드를 단순하게 유지하는 방법에는 두 가지가 있습니다.첫 번째 방법은 배열을 100개의 정수로 이루어진 배열로 정의하는 글로벌 구조를 작성하는 것입니다.이 방법을 통해 배열을 전달하면 배열의 길이가 유지됩니다.두 번째 방법은 어레이의 길이를 find 인수로 전달하고 어레이를 작성하기 전에 #define만 사용하고 #define을 사용합니다.스코프가 실행 시 오버헤드가 0인 sizeof(A)/sizeof(A[0])를 통해 어레이의 크기를 인식하기 때문에 컴파일러는 100을 추론하여 붙여넣습니다.
이 문제를 세 번째 방법으로 해결하기 위해 범용 어레이를 작성하기 위한 헤더를 만들었습니다.추상적인 데이터 타입이지만 자동화된 데이터 구조라고 부르고 싶습니다.
Simple Array.h
/**
* Make sure that all the options needed are given in order to create our array.
*/
#ifdef OPTION_UNINSTALL
#undef OPTION_ARRAY_TYPE
#undef OPTION_ARRAY_LENGTH
#undef OPTION_ARRAY_NAME
#else
#if (!defined OPTION_ARRAY_TYPE) || !defined OPTION_ARRAY_LENGTH || (!defined OPTION_ARRAY_NAME)
#error "type, length, and name must be known to create an Array."
#endif
/**
* Use the options to create a structure preserving structure for our array.
* that is, in contrast to pointers, raw arrays.
*/
struct {
OPTION_ARRAY_TYPE data[OPTION_ARRAY_LENGTH];
} OPTION_ARRAY_NAME;
/**
* if we are asked to also zero out the memory, we do it.
* if we are not granted access to string.h, brute force it.
*/
#ifdef OPTION_ZERO_MEMORY
#ifdef OPTION_GRANT_STRING
memset(&OPTION_ARRAY_NAME, 0, OPTION_ARRAY_LENGTH * sizeof(OPTION_ARRAY_TYPE));
#else
/* anonymous scope */
{
int i;
for (i = 0; i < OPTION_ARRAY_LENGTH; ++i) {
OPTION_ARRAY_NAME.data[i] = 0;
}
}
#endif
#undef OPTION_ZERO_MEMORY
#endif
#endif
이 헤더는 기본적으로 모든 C 데이터 구조 헤더가 C 프리프로세서를 사용해야 하는 경우(PHP/Templating toolkit/ASP/자신의 임베디드 가능한 스크립트 언어와는 대조적으로 lisp에 관계없이)와 같아야 합니다.
한 바퀴 돌아보자.
#include <stdio.h>
int Find(int A[], int A_length)
{
int j;
for (j = 0; j < A_length; ++j) {
if (A[j] < 0) {
return j;
}
}
return -1;
}
int main(void)
{
// std::array<int, 100> A;
#define OPTION_ARRAY_TYPE int
#define OPTION_ARRAY_LENGTH 100
#define OPTION_ARRAY_NAME A
#include "SimpleArray.h"
/**
* anonymous scope #1
* initialize our array to [0..99],
* then set 18th element to its negative value(-18)
* to make the search more interesting.
*/
{
// loop index, nothing interesting here.
int i;
// initialize our array to [0..99].
for (i = 0; i < (sizeof(A.data) / sizeof(A.data[0])); ++i) {
A.data[i] = i * i;
}
A.data[17]= -A.data[17];
}
/**
* anonymous scope #2
* find the index of the smallest number and print it.
*/
{
int result = Find(A.data, (sizeof(A.data) / sizeof(A.data[0])));
printf(
"First negative integer in A found at index = %d.\n",
result
);
}
// wait for user input before closing.
getchar();
// making sure all macros of SimpleArray do not affect any code
// after this function; macros are file-wide, so we want to be
// respectful to our other functions.
#define OPTION_UNINSTALL
#include "SimpleArray.h"
return 0;
}
순수 C와 C의 프리프로세서로 순진한 std::array를 발명했습니다!우린 매크로를 사용했지만 악마는 아니야. 우리가 뒷처리를 하니까!델의 매크로는 모두 정의되어 있지 않습니다.
있습니다알 수 된 은, 「배열」을 사용하지 않는 . 을 사용하다렇지않않 않않않다다(sizeof(A.data) / sizeof(A.data[0]))
이것은 컴파일러에 오버헤드는 없지만, 아이들에게는 적합하지 않습니다.매크로도 그렇지만, 여기에서는 박스내에서 작업하고 있습니다.나중에 PHP와 같은 보다 친숙한 프리프로세서를 사용해 아이에게 친숙하게 만들 수 있습니다.
이 문제를 해결하기 위해 "자유" 어레이 데이터 구조에서 메서드 역할을 하는 유틸리티 라이브러리를 만들 수 있습니다.
Simple Array Utils.h
/**
* this is a smart collection that is created using options and is
* removed from scope when included with uninstall option.
*
* there are no guards because this header is meant to be strategically
* installed and uninstalled, rather than kept at all times.
*/
#ifdef OPTION_UNINSTALL
/* clean up */
#undef ARRAY_FOREACH_BEGIN
#undef ARRAY_FOREACH_END
#undef ARRAY_LENGTH
#else
/**
* array elements vary in number of bytes, encapsulate common use case
*/
#define ARRAY_LENGTH(A) \
((sizeof A.data) / (sizeof A.data[0]))
/**
* first half of a foreach loop, create an anonymous scope,
* declare an iterator, and start accessing the items.
*/
#if defined OPTION_ARRAY_TYPE
#define ARRAY_FOREACH_BEGIN(name, iter, arr)\
{\
unsigned int iter;\
for (iter = 0; iter < ARRAY_LENGTH(arr); ++iter) {\
OPTION_ARRAY_TYPE name = arr.data[iter];
#endif
/**
* second half of a foreach loop, close the loop and the anonymous scope
*/
#define ARRAY_FOREACH_END \
}\
}
#endif
이것은 기능이 풍부한 라이브러리이며 기본적으로는
ARRAY_LENGH :: 데이터 필드가 -> int 인 모든 것
OPTION_ARRAY_SIZE가 아직 정의되어 있거나 재정의되어 있는 경우에는 헤더에 foreach 루프를 실행하는 방법도 정의되어 있습니다.이것은 귀엽습니다.
이제 미쳐보자.
Simple Array.h
/**
* Make sure that all the options needed are given in order to create our array.
*/
#ifdef OPTION_UNINSTALL
#ifndef OPTION_ARRAY_TYPE
#undef OPTION_ARRAY_TYPE
#endif
#ifndef OPTION_ARRAY_TYPE
#undef OPTION_ARRAY_LENGTH
#endif
#ifndef OPTION_ARRAY_NAME
#undef OPTION_ARRAY_NAME
#endif
#ifndef OPTION_UNINSTALL
#undef OPTION_UNINSTALL
#endif
#else
#if (!defined OPTION_ARRAY_TYPE) || !defined OPTION_ARRAY_LENGTH || (!defined OPTION_ARRAY_NAME)
#error "type, length, and name must be known to create an Array."
#endif
/**
* Use the options to create a structure preserving structure for our array.
* that is, in contrast to pointers, raw arrays.
*/
struct {
OPTION_ARRAY_TYPE data[OPTION_ARRAY_LENGTH];
} OPTION_ARRAY_NAME;
/**
* if we are asked to also zero out the memory, we do it.
* if we are not granted access to string.h, brute force it.
*/
#ifdef OPTION_ZERO_MEMORY
#ifdef OPTION_GRANT_STRING
memset(&OPTION_ARRAY_NAME, 0, OPTION_ARRAY_LENGTH * sizeof(OPTION_ARRAY_TYPE));
#else
/* anonymous scope */
{
int i;
for (i = 0; i < OPTION_ARRAY_LENGTH; ++i) {
OPTION_ARRAY_NAME.data[i] = 0;
}
}
#endif
#undef OPTION_ZERO_MEMORY
#endif
#endif
Simple Array Utils.h
/**
* this is a smart collection that is created using options and is
* removed from scope when included with uninstall option.
*
* there are no guards because this header is meant to be strategically
* installed and uninstalled, rather than kept at all times.
*/
#ifdef OPTION_UNINSTALL
/* clean up, be mindful of undef warnings if the macro is not defined. */
#ifdef ARRAY_FOREACH_BEGIN
#undef ARRAY_FOREACH_BEGIN
#endif
#ifdef ARRAY_FOREACH_END
#undef ARRAY_FOREACH_END
#endif
#ifdef ARRAY_LENGTH
#undef ARRAY_LENGTH
#endif
#else
/**
* array elements vary in number of bytes, encapsulate common use case
*/
#define ARRAY_LENGTH(A) \
((sizeof A.data) / (sizeof A.data[0]))
/**
* first half of a foreach loop, create an anonymous scope,
* declare an iterator, and start accessing the items.
*/
#if defined OPTION_ARRAY_TYPE
#define ARRAY_FOREACH_BEGIN(name, iter, arr)\
{\
unsigned int iter;\
for (iter = 0; iter < ARRAY_LENGTH(arr); ++iter) {\
OPTION_ARRAY_TYPE name = arr.data[iter];
#endif
/**
* second half of a foreach loop, close the loop and the anonymous scope
*/
#define ARRAY_FOREACH_END \
}\
}
#endif
메인
#include <stdio.h>
// std::array<int, 100> A;
#define OPTION_ARRAY_TYPE int
#define OPTION_ARRAY_LENGTH 100
#define OPTION_ARRAY_NAME A
#include "SimpleArray.h"
#define OPTION_UNINSTALL
#include "SimpleArray.h"
int Find(int A[], int A_length)
{
int j;
for (j = 0; j < A_length; ++j) {
if (A[j] < 0) {
return j;
}
}
return -1;
}
int main(void)
{
#define OPTION_ARRAY_NAME A
#define OPTION_ARRAY_LENGTH (sizeof(A.data) / sizeof(A.data[0]))
#define OPTION_ARRAY_TYPE int
#include "SimpleArray.h"
/**
* anonymous scope #1
* initialize our array to [0..99],
* then set 18th element to its negative value(-18)
* to make the search more interesting.
*/
{
#include "SimpleArrayUtils.h"
printf("size: %d.\n", ARRAY_LENGTH(A));
ARRAY_FOREACH_BEGIN(item, i, A)
A.data[i] = i * i;
ARRAY_FOREACH_END
A.data[17] = -A.data[17];
// uninstall all macros.
#define OPTION_UNINSTALL
#include "SimpleArrayUtils.h"
}
/**
* anonymous scope #2
* find the index of the smallest number and print it.
*/
{
#include "SimpleArrayUtils.h"
int result = Find(A.data, (sizeof(A.data) / sizeof(A.data[0])));
printf(
"First negative integer in A found at index = %d.\n",
result
);
// uninstall all macros.
#define OPTION_UNINSTALL
#include "SimpleArrayUtils.h"
}
// wait for user input before closing.
getchar();
// making sure all macros of SimpleArray do not affect any code
// after this function; macros are file-wide, so we want to be
// respectful to our other functions.
#define OPTION_UNINSTALL
#include "SimpleArray.h"
return 0;
}
보다시피, 우리는 이제 자유로운 추상화를 표현할 수 있는 힘을 가지고 있다(컴파일러가 우리를 대신한다). 우리는 필요한 것(구조)만 지불하고 나머지는 버려지고, 글로벌 범위를 오염시키지 않는다.
여기서 PHP의 힘을 강조하는 이유는 HTML 문서의 컨텍스트 밖에서 PHP를 본 사람은 거의 없기 때문입니다.그러나 C 문서나 다른 텍스트 파일에서는 PHP를 사용할 수 있습니다.Templating Toolkit을 사용하면 원하는 스크립트 언어를 매크로에 추가할 수 있습니다.이러한 언어는 네임스페이스, 변수 및 실제 함수를 갖추고 있기 때문에 C 프리프로세서보다 훨씬 좋습니다.이러한 언어는 코드를 생성하는 실제 스크립트를 디버깅하기 때문에 C 프리프로세서가 아니라 C 프리프로세서보다 훨씬 쉽습니다.디버깅을 하는 것은 주로 익숙하기 때문입니다(정신이 정상인 사람은 C 프리프로세서를 가지고 노는 데 몇 시간을 할애하고 익숙해지는 사람).거의 없습니다).
다음은 PHP를 사용하여 이를 수행하는 예입니다.
심플 어레이php
<?php
class SimpleArray {
public $length;
public $name;
public $type;
function __construct($options) {
$this->length = $options['length'];
$this->name = $options['name'];
$this->type = $options['type'];
}
function getArray() {
echo ($this->name . '.data');
}
function __toString() {
return sprintf (
"struct {\n" .
" %s data[%d];\n" .
"} %s;\n"
,
$this->type,
$this->length,
$this->name
);
}
};
?>
main.discloss.main.discloss.
#include <stdio.h>
<?php include('SimpleArray.php'); ?>
int Find(int *A, int A_length)
{
int i;
for (i = 0; i < A_length; ++i)
{
if (A[i] < 0) {
return i;
}
}
return -1;
}
int main(int argc, char **argv)
{
<?php
$arr = new SimpleArray(array(
'name' => 'A',
'length' => 100,
'type' => 'int'
));
echo $arr;
?>
printf("size of A: %d.\n", <?php echo($arr->length); ?>);
/* anonymous scope */
{
int i;
for (i = 0; i < <?php echo($arr->length)?>; ++i) {
<?php $arr->getArray(); ?>[i] = i * i;
}
<?php $arr->getArray(); ?>[17] = -<?php $arr->getArray()?>[17];
}
int result = Find(<?php $arr->getArray();?>, <?php echo $arr->length; ?>);
printf(
"First negative integer in A found at index = %d.\n",
result
);
getchar();
return 0;
}
려려를 php main.php > main.c
그리고나서
gcc main.c -o main
./main
이것은 오브젝트 C와 매우 비슷해 보입니다.이는 기본적으로 목적 C가 하는 일이기 때문입니다.단, 컴파일 시간의 "매크로스"를 실제 런타임에 링크하는 경향이 있습니다(예를 들어 C가 실행 중인 런타임에 php를 사용할 수 있었던 것처럼, C는 php와 대화할 수 있고, php는 C와 대화할 수 있습니다.단, php는 다수의 brack과 같은 작은 언어입니다).ets)의 주요 차이점은 오브젝트 C는 여기서와 같이 "정적"구조를 만드는 방법을 가지고 있지 않다는 것입니다.실제로 오브젝트 C의 오브젝트는 런타임이며, 그 때문에 접근 비용이 훨씬 비싸지만 훨씬 유연하고 구조를 유지하는 반면, C 구조는 헤더가 스코프를 벗어나자마자 바이트로 축소됩니다(개체로서의 위치).내부 태그 부착 유니언을 사용하여 원래 상태로 되돌릴 수 있습니다.)...
다음으로 (프리프로세서를 통해) 인스턴스화하여 같은 C 파일에서 여러 유형을 사용할 수 있는 버전을 나타냅니다.
#include <stdio.h>
#define DEFINE_LL_NODE(CONCRETE_TYPE) \
struct node_of_ ## CONCRETE_TYPE \
{ \
CONCRETE_TYPE data; \
struct node_of_ ## CONCRETE_TYPE *next; \
};
#define DECLARE_LL_NODE(CONCRETE_TYPE,VARIABLE_NAME) \
struct node_of_ ## CONCRETE_TYPE VARIABLE_NAME;
/* Declarations for each type. */
DEFINE_LL_NODE(int)
DEFINE_LL_NODE(char)
int main (void)
{
/* Declaration of instances of each type. */
DECLARE_LL_NODE (int, foo)
DECLARE_LL_NODE (char, bar)
/* And you can then use these instances. */
foo.data = 1;
foo.next = NULL;
bar.data = 'c';
bar.next = NULL;
}
cpp
해했습습니니다
struct node_of_int { int data; struct node_of_int *next; };
struct node_of_char { char data; struct node_of_char *next; };
int main (void)
{
struct node_of_int foo;
struct node_of_char bar;
foo.data = 1;
foo.next = ((void *)0);
bar.data = 'c';
bar.next = ((void *)0);
}
C에서는 프리프로세서 매크로에서는 고품질 템플릿과 같은 작업을 할 수 없습니다.왜냐하면 이러한 매크로는 한 번만 확장되기 때문에 데이터 구조를 재입력할 수 있지만, 일단 처리되면 프로그램 전체가 해당됩니다.
, 이 .void *
C c 、 C 、 C c c c c c 。약화된 유형 체크를 수정하려면 구조물에 "type" 필드를 포함시키는 것을 고려하십시오. 건축시 한 번 사용, 무효가 아니다.그런 다음 구조 유지 보수와 관련된 함수 내에서 유형 검사가 부족하다는 점을 개선할 수 있습니다. 그런 이라면, 그 일은 당신에게도 중요합니다.
정말 하고 싶다면 간단한 방법으로 해결할 수 있다.typedef
:
typedef int data_t;
struct queue
{
data_t* data;
}
해서 '어울리지 않다'를 할 수 되었습니다.data_t
평이한 것이 int
s. 단, 한 번에 여러 유형을 사용할 수 없습니다(적어도 C++ 템플릿의 특정 동작을 C 플레인에서 시뮬레이션할 수 있는 방법은 없습니다).
다른 답변에서는 코드 gen 매크로 중 하나를 사용하여 C11 과부하 매크로로 마무리합니다.이렇게 하면 콜사이트에 너무 많은 타입 정보를 낭비할 필요가 없어집니다.
http://en.cppreference.com/w/c/language/generic
제가 본 댓글 몇 개에 대한 댓글입니다.
실제로 C에서 이 문제를 해결하는 방법은 #define 매크로와 함수 포인터를 중심으로 하는 것입니다.첫 번째 버전에서는 C++ 템플릿은 코드를 복사하고 기호를 생성하여 원본을 텍스트로 "파라미터화"하는 단순한 방법이었다.여기서 스카이는 상상력을 발휘하는 방법의 한계입니다.여러 가지 점에서 활자체크 등에 관해서는 컴파일러의 도움을 크게 기대하지 않기 때문에 주의해 주십시오.
여기서 "C++를 사용하는 것은 어떨까요?"라고 말하는 것은 역효과를 가져옵니다.특히 기능이 없을 때 시뮬레이션하는 방법이 문제였습니다.제 경험상 C++에서도 템플릿을 시뮬레이트한 적이 있습니다.이유를 짐작할 수 있나요?1990년 초였기 때문에 C++와 C++에 템플릿 아이디어가 있었지만, 거의 구현되지 않았습니다.그래서 그런 거야.그 전에도 C에서 했었어요C++는 적어도 함수 포인터를 사용하여 더 이상 클래스 메서드를 시뮬레이션할 필요가 없기 때문에 어느 정도 쉬워졌습니다. 왜냐하면, 음, 당신은 그것에 대한 네이티브 언어 지원을 받았기 때문입니다.그렇지 않으면 C에서와 마찬가지로 #define이 파라메트릭 프로그래밍의 유일한 친구였습니다.
#define q(t) \
typedef struct _q_##t {t v; struct q_##t *next} q_##t;
q(char);
q(int);
int main(void)
{
q_char qc;
q_int qi;
qc.v = 'c';
qc.next = (void *) 0;
qi.v = 42;
qi.next = (void *) 0;
return 0;
}
하지만 그게 네가 원하는 건지 모르겠어...
언급URL : https://stackoverflow.com/questions/10950828/simulation-of-templates-in-c-for-a-queue-data-type
'programing' 카테고리의 다른 글
일식이 시작되지 않음 - Java 가상 시스템을 찾을 수 없습니다. (0) | 2022.10.03 |
---|---|
Javascript를 사용하여 DOM 요소를 대체하려면 어떻게 해야 합니까? (0) | 2022.10.03 |
MySQL의 기본 ON DELETE 동작은 무엇입니까? (0) | 2022.10.03 |
Python 문자열에서 HTML 제거 (0) | 2022.10.03 |
비누 연장 설치 방법 (0) | 2022.10.03 |