Reading a long from a struct on 32 bit system(C) - c

In C, I have a struct with a member "frequency", which is a long unsigned int. The hardware this code is running on is 32 bits.
The struct has its value set at instantiation.
struct config_list configuration = {
...
.frequency = (long unsigned int)5250000000u,
...
}
In my code, I pass this struct, via pointer, to a subroutine. Inside this subroutine, I don't seem to be able to get the right value, so to check, I put in this:
printf("Config frequency: %lu\n", ptr->frequency);
printf("Derefernced: %lu\n", (*ptr).frequency);
As those are the two ways I believe you would be able to access the struct data from the pointer.
However, in both cases the output I see is 955,032,704. This I recognize as just the first 32 bits of the frequency I set. My question is, why is my long unsigned int being cut to 32 bits? Isn't a "long" supposed to extend the range to 64 bits?

5250000000 is 0x1 38EC A480... it just peeks into the 33rd bit.
I would recommend that you use the following:
#include <stdio.h>
#include <stdint.h> /* gives us uint64_t and UINT64_C() */
#include <inttypes.h> /* gives us PRIu64 */
int main(void) {
uint64_t d = UINT64_C(5250000000);
printf("%"PRIu64"\n", d);
return 0;
}
uint64_t is guaranteed to be a 64-bit unsigned, on any system.
UINT64_C will append the correct suffix (typically UL or ULL).
PRIu64 will specify the correct format string for a 64-bit unsigned.
On my 64-bit system, it looks like this after the pre-processor (gcc -E):
int main(void) {
uint64_t d = 5250000000UL;
printf("%""l" "u""\n", d);
return 0;
}
And for a 32-bit build, it looks like this (gcc -E -m32):
int main(void) {
uint64_t d = 5250000000ULL;
printf("%""ll" "u""\n", d);
return 0;
}

Related

Save 128 bit value (unsigned) when max data type has 64 bits

I have to save the number of non zero entries in a matrix with dimensions that could be
as big as uint64_t x uint64_t resulting in a 128 bit value.
Im not sure which data-type would be right for this variable in C as it would require 128 bits (unsigned).
I would use __int128 as a data type but my problem is that when I test the max. supported data type on my system with
#include <stdio.h>
#include <stdint.h>
int main() {
printf("maxUInt: %lu\n", sizeof(uintmax_t));
printf("maxInt: %lu", sizeof(intmax_t));
}
It gives the following result:
maxUInt: 8
maxInt: 8
meaning that 8 Bytes is the maximum for number representation.
So this is troubling me as the result is possibly 128 bits == 16 Bytes big.
Will __int128 still work in my case?
We're talking about the size of an array, so uintmax_t and intmax_t are irrelevant.
malloc() accepts a size_t. The following therefore computes the limit of how much you can request:
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
printf( "2^( %zu * %d ) bytes\n", sizeof( size_t ), CHAR_BIT );
For me, that's 2^( 8 * 8 ) octets.
18,446,744,073,709,551,616
But I'm an an x86-64 machine. Those don't support nearly that much memory. The instruction set only supports 2^48 octets of memory.
281,474,976,710,656 (1/65,536 of what 64 bits can support)
But no x86-64 machine supports that much. Current hardware only supports 2^40 octets of memory.
1,099,511,627,776 (1/16,777,216 of what 64 bits can support)
So unless you have some very special hardware, 64 bits is more than enough to store the size of any array your machine can handle.
Still, let's answer your question about support for __int128 and unsigned __int128. These two types, if supported, are an extension to the standard. And they are apparently not candidates for intmax_t and uintmax_t, at least on my compiler. So checking the size of intmax_t and uintmax_t is not useful for detecting their support.
If you want to check if you have support for __int128 or unsigned __int128, simply try to use them.
__int128 i = 0;
unsigned __int128 u = 0;
If both uintmax_t and unsigned __int128 are too small, you can still use extended precision math, such as by using two 64-bit integers in the manner showed in Maxim Egorushkin's answer.
One portable option is to construct a counter out of multiple smaller units:
typedef struct BigCounterC {
uint64_t count_[2];
} BigCounterC;
void BigCounterC_increment(BigCounterC* counter) {
// Increment the higher units when the lower unit of unsigned type wraps around reaching 0.
for(size_t n = sizeof counter->count_ / sizeof *counter->count_; n-- && !++counter->count_[n];);
}
int main() {
BigCounterC c2 = {0}; // Zero-initialize.
BigCounterC_increment(&c2);
return 0;
}
C++ version:
#include <cstdint>
#include <type_traits>
template<class Unit, size_t N>
struct BigCounter {
static_assert(std::is_unsigned_v<Unit>); // Unsigned overflow is well defined.
Unit count_[N] = {}; // Zero-initialize.
BigCounter& operator++() noexcept {
// Increment the higher units when the lower unit of unsigned type wraps around reaching 0.
for(auto n = N; n-- && !++count_[n];);
return *this;
}
};
int main() {
BigCounter<uint64_t, 2> c;
++c;
}

How do I sign extend and then find the value of the unsigned binary number in C?

I have a variable declared as an int
int a = -3;
I want the twos' complement values sign extended to 16 bits. So, it becomes: 1111 1111 1111 1101 and then find the unsigned value of this number, which would be 65533 (I believe).
In other words, I want to go from -3 to 65533.
Following this answer: Sign extension from 16 to 32 bits in C I'm stuck on the first step. Here's a shortened version of my code:
#include <stdio.h>
#include <string.h>
int main () {
int s = -3;
printf("%x\n", s);
s = (int16_t)s;
printf("%x\n", s);
int16_t i = s;
printf("%x\n", i);
return(0);
}
I compile with gcc test.c and all three printf statements give "fffffffd"
Do you know why the cast isn't working and perhaps any better solutions to the original problem?
Where you appear to be struggling with the issue is understanding just exactly what bits you are dealing with in interpreting the bits as signed or unsigned or as exact-width types.
How do I sign extend and then find the value of the unsigned binary
number in C?
Answer: you don't -- the bits never change....
When you declare int a = -3;, the bits are set in memory. Thereafter, unless you change them, they are the exact same 32-bits (or whatever sizeof a is on your hardware).
The key to understanding sign-extension is it only applies when interpreting a negative value under a two's complement system when casting or assigning to a larger-size type. Otherwise, you are not extending anything, you are just interpreting the bits as a different type.
A short example for your problem will illustrate. Here int a = -3; is declared (defined) and the bits of a thereafter never change. However, you can interpret those bits (or by lose analogy look at them from a different viewpoint) and use those bits as short, unsigned short, int16_t or uint16_t and in all unsigned cases, interpret them as a hexadecimal value, e.g.
#include <stdio.h>
#include <stdint.h>
#ifdef __GNUC__
#include <inttypes.h>
#endif
int main (void) {
int a = -3;
printf ("a (as int) : %d\n"
"a (as short) : %hd\n"
"a (as unsigned short) : %hu\n"
"a (as unsigned short hex) : 0x%0x\n"
"a (as PRId16) : %" PRId16 "\n"
"a (as PRIu16) : %" PRIu16 "\n"
"a (as PRIx16) : 0x%" PRIx16 "\n",
a, (short)a, (unsigned short)a, (unsigned short)a,
(int16_t)a, (uint16_t)a, (uint16_t)a);
return 0;
}
Example Use/Output
$ ./bin/exact3
a (as int) : -3
a (as short) : -3
a (as unsigned short) : 65533
a (as unsigned short hex) : 0xfffd
a (as PRId16) : -3
a (as PRIu16) : 65533
a (as PRIx16) : 0xfffd
Look things over, and look at all the answers, and let us know if you have any further questions.
Your code causes undefined behaviour by using the wrong format specifier for the argument type in printf.
Here is some correct code:
#include <stdio.h>
int main(void)
{
int s = -3;
uint16_t u = s; // u now has the value 65533
printf("%u\n", (unsigned int)u);
printf("%x\n", (unsigned int)u);
}
The code to printf a uint16_t is slightly complicated, it's simpler to cast to unsigned int and use %u or %x which are specifiers for unsigned int.
fffffffd is the correct two's complement value it's just being printed in hex
use %d in your printf statements
#include <stdio.h>
#include <string.h>
int main () {
int s = -3;
printf("%d\n", s);
s = (int16_t)s;
printf("%d\n", s);
int16_t i = s;
printf("%d\n", i);
return(0);
}
and you should see that 65533 value
In C casting signed value to a wider type automatically extends its sign.
To get a complement value you need to cast your value to appropriate unsigned type:
#include <stdio.h>
#include <stdint.h>
int main ()
{
int s = -3;
printf("%x\n", s);
int16_t s16 = (int16_t)s;
printf("%hd\n", s16);
uint16_t c16 = (uint16_t)s16;
printf("%hu\n", c16);
}
The output I get:
fffffffd
-3
65533

Compile time/macro swap of endianess of float in c99

I have some floats (IEEE-754) that I want to initialize. The floats are fetched by another device (automagically) which runs big endian where I am using little endian and I can't change that.
Normally I would just swap with some built in function, but they are all run-time functions. I'd perfer not having to have an init() function just to swap endianess and it would be great if I could use it for const initializations also.
Something that result in this would be perfect:
#define COMPILE_TIME_SWAPPED_FLOAT(x) (...)
const float a = COMPILE_TIME_SWAPPED_FLOAT(1.0f);
Any great ideas?
Compile time/macro swap of endian-ness of float in c99
OP has other problem with using "reverse" float as a float
A local variable of type float encoding the "reverse" endian floating point value cannot certainly be initialized as a float. Many of the values in reverse byte order would correspond to a Not-A-Number (NAN) in the local float. The assignment may not be stable (bit pattern preserving). It could be:
// not a good plan
float f1 = some_particulate_not_a_number_bit_pattern;
float f2 = some_other_particulate_not_a_number_bit_pattern;
Instead the local "reversed" endian float should just be a uint32_t, 4-byte structure/union or 4-byte array initialized in some way with a float.
// Demo of why a reversed `float` can fail
// The Not-a-numbers bit to control signaling NaN vs. quiet NaN isn't certainly preserved.
int main(void) {
for (;;) {
union {
int32_t i32;
int32_t u32;
float f;
} x,y;
x.i32 = rand();
y.f = x.f;
if (x.u32 ^ y.u32) {
// If bit pattern preserved, this should never print
// v-------+---- biased exponent max (NaN)
// |-------|v--- signaling/quiet bit
// On my machine output is always x1111111 1?xxxxxx xxxxxxxx xxxxxxxx
printf("%08x\n", (unsigned) x.u32);
printf("%08x\n\n", (unsigned) y.u32);
}
}
}
Output
7f8181b1
7fc181b1
...
The below uses a compound literal to meet OP's goal. First initialize a union's float member with the desired float. Then extract it byte-by-byte from its uint8_t member (per desired endian) to initialize a new compound literal's uint8_t array member. Then extract the uint32_t. Works for local variables.
#include <stdint.h>
#include <stdio.h>
typedef uint32_t float_reversed;
typedef union {
uint8_t u8[4];
float_reversed u32;
float f;
} endian_f;
#define ENDIAN_FN(_f,_n) ( (endian_f){.f=(_f)}.u8[(_n)] )
#define ENDIAN_F(_f) ((endian_f){ \
ENDIAN_FN(_f,3), ENDIAN_FN(_f,2), \
ENDIAN_FN(_f,1), ENDIAN_FN(_f,0)}.u32)
void print_hexf(void *f) {
for (size_t i=0; i<sizeof f; i++) {
printf("%02X", ((unsigned char *)f)[i]);
}
puts("");
}
int main(void) {
float f1 = 1.0f;
print_hexf(&f1);
float_reversed f1r = ENDIAN_F(f1);
print_hexf(&f1r);
float_reversed f2r = ENDIAN_F(1.0);
print_hexf(&f2r);
}
Output
0000803F
3F800000
3F800000
I'd say having the preprocessor to swap bytes of some non byte variable isn't possible.
The preprocessor does not know about data types and their representation on byte-level.
If the endian reversal code is available to be inlined then any half decent optimizing compiler will work out the reversed value at compile time.
Taking the reversal code from https://stackoverflow.com/a/2782742/2348315 :
inline float ReverseFloat( const float inFloat )
{
float retVal;
char *floatToConvert = ( char* ) & inFloat;
char *returnFloat = ( char* ) & retVal;
// swap the bytes into a temporary buffer
returnFloat[0] = floatToConvert[3];
returnFloat[1] = floatToConvert[2];
returnFloat[2] = floatToConvert[1];
returnFloat[3] = floatToConvert[0];
return retVal;
}
And using it in away that compiler can see all the details:
float reversed10(){
const float reversed = ReverseFloat(10.0f);
return reversed;
}
Compiles to:
reversed10():
vmovss xmm0, DWORD PTR .LC0[rip]
ret
.LC0:
.long 8257
with GCC 7.1 with -O2 enabled.
You can try other compilers over here:
https://godbolt.org/g/rFmJGP

Casting hex string to signed int results in different values in different platforms

I am dealing with an edge case in a program that I want to be multi-platform. Here is the extract of the problem:
#include <stdio.h>
#include <string.h>
void print_bits(size_t const size, void const * const ptr){
unsigned char *b = (unsigned char*) ptr;
unsigned char byte;
int i, j;
for (i=size-1;i>=0;i--)
{
for (j=7;j>=0;j--)
{
byte = (b[i] >> j) & 1;
printf("%u", byte);
}
}
puts("");
}
int main() {
char* ascii = "0x80000000";
int myint = strtol(ascii, NULL, 16);
printf("%s to signed int is %d and bits are:\t", ascii, myint);
print_bits(sizeof myint, &myint);
return 0;
}
So when I compile with GCC on Linux I get this output:
0x80000000 to signed int is -2147483648 and bits are: 10000000000000000000000000000000
On a Windows, using MSVC and MinGW I get:
0x80000000 to signed int is 2147483647 and bits are: 01111111111111111111111111111111
I think the GCC outputs the correct expected values. My question is, where does this difference come from and how to make sure that on all compilers I get the correct result?
UPDATE
The reason behind this code is, I have to check if the MSB (bit #31) of the HEX value is 0 or 1. Then, I have to get the unsigned integer value of the next 7 bits (#30 to #24) result (in case of 0x80000000these 7 bits should result in 0:
int msb_is_set = myint & 1;
uint8_t next_7_bits;
next_7_bits = myint >> 24; //fine on GCC, outputs 0 for the next 7 bits
#ifdef WIN32 //If I do not do this, next_7_bit will be 127 on Windows instead of 0
if(msb_is_set )
next_7_bits = myint >> 1;
#endif
P.S. This is on the same machine (i5 64bit)
You're dealing with different data models here.
Windows 64 uses LLP64, which means only long long and pointers are 64bit. As strtol converts to long, it converts to a 32bit value, and 0x80000000 in a 32bit signed integer is negative.
Linux 64 uses LP64, so long, long long and pointers are 64bit. I guess you see what's happening here now ;)
Thanks to the comments, I realize my initial answer was wrong. The different outcome indeed has to do with the differing models on those platforms. But: in case of the LP64 model, you have a conversion to a signed type that cannot hold the value, which is implementation defined. int is 32bit on both platforms and a 32bit int just cannot hold 0x80000000. So the correct answer is: you shouldn't expect any result from your code on Linux64. On Win64, as long is only 32bit, strtol() correctly returns LONG_MAX for 0x80000000, which happens to be just one smaller than your input.
int myint = strtol(ascii, NULL, 16);
strtol is 'string to long', not string to int.
Also, you probably want 0x800000000 to be an unsigned long.
You may find that on (that version of ) Linux that int is 64bit, whereas on (that version of) Windo3ws, int is 32bits.
Don't do this:
#ifdef __GCC__
because a compiler switch might change the way things work. Better to do something like:
In some header somewhere:
#ifdef __GCC__
#define FEATURE_SHIFT_RIGHT_24
#endif
#ifdef __MSVC__
#define FEATURE_SHIFT_RIGHT_1
#endif
Then in your main code:
#ifdef FEATURE_SHIFT_RIGHT_24
next_7_bits = myint >> 24;
#endif
#ifdef FEATURE_SHIFT_RIGHT_1
if(msb_is_set )
next_7_bits = myint >> 1;
#endif
Your code should handle the implementation details, and the header should check which implementation is required by which compiler.
This separates out the code required from detecting which method is required for this compiler. In your header you can do more complex detection of compiler features.
e.g.
#ifdef __GCC__ && __GCCVERION__ > 1.23
etc
This is about your update. Although I'm not sure what your intention is, let's first point out some mistakes:
#ifdef WIN32
The macro always defined when targeting win32 is _WIN32, not WIN32.
Then you have another #ifdef checking for GCC, but this will not do what you expect: GCC also exists on win32 and it uses the same data model as MSVC. IOW, you can have both defined, __GCC__ and _WIN32.
You say you want to know whether the MSB is set. Then just make sure to convert your string to an unsigned int and directly check this bit:
#include <limits.h>
// [...]
unsigned int myint = strtoul(ascii, NULL, 16); // <- strtoul(), not strtol()!
unsigned int msb = 1U << (sizeof(unsigned int) * CHAR_BIT - 1);
if (myint & msb)
{
// msb is set
}
Btw, see this answer for a really portable way to get the number of bits in an integer type. sizeof() * CHAR_BIT will fail on a platform with padding bits.

How do I work with doubles at the bit level in standard C89?

I'm toying with implementing NaN tagging in a little language implementation I'm writing in C. To do this, I need to take a double and poke directly at its bits.
I have it working now using union casting:
typedef union
{
double num;
unsigned long bits;
} Value;
/* A mask that selects the sign bit. */
#define SIGN_BIT (1UL << 63)
/* The bits that must be set to indicate a quiet NaN. */
#define QNAN (0x7ff8000000000000L)
/* If the NaN bits are set, it's not a number. */
#define IS_NUM(value) (((value).bits & QNAN) != QNAN)
/* Convert a raw number to a Value. */
#define NUM_VAL(n) ((Value)(double)(n))
/* Convert a Value representing a number to a raw double. */
#define AS_NUM(value) (value.num)
/* Converts a pointer to an Obj to a Value. */
#define OBJ_VAL(obj) ((Value)(SIGN_BIT | QNAN | (unsigned long)(obj)))
/* Converts a Value representing an Obj pointer to a raw Obj*. */
#define AS_OBJ(value) ((Obj*)((value).bits & ~(SIGN_BIT | QNAN)))
But casting to a union type isn't standard ANSI C89. Is there a reliable way to do this that:
Is -std=c89 -pedantic clean?
Doesn't run afoul of strict aliasing rules?
Can be used in an expression context like this:
Value value = ...
printf("The number value is %f\n", AS_NUM(value));
Here is a quick proof-of-concept which compiles clean and appears to run correctly for me. I use memcpy to finesse the type-pun issue. This may of course be unacceptable in a real system, but it's at least portable. Likewise, I don't know if you intend to require that AS_NUM be implemented as a macro.
#include <stdio.h>
#include <string.h>
typedef struct {
char raw[sizeof(double)];
} Value;
static Value valueFromDouble(double d) {
Value result;
memcpy(result.raw, &d, sizeof(result));
return result;
}
static double AS_NUM(Value value) {
double result;
memcpy(&result, value.raw, sizeof(result));
return result;
}
int main(int argc, char **argv) {
Value value = valueFromDouble(1.0);
printf("The number value is %f\n", AS_NUM(value));
}
Here's a transcript of it compiling (with Clang on OS X) and running:
$ cc -std=c89 -pedantic blort.c
$ ./a.out
The number value is 1.000000

Resources