Thread: memcpy for char *

  1. #1
    Registered User
    Join Date
    Nov 2007
    Posts
    99

    memcpy for char *

    dear experts,

    i encounter a problem with the memcpy function here is the piece of code

    Code:
    char ss[1000];
    int ss_cnt=0;
    
    case 0:
    	tmp_val = va_arg(vlist,int);
    	memcpy(&ss[ss_cnt], &tmp_val, sizeof(int));
    	ss_cnt += sizeof(int);
    	printf("int argument=%d\n", ss[ss_cnt]);//here i am getting the value that i have copied
    	break;
    			
    case 2:
    	  
    	tmp_val4 = va_arg(vlist,char *);
    	memcpy(&ss[ss_cnt], &tmp_val4, sizeof(char *));
    	printf("string ss[ss_cnt]=%s\n",ss[ss_cnt]);//here i am not getting the value insted some exception i am getting 
    	ss_cnt += sizeof(char *);
    		break;

    here i am passing some arguments , in case 0: when i print the ss[ss_cnt] it gives me right value , when i print the same thing in second case with char *, it gives me exceptions and quits so how to handle for char * is there any modifications need to be done.

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Is your integer value a small value? I'd expect BOTH of these to go wrong, actually. In the first case, you get away with it if the integer value is in the range -128..127, but larger values would not work correctly. You are, after all, only passing in a char, which is converted to an integer by the rules of variable argument passing. To properly print an integer from that [assuming integer values are correctly aligned within the array or the processor&OS supports unaligned access], you would need to do:
    Code:
    	printf("int argument=%d\n", *(int *)(&ss[ss_cnt]));//here i am getting the value that i have copied


    In the second case, you are printing a string from an address, but you pass in one char value - so you get an address between -128..127, which of course is not the content of the char * you just copied (not even a valid address of a string). Again, you need to copy the char * from the array by using casts and pointer dereference:
    Code:
        printf(... *(char **)(&ss[ss_cnt]));
    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > ss_cnt += sizeof(int);
    > printf("int argument=%d\n", ss[ss_cnt]);//here i am getting the value that i have copied
    How so, when you've just incremented ss_cnt past where you wrote the data?

    > memcpy(&ss[ss_cnt], &tmp_val4, sizeof(char *));
    I'm going to guess you wanted to copy the string, not copy the pointer to the string.
    You are attempting to serialise some data here?

    Consider
    memcpy(&ss[ss_cnt],&tmp_val4, strlen(tmp_val4));
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User
    Join Date
    Nov 2007
    Posts
    99
    thank you matsp,
    really you are genius men really you solved the problem ,
    thats why you people are called experts, really thanks to you men,

    one more query i have how you will do that for float here also i am getting the problem

    Code:
    case 1:
    	tmp_val1 = va_arg(vlist,float);
    	memcpy(&ss[ss_cnt], &tmp_val1, sizeof(float));
                    printf("float argument=%f\n", *(float *)(&ss[ss_cnt]));// it is printing NULL
    	ss_cnt += sizeof(float);
    	break;
    what is the conversion for float thanks in advance.

  5. #5
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Are you sure you have posted the code you are actually running, as I have a hard time understanding how printf() with "%f" would ever output NULL.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  6. #6
    Registered User
    Join Date
    Nov 2007
    Posts
    99
    dear Matsp,

    ya some time i am getting 0.0000 and some time garbage,
    my main question is how to handle the floats,
    again one more requirement is that i want to replace the memcpy function with va_arg for boundary alignment, please give me some inputs regarding this because va_arg by itself takes care of boundary alignment and is the requirement, please help me in this regards.
    Last edited by vin_pll; 02-24-2009 at 10:04 PM.

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Well if you take your aligned float tmp_val1 and print that, then it will be fine.

    But if you then take your unaligned copy of it in your ss buffer, and force a (float*) pointer to it, then try and dereference your mis-aligned pointer, then all sorts of stuff can happen.

    Once you've copied things to ss, it's opaque. The only way to examine it properly is to reverse the process and copy it back into an actual float variable which will be correctly aligned by the compiler.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User
    Join Date
    Nov 2007
    Posts
    99
    thank you for your reply,

    i am trying to do the same
    Code:
    char ss[1000];
    char ss_ptr = (char *)((((int)ss)+(7)) & ~7);
    what i am trying to do is i want to create stack with all the arguments,
    with memcpy it is not possible to align to the memory thats why i want to use only va_arg, but it should replace memcpy and should copy anytype of data into ss.

    i am trying to write like this
    Code:
    int tmp_val;
    char *tmp_val1;
    //for int 
    
    case 0:   tmp_val = va_arg(vlist,int);
                   //memcpy(&ss[ss_cnt], &tmp_val, sizeof(int));
    	ss_ptr=(char *)tmp_val;
    	printf("\n int ss[ss_cnt]=%d",ss_ptr);//which is printing the right value
    //for  float
     case 1:tmp_val1 = va_arg(vlist,float);
               //memcpy(&ss[ss_cnt], &tmp_val1, sizeof(float));
                ss_ptr=(char *)&tmp_val1;
                printf("float val=%f\n", ........_ptr);// iam not getting the right value
    as float directly cannot given to char * i thought of assigning its address to char *
    and get the value from that address but not working how to solve this any inputs will be great.
    Last edited by vin_pll; 02-25-2009 at 03:41 AM.

  9. #9
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    What processor is this on?

    Also, could you perhaps post the whole code (or even better, a complete, compilable example with your memcpy()/printf() code along with a main() driver).

    --
    Mats
    Last edited by matsp; 02-25-2009 at 03:25 AM.
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  10. #10
    Registered User
    Join Date
    Nov 2007
    Posts
    99
    right now i am working on intel xeon 64 bit m/c later this should work on all intel and linux and unix platforms,
    Code:
    char ss[1000];
    char ........_ptr = (char *)((((int)ss)+(7)) & ~7);
    int ss_cnt=0;
    
    char *sendList(int numArgs,...)
    {
    	
    		switch(type)
    		{
    			case 0:
    				tmp_val = va_arg(vlist,int);
    								
    				ss_ptr=(char *)tmp_val;
    				printf("\n int ss[ss_cnt]=%d",ss_ptr);
    				ss_cnt += sizeof(int);
    			break;
    			case 1:
    				tmp_val1 = va_arg(vlist,float);
    				ss_ptr=(char *)&tmp_val1;
    				printf("float val=%f\n", ........_ptr);
    				ss_cnt += sizeof(float);
    
          }
    return ss_ptr;
    }
    
    
    
    int main()
    {
    	char * temp_ptr = sendList(4,0,1117,1,12.34);
    	printf("ss_cnt = %d\n", ss_cnt);	
    }

    the method goes inside the switch after that the problem with the float how to resolve that.

  11. #11
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    So, that is not a compilable program...

    However, x86-64 is capable of reading anything from any address in memory, so there's no reason that I see that the float value would be wrong because of that.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  12. #12
    Registered User
    Join Date
    Nov 2007
    Posts
    99
    thank you for your reply,

    i just wanted to know whether this is the right way
    Code:
    tmp_val1 = va_arg(vlist,float);
    				ss_ptr=(char *)&tmp_val1;
    				printf("float val=%f\n", *(ss_ptr));
    assigning the address to ss_ptr and getting its value through *(ss_ptr) , i think we can achieve the results ,
    right .

  13. #13
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by vin_pll View Post
    thank you for your reply,

    i just wanted to know whether this is the right way
    Code:
    tmp_val1 = va_arg(vlist,float);
    				ss_ptr=(char *)&tmp_val1;
    				printf("float val=%f\n", ........_ptr);
    assigning the address to ss_ptr and getting its value through ........_ptr , i think we can achieve the results ,
    right .
    In x86-64, floating point values are passed in SSE registers to printf, so you need to make sure that the printf understands that the value is a floating point value when passing it. You may want to check the generated code to see if it sets EAX (or AL) to 1 before the call printf line. What is ......_ptr?

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  14. #14
    Registered User
    Join Date
    Nov 2007
    Posts
    99
    it is not _ptr

    it is actually ss_ptr pointer to ss_ptr, *(ss_ptr) it is is not the right way to print
    printf("float val=%f\n", *(ss_ptr));

  15. #15
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by vin_pll View Post
    it is not _ptr

    it is actually ss_ptr pointer to ss_ptr, *(ss_ptr) it is is not the right way to print
    printf("float val=%f\n", *(ss_ptr));
    You need to make sure that the compiler understands that the content is a floating point value, e.g.
    Code:
    printf("float val=%f\n",  *(float *)(ss_ptr));[/QUOTE]
    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Disagreement about memcpy
    By ch4 in forum C Programming
    Replies: 9
    Last Post: 05-28-2009, 10:12 AM
  2. Replies: 14
    Last Post: 06-28-2006, 01:58 AM
  3. Memcpy(); Errors...
    By Shamino in forum C++ Programming
    Replies: 4
    Last Post: 03-24-2006, 11:35 AM
  4. memcpy with 128 bit registers
    By grady in forum Linux Programming
    Replies: 2
    Last Post: 01-19-2004, 06:25 AM
  5. memcpy
    By doubleanti in forum C++ Programming
    Replies: 10
    Last Post: 02-28-2002, 04:44 PM