在上一学期的系统编程课程中,我们必须在C中实现一个基本的客户端/服务器.初始化结构,比如sock_addr_in
,或者char缓冲区(我们用来在客户端和服务器之间来回发送数据)教授指示我们只使用bzero
而不是memset
初始化它们.他从未解释过为什么,而且我很好奇是否有正当理由呢?
我在这里看到:http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown这bzero
是更有效的,由于一个只能将要归零记忆的事实,所以也没有必须做任何额外的检查memset
.尽管如此,这仍然不一定是绝对不能memset
用于归零内存的理由.
bzero
被认为已弃用,而且不是标准的C函数.根据手册,memset
因此优先考虑bzero
.所以,你为什么要仍然使用bzero
过memset
?只是为了提高效率,还是更多?同样,有什么好处memset
了bzero
,使它成为新的程序的事实上的首选?
假设我们有一个T myarray[100]
带有T = int,unsigned int,long long int或unsigned long long int,将所有内容重置为零的最快方法是什么(不仅用于初始化,而且在我的程序中多次重置内容) ?也许有memset?
像动态数组一样的问题T *myarray = new T[100]
.
我想在C中反复清零一个大的2d数组.这就是我现在所做的:
// Array of size n * m, where n may not equal m
for(j = 0; j < n; j++)
{
for(i = 0; i < m; i++)
{
array[i][j] = 0;
}
}
Run Code Online (Sandbox Code Playgroud)
我尝试过使用memset:
memset(array, 0, sizeof(array))
Run Code Online (Sandbox Code Playgroud)
但这仅适用于1D阵列.当我打印2D阵列的内容时,第一行是零,但随后我得到了一大堆随机大数字,它崩溃了.
memset()
声明返回void*
,它始终与传递给函数的地址相同.
返回值的用途是什么?为什么不回来void
?
我需要byte[]
用一个非零值填充一个.如何在C#中执行此操作而不循环遍历byte
数组中的每个?
更新:评论似乎将此分为两个问题 -
memset
我完全同意,正如埃里克和其他人所指出的,使用一个简单的循环就可以了.问题的关键是看我是否可以学习一些关于C#的新东西:)我认为Juliet的并行操作方法应该比简单的循环更快.
基准: 感谢Mikael Svenson:http://techmikael.blogspot.com/2009/12/filling-array-with-default-value.html
事实证明,for
除非你想使用不安全的代码,否则简单的循环是可行的.
抱歉我的原帖不清楚.埃里克和马克的评论都是正确的; 需要有更多专注的问题.感谢大家的建议和回应.
我在一个系统std::fill
上观察到,与常量值或动态值相比,std::vector<int>
设置常量值时,大型系统显着且持续地较慢:0
1
5.8 GiB/s vs 7.5 GiB/s
但是,对于较小的数据大小,结果是不同的,其中fill(0)
更快:
对于4个GiB数据大小的多个线程,fill(1)
显示更高的斜率,但达到的峰值远低于fill(0)
(51 GiB/s对90 GiB/s):
这提出了次要问题,为什么峰值带宽fill(1)
要低得多.
测试系统是一个双插槽Intel Xeon CPU E5-2680 v3,设置为2.5 GHz(通道/sys/cpufreq
),带有8x16 GiB DDR4-2133.我使用GCC 6.1.0(-O3
)和英特尔编译器17.0.1(-fast
)进行了测试,结果都相同.GOMP_CPU_AFFINITY=0,12,1,13,2,14,3,15,4,16,5,17,6,18,7,19,8,20,9,21,10,22,11,23
被设定了.Strem/add/24个线程在系统上获得85 GiB/s.
我能够在不同的Haswell双插槽服务器系统上重现这种效果,但没有任何其他架构.例如在Sandy Bridge EP上,内存性能是相同的,而在缓存fill(0)
中则要快得多.
这是重现的代码:
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <omp.h>
#include <vector>
using value = int;
using vector = std::vector<value>;
constexpr size_t write_size = 8ll * 1024 * 1024 * 1024;
constexpr size_t …
Run Code Online (Sandbox Code Playgroud) 该联机帮助页说memset
:
Run Code Online (Sandbox Code Playgroud)#include <string.h> void *memset(void *s, int c, size_t n)
的
memset()
功能填充第一n
字节的存储器区域的指向s
与恒定字节c
.
很明显,memset
不能用于初始化int
数组,如下所示:
int a[10];
memset(a, 1, sizeof(a));
Run Code Online (Sandbox Code Playgroud)
它是因为int
由4个字节(比如说)表示,并且一个不能得到数组中整数的所需值a
.
但我经常看到程序员 memset
用来将int
数组元素设置为0
或者-1
.
int a[10];
int b[10];
memset(a, 0, sizeof(a));
memset(b, -1, sizeof(b));
Run Code Online (Sandbox Code Playgroud)
根据我的理解,使用整数初始化0
是可以的,因为0
可以用1个字节表示(在这种情况下可能是我错了).但是,如何可以初始化b
与-1
(一个4个字节的值)?
为什么memset
采取int
作为第二个参数,而不是一个char
,而wmemset
需要wchar_t
的,而不是像long
或long long
?
我正在尝试编写一些带有memset
-style 循环的裸机代码:
for (int i = 0; i < N; ++i) {
arr[i] = 0;
}
Run Code Online (Sandbox Code Playgroud)
它是用 GCC 编译的,GCC 足够聪明,可以将其转换为对memset()
. 不幸的是,因为它是裸机,我没有memset()
(通常在 libc 中)所以我收到链接错误。
undefined reference to `memset'
Run Code Online (Sandbox Code Playgroud)
似乎进行这种转换的优化是-ftree-loop-distribute-patterns
:
执行可以通过调用库生成代码的模式的循环分布。默认情况下,此标志在 -O2 及更高级别以及由
-fprofile-use
和启用-fauto-profile
。
所以一个人的解决方案是降低优化级别。不是很满意。
我还发现这真的有用的网页,说明这-ffreestanding
是不足以让GCC没有做到这一点,而且也根本没有选择,只能提供自己的实现memcpy
,memmove
,memset
和memcmp
。我很乐意这样做,但是怎么做?
如果我只是编写memset
编译器将检测其中的循环并将其转换为对 memset 的调用!事实上,在我使用的 CPU 供应商提供的代码中,我发现了这条评论:
/*
// This is commented out because the assembly code that the compiler generates …
Run Code Online (Sandbox Code Playgroud) 我听说c ++程序员应该避免使用memset,
class ArrInit {
//! int a[1024] = { 0 };
int a[1024];
public:
ArrInit() { memset(a, 0, 1024 * sizeof(int)); }
};
Run Code Online (Sandbox Code Playgroud)
所以考虑到上面的代码,如果你不使用memset,怎么能把[1..1024]填充为0?在C++中memset有什么问题?
谢谢.