I find that memset is not included in either string.h or cstring in
C++Builder. I think this is very serious bug which degrade C++Builder's
standard conformance.
Li Zhou
. Ed
> Li Zhou wrote in message
> news:4556...@newsgroups.borland.com...
Can you verify that by compiling a program? _str.h is included by
string.h and cstring but my C++Builder ( Part of Borland Developer
Studio 2006 ) just can't find memset.
Li Zhou
John.
> Show the code that does not compile.
>
> John.
To duplicate this error, visit http://www.itk.org/files/v2.2/ and
download InsightToolkit-2.2.0 ( either the tar.gz or the zip ).
Uncompress the archive and use cmake ( download from
http://www.cmake.org ) to generate borland makefiles. The error will
appear while compiling metaEllipse.cxx
Li Zhou
For that you need to pay money for a consultant to do the significant hours
needed for that.
You are in a peer support group where fellow developers offer help on their
own time without asking for compensation.
Cut down the code you have to a minimum piece which compiles except for the
problem you have mentioned. Post that minimum piece of code. It typically
will be less than 50 lines.
Do not be suprised if you find that you have solved the problem in the
process of understanding the code enough to cut it down.
. Ed
> Li Zhou wrote in message
> news:4557...@newsgroups.borland.com...
Here is the code of metaEllipse.cxx. The memset call is in the Clear()
member function. The rest code is irrelevant.
#include <stdio.h>
#include <ctype.h>
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <metaUtils.h>
#include <metaObject.h>
#include <metaEllipse.h>
//
// MedImage Constructors
//
MetaEllipse::
MetaEllipse()
:MetaObject()
{
if(META_DEBUG) std::cout << "MetaEllipse()" << std::endl;
Clear();
}
//
MetaEllipse::
MetaEllipse(const char *_headerName)
:MetaObject()
{
if(META_DEBUG) std::cout << "MetaEllipse()" << std::endl;
Clear();
Read(_headerName);
}
//
MetaEllipse::
MetaEllipse(const MetaEllipse *_ellipse)
:MetaObject()
{
if(META_DEBUG) std::cout << "MetaEllipse()" << std::endl;
Clear();
CopyInfo(_ellipse);
}
MetaEllipse::
MetaEllipse(unsigned int dim)
:MetaObject(dim)
{
if(META_DEBUG) std::cout << "MetaEllipse()" << std::endl;
Clear();
}
//
MetaEllipse::
~MetaEllipse()
{
M_Destroy();
}
//
void MetaEllipse::
PrintInfo() const
{
MetaObject::PrintInfo();
std::cout << "Radius = ";
for(int i=0;i<m_NDims;i++)
{
std::cout << m_Radius[i] << " ";
}
std::cout << std::endl;
}
void MetaEllipse::
CopyInfo(const MetaEllipse * _ellipse)
{
MetaObject::CopyInfo(_ellipse);
}
void MetaEllipse::
Radius(const float* radius)
{
for(int i=0; i<m_NDims; i++)
{
m_Radius[i] = radius[i];
}
}
void MetaEllipse::
Radius(float radius)
{
for(int i=0;i<m_NDims;i++)
{
m_Radius[i] = radius;
}
}
void MetaEllipse::
Radius(float r1,float r2)
{
m_Radius[0] = r1;
m_Radius[1] = r2;
}
void MetaEllipse::
Radius(float r1,float r2, float r3)
{
m_Radius[0] = r1;
m_Radius[1] = r2;
m_Radius[2] = r3;
}
const float* MetaEllipse::
Radius(void) const
{
return m_Radius;
}
/** Clear ellipse information */
void MetaEllipse::
Clear(void)
{
if(META_DEBUG) std::cout << "MetaEllipse: Clear" << std::endl;
MetaObject::Clear();
memset(m_Radius, 0, 100*sizeof(float));
for(int i=0; i<m_NDims; i++)
{
m_Radius[i] = 1;
}
}
/** Destroy ellipse information */
void MetaEllipse::
M_Destroy(void)
{
MetaObject::M_Destroy();
}
/** Set Read fields */
void MetaEllipse::
M_SetupReadFields(void)
{
if(META_DEBUG) std::cout << "MetaEllipse: M_SetupReadFields" <<
std::endl;
MetaObject::M_SetupReadFields();
MET_FieldRecordType * mF;
int nDimsRecNum = MET_GetFieldRecordNumber("NDims", &m_Fields);
mF = new MET_FieldRecordType;
MET_InitReadField(mF, "Radius", MET_FLOAT_ARRAY, true,nDimsRecNum);
mF->terminateRead = true;
m_Fields.push_back(mF);
}
void MetaEllipse::
M_SetupWriteFields(void)
{
strcpy(m_ObjectTypeName,"Ellipse");
MetaObject::M_SetupWriteFields();
MET_FieldRecordType * mF;
mF = new MET_FieldRecordType;
MET_InitWriteField(mF, "Radius", MET_FLOAT_ARRAY, m_NDims,m_Radius);
m_Fields.push_back(mF);
}
bool MetaEllipse::
M_Read(void)
{
if(META_DEBUG) std::cout << "MetaEllipse: M_Read: Loading Header" <<
std::endl;
if(!MetaObject::M_Read())
{
std::cout << "MetaEllipse: M_Read: Error parsing file" << std::endl;
return false;
}
if(META_DEBUG) std::cout << "MetaEllipse: M_Read: Parsing Header" <<
std::endl;
MET_FieldRecordType * mF;
mF = MET_GetFieldRecord("Radius", &m_Fields);
if(mF->defined)
{
for(int i=0;i<m_NDims;i++)
{
m_Radius[i]= (float)mF->value[i];
}
}
return true;
}
1) You could have redused code to 3 lines.
2) memset is part of std
3) just add std:: before memset
Hans Zandbergen
The whole point is that C++ standard says memset is included from
string.h or cstring. Therefore accessing it under std nameplace is an error.
>The whole point is that C++ standard says memset is included from
>string.h or cstring. Therefore accessing it under std nameplace is an error.
--------------------------------------------------------------------------
4 Except as noted in clauses 18 through 27, the contents of each header
cname shall be the same as that of the corresponding header name.h,
as specified in ISO/IEC 9899:1990 Programming Languages C (Clause 7),
or ISO/IEC:1990 Programming Languages佑 AMENDMENT 1: C Integrity,
(Clause 7), as appropriate, as if by inclusion. In the C++ Standard
Library, however, the declarations and definitions (except for names
which are defined as macros in C) are within namespace scope (3.3.5)
of the namespace std.
--------------------------------------------------------------------------
Note that last sentence - it's why Hans is correct, and you are not.
Alan Bellingham
--
ACCU Conference: 11-14 April 2007 - Paramount Oxford Hotel
>#include <cstring>
> memset(m_Radius, 0, 100*sizeof(float));
To expand on what Hans said ...
Must be std::memset()
When including the xxx.h headers, the relevant declarations are all in
the global namespace. When including the cxxx headers, they are all
(except macros, of course) in std namespace.
This is as per the C++ Standard.
Note that some compilers - I'm looking at you, Visual C++ 5 - got this
wrong.
What happens when you include both xxx.h and cxxx versions of the same
header, I'm not sure. I suspect that the first inclusion is what
matters.
> #include <cstring>
...
> /** Clear ellipse information */
> void MetaEllipse::
> Clear(void)
> {
...
> memset(m_Radius, 0, 100*sizeof(float));
...
> }
Whenever you include a C++ header from the C standard library (with
'c' at the beginning of the name, and without the trailing .h) the
functions in that file are in the standard C++ namespace, std.
Therefore you must qualify your function calls with a std:: prefix.
--
Chris (TeamB);
Even if i include <string.h> instead of <cstring> memset could not be
found unless calling it under std nameplace. You can try it for
yourself. This is a real bug.
> Even if i include <string.h> instead of <cstring> memset could not be
> found unless calling it under std nameplace. You can try it for
> yourself. This is a real bug.
I cannot try it for myself, but I'll take your word on it.
Sounds strange, though.
--
Chris (TeamB);
Ok, I've created a new console app in C++Builder 6, and used the
following code in the .cpp file:
#pragma hdrstop
#include <string.h>
int main(int argc, char* argv[])
{
char a[10];
memset(reinterpret_cast<void*>(a), '\0', 10);
return 0;
}
This compiles fine. no std:: required. As someone else mentioned if
you include <cstring> before <string.h> then this code will fail as
string.h will be ignored due to header guards.
Are you sure that <cstring> isn't being included somehow before string.h
in your case because as this example shows, if you just include
<string.h> then C++Builder *does* work correctly and puts memset in the
global namespace.
Have you tried this?
Cheers
Russell
Whoa, there's void* popping up again. Untyped pointers rule!
In reading this thread as a latecomer, I can't help but think there may
in fact be a real bug in here somewhere. A type of bug that is similar
to bugs that I remember from the past. Bugs involving the std namespace,
C library functions that are implemented as intrinsics, release builds,
and precompiled headers.
The cpp file that was posted looked like this:
#include <stdio.h>
#include <ctype.h>
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
...
Li tried changing <cstring> to string.h, and *claims* that memset still
cannot be found. Now, throughout this thread, Li has been confused and
incorrect at various times, but his last post seems to indicate that he
now understands <cstring> vs <string.h>. So maybe there is a real bug.
The source file both includes <string> and string.h. Since there is no
#pragma hdrstop, the compiler is most likely trying to precompile these.
This is a slightly different than the code that you posted. Try
something along these lines instead:
#include <string>
#include <string.h>
#pragma hdrstop
int main(int argc, char* argv[])
{
char a[10];
memset(reinterpret_cast<void*>(a), '\0', 10);
return 0;
}
Compile both release and debug builds and see if you get an error (I
don't have BCB with me, but can try later).
I dug through my past bug reports to find code why this seems familiar.
The closest thing I could find was a bcb5 bug using this code:
#include <cstring>
#pragma hdrstop
#pragma argsused
int main(int argc, char* argv[])
{
char *s1 = "foo";
char *s2 = "bar";
std::strcmp(s1, s2);
return 0;
}
This used to generate a compiler error:
[C++ Error] Unit1.cpp(14): E2316 '__strcmp__' is not a member of 'std'
This is the opposite problem than the poster is having. This bug
involved precompiled headers and intrinsics, and only occurred in
release builds. It has since been fixed (I think).
H^2
Indeed, this is a bug in BCB 2006:
[C++ Error] Unit1.cpp(7): E2268 Call to undefined function 'memset'
The pragma is not needed. PCHs can be on or off, and it doesn't matter
whether you are doing a debug or a release build. Switching the order of
<string.h> and <string> makes the error go away.
This code compiles fine with MSVC 8.
H^2
Doesn't the <string> bring memset into std namespace, so string.h
becomes irrelevant? Or should both std::memset and ::memset compile fine
with the given order of inclusion?
Comeau compiles this fine
//#include <string>
#include <string.h>
int main(int argc, char* argv[])
{
char a[10];
memset(reinterpret_cast<void*>(a), '\0', 10);
::memset(reinterpret_cast<void*>(a), '\0', 10);
return 0;
}
And this too:
#include <string>
//#include <string.h>
int main(int argc, char* argv[])
{
char a[10];
memset(reinterpret_cast<void*>(a), '\0', 10);
::memset(reinterpret_cast<void*>(a), '\0', 10);
return 0;
}
I don't know. In practice, including <string> seems to pull memset into
the global namespace in both VC 8 and gcc 3.4.4, but not in BCB.
However, the standard only mentions memset when discussing string.h and
cstring. Maybe BCB is correct here?
Both VC8 and gcc compile the example I posted where <string> is followed
by <string.h>. BCB seems wrong in this case, but I'm not as confident as
I was an hour ago.
H^2
So the problem is from <string>? Which should not be included to begin
with? So the proper thing to do is to report that <string> could not be
found, instead of accept it and disregard late appearance of <string.h>?
> Doesn't the <string> bring memset into std namespace, so string.h
> becomes irrelevant? Or should both std::memset and ::memset compile
> fine with the given order of inclusion?
<string> and <string.h> contain entirely different things--the first
being the std::string class, and the second the typical C library
header. You are thinking of <cstring> for the header that memset into
std namespace.
--
Chris (TeamB);
> So the problem is from <string>? Which should not be included to begin
> with? So the proper thing to do is to report that <string> could not be
> found, instead of accept it and disregard late appearance of <string.h>?
<string> is a valid header file, and is separate from <string.h>. I
don't know why the code you posted is including <string>, as it does not
seem to use anything provided by that header.
H^2
Argh! Why the pointless and ugly cast? Better:
memset(a, '\0', 10);
In fact, for purposes of testing the compiler, all you
need is:
int main()
{
memset;
}
because it was test code and I didn't think it would work without the
cast and didn't bother to try. I'd really use something like this:
boost::array<char,10> a;
std::fill(a.begin(), a.end(), '\0');
If I were doing this correctly but that doesn't prove the problem.
Cheers
Russell
Probably but I'm never sure on initialisation syntax and/or Borland's
conformance to the standard in this way, especially if it was an array
of structs, so tend to avoid it.
Cheers
Russell
One of the goals of the array class was to permit use as if it were a
real array, such as aggregate initialization (the curly braces), etc.
I don't know how well it works with Borland's compiler either, and
only assume it's ok.
--
Chris (TeamB);