0

I am trying to use memset with INFINITY or NAN present in C header file <math.h> My code is:

double *dist;
dist = (double *)malloc(7*sizeof(double));
memset(dist, INFINITY, 7*sizeof(dist[0]));

However, on execution it gives me the following errors:

main.c:10:18: warning: overflow in conversion from ‘float’ to ‘int’ changes value from ‘+Inff’ to ‘2147483647’ [-Woverflow]
   11 |     memset(dist, INFINITY, 7*sizeof(dist[0]));

But I know INFINITY and NAN is represented using float. So why is it giving me an error? I even tried by using float instead of double but same issue. But, with any other floating point values it is working perfectly. Please help.

P.S.: It works perfectly fine if I use a loop instead of memset.

Edit: Is there any other way of doing this by avoiding the loop?

  • 1
    `memset()` sets each byte of the destination to the specified value. You can't use it with values larger than a byte. Just write an ordinary `for` loop. – Barmar May 20 '22 at 17:02
  • If all else fails, [read the instructions](https://en.cppreference.com/w/c/string/byte/memset). – Adrian Mole May 20 '22 at 17:04
  • But then @Barmar how is it possible with other large double values or with loops? Can you please explain? – Surya Majumder May 20 '22 at 17:04
  • What's `d`? That seems to be missing a definition – Tim Randall May 20 '22 at 17:04
  • @SuryaMajumder Because most other floating point values can be converted to `int`. It still won't do what you want. – Barmar May 20 '22 at 17:05
  • `INFINITY` is a macro based on a `float` expression, per the ISO C standard. Typically, `float` is implemented via the `binary32` type of the IEEE-754 standard (i.e. 4 bytes). The second argument to `memset` is an `int`, and an `unsigned char` typecast is applied to it, meaning it is a effectively a 1 byte argument. Unsurprisingly, this results in a *warning*, because the effect of what is being done here is unlikely to be what the programmer intended. There is no error message shown. `memset` *cannot* be used to initialize `float` data to `INFINITY`. – njuffa May 20 '22 at 17:05
  • 1
    For instance, `123.0` will be converted to the integer `123` without generating an error. But setting each byte of a float to `123` will not initialize the float to `123.0`. – Barmar May 20 '22 at 17:06

2 Answers2

3

As mentioned in other answers, the memset is not going to work because it fills the data with a single byte pattern. In the single precision floating point standard 754, the "infinity" is be encoded as 00 00 80 7f bytes (assuming little endian). Therefore it is not possible to use memset for desired initialization. Frankly, it's difficult to use this function for initialization with anything other than zeros or all-one bits.

However, if you use GCC, CLANG or ICC then there is an extensions allowing specify ranges in designated initializers:

float arr[] = { [0 ... 6] = INFINITY };

The either use arr as dist or copy it with memcpy.

memcpy(dist, arr, sizeof arr);

The compiler may be smart enough to optimize this operation.

The operation can be "one-lined" with a help of compound initializer.

memcpy(dist, (float[]){ [0 ... 6] = INFINITY }, 7 * sizeof *dist);
tstanisl
  • 13,520
  • 2
  • 25
  • 40
  • I believe the loop method is more efficient, because instead of having a separate object storing the repeated value, you only store the value once in the binary – user16217248 May 20 '22 at 18:43
  • @user16217248, probably loop is faster or the same. However OP was asking about non-loop solution – tstanisl May 20 '22 at 19:21
2

memset sets each byte to a given byte value. A double is bigger than a byte so one cannot use memset to set a double buffer to INFINITY. The best way to accomplish this is via a loop.

for (int i = 0; i < 7; ++i)
    dist[i] = INFINITY;
user16217248
  • 3,119
  • 19
  • 19
  • 37