memset

G

Gaijinco

I'm having a headache using memset()

Given:

int v[1000000];
memset((void*)v, 1, sizeof(v));

Can I be 100% positive than v = 1 for i > 0, or there is something
else I have to do?.

In various computers that I have tried it seems that the only value I
can copy to a range with memset() that works is 0.

Thanks.
 
M

Martin Vuille

ps.com:
I'm having a headache using memset()

Given:

int v[1000000];
memset((void*)v, 1, sizeof(v));

Can I be 100% positive than v = 1 for i > 0, or there is
something else I have to do?.

In various computers that I have tried it seems that the only
value I can copy to a range with memset() that works is 0.

Thanks.


What you are trying to do will only work if sizeof( int ) == 1 in
your environment.

memset() manipulates bytes. If sizeof( int ) == 4 in your
environment, then each element of v will be set to 0x01010101.

MV
 
M

Martin Ambuhl

Gaijinco said:
I'm having a headache using memset()

Given:

int v[1000000];

You have no guarantee that v can be that large.
memset((void*)v, 1, sizeof(v));

The cast to (void *) is just typing practice. Lose it.
Can I be 100% positive than v = 1 for i > 0, or there is something
else I have to do?.


Unless sizeof(int) == 1, you can be 100% positive that v != 1.
Each of the sizeof(v) bytes, interpreted as unsigned chars, will have 1
stored in it. That means, on a binary machine, that each of the v
will have sizeof(int) bits set. With the exception for sizeof(int) == 1,
that value cannot be 1.
In various computers that I have tried it seems that the only value I
can copy to a range with memset() that works is 0.

You are completely wrong. Note the recurring patterns in the output
from the following program:
#include <stdio.h>
#include <string.h>

int main(void)
{
unsigned int v;
unsigned int i;

printf("Output on an implementation with sizeof(int) = %zu\n\n",
sizeof(int));

for (i = 0; i < 17; i++) {
printf("Setting each byte in the unsigned int v to %#x:\n", i);
memset(&v, i, sizeof v);
printf(" %#0x\n", v);
}
return 0;
}


Output on an implementation with sizeof(int) = 4

Setting each byte in the unsigned int v to 0:
0
Setting each byte in the unsigned int v to 0x1:
0x1010101
Setting each byte in the unsigned int v to 0x2:
0x2020202
Setting each byte in the unsigned int v to 0x3:
0x3030303
Setting each byte in the unsigned int v to 0x4:
0x4040404
Setting each byte in the unsigned int v to 0x5:
0x5050505
Setting each byte in the unsigned int v to 0x6:
0x6060606
Setting each byte in the unsigned int v to 0x7:
0x7070707
Setting each byte in the unsigned int v to 0x8:
0x8080808
Setting each byte in the unsigned int v to 0x9:
0x9090909
Setting each byte in the unsigned int v to 0xa:
0xa0a0a0a
Setting each byte in the unsigned int v to 0xb:
0xb0b0b0b
Setting each byte in the unsigned int v to 0xc:
0xc0c0c0c
Setting each byte in the unsigned int v to 0xd:
0xd0d0d0d
Setting each byte in the unsigned int v to 0xe:
0xe0e0e0e
Setting each byte in the unsigned int v to 0xf:
0xf0f0f0f
Setting each byte in the unsigned int v to 0x10:
0x10101010
 
J

Jack Klein

I'm having a headache using memset()

Given:

int v[1000000];
memset((void*)v, 1, sizeof(v));

No need for the cast to void pointer here, the conversion is
automatic. But do make sure to include <string.h>. Also there is no
need for the parentheses abound the 'v' as an operand to the sizeof
operator, as 'v' is an object, not a type.
Can I be 100% positive than v = 1 for i > 0, or there is something
else I have to do?.


No you can't, and on most implementations it will not be. memset()
will place the value 1 into every byte that makes up the array, and
there are 1,000,000 times sizeof (int) bytes in the array.

There are a few implementations, mostly digital signal processors,
where CHAR_BIT is 16 and char and int have the same size and
representation, where every int in the array will be set to the value
1.

But on most platforms, especially anything in a desktop computer, you
won't get that value.

On old 16-bit implementations for MS-DOS, each int in the array will
wind up with the value 257.

On 32-bit Windows, Macintosh, or Linux platforms using x86 processors,
each int in the array will have the value 16843009.

On 64-bit operating systems using x86, the result will be
72340172838076673.
In various computers that I have tried it seems that the only value I
can copy to a range with memset() that works is 0.

It works for a value of 0 because memset() with a value of 0 will set
every bit in every byte to all bits 0. C guarantees that any integer
type with a value of all bits 0 has the value 0. This is not
guaranteed for floating point types or pointers.

As to how to do it, you need to use a loop:

#define ARRAY_SIZE 1000000

int v [ARRAY_SIZE];

size_t index;

for (index = 0; index < ARRAY_SIZE]; ++index)
{
v [index] = 1;
}

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
 
W

William Ahern

Gaijinco said:
I'm having a headache using memset()

int v[1000000];
memset((void*)v, 1, sizeof(v));
Can I be 100% positive than v = 1 for i > 0, or there is something
else I have to do?.

In various computers that I have tried it seems that the only value I
can copy to a range with memset() that works is 0.

Mental exercise:

What's the difference, and expected result, of

char v[1000000];
memset(v, 1, sizeof v);

Hint: How does memset() know the stride when setting each element in the
array? Particularly given that in your example you explicitly cast the array
to a void pointer. Do you believe that memset() actually possesses this sort
of magic? It certainly _could_, cast or not, notwithstanding the correct
answer.

The precise answer is much more involved, of course.
 
K

Keith Thompson

Gaijinco said:
I'm having a headache using memset()

Given:

int v[1000000];
memset((void*)v, 1, sizeof(v));

Can I be 100% positive than v = 1 for i > 0, or there is something
else I have to do?.


No, you can be 99% positive that v != 1 for i > 0. (The remaining
1% is for systems with sizeof(int)==1, and therefore CHAR_BIT>=16;
you're unlikely to run into such a system unless you're working with
embedded DSPs.)
In various computers that I have tried it seems that the only value I
can copy to a range with memset() that works is 0.

Right. memset sets each *byte* of an object to a specified value. It
happens that setting each byte of an int to 0 sets the entire int to
0. Setting each byte of an int to 1 will probably set the entire int
to something like 0x0101 (257), or 0x01010101 (16843009), or even
0x0101010101010101 (72340172838076673, if I've done the math right).

The C standard library doesn't provide functions to set each element
of an array to a specified value, other than memset. You'll just have
to write a loop (untested code follows):

int v[1000000];
size_t i;
for (i = 0; i < sizeof v / sizeof v[0]; i ++) {
v = 1;
}

It's likely to be about as fast as memset() would have been anyway.
 
E

Eric Sosman

Keith said:
Gaijinco said:
I'm having a headache using memset()

Given:

int v[1000000];
memset((void*)v, 1, sizeof(v));

Can I be 100% positive than v = 1 for i > 0, or there is something
else I have to do?.


No, you can be 99% positive that v != 1 for i > 0. (The remaining
1% is for systems with sizeof(int)==1, and therefore CHAR_BIT>=16;
you're unlikely to run into such a system unless you're working with
embedded DSPs.)
In various computers that I have tried it seems that the only value I
can copy to a range with memset() that works is 0.

Right. memset sets each *byte* of an object to a specified value. It
happens that setting each byte of an int to 0 sets the entire int to
0. Setting each byte of an int to 1 will probably set the entire int
to something like 0x0101 (257), or 0x01010101 (16843009), or even
0x0101010101010101 (72340172838076673, if I've done the math right).

The C standard library doesn't provide functions to set each element
of an array to a specified value, other than memset. You'll just have
to write a loop (untested code follows):

int v[1000000];
size_t i;
for (i = 0; i < sizeof v / sizeof v[0]; i ++) {
v = 1;
}

It's likely to be about as fast as memset() would have been anyway.


For very large arrays that need to be filled/refilled very
many times, here's a function I cooked up long ago:

#include <string.h>
void fillmem(void *pdest, size_t sdest,
const void *pfrom, size_t sfrom)
/*
* Fills the `sdest' bytes starting at `pdest' with copies
* of the `sfrom' bytes starting at `pfrom'. The final copy
* will be partial if `sfrom' does not divide `sdest'.
*/
{
if (sdest > sfrom) {
memcpy (pdest, pfrom, sfrom);
pfrom = pdest;
pdest = (char*)pdest + sfrom;
sdest -= sfrom;

while (sdest > sfrom) {
memcpy (pdest, pfrom, sfrom);
pdest = (char*)pdest + sfrom;
sdest -= sfrom;
sfrom += sfrom;
}
}

memcpy (pdest, pfrom, sdest);
}

<off-topic> At first glance and even at second glance, this looks
like a cache-killer. But on the platforms I've tested it doesn't
appear to suffer from cache-aliasing problems. It seems likely
that memcpy() on these platforms is implemented cleverly (and non-
portably) to dodge such issues. </off-topic>
 
P

Pedro Graca

Gaijinco said:
I'm having a headache using memset()

int v[100];
memset(v, 1, sizeof v);

How many times are you copying the 1?
It is not 100 times!

----------------
#include <stdio.h>
int main(void) {
int v[100];
/* sorry about the cast: my compiler doesn't like %zu */
printf("sizeof v is %lu.\n", (unsigned long)sizeof v);
return 0;
}
 
A

Army1987

Martin said:
memset((void*)v, 1, sizeof(v));
Can I be 100% positive than v = 1 for i > 0, or there is something
else I have to do?.


Unless sizeof(int) == 1, you can be 100% positive that v != 1.

Let's say 99.99999999%, since it is possible that the least significant bit
of each byte except one of them is a padding bit.
 
D

dj3vande

Eric Sosman said:
For very large arrays that need to be filled/refilled very
many times, here's a function I cooked up long ago:

#include <string.h>
void fillmem(void *pdest, size_t sdest,
const void *pfrom, size_t sfrom)
/*
* Fills the `sdest' bytes starting at `pdest' with copies
* of the `sfrom' bytes starting at `pfrom'. The final copy
* will be partial if `sfrom' does not divide `sdest'.
*/
{
if (sdest > sfrom) {
memcpy (pdest, pfrom, sfrom);
pfrom = pdest;
pdest = (char*)pdest + sfrom;
sdest -= sfrom;

while (sdest > sfrom) {
memcpy (pdest, pfrom, sfrom);
pdest = (char*)pdest + sfrom;
sdest -= sfrom;
sfrom += sfrom;
}
}

memcpy (pdest, pfrom, sdest);
}

<off-topic> At first glance and even at second glance, this looks
like a cache-killer. But on the platforms I've tested it doesn't
appear to suffer from cache-aliasing problems. It seems likely
that memcpy() on these platforms is implemented cleverly (and non-
portably) to dodge such issues. </off-topic>

How 'bout something like this?
--------
void fillmem(void *pdest,size_t sdest,const void *pfrom,size_t sfrom)
{
if(sdest <= sfrom)
{
memcpy(pdest,pfrom,sdest);
return;
}
/*Make the first copy of from*/
memcpy(pdest,pfrom,sfrom);
/*Now make the rest of the copies from the last copy
we made
*/
memmove((char *)pdest + sfrom,pdest,sdest-sfrom);
}
--------
I would expect this to be more cache-friendly[1], since after the
initial copy it's (in the abstract, at least) a simple linear walk
through memory for each of read and write, instead of walking through
the beginning of the array log2(N) times (going farther each time).
This takes advantage of the defined-on-overlap semantics of memmove; is
losing any optimizations memcpy can make that memmove can't a
sufficiently low price to pay for any benefits this approach might
have?

(Interestingly, I invented this independently about a week before
reading a description in comp.arch of the same technique being used in
a system older than I am.)


dave

[1] Keeping in mind that I know next to nothing about caching behavior
of modern processors
 
E

Eric Sosman

How 'bout something like this?
--------
void fillmem(void *pdest,size_t sdest,const void *pfrom,size_t sfrom)
{
if(sdest <= sfrom)
{
memcpy(pdest,pfrom,sdest);
return;
}
/*Make the first copy of from*/
memcpy(pdest,pfrom,sfrom);
/*Now make the rest of the copies from the last copy
we made
*/
memmove((char *)pdest + sfrom,pdest,sdest-sfrom);
}

memmove() doesn't "smear" the data the way this needs it
to. You'll end up with two copies of the fill pattern followed
by a big blob of whatever was in the destination beforehand,
slid rightwards by sfrom bytes.

7.21.2.2p2: "[...] Copying takes place as if the n
characters from the object pointed to by s2 are first
copied into a temporary array of n characters that does
not overlap the objects pointed to by s1 and s2, and
then the n characters from the temporary array are copied
into the object pointed to by s1."
(Interestingly, I invented this independently about a week before
reading a description in comp.arch of the same technique being used in
a system older than I am.)

This technique for "smearing" has been around since the days
of the dawn; I first encountered it in 1966 as a clear-core
program that was one instruction long. But that's not what
memmove() does.
 
D

dj3vande

Eric Sosman said:
memmove() doesn't "smear" the data the way this needs it
to. You'll end up with two copies of the fill pattern followed
by a big blob of whatever was in the destination beforehand,
slid rightwards by sfrom bytes.

7.21.2.2p2: "[...] Copying takes place as if the n
characters from the object pointed to by s2 are first
copied into a temporary array of n characters that does
not overlap the objects pointed to by s1 and s2, and
then the n characters from the temporary array are copied
into the object pointed to by s1."

Hmmmmmmm....

I could've sworn that said something different last time I read it,
which must have been too many lost neurons ago.
I suppose it's a Good Thing you pointed that out before I got around to
finishing the project I was planning to use it in, then.

This technique for "smearing" has been around since the days
of the dawn; I first encountered it in 1966 as a clear-core
program that was one instruction long. But that's not what
memmove() does.

Is there a reason (well, a reason behind history, which is probably the
currently-live reason) why memmove does a non-destructive copy instead
of smearing? It seems, to my limited imagination, that smearing would
be a lot more useful.


dave
 
B

Billy Bong

I'm having a headache using memset()

Given:

int v[1000000];
memset((void*)v, 1, sizeof(v));

No need for the cast to void pointer here, the conversion is automatic.
But do make sure to include <string.h>. Also there is no need for the
parentheses abound the 'v' as an operand to the sizeof operator, as 'v'
is an object, not a type.
Can I be 100% positive than v = 1 for i > 0, or there is something
else I have to do?.


No you can't, and on most implementations it will not be. memset() will
place the value 1 into every byte that makes up the array, and there are
1,000,000 times sizeof (int) bytes in the array.

There are a few implementations, mostly digital signal processors, where
CHAR_BIT is 16 and char and int have the same size and representation,
where every int in the array will be set to the value 1.

But on most platforms, especially anything in a desktop computer, you
won't get that value.

On old 16-bit implementations for MS-DOS, each int in the array will
wind up with the value 257.

On 32-bit Windows, Macintosh, or Linux platforms using x86 processors,
each int in the array will have the value 16843009.

On 64-bit operating systems using x86, the result will be
72340172838076673.
In various computers that I have tried it seems that the only value I
can copy to a range with memset() that works is 0.

It works for a value of 0 because memset() with a value of 0 will set
every bit in every byte to all bits 0. C guarantees that any integer
type with a value of all bits 0 has the value 0. This is not guaranteed
for floating point types or pointers.

As to how to do it, you need to use a loop:

#define ARRAY_SIZE 1000000

int v [ARRAY_SIZE];

size_t index;

for (index = 0; index < ARRAY_SIZE]; ++index) {
v [index] = 1;
}


Sans the extraneous ']' character after ARRAY_SIZE in the above for loop
(which requires a compiler diagnostic, and which is obviously a typo by
Mr. Klein), this is the way to do it.

If you want to initialize an array and do it in a portable, Standard C
compliant way, then using a for loop as above will guarantee this. Using
memset will not always guarantee this.

This should be a part of everyone's coding standard:

In code, always use a for loop (instead of, for example, memset) to
initialize an array.
 
R

Richard Heathfield

[comp.std.c added, no followups set - can we keep this in both groups
please? Ta.]

Billy Bong said:
On Sat, 26 Jan 2008 15:31:41 -0600, Jack Klein wrote:
int v [ARRAY_SIZE];

size_t index;

for (index = 0; index < ARRAY_SIZE]; ++index) {
v [index] = 1;
}

Sans the extraneous ']' character after ARRAY_SIZE in the above for loop
(which requires a compiler diagnostic, and which is obviously a typo by
Mr. Klein), this is the way to do it.

If you want to initialize an array and do it in a portable, Standard C
compliant way, then using a for loop as above will guarantee this. Using
memset will not always guarantee this.

....unless the array is of objects with integer type and the value you wish
to write into the array is 0, as we are assured from time to time by
various ISO members. This cannot AFAIK be deduced directly from the
Standard, though. Did it ever make it as far a TC?
 
E

Eric Sosman

[...]
Is there a reason (well, a reason behind history, which is probably the
currently-live reason) why memmove does a non-destructive copy instead
of smearing? It seems, to my limited imagination, that smearing would
be a lot more useful.

memmove() copies N bytes from source to destination.
The bytes that land in the destination are duplicates of
those that were in the source prior to the operation. So,
for example, you can use it to open a gap in an array:

memmove (array+C+i, array+C, (N-C-i) * sizeof array[0]);

.... or to close a gap:

memmove (array+C, array+C+i, (N-C-i) * sizeof array[0]);

With the "smearing" semantics -- which we've seen can be
obtained by other means -- these wouldn't work.

Look at it this way: memmove() and memcpy() "do the same
thing," except that the former promises to behave nicely even
when source and destination overlap, while the latter doesn't.
 
A

Army1987

Richard said:
...unless the array is of objects with integer type and the value you wish
to write into the array is 0, as we are assured from time to time by
various ISO members. This cannot AFAIK be deduced directly from the
Standard, though. Did it ever make it as far a TC?

n1256 in 6.2.6.2p5 has: A valid (non-trap) object representation
of a signed integer type where the sign bit is zero is a valid object representation of the
corresponding unsigned type, and shall represent the same value. For any integer type,
the object representation where all the bits are zero shall be a representation of the value
zero in that type.

There are change bars beside the last sentence.
See http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_263.htm
 
R

Richard Heathfield

Army1987 said:
n1256 in 6.2.6.2p5 has: A valid (non-trap) object representation
of a signed integer type where the sign bit is zero is a valid object
representation of the corresponding unsigned type, and shall represent
the same value. For any integer type, the object representation where
all the bits are zero shall be a representation of the value zero in
that type.

There are change bars beside the last sentence.
See http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_263.htm

Well, that answers that. Thanks, Army1987.
 
D

dj3vande

Eric Sosman said:
Look at it this way: memmove() and memcpy() "do the same
thing," except that the former promises to behave nicely even
when source and destination overlap, while the latter doesn't.

I think the source of my confusion may have been combining this with
understanding the behavior of memcpy as "copies as if by a simple
byte-copying loop" rather than "makes a duplicate copy".

The two behaviors are equivalent for non-overlapping chunks of memory,
but a simple byte-copying loop with (char*)src < (char*)dest <
(char*)src+size would do a smearing copy, while "making a duplicate
copy" excludes smearing by definition.


(It should be obvious by now that I rarely (never, as far as I can
remember) have to copy data between overlapping chunks of memory.)


dave
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,813
Latest member
lawrwtwinkle111

Latest Threads

Top