如果我需要为一块内存分配零。如果架构是 32 位,long long
那么分配(在特定架构上是 8 个字节)比分配int
(4 个字节)更有效,还是等于两个 int 分配?并且int
分配比使用相同的内存块分配更有效,因为如果我使用vs char
,我需要循环 4 次char
int
5 回答
为什么不使用memset()
?
http://www.elook.org/programming/c/memset.html
(来自上面的网站)
句法:
#include <string.h>
void *memset( void *buffer, int ch, size_t count );
描述:
函数 memset() 将 ch 复制到缓冲区的第一个 count 个字符中,并返回缓冲区。memset() 对于将一段内存初始化为某个值很有用。例如,这个命令:
memset( the_array, '\0', sizeof(the_array) );
是将 the_array 的所有值设置为零的一种非常有效的方法。
对于您的问题,如果编译器是智能/优化的,答案将是肯定的。
有趣的是,在具有 SSE 的机器上,我们仍然可以使用 128 位块 :),这只是我的观点,始终尝试强调可读性与简洁性之间的平衡,所以是的......我倾向于使用memset
,它并不总是完美的,并且可能不是最快的,但它告诉维护代码的人“嘿,我正在初始化或设置这个数组”
无论如何,这里有一些测试代码,如果需要任何更正,请告诉我。
#include <time.h>
#include <xmmintrin.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define NUMBER_OF_VALUES 33554432
int main()
{
int *values;
int result = posix_memalign((void *)&values, 16, NUMBER_OF_VALUES * sizeof(int));
if (result)
{
printf("Failed to mem allocate \n");
exit(-1);
}
clock_t start, end;
int *temp = values, total = NUMBER_OF_VALUES;
while (total--)
*temp++ = 0;
start = clock();
memset(values, 0, sizeof(int) * NUMBER_OF_VALUES);
end = clock();
printf("memset time %f\n", ((double) (end - start)) / CLOCKS_PER_SEC);
start = clock();
{
int index = 0, total = NUMBER_OF_VALUES * sizeof(int);
char *temp = (char *)values;
for(; index < total; index++)
temp[index] = 0;
}
end = clock();
printf("char-wise for-loop array indices time %f\n", ((double) (end - start)) / CLOCKS_PER_SEC);
start = clock();
{
int index = 0, *temp = values, total = NUMBER_OF_VALUES;
for (; index < total; index++)
temp[index] = 0;
}
end = clock();
printf("int-wise for-loop array indices time %f\n", ((double) (end - start)) / CLOCKS_PER_SEC);
start = clock();
{
int index = 0, total = NUMBER_OF_VALUES/2;
long long int *temp = (long long int *)values;
for (; index < total; index++)
temp[index] = 0;
}
end = clock();
printf("long-long-int-wise for-loop array indices time %f\n", ((double) (end - start)) / CLOCKS_PER_SEC);
start = clock();
{
int index = 0, total = NUMBER_OF_VALUES/4;
__m128i zero = _mm_setzero_si128();
__m128i *temp = (__m128i *)values;
for (; index < total; index++)
temp[index] = zero;
}
end = clock();
printf("SSE-wise for-loop array indices time %f\n", ((double) (end - start)) / CLOCKS_PER_SEC);
start = clock();
{
char *temp = (char *)values;
int total = NUMBER_OF_VALUES * sizeof(int);
while (total--)
*temp++ = 0;
}
end = clock();
printf("char-wise while-loop pointer arithmetic time %f\n", ((double) (end - start)) / CLOCKS_PER_SEC);
start = clock();
{
int *temp = values, total = NUMBER_OF_VALUES;
while (total--)
*temp++ = 0;
}
end = clock();
printf("int-wise while-loop pointer arithmetic time %f\n", ((double) (end - start)) / CLOCKS_PER_SEC);
start = clock();
{
long long int *temp = (long long int *)values;
int total = NUMBER_OF_VALUES/2;
while (total--)
*temp++ = 0;
}
end = clock();
printf("long-ling-int-wise while-loop pointer arithmetic time %f\n", ((double) (end - start)) / CLOCKS_PER_SEC);
start = clock();
{
__m128i zero = _mm_setzero_si128();
__m128i *temp = (__m128i *)values;
int total = NUMBER_OF_VALUES/4;
while (total--)
*temp++ = zero;
}
end = clock();
printf("SSE-wise while-loop pointer arithmetic time %f\n", ((double) (end - start)) / CLOCKS_PER_SEC);
free(values);
return 0;
}
这里有一些测试:
$ gcc time.c
$ ./a.out
memset time 0.025350
char-wise for-loop array indices time 0.334508
int-wise for-loop array indices time 0.089259
long-long-int-wise for-loop array indices time 0.046997
SSE-wise for-loop array indices time 0.028812
char-wise while-loop pointer arithmetic time 0.271187
int-wise while-loop pointer arithmetic time 0.072802
long-ling-int-wise while-loop pointer arithmetic time 0.039587
SSE-wise while-loop pointer arithmetic time 0.030788
$ gcc -O2 -Wall time.c
MacBookPro:~ samyvilar$ ./a.out
memset time 0.025129
char-wise for-loop array indices time 0.084930
int-wise for-loop array indices time 0.025263
long-long-int-wise for-loop array indices time 0.028245
SSE-wise for-loop array indices time 0.025909
char-wise while-loop pointer arithmetic time 0.084485
int-wise while-loop pointer arithmetic time 0.025277
long-ling-int-wise while-loop pointer arithmetic time 0.028187
SSE-wise while-loop pointer arithmetic time 0.025823
我的资料:
$ gcc --version
i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5666) (dot 3)
Copyright (C) 2007 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ uname -a
Darwin MacBookPro 10.8.0 Darwin Kernel Version 10.8.0: Tue Jun 7 16:33:36 PDT 2011; root:xnu-1504.15.3~1/RELEASE_I386 i386
memset
可能使用内联汇编进行了相当优化,尽管这又因编译器而异...
当一些时间开始收敛时,gcc 似乎在非常积极地优化-O2
我想我应该看看程序集。
如果你是古玩,只需打电话gcc -S -msse2 -O2 -Wall time.c
,大会就在time.s
始终避免在高级编程语言中进行额外的迭代。如果您只在 int 上迭代一次,而不是在其字节上循环,您的代码将更有效率。
大多数体系结构都进行了分配优化,因此它们与 32 位 x86 的 4 字节字长对齐。因此,分配相同大小的内存并不重要(1MB 的 long 类型的 memset 和 1MB 的 char 类型之间没有区别)。
1. long long(8 bytes) vs two int(4 bytes)
- 最好长期长期。因为分配一个 8 字节元素而不是两个 4 字节元素时性能会更好。
2. int (4 bytes) vs four char(1 bytes)
- 最好在这里寻找 int。
如果您只声明一个元素,那么您可以直接分配零,如下所示。
long long a;
int b;
....
a = 0; b = 0;
但是,如果您要声明n
元素数组,那么请使用memeset
如下所示的功能。
long long a[10];
int b[20];
....
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
如果您想在声明本身期间进行初始化,则不需要memset
.
long long a = 0;
int b = 0;
或者
long long a[10] = {0};
int b[20] = {0};