优化(C语言):多个函数调用与一个函数调用
例如,我想创建一个函数(优化(C语言):多个函数调用与一个函数调用,c,optimization,function-calls,C,Optimization,Function Calls,例如,我想创建一个函数(insertNode),将节点添加到列表中。每次我想添加一个节点时,调用insertNode,或者将所有节点存储在一个数组中,通过将数组作为参数传递给函数,只调用一次insertNode,让函数完成其余的工作,是不是更快 代码示例: typedef struct Data { int *myArray; //the array where all integers are stored int firstAvailablePos;
insertNode
),将节点添加到列表中。每次我想添加一个节点时,调用insertNode
,或者将所有节点存储在一个数组中,通过将数组作为参数传递给函数,只调用一次insertNode
,让函数完成其余的工作,是不是更快
代码示例:
typedef struct Data {
int *myArray; //the array where all integers are stored
int firstAvailablePos; //the first free position of myArray
} Data;
insertNode(Data *data, int newNum) {
(data->myArray)[data->firstAvailablePos] = newNum;
(data->firstAvailablePos)++;
}
alt_insertNode(Data *data, int *array, int arraySize) {
int i;
for(i = 0; i < arraySize; i++)
(data->myarray)[i] = array[i];
}
anArraySize = 0;
while (...) {
...
anArray[i] = newNum;
anArraySize++;
...
}
alt_insertNode(data, anArray, anArraySize);
这将取决于程序中的许多内容。具体来说,节点是通过某种算法排序的,还是顺序不重要?如果是这样的话,传递数组节点或单独插入不会有太大的区别(对块或信息进行排序和将节点插入到排序位置应该是等效的)
你也可以考虑程序中的哪些节点需要插入到列表中。如果列表使用动态内存,则需要在需要时沿线路插入节点。
这取决于基线列表实现的结构。如果这是一个数组,并且insertNode附加了它,那么它会被复制到内存中的一个新位置,在这个位置上有更多的可用空间,以便新元素也可以放入。新元素也得到了memcpyd。这很快,因为它发生在内核中,而不是在用户空间程序中 另一方面,如果你有类似链表的东西,其中以数组形式存储指向其他列表的指针。这样,您甚至不必复制列表中的所有元素,只需插入一个指向链接列表的新指针,该指针指向包含新元素的数组。那太快了从我目前所知道的情况来看,最好的答案是:这取决于调用代码的样子。这取决于调用代码的样子,但一般来说,如果短函数调用可以内联,则开销为零。创建一个临时数组只是为了避免函数调用开销几乎肯定是一个错误——但在某些情况下,像这样的“批处理”可以避免一系列每次插入的开销,而且可能有意义
同时尝试和基准测试。函数调用比迭代花费的时间更长。如果通过调用insertNode函数插入节点,则需要一些迭代(取决于要插入的位置)才能在列表中插入该节点,但如果要插入大量节点,则每次都需要调用该函数。这可能会耗费时间 如果通过将某个节点放入数组并最后调用insertNode将数组的节点复制到列表中来插入节点。这次insertNode的调用时间将减少,但交互次数将增加。这不会像函数调用那样耗费时间
这里需要注意的一点是,阵列需要额外的内存。您的代码有问题:
- 函数定义使用过时的语法。隐式返回类型在现代C代码中不再受支持,您应该将其指定为
void
- 使用额外的括号会使代码看起来很尴尬
- 函数
不检查insertNode
指向的数组是否足够大。如果需要,您应该检查并重新分配阵列myArray
- 函数
不检查可用空间,也不更新alt\u insertNode
firstAvailablePos
malloc()
分配中间数组。对特定测试用例进行基准测试将告诉您哪一个更有效。然而,请注意,使代码尽可能简单是很有价值的
下面是一个更完整的实现,可用于运行测试:
typedef struct Data {
int *myArray; // the array where all integers are stored
size_t size; // the number of int that can be stored
size_t firstAvailablePos; // the first free position of myArray
} Data;
/* reallocating the array with a simple exponential growth */
int insertNode(Data *data, int newNum) {
if (data->firstAvailablePos == data->size) {
size_t newSize = (data->size < 32) ? 32 : data->size + data->size / 2;
int *array = realloc(myArray, newSize * sizeof(*array));
if (array == NULL)
return -1;
data->myArray = array;
data->size = newSize;
}
data->myArray[data->firstAvailablePos++] = newNum;
return 0;
}
int alt_insertNode(Data *data, int *array, size_t arraySize) {
if (data->firstAvailablePos + arraySize > data->size) {
size_t newSize = (data->size < 32) ? 32 : data->size + data->size / 2;
while (newSize < data->firstAvailablePos + arraySize) {
newSize += newSize / 2;
}
int *array = realloc(myArray, newSize * sizeof(*array));
if (array == NULL)
return -1;
data->myArray = array;
data->size = newSize;
}
memcpy(data->myArray + data->firstAvailablePos, array, arraySize * sizeof(*array));
data->firstAvailablePos += arraySize;
return 0;
}
typedef结构数据{
int*myArray;//存储所有整数的数组
size\u t size;//可以存储的int数
size\u t firstAvailablePos;//myArray的第一个可用位置
}数据;
/*以简单的指数增长重新分配阵列*/
int insertNode(数据*Data,int newNum){
如果(数据->第一个可用EPOS==数据->大小){
大小\u t新闻大小=(数据->大小<32)?32:数据->大小+数据->大小/2;
int*array=realloc(myArray,newSize*sizeof(*array));
if(数组==NULL)
返回-1;
数据->myArray=array;
数据->大小=新闻大小;
}
data->myArray[data->firstAvailablePos++]=newNum;
返回0;
}
int alt_insertNode(数据*数据,int*数组,大小\u t数组大小){
如果(数据->第一个可用项+阵列大小>数据->大小){
大小\u t新闻大小=(数据->大小<32)?32:数据->大小+数据->大小/2;
而(新闻大小firstAvailablePos+arraySize){
newSize+=newSize/2;
}
int*array=realloc(myArray,newSize*sizeof(*array));
if(数组==NULL)
返回-1;
数据->myArray=array;
数据->大小=新闻大小;
}
memcpy(data->myArray+data->firstAvailablePos,array,arraySize*sizeof(*array));
data->firstAvailablePos+=阵列化;
返回0;
}
将代码发布到您的两种方法中会产生更好的具体反馈。这取决于您必须选择的每种方法在列表中添加一项的单独成本。你能测量一下吗?或者发布代码,让我们计算复杂性。我认为在这种情况下,每次调用都会更加优化,因为如果将它们放入数组中(这是赋值操作+查找空的操作),那么当您得到完整的表时,您将调用函数insert的节点,该节点最终将与第一个选项中的函数相同,但具有大的for循环“内核”绝对不是
typedef struct Data {
int *myArray; // the array where all integers are stored
size_t size; // the number of int that can be stored
size_t firstAvailablePos; // the first free position of myArray
} Data;
/* reallocating the array with a simple exponential growth */
int insertNode(Data *data, int newNum) {
if (data->firstAvailablePos == data->size) {
size_t newSize = (data->size < 32) ? 32 : data->size + data->size / 2;
int *array = realloc(myArray, newSize * sizeof(*array));
if (array == NULL)
return -1;
data->myArray = array;
data->size = newSize;
}
data->myArray[data->firstAvailablePos++] = newNum;
return 0;
}
int alt_insertNode(Data *data, int *array, size_t arraySize) {
if (data->firstAvailablePos + arraySize > data->size) {
size_t newSize = (data->size < 32) ? 32 : data->size + data->size / 2;
while (newSize < data->firstAvailablePos + arraySize) {
newSize += newSize / 2;
}
int *array = realloc(myArray, newSize * sizeof(*array));
if (array == NULL)
return -1;
data->myArray = array;
data->size = newSize;
}
memcpy(data->myArray + data->firstAvailablePos, array, arraySize * sizeof(*array));
data->firstAvailablePos += arraySize;
return 0;
}