2

I'm trying to increment LARGE_INTEGER in c++ but I get following error.

Error C2397: conversion from 'LONGLONG' to 'DWORD' requires a narrowing conversion

I have no idea what I'm doing wrong. its very simple problem, I tried to rebuild project but error just wont go away.

std::atomic<LARGE_INTEGER> value; // this field is defined in header

these line are what I have tried, all of them give same error.

// inside a method in cpp
value = {get_some_large_integer().QuadPart + 1};

value = LARGE_INTEGER{get_some_large_integer().QuadPart + 1};

value = static_cast<LARGE_INTEGER>(LARGE_INTEGER{get_some_large_integer().QuadPart + 1});
M.kazem Akhgary
  • 18,645
  • 8
  • 57
  • 118
  • yes, I must use `LARGE_INTEGER` because I'm limited to library windows functions that is using this data type. Yes, `value = {get_some_large_integer()};` works for me too, but `value = {get_some_large_integer().QuadPart};` gives the error. it seems incrementing is not problem but accessing QuadPart is some how a problem. @CodyGray – M.kazem Akhgary Aug 11 '17 at 20:58
  • @CodyGray I see, but its weird that ctor doesn't accept 64bit value. its weird if its 64bit value it should have that! – M.kazem Akhgary Aug 11 '17 at 21:00
  • 1
    It's initializing a `LARGE_INTEGER` from `li.QuadPart` that is the problem. Try it without `std::atomic`. You'll have the same problem. There is no way to construct `LARGE_INTEGER` directly from a 64-bit value (since, unfortunately, C++ doesn't have [designated initializers](https://stackoverflow.com/questions/31638182/initialize-union-using-largest-member-under-msvc-compiler)). You need to construct it using the two 32-bit halves. I don't know a good solution here. Maybe someone else will. – Cody Gray - on strike Aug 11 '17 at 21:00
  • I've never had any problems dealing with 64 bit integers since VS 2008. The problem is probably due to the fact that LARGE_INTEGER is a union, and not a struct. – Michaël Roy Aug 11 '17 at 23:29

2 Answers2

2

You can simply directly use the Quadpart. Note that it is a 64 bit long integer. also known as long long and __int64 by the MS compiler and gcc. Since it is a plain old data type, the compilers support all arithmetics and bit-wise operations done with it.

The definition of LARGE INTEGER

typedef union _LARGE_INTEGER {
  struct {
    DWORD LowPart;
    LONG  HighPart;
  };
  struct {
    DWORD LowPart;
    LONG  HighPart;
  } u;
  LONGLONG QuadPart;       // <--  this is a 64 bit integer.
} LARGE_INTEGER, *PLARGE_INTEGER;

LARGE_INTEGER is a plain C union, and as such does not provide any constructors. You can, however use the C aggregate initializer to initialize it to zero.

LARGE_INTEGER li = {};  // initialize to zero.

Using QuadPart, you can manipulate a LARGE_INTEGER as you would any long long integer...

Incrementing:

li.QuadPart++;

adding:

__int128 i = 123456LL;
 li.QuadPart += i;

etc...

li.QuadPart = 123456LL * 5;

IMPORTANT: MS uses the LARGE_INTEGER union for passing such long long values for both historical reasons and for forcing alignment of the long long. Some of the Windows API will crash if Quadpart is not aligned correctly. So simply casting an __int64* to LARGE_INTEGER* in calls to the Windows API is not good practice.

In 64-bit windows a 64 bit increment ie li.Quadpart++ is an atomic operation.

Michaël Roy
  • 6,338
  • 1
  • 15
  • 19
1

As problem addressed by @CodyGray in comments I came up with this solution. the operation is still atomic since atomic_store is only concerned and variables x and y are local to thread and the method.

LARGE_INTEGER x = get_some_large_integer();
LONGLONG y = x.QuadPart + 1; // increment
x.LowPart = (LONG)y;
x.HighPart = (LONG)(y >> 32);
value = x; // atomic operation.
M.kazem Akhgary
  • 18,645
  • 8
  • 57
  • 118