_memcpy、_memset 的问题,搞了3天快疯了!

Sandrer 2009-10-24 08:26:35
我使用的是 VS2005,正在写一个标准库文件!
我设置编译器忽略所有默认库,然后自己写了一个 Memset、Memcpy 的函数来替换默认的函数(代码里也没有使用 new,而改用 GlobalAlloc 函数)!
但是当编译的时候,总是提示:
error LNK2001: 无法解析的外部符号 _memcpy
或者
error LNK2001: 无法解析的外部符号 _memset

但是我综观所有代码,都没有调用 memcpy 和 memset 函数啊!

下面是我自己写的 Memset 和 Memcpy 函数:
void * Memset(void *dst, int val, UINT count)
{
void *start = dst;

while (count--) {
*(char *)dst = (char)val;
dst = (char *)dst + 1;
}

return start;
}

void * Memcpy(void *lpDst, const void *lpSrc, UINT uSize)
{
void *lpRet = lpDst;

while (uSize--) {
*(char *)lpDst = *(char *)lpSrc;
lpDst = (char *)lpDst + 1;
lpSrc = (char *)lpSrc + 1;
}

return lpRet;
}


出错的地方(我都是把每个代码文件都注释一部分,然后看看有没有错误!如果有则表示出错的地方不在注释的部分;如果没有则表示出错的地方就是我注释掉的位置)总是出现在下面几个情况:

1、调用 Memcpy 或 Memset 时
我在包含这两个函数体实现代码的 cpp 文件中调用它们的时候没出错!但在其它的 cpp 文件中调用的话就会出错(我已经引用了头文件,或者使用 extern 来定义它们,但还是出现 error LNK2001: 无法解析的外部符号 _memxxx 这个错误

2、初始化结构变量的时候
例如:
NONCLIENTMETRICS ncm = {sizeof(NONCLIENTMETRICS)}; ← 这样会出错:error LNK2001: 无法解析的外部符号 _memset
但是:
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(NONCLIENTMETRICS);
这样就没有错误!

连续搞了三天了,网上也没有发现我这情况,也不知道问题出在哪里!!!!!!

可能我表达的问题不够详细,有不明白的地方请举手!
...全文
2517 23 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
fire_cpp 2010-02-16
  • 打赏
  • 举报
回复 1
楼主,我也遇到同样的问题——优化惹的祸。
看到这样的循环,VC可能给你优化成了memset。
把优化disable掉就OK了。日的……
bragi523 2009-10-27
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 tr0j4n 的回复:]
和系统函数重名了嘛,你换个函数名就好了


[/Quote]up
MoXiaoRab 2009-10-27
  • 打赏
  • 举报
回复
和系统函数重名了嘛,你换个函数名就好了

loop_k 2009-10-27
  • 打赏
  • 举报
回复
up
awperpvip 2009-10-24
  • 打赏
  • 举报
回复
up,现场看看才好定。。
Sandrer 2009-10-24
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 weiym 的回复:]
1. 不知道程序的入口点有没有自定义, 系统Crt在调用我们的Main函数之前还有一段初始化代码,你应该自定义程序入口
2. C++中用 extern C void * Memset(void *dst, int val, UINT count);来申明函数,不然编译器生成的函数名不是_Memset

[/Quote]
关于第2点,好象没什么关系吧~~~~~~~
况且我照你说的改了,还是相同错误......
Sandrer 2009-10-24
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 weiym 的回复:]
1. 不知道程序的入口点有没有自定义, 系统Crt在调用我们的Main函数之前还有一段初始化代码,你应该自定义程序入口
2. C++中用 extern C void * Memset(void *dst, int val, UINT count);来申明函数,不然编译器生成的函数名不是_Memset

[/Quote]
VS2005 在写 WIN32 工程的时候,都会默认生成一个 DllMain 函数!
我把入口点改为了这个函数,不使用默认库里提供的函数了!
Sandrer 2009-10-24
  • 打赏
  • 举报
回复
还有一点,如果不去除默认库,到时把文件发给客户的时候,需要把 C++ Runtime 库连带发给对方!
如果你不发,万一程序到了对方手里运行不了,他会说你程序有问题(其实有很多 C++ Runtime 库系统不一定自带的)!
如果发,他又说你做的程序怎么这么大、这么多文件!
好吧,就用静态连接到库吧!!谁知道对方又说你:就这么个标准库,就几个函数而已,干嘛要搞到过百KB的大小!
weiym 2009-10-24
  • 打赏
  • 举报
回复
1. 不知道程序的入口点有没有自定义, 系统Crt在调用我们的Main函数之前还有一段初始化代码,你应该自定义程序入口
2. C++中用 extern C void * Memset(void *dst, int val, UINT count);来申明函数,不然编译器生成的函数名不是_Memset
Sandrer 2009-10-24
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 heksn 的回复:]
如果是自己用的话  为何不换个函数名字呢
[/Quote]

试过了,但是还是照样在相同的位置发生错误!!!!
连参数类型、参数名称我都试过更换,但还是一样错误!
所以不知道是不是编译器的问题!
Sandrer 2009-10-24
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 muzizongheng 的回复:]
我设置编译器忽略所有默认库,char类型什么的程序认识?
[/Quote]
认识!TCHAR 类型是定义在 WinNT.h 中,所以程序里只包含一个 Windows.h 文件头就可以了!


所谓的忽略所有默认库,其实就是指 C++ 的 Runtime 库
请看下图:
可以看到,如果不忽略所有库的话,文件的大小是忽略库后的大小的几倍!
注:图中大小8K的文件,就是最终生成的文件!我是把所有发生连接错误的地方都注释掉才生成的,否则会失败!


[Quote=引用 9 楼 zoulie 的回复:]
标准库里的函数是静态联接的,只有一个lib文件的
NONCLIENTMETRICS ncm = {sizeof(NONCLIENTMETRICS)}; 出错
估计是结构体的赋值操作是bit copy,底层可能调用了memset之类的函数来实现
[/Quote]
那为什么我在调用我自己写的 Memcpy 函数的时候,也会发生连接错误呢?
Memcpy 函数里是直接用指针操作,并没有调用 _memcpy 吧~~~~~
而且这个连接错误只在包含有函数体实现代码之外的 CPP 文件里才会发生~~~
  • 打赏
  • 举报
回复
如果是自己用的话 为何不换个函数名字呢
whs1980 2009-10-24
  • 打赏
  • 举报
回复
关于Initializer Lists和memset的内容

Q
I have a question about initializing class members in C++. I see a lot of co
de (your column included) that does this:
CSomeClass::CSomeClass()
{
x=0;
y=1;
}
and in other places I see it written this way:
CSomeClass::CSomeClass() : x(0), y(1)
{
}
Some of my programmer friends say that it's better to do it the second way,
but no one knows why. Can you tell me the difference between these two metho
ds of initializing class members?
A
Technically your friends are right, but in most cases it makes no difference
. There are two reasons to use the second syntax, which is called a member i
nitialization list: one is necessity, the other efficiency.
Let's examine the first reason—necessity. Suppose you have a class me
mber that is itself a class or struct, and this class only has one construct
or that requires an argument.
class CMember {
public:
CMember(int x) { ... }
};
Since CMember has an explicit constructor, the compiler does not generate a
default constructor (one with no arguments) and there is no way to create an
instance of CMember without an integer.
CMember* pm = new CMember; // Error!!
CMember* pm = new CMember(2); // OK
How do you initialize CMember if it's a member of another class? You m
ust use the member initialization list.
class CMyClass {
CMember m_member;
public:
CMyClass();
};
// must use initializer list
CMyClass::CMyClass() : m_member(2)
{
???
}
There's simply no other way to pass the argument to m_member. The same is tr
ue if the member is a const object or reference. According to the rules of C
++, const objects and references cannot be assigned; they can only be initia
lized.
The second reason for using the initializer list—efficiency—arises w
hen the member class has a default constructor as well as an assignment oper
ator. MFC's CString offers a perfect example. Say you have a class CMyClass
with a CString member m_str and you want to initialize m_str to "yada yada."
You have two choices
CMyClass::CMyClass() {
// use assignment operator
// CString::operator=(LPCTSTR);
m_str = _T("yada yada");
}
or
// use initializer list
// and constructor CString::CString(LPCTSTR)
CMyClass::CMyClass() : m_str(_T("yada yada"))
{
}
Is there any difference between these methods? Yes. The compiler alway
s insures that all member objects are initialized before the body of the con
structor executes, so in the first example the compiled code will call CStri
ng::CString to initialize m_str before control reaches the assignment statem
ent. In the second example, the compiler generates a call to CString:: CStri
ng(LPCTSTR), passing "yada yada" as the string. The upshot is that in the fi
rst example two CString functions are called (constructor and assignment ope
rator), whereas in the second example only one function is called.
In the case of CString it hardly matters, since the default constructo
r is inline and CString only allocates storage for the string when it's need
ed (that is, when you actually set it to something). But, in general, the du
plicate function call can be wasteful, particularly if both constructor and
assignment operator allocate storage. In some large classes, you may have a
constructor and assignment operator that both call the same Init function, w
hich allocates a large amount of memory. In that particular case, you must u
se the initializer list in order to avoid needlessly allocating the storage
twice.
In the case of built-in types like ints or longs or other types with n
o constructors, there's no performance difference between initializing an in
t in the initializer list or assigning it in the constructor body. Either wa
y, there will be one assignment. Some programmers say you should always use
the initializer list just to get in the habit, but I have never found it dif
ficult to switch between the two methods as needed. Stylistically, I prefer
assignment in the body because there's more room for formatting and comments
, and you can write things like
x=y=z=0;
or
memset(this,0,sizeof(this));
Note that the second snippet is decidedly non-object-oriented.
While I'm on the subject of initializer lists, there's one peculiar fe
ature I should warn you about. C++ initializes class members in the order th
ey are declared, not the order they appear in the initializer list.
class CMyClass {
CMyClass(int x, int y);
int m_x;
int m_y;
};
CMyClass::CMyClass(int i) : m_y(i), m_x(m_y)
{
}
You might think that the previous code would first assign m_y=i and th
en m_x=m_y so that both m_x and m_y would have the same value. But the compi
ler initializes m_x first then m_y, since that's the order in which they are
declared. The result is that m_x will have an unpredictable value. My examp
le is contrived to illustrate the point, but there are times when this bug a
rises more naturally. There are two ways to avoid it. First, always declare
members in the order you want them initialized. Second, if you decide to use
an initializer list, always list the members in the same order they're decl
ared. This will help you avoid confusion.


百事烟 2009-10-24
  • 打赏
  • 举报
回复
这么说atl用的不是标准库
zoulie 2009-10-24
  • 打赏
  • 举报
回复
标准库里的函数是静态联接的,只有一个lib文件的
NONCLIENTMETRICS ncm = {sizeof(NONCLIENTMETRICS)}; 出错
估计是结构体的赋值操作是bit copy,底层可能调用了memset之类的函数来实现
百事烟 2009-10-24
  • 打赏
  • 举报
回复
MSVCRT40.DLL
心留 2009-10-24
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 delphigis 的回复:]
Memset、Memcpy 用C/C++ Runtime提供的就好,不用自己写
C/C++ Runtime的DLL文件在操作系统目录下,只要安装操作系统就有了
[/Quote]

同意
百事烟 2009-10-24
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 wltg2001 的回复:]
引用 2 楼 delphigis 的回复:
Memset、Memcpy 用C/C++ Runtime提供的就好,不用自己写
C/C++ Runtime的DLL文件在操作系统目录下,只要安装操作系统就有了

C/C++ Runtime并不提供DLL文件,也不在操作系统目录下,它是用静态连接的.
[/Quote]
无语...
  • 打赏
  • 举报
回复
帮顶!
wltg2001 2009-10-24
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 delphigis 的回复:]
Memset、Memcpy 用C/C++ Runtime提供的就好,不用自己写
C/C++ Runtime的DLL文件在操作系统目录下,只要安装操作系统就有了
[/Quote]
C/C++ Runtime并不提供DLL文件,也不在操作系统目录下,它是用静态连接的.
加载更多回复(3)

16,547

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧