Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

I want a better memcpy() function. 1

Status
Not open for further replies.

rossno

Programmer
Feb 8, 2002
46
US
Hi C++ Pros,

I have a lecacy C program that has been converted to C++, but is really still C. The program reads column delimited data into structures. The structures are designed to receive the data EXACTLY as mapped for each data element. To read each data element from the structures, instructions like this are used:

memcpy(PolFxdFndOut.Extractiondate, Var_Dat.PolEffDate, (size_t)sizeof(PolFxdFndOut.Extractiondate));

I would like something like:

newcpy(PolFxdFndOut.Extractiondate, Var_Dat.PolEffDate);

where newcpy figures out how many characters to copy.

There are thousands of similar memcpy statements in the program. It is not feasable to completely redesign the program using C++ String classes.

Here is an example (using memset) of what I would like, but doesn't work as is:


#include <iostream>

using namespace std;

typedef struct foo {
char x1[5];
char x2[9];
char x3[3];
int x4;
} FOO;


void mySet(char * data, const char val) {

//*** This doesn't work RIGHT because sizeof operator
//*** returns the size of the char pointer, NOT the size of
//*** the data (foo1.x2) that the pointer is pointing to.
//*** Nuts!
short lenth = sizeof(data);
memset(data, val, lenth);
}

int main () {

FOO foo1;
memset(foo1.x2, '?', sizeof(foo1.x2));
mySet(foo1.x2, '7');
cout << "foo1.x2 = " << foo1.x2 << " bummer!\n";
return 0;

}

Any brilliant ideas will be most welcome.

Thank you,

Norm
 
As you are using C++, you can try to write a generic memcpy, thanks to templates:
Code:
template<class G>
G* generic_memory_copy (G* dst, G* src)
{
  memcpy (dst, src, sizeof (G));

  return dst;
}

Here is some code to test if it is ok for you:
Code:
#include <stdlib.h>
#include <string.h>

#include <iostream>
using namespace std;

// Here is the generic memcpy:
template<class G>
G* generic_memory_copy (G* dst, G* src)
{
  memcpy (dst, src, sizeof (G));

  return dst;
}

// A structure for testing purposes:
struct test_s
{
  int a;
  int b;
  char c[5];
};

// The little test:
int main ()
{
  test_s s1;
  test_s s2;

  s1.a = 5;
  s1.b = 10;
  s1.c[0] = 't';
  s1.c[1] = 'e';
  s1.c[2] = 's';
  s1.c[3] = 't';
  s1.c[4] = 0;

  cout << "src :" << endl;
  cout << s1.a << ' ' << s1.b << ' ' << s1.c << endl;

  generic_memory_copy (&s2, &s1);

  cout << "dst :" << endl;
  cout << s2.a << ' ' << s2.b << ' ' << s2.c << endl;
  return 0;
}

--
Globos
 
Hey. Thanks Globos,

Geeee, I never would have thought of that!!

I ran your sample. I ran just fine. Now I will massage it, [lol], to wotrk in my app.

Thanks, thanks, thanks again,

Norm
 
OK ...

I notice that you null terminated s1.c I don't have that luxary. I need the generic memcpy to be able to determine the length by somehow getting THE DECALRED LENGTH of s1.c which is 5 in this example.
 
This is not a luxary, all your char* strings must be zero terminated.
Even if you don't assign zero after the last character, the generic copy does not care of this.
In the test case, it is just for the sake of right printing to the standard output.
Try to remove line "s1.c[4] = 0;", it will still work, but strange things will be printed after "test".


--
Globos
 
Hi Globos,

The first test that I did was to comment out the s1.c[4]='0'; statement.

The program is reading from a flat file directly into a struct that matches the data EXACTLY. There is no notion of null termination. The program only moves n number of characters from input structs to output structs. Very fast, but cumbersome to look and error prone to program all the sizeof stuff in the memcpy statements. Note that there is no way to "squeeze" in a null termination char for each data element as each record read from the flat file must match the struct char for char. The whole record is read from the flat file into the struct with 1 read stmt.

Note in my original example that sizeof(foo1.x2) works fine in the main program, but DOES NOT work correctly in mySet(). mySet only gets a pointer to foo1.x2. I was hoping that <typeinfo> might help, with something like:

int lenth = sizeof(typeid(data).raw_name());

but that still only returns the length of the pointer, NOT the declared length of foo1.x2 which is 9 in my example.

My question remains - is there a way to get the custom memcpy to glean the declared length of the destination length?
 
Hi Globos,

I got this working right for me now. Here is the source:

//*** src: boo.cpp

#include <stdlib.h>
#include <string.h>

#include <iostream>
#include <typeinfo>

using namespace std;

// ---------------- *** A generic memcpy:
template<class G>
G * gen_memcpy (G * dst, char * src)
{
int lenth = sizeof(G);

memcpy (dst, src, lenth);

return dst;
}

// ----------------- *** A generic memset:
template<class G>
G * gen_memset (G * dst, const char src)
{
int lenth = sizeof(G);

memset (dst, src, lenth);

return dst;
}


typedef struct foo {
char x1[5];
char x2[9];
char x3[3];
int x4;
} FOO;


// -----------------
int main () {

FOO foo1;

memset(foo1.x2, '?', sizeof(foo1.x2));
gen_memset(&foo1.x2, 'X');

cout << "foo1.x2 = " << foo1.x2 << " great!\n";

// only copy "98765" and ignore the rest of str.
gen_memcpy(&foo1.x1, "987654321");
cout << "foo1.x1 = " << foo1.x1 << " great!\n";

return 0;

}

NOTE: In my earlier tests, I had removed the addr of (&) on the call. I screwed up!

You might wanna try it too. The cout isn't pretty, because the struct elements are not null terminated, but thats OK.

Thanks for your persistance. How do I give you a STAR??
Thanks,
Thanks,
...


Norm
 
Not to worry Globos, I found the STAR thing at thebottom of your first post.

You will never know [maybe] how helpful you have been.
I'm gonna vote for you for President!

Thanks again,

Norm
 
Thanks for the star, rossno, I'm so pleased that I have somewhat made more elegant our previous code, I hope you will like it :

Code:
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <iostream>
using namespace std;

// ---------------- *** A generic memcpy:
template<class DestinationType, class SourceType>
DestinationType& gen_memcpy (DestinationType& dst, const SourceType& src)
{
  memcpy (&dst, &src, sizeof (DestinationType));

  return dst;
}

// ---------------- *** The 'char*' version of gen_memcpy:
// ---------------- *** It allows to copy dynamically allocated strings
char* gen_memcpy (char* dst, const char* src)
{
  memcpy (dst, src, sizeof (char) * (strlen (src) + 1));//same as strcpy

  return dst;
}

// -----------------  *** A generic memset:
template<class DestinationType, class FillingType>
DestinationType& gen_memset (DestinationType& dst, const FillingType& src)
{
  memset (&dst, src, sizeof (DestinationType));

  return dst;
}


typedef struct foo {
    char x1[5];
    char x2[9];
    char x3[3];
    int  x4;
} FOO;


// -----------------
int main ()  {

    FOO  foo1;
   
    memset (foo1.x2, '?', sizeof (foo1.x2));
    gen_memset (foo1.x2, 'X');
    
    cout << "foo1.x2 = " << foo1.x2 << " great!\n";
    // only copy "98765" and ignore the rest of str.
    gen_memcpy(foo1.x1, "987654321");
    cout << "foo1.x1 = " << foo1.x1 << " great!\n";

    // Test for the specific char* version of gen_memcpy
    char* dst = (char*) malloc (15);
    char* src = (char*) malloc (10);

    strcpy (dst, "haaaa");
    strcpy (src, "hooooooo");

    cout << "dst before copy: " << dst << endl;
    cout << "src before copy: " << src << endl;

    gen_memcpy (dst, src);

    cout << "dst after copy: " << dst << endl;
    cout << "src after copy: " << src << endl;

    assert (strcmp (dst, src) == 0);//dst_equals_src

    return 0;
}

What is really new is the peculiar overload of gen_memcpy, dedicated to the copy of char* strings(dynamically allocated and null terminated).
This way, you won't have bad surprises when using char* strings.

I have also made the semantics of the two generic functions cleaner, with right generic formal arguments, consts, and references(no more problems with Void pointers by now). This gives a strong C++ touch.

Can you tell me what is your country so that I can postulate for the next presidentials sessions? [smile]

--
Globos
 
Hey thanks Globos,

Ya, I will ponder your embellishments some more and include those too. Yes, I have already overloaded several of the template functions. So far, I have made templates for memcpy, memcmp, memicmp, and memset. That's probably all I will need.

I started programming in 1968 with APL, and been back-sliding ever since ... LOL. I have a BSCS & MSCS from CSU Fullerton, with further post grad work at UC Irvine, and got certified with C++ at brainbench.com. Never really got into templates very much before. I live in Garden Grove, CA, and am currently contracting in Irvine.

Your help has been VERY greatly appreciated.

Thanks again, Globos,

Norm
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top