1

I have to generate a unique number in Java (for my machine on which the code is running) so that in C++ it can correspond to uint32_t. In general other C++ program should be able to read this unique number properly as uint32_t. I am sending this info in a byte array which other C++ program is deserializing it to get this number. I cannot change the datatype for this number in C++ program as of now.

  private static final AtomicInteger clientId = new AtomicInteger(0);

  // will be called many time when the program is running after initialization
  public static int getClientId() {
    int counter = clientId.incrementAndGet();
    return counter == Integer.MAX_VALUE ? 0 : counter;
  }

  // called only once at startup
  public static void setClientId(final int counter) {
    clientId.addAndGet(counter == Integer.MAX_VALUE ? 0 : counter);
  }

So I came up with above code. My setClientId method will be called only once during the application startup (initialization phase):

  • If this machine is running code for the first time, like it's a new machine then I will pass 0 to setClientId method.
  • If this machine was running code already but we restarted the server, then I will look up in a database what was the last saved value for this machine (as we are also saving this value in db every few minutes) and then I will pass that value to setClientId method.

And then later on when my program is running (after the initialization) it will keep calling getClientId method to give me the actual unique clientId.

Is this the right way of generating unique id for my machine which will be uint32_t for the C++ program? I am also making sure that if the value reaches Integer.MAX_VALUE then set it to 0 and start again. Do I have to do this? Or I can take negative values as well for this uint32_t?

Basically, I want to generate a unique number for my machine that should always corresonds to uint32_t. If machine is a new machine, we can start with number 0 (bcoz when we look up the value for this machine the db, there won't be any value so we will start with 0) but if machine has already ran this code before, then start with what was the last saved value in the database.

john
  • 11,311
  • 40
  • 131
  • 251
  • Java integers are signed, if you want the full range, you have to take the negative values as well. – xiaofeng.li Jan 22 '17 at 23:56
  • So `uint32_t` will be able to understand negative integer values as well? pardon my ignorance for c++ here. – john Jan 22 '17 at 23:58
  • This will be an issue only if you expect to generate more than 2,147,483,647 unique ID's. But if you serialize a Java signed `int` (which could be negative) as four bytes, and deserialize those 4 bytes in your C++ program as `uint32_t`, the C++ program will see the negative Java integers as integers in the range 2147483648 to 4294967295. – ajb Jan 23 '17 at 00:03
  • I see got it.. Then its better to send only positive Integer values so that it can deserialize positive integer values only. And there is a possibility it can go more than `2,147,483,647 unique ID's` for the machine which is running code from a long time and as soon as it hits that limit, I was resetting it back to 0 again. – john Jan 23 '17 at 00:06
  • @david good idea. The other way would be to use a `long` in Java and manually convert things to the format that C would expect (only send the lower 32 bits). –  Jan 23 '17 at 00:26

1 Answers1

1

Do I have to do this? Or I can take negative values as well for this uint32_t?

No, you don't have to, and you can take negative values as well. If you pass the Java integer to C++ bit-by-bit, the unit32_t in C++ is going to keep increasing even when the Java variable goes over the max value and becomes negative. That's the good thing about 2's complement signed integers, which is what Java uses to represent integral values.

Here's a 4-bit example illustrating what's happening:

Bits  Unsigned  Signed
0000         0       0
0001         1       1
0010         2       2
0011         3       3
0100         4       4
0101         5       5
0110         6       6
0111         7       7
1000         8      -8
1001         9      -7
1010        10      -6
1011        11      -5
1100        12      -4
1101        13      -3
1110        14      -2
1111        15      -1

Also see this answer: What happens when you increment an integer beyond its max value.

Community
  • 1
  • 1
xiaofeng.li
  • 8,237
  • 2
  • 23
  • 30
  • I see.. so then how does my method look like for both get and set? I guess then I don't need that max value check anymore. – john Jan 23 '17 at 01:14
  • IMHO the max value check is just limiting the value of the counter to non-negative. If you drop the check, the variable is going to wrap around anyway (just more slowly). – xiaofeng.li Jan 23 '17 at 01:21
  • Another question is, you're getting duplicates when you wrap around (yes it's a very long sequence, but still...) – xiaofeng.li Jan 23 '17 at 01:23