In the course of porting an implementation of the SHA-x series of message digest algorithms (SHA-224, SHA-256, SHA-384, and SHA-512) from Unix C to Microsoft C, using the Visual C++ 6.0 compiler, I needed to convert several hard coded initialization vectors, each composed of 64 bit integer literals, to a format acceptable to the Visual C++ compiler. This was my first serious foray into 64 bit integer math, which is essential to the higher order SHA-x algorithms.
In the Unix C code, the literals look like this.
- 0xcbbb9d5dc1059ed8ULL
The Microsoft Visual C++ compiler needs something like this.
- 0xcbbb9d5dc1059ed8
Following is the shortest of the initialization vectors.
- #if defined(_MSC_VER) defined(__BORLANDC__)
uint64 sha384_h0[8] =
{0xcbbb9d5dc1059ed8, 0x629a292a367cd507,
0x9159015a3070dd17, 0x152fecd8f70e5939,
0x67332667ffc00b31, 0x8eb44a8768581511,
0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4};
#else
uint64 sha384_h0[8] =
{0xcbbb9d5dc1059ed8ULL, 0x629a292a367cd507ULL,
0x9159015a3070dd17ULL, 0x152fecd8f70e5939ULL,
0x67332667ffc00b31ULL, 0x8eb44a8768581511ULL,
0xdb0c2e0d64f98fa7ULL, 0x47b5481dbefa4fa4ULL}; - #endif
The second block, between #else and #endif, contains the original definition, which probably works fine on any C compiler that runs on Unix or any of its many variations, especially if the target CPU has a 64 bit word, but a half-dozen or so of these made Visual C++ hurl.
I suspected that I needed only to lose the ULL size suffixes, and almost tried the change without doing any research. Amazingly, the following query, fed into Google, promptly returned exactly one link, MatLab® 7: External Interfaces. When I saw the title, I felt certain that I had hit pay dirt.
"64 bit integer literal" "visual c++ 6.0"
Repeating the first of the two search tokens, "64 bit integer literal," within the returned "page," which is a massive Adobe PDF document, instantly took me to the following section, on page 186
Specifying Constant Literal Values
To assign signed and unsigned 64-bit integer literal values, use typedefinitions int64_T and uint64_T.
On UNIX systems, to assign a literal value to an integer variable where thevalue to be assigned is greater than 2 31-1 signed, you must suffix the valuewith LL. If the value is greater than 2 32-1 unsigned, then use LLU as thesuffix. These suffixes apply only to UNIX systems and are considered invalidon the Microsoft Windows systems.
Note The LL and LLU suffixes are not required for hardcoded (literal) valuesless than 2 G (2 31-1), even if they are assigned to a 64-bit int type.
The following example declares a 64-bit integer variable initialized with alarge literal int value, and two 64-bit integer variables:
void mexFunction(int nlhs, mxArray *plhs[], int nrhs,
const mxArray *prhs[])
#if defined(_MSC_VER) defined(__BORLANDC__) /* Windows */
int64_T large_offset_example = 9000222000;
#else /* UNIX */
int64_T large_offset_example = 9000222000LL;
#endif
int64_T offset = 0;
int64_T position = 0;
This was exactly the information that I needed. Application of the same technique to my source code quickly yielded code that compiles cleanly, without errors or warnings.
I've used hundreds of similar queries with Google and other search engines, followed by hours of wasted time reading irrelevant material. More often than not, they have yielded either nothing, or a hopelessly long list of mostly useless articles.
Persistence pays, and, sometimes, you really do get lucky.