1
  char *sBuffer=new char[20];
    char * sStringStart = sBuffer;

    long * plMsgStart = (long *) sBuffer;// what is this line doing

    long i=500;

    *plMsgStart = i // what is this line doing

Is the last line assigning 500 in char array ? but when i print the array i get garbage values

Hey guys below is the actual code and i encountered it when i was converting code from c++ to c#, this below code is part from c++ function, now why below function gives garbage values ?

char *sBuffer=new char[20];
char * sStringStart = sBuffer;
BSTR bsMsgBody= SysAllocString(L"Helo");
sStringStart+=4;
long * plMsgStart = (long *) sBuffer;

long l=50;

*plMsgStart=l;

sprintf(sStringStart, "%S", bsMsgBody);

printf("%S",sBuffer);
kamal
  • 739
  • 1
  • 9
  • 21
  • assuming its not crazy, the first `sizeof(long)` characters are treated as a long variable and is set to 500. depends on the endianess how the data is stored. yeah it **looks** like garbage but going through it, you can see how '500' is stored – Koushik Shetty Apr 04 '13 at 16:26

3 Answers3

6

That's a cast. It says "I know what I'm doing, I want to treat this char* as if it were a long*". Afterwards, it assigns i to the first element (equivalent to plMsgStart[0] = i;.

Depending on the size of long, you'll overwrite the first 4 or 8 elements in the char array. Printing it is still undefined behavior, because sBuffer wasn't null-terminated to start with.

If you did

 char *sBuffer=new char[20]();

and then attempt to print sBuffer (after the long overwrite), you'll see 4 (or 8) characters corresponding to the binary representation of 500.

Visual

 char *sBuffer=new char[20];

 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 | | | | | | | | | | | | | | | | | | | | |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

 long * plMsgStart = (long *) sBuffer;

 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |       |       |       |       |       |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

                 ^^^^^
    note this is still the same memory,
   but "seen through the eyes" of a long*


 *plMsgStart = 500;

 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |  500  |       |       |       |       |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 2
    I think the whole thing is UB, because it's a violation of type-aliasing rules. And there maybe an alignment issue as well... – Oliver Charlesworth Apr 04 '13 at 16:27
  • I *think* so; it's accessing an object via a pointer to an incompatible type (I'm extrapolating slightly from the rules in C here, perhaps it's different in C++). As for alignment, that could certainly be a problem (depending on what your platform allows). – Oliver Charlesworth Apr 04 '13 at 16:37
  • @OliCharlesworth I think `new` returns a correctly-aligned pointer to word size. I'm not sure it isn't, but I doubt it. – Luchian Grigore Apr 04 '13 at 16:39
  • Is that alignment guaranteed? – Oliver Charlesworth Apr 04 '13 at 16:39
  • but why printf("%s",sBuffer); gives garbage values. – kamal Apr 04 '13 at 16:44
  • @kamal it's undefined behavior because `sBuffer` isn't initialized - it's not null terminated. Did you try the test I suggested? – Luchian Grigore Apr 04 '13 at 16:46
  • @OliCharlesworth §5.3.4/10 and §3.7.4.1/2 - didn't check, taken from http://stackoverflow.com/a/14774681/673730 – Luchian Grigore Apr 04 '13 at 16:50
  • @kamal: Because `printf("%s",...)` expects an array of printable characters with a null terminator at the end. Instead, you're using an evil cast to give it the bytes that represent `(long)500`. As a string, that's garbage, so you'll get garbage (or other undefined behaviour) out. – Mike Seymour Apr 04 '13 at 16:53
  • @LuchianGrigore: Ah, that's interesting. I had a brief look at those paragraphs, and it seems like the alignment is indeed not an issue (although I find the C++ standard pretty tough to parse...) – Oliver Charlesworth Apr 04 '13 at 17:01
2

This code creates a 20 byte long buffer called sBuffer, then stores a long with the value 500 in the first n bytes of the buffer, where n is the number of bytes required to store a long on your system.

long * plMsgStart = (long *) sBuffer;// what is this line doing

This line is the one that tells the compiler that you want plMsgStart to be the same memory block as sBuffer, but the block should be treated as if it stores longs.

Eric Finn
  • 8,629
  • 3
  • 33
  • 42
  • but why printf("%s",sBuffer); gives garbage values – kamal Apr 04 '13 at 16:45
  • Because %s expects an array of bytes containing ASCII values followed by a byte with the value of 0. If you want to print out `500`, then you want `printf("%ld", plMsgStart[0]);` – Eric Finn Apr 04 '13 at 22:52
2

...I'm not sure how to make it much simpler, but I'll try:

char *sBuffer // sBuffer is a pointer to a character type

long * plMsgStart  // plMsgStart is a pointer to a long type

(long *) sBuffer;// this tells the compiler that I want my char pointer to be treated
                 // as a long pointer during this assignment.

This makes it such that plMsgStart is pointing at sBuffer.

*plMsgStart = i; // this is dereferencing the pointer, it says: 
                 // "at the current memory location" store the value i

So in effect, the memory pointed to by sBuffer is being set the value of 500, if you try to access this as a long you should see 500; if you try to access sBuffer as a char (or char array) you're most likely going to get a garbage. This is a perfect reason not to typecast, because the compiler shouldn't complain about anything you did, but you just overflowed the first element of your character array (char takes values up to 255)

you stored 500 into that memory, that would be:

0000 0001 1111 01002 If you look at this in byte form:

[00000001] [11110100] ==> [0x1][-0x12] (signed)
or
[00000001] [11110100] ==> [0x1][0xF4] (unsigned)

So when you try to print that "string" you're seeing garbage (or at best an 'O' if char is unsigned on your system).

Community
  • 1
  • 1
Mike
  • 47,263
  • 29
  • 113
  • 177
  • since its an array, and that he casts it to type `long` the first `sizeof(long)` will hold 500?. and char should take -128 to 127? – Koushik Shetty Apr 04 '13 at 16:33
  • @Koushik, you're right about the first part (at least on most systems). About `char`, the standard doesn't define if plain `char` is signed or unsigned. So, the "correct" range is `CHAR_MIN` to `CHAR_MAX`. – Alok Singhal Apr 04 '13 at 16:37
  • @Alok thanks for the correction. so 'char''s sign is implementation defined? – Koushik Shetty Apr 04 '13 at 16:39
  • @Koushik - An array is just a bunch of contiguous bytes. The size of a `char` is 1 byte, the size of a `long` depends on your system, but 8 bytes is a safe bet. So technically, yes, you can store a `long` into a character array of size 20 and access it as a long. But this makes no sense... 20 bytes can only store 2 full `long`s.. WRT the values a char holds, the MAX a char can ever hold (regardless of sign) is 255, so I mentioned that number – Mike Apr 04 '13 at 16:39
  • 2
    @Mike i agree with that but your **sBuffer's first element is set the value of 500** is what i had in mind while commenting. – Koushik Shetty Apr 04 '13 at 16:41
  • but why printf("%s",sBuffer); gives garbage values – kamal Apr 04 '13 at 16:45
  • @Koushik - OK, I see what you're saying. Yes, I worded it funny, but if you were to access `sBuffer` as a long (ie `printf("%ld",*plMsgStart);`) then you'd get 500 (taking up the first 8 of 20 reserved bytes). However if you try to access it as a char buffer as `sBuffer` was originally defined as, the first element is not going to be the expected 500 because that overflows a char type. Is I guess what I meant to say. – Mike Apr 04 '13 at 16:46
  • @kamal - because you overflowed the `char` type, so you're getting (I assume) non-printable characters.. alphanumeric at least. – Mike Apr 04 '13 at 16:48
  • +1 for detailed explanation. this and lucian grigore's answer should leave no doubts. – Koushik Shetty Apr 04 '13 at 17:02