模拟C语言中的模板(针对队列数据类型)
我试图用C实现一个模拟C语言中的模板(针对队列数据类型),c,templates,C,Templates,我试图用C实现一个队列结构;队列只能容纳ints,不能容纳其他内容。我想知道我是否可以在C中模拟C++模板(可能通过使用预处理器#define),这样我的队列可以容纳任何数据类型 注意:我不想使用void*。我认为这有点冒险,很容易导致奇怪的运行时错误。实现一个包含void*数据的队列,并将此void*解释为指向任何类型,甚至是int之类的基本类型的指针 使用#define是可能的,但是考虑一下调试,如果出现问题…如果您真的想这样做,可以通过简单的typedef来解决: typedef int
队列结构;队列只能容纳int
s,不能容纳其他内容。我想知道我是否可以在C
中模拟C++
模板(可能通过使用预处理器#define
),这样我的队列可以容纳任何数据类型
注意:我不想使用void*
。我认为这有点冒险,很容易导致奇怪的运行时错误。实现一个包含void*数据的队列,并将此void*解释为指向任何类型,甚至是int之类的基本类型的指针
使用#define是可能的,但是考虑一下调试,如果出现问题…如果您真的想这样做,可以通过简单的typedef
来解决:
typedef int data_t;
struct queue
{
data_t* data;
}
您现在可以在所有位置使用data\u t
,而不是普通的int
s。但是,请注意,你不能同时使用多个类型(至少,我不知道C++ C++模板的特定行为如何在普通C中模拟)。因为,这些宏只会扩展一次,所以您最多只能得到一个可以重新键入的数据结构,但一旦处理,整个程序的数据结构就是这种类型
这意味着您需要考虑<代码>空白> /COD>类型解决方案,这削弱了C的类型检查。若要尝试修复弱化类型检查,请考虑在结构中嵌入“类型”字段,该字段是“在结构中赋值一次”字符串,表示非空洞*类型。然后,您可以改进与维护结构相关的函数中缺少类型检查的情况。也就是说,如果这样的事情对你来说甚至很重要的话。
那么,我脑海中唯一想到的可能就是宏(#define
s)。可能是这样的:
队列.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
...
队列\u impl.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%确定,因为我不是这样的预处理器专家),它应该给你结构int\u queue
和float\u queue
,以及函数
void int_queue_insert(int_queue *queue, int data);
void float_queue_insert(float_queue *queue, float data);
当然,对于所有需要的类型,您必须自己实例化“模板”,但这相当于重复queue.h
中的5行块。实际实现只需编写一次。当然,您可以进一步完善这一点,但基本思想应该是明确的
这将至少为您提供完全类型安全的队列模板,尽管缺乏完全匹配接口的便利性(函数必须带有类型名,因为C不支持重载函数)
但我不确定这是您想要的…这里有一个版本,可以让您实例化(通过预处理器)并在同一个C文件中使用多种类型(小心,它使用):
您可以使用微妙和丑陋的技巧来创建此类模板。下面是我要做的:
创建模板化列表
宏来定义列表
我首先创建一个宏,我们称之为define\u list(type)
,它将为给定类型的列表创建所有函数。然后,我将创建一个全局结构,其中包含指向所有列表函数的函数指针,然后在列表的每个实例中都有一个指向该全局结构的指针(请注意,它与。这种事情,
#定义列表(类型)\
\
结构列表类型\
\
类型定义结构\
{ \
int(*为空)(常量结构列表类型*)\
大小(*大小)(常量结构列表类型*)\
常量类型(*前面)(常量结构列表类型*)\
void(*推前)(结构列表类型*,类型)\
}_列表u函数35;#类型\
\
类型定义结构列表元素类型\
{ \
类型数据\
结构列表元素类型*下一步\
}列表元素类型\
\
typedef结构u列表35;#类型\
{ \
大小(t)大小;\
首先列出元素类型*\
列表元素类型*\u最后\
_列出u函数35;#类型*_函数\
}列表类型\
\
列表类型*新列表类型()\
bool list_为空35;##类型(const list_35;##类型*列表)\
大小列表大小类型(常数列表类型*列表)\
常数类型列表u前35;#类型(常数列表##类型*列表)\
无效列表u push 35; front 35;#type(列表###type*list,type elem)\
\
布尔列表为空类型(常量列表类型*列表)\
{ \
返回列表->\u size==0\
} \
\
大小列表大小类型(常数列表类型*列表)\
{ \
返回列表->\u大小\
} \
\
常数类型列表u前35;#类型(常数列表##类型*列表)\
{ \
返回列表->\u第一->\u数据\
} \
\
无效列表u推35;前35;##类型(列表###类型*列表,类型elem)\
{ \
... \
} \
\
_列表函数类型列表函数类型={\
&列表为空类型\
&列表大小类型\
&列表前面的类型\
&列表(推)前(推###类型)\
}; \
\
列表类型*新列表类型()\
{ \
List##type*res=(List##type*)malloc(sizeof(List#type))\
res->_size=0\
res->_first=NULL\
res->_functions=&_list_funcs_35;#type\
返回res\
}
#定义列表(类型)\
列表类型
#定义新列表(类型)\
新的列表类型()
通用接口
以下是一些宏,它们通过存储的函数指针简单地调用列表的函数:
#定义为空(集合)\
集合->函数->为空(集合)
#定义大小(集合)\
集合->函数->大小(集合)
#定义前端(集合)\
收集->功能->前部(收集)
#定义推送前端(集合、元素)\
收集->功能->向前推送(收集,元素)
请注意,如果使用相同的结构来设计列表以外的其他集合,则可以使用la
#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;
}
#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;
}
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);
}
#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;
}
/**
* 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
#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;
}
/**
* 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
/**
* 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
/**
* 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
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
);
}
};
?>
#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;
}
gcc main.c -o main
./main