I am a beginner in C programming language, I don't understand why there is -1 in the 2nd command line. thank you in advance.
printf("The maximum value of UNSIGNED INT = %u\n", UINT_MAX);
result: 4294967295
printf("The maximum value of UNSIGNED INT = %d\n", UINT_MAX);
result : -1 (why?)
%d tells printf to format an int that you pass it. You did not pass it an int; you passed it an unsigned int. It has no knowledge of that and attempts to work with the data that you passed.
“-1” is a common result because the bits for the maximum unsigned int (all bits 1) is the same as the bits used for the two’s complement −1 int (also all bits 1). However, when you mismatch format conversions and arguments, a variety of things can go wrong. C was developed as a language for telling the computer what to do in a human-friendly way (using symbol names and arithmetic operations and convenient functions rather than assembly language instructions). This makes it easy to tell the computer to do wrong things. This is unlike other languages that add a lot of rules and software to handle things for you automatically, such as managing types more strictly.
Related
I'm sorry if this question is too basic...I just have not found the answer to it anywhere.
Say I declare a C variable like this:
unsigned int var = 241;
In this case the var is unsigned so my intention is for it to have decimal value 241.
Alternatively I could declare it like this:
signed int var = -15;
In this case I declared it as signed integer so, as per my understanding it should have the decimal value -15.
However both times, I assume the var will be declared in memory(hardware) like this:
1111 0001.
So how does the processor know, at the lowest level which is in the hardware that I intended to declare this as 241 or -15?
I'm aware of the two's complement notation that is used to represent negative numbers and such but, I assume in hardware the processor only sees a sequence of ones and zeroes and then does some operation with it by switching the states of some ICs. How does the processor know whether to interpret the sequence of bits in standard binary(for unsigned) or 2's complement(for signed)?
Also another somewhat unrelated questions:
In C I can do this:
unsigned int var = -15;
printf("The var is: %d ", var);
This will as expected print -15.
Why, when I do this:
signed int var = 0xF1; //or 0b11110001
printf("The var is: %d ", var);
I get 241 instead of -15? Since I declared it as signed and in two's complement 0xF1 is -15 why am I getting the value 241 which is the equivalent of 0xF1 in standard binary?
Why does the compiler let me do stuff like:
unsigned int var = -15;
Shouldn't it throw an error telling me I can't assign negative values to a variable which I have declared as unsigned?
Thank you and I apologize for my many and perhaps basic questions, there is so much I do not know :D.
The hardware does not know.
The compiler knows.
The compiler knows because you said so here signed int var = -15;, "This, dear compiler, is a variable which can be negative and I init it to a negative value."
Here you said differently unsigned int var = 241;, "This, dear compiler, is a variable which cannot be negative and I init it to a positive value."
The compiler will keep that in mind for anything you later do with the variable and its values. The compiler will turn all corresponding code into that set of instructions in machine language, which will cause the hardware to behave accordingly. So the hardware ends up doing things appropriate to negative or not; not because of knowing, but because of not getting a choice on it.
An interesting aspect of "corresponding instructions" (as pointed out by Peter Cordes in a comment below) is the fact that for the special (but very widely used) case of 2-complement representation of negative values, the instructions are actually identical for both (which is an important advantage of 2-complement).
If the two values were char (signed or not), then their internal representation (8-bit pattern) would be the same in memory or register.
The only difference would be in the instructions the compiler emits when dealing with such values.
For example, if these values are stored in variables declared signed or unsigned in C, then a comparison between such values would make the compiler generate a signed or unsigned specific comparison instruction at assembly level.
But in your example you use ints.
Assuming that on your platform these ints use four bytes, then the two constants you gave are not identical when it comes to their 32-bit pattern.
The higher bits take in consideration the sign of the value and propagate to fill with 0 or 1 up to 32-bits (see the sequences of 0 or f below).
Note that assigning a negative value to an unsigned int produces a warning at compilation if you use the proper compiler flags (-Wconversion for example).
In his comment below, #PeterCordes reminds us that such an assignment is legal in C, and useful in some situations; the usage (or not) of compiler flags to detect (or not) such cases is only a matter of personal choice.
However, assigning -15U instead of -15 makes explicit the intention to consider the constant as unsigned (despite the minus sign), and does not trigger the warning.
int i1=-15;
int i2=0xF1;
int i3=241;
printf("%.8x %d\n", i1, i1); // fffffff1 -15
printf("%.8x %d\n", i2, i2); // 000000f1 241
printf("%.8x %d\n", i3, i3); // 000000f1 241
unsigned int u1=-15; // warning: unsigned conversion from ‘int’ to ‘unsigned int’ changes value from ‘-15’ to ‘4294967281’
unsigned int u2=0xF1;
unsigned int u3=241;
printf("%.8x %u\n", u1, u1); // fffffff1 4294967281
printf("%.8x %u\n", u2, u2); // 000000f1 241
printf("%.8x %u\n", u3, u3); // 000000f1 241
Here is a question from my book,
Actually, I don't know what will be the effect on printf function, so I tried the statements in the original system of C lang. Here is my code:
#include <stdio.h>
void main() {
int x = 4;
printf("%hi\n", x);
printf("%hu\n", x);
printf("%i\n", x);
printf("%u\n", x);
printf("%li\n", x);
printf("%lu\n", x);
}
Try it online!
So, the output is very simple. But, is this really the solution to above problem?
There are numerous problems in this question that make it unsuitable for teaching C.
First, to work on this problem at all, we have to assume a non-standard C implementation is used. In standard C, %x is a complete conversion specification, so %xu and %xd cannot be; the conversion specification has already ended before the u or d. And the uses of z in a conversion specification interferes with its standard use for size_t.
Nonetheless, let’s assume this C variant does not have those standard conversion specifications and instead uses the ones shown in the table but that this C variant otherwise conforms to the C standard with minimal changes.
Our next problem is that, in Y num = 42;, we have a plain Y, not the signed Y or unsigned Y shown in the table. Let’s assume signed Y is intended.
Then num is a signed four-bit integer. The greatest value it can represent is 01112 = 710. So it cannot represent 42. Attempting to initialize it with 42 results in a conversion specified by C 2018 6.3.1.3, which says, in part:
Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.
The result is we do not know what value is in num or even whether the program continues to execute; it may trap and terminate.
Well, let’s assume this implementation just takes the low bits of the value. 42 is 1010102, so its low four bits are 1010. So if the bits in num are 1010, it is negative. The C standard permits several methods of representation for negative numbers, but we will assume the overwhelmingly most common one, two’s complement, so the bits 1010 in num represent −6.
Now, we get to the printf statements. Except the problem text shows Printf, which is not defined by the C standard. (Are you sure this problem relates to C code at all?) Let’s assume it means printf.
In printf("%xu",num);, if the conversion specification is supposed to work like the ones in standard C, then the corresponding argument should be an unsigned X value that has been promoted to int for the function call. As a two-bit unsigned integer, an unsigned X can represent 0, 1, 2, or 3. Passing it −6 is not defined. So we do not know what the program will print. It might take just the low two bits, 10, and print “2”. Or it might use all the bits and print “-6”. Both of those would be consistent with the requirement that the printf behave as specified for values that are in the range representable by unsigned X.
In printf("%xd",num); and printf("%yu",num);, the same problem exists.
In printf("%yd",num);, we are correctly passing a signed Y value for a signed Y conversion specification, so “-6” is printed.
Then printf("%zu",num); has the same problem with the value mismatched for the type.
Finally, in printf("%zd",num);, the value is again in the correct range, and “-6” is printed.
From all the assumptions we had to make and all the points where the behavior is undefined, you can see this is a terrible exercise. You should question the quality of the book it is in and of any school using it.
My question involves the memory layout and mechanics behind the C printf() function. Say I have the following code:
#include <stdio.h>
int main()
{
short m_short;
int m_int;
m_int = -5339876;
m_short = m_int;
printf("%x\n", m_int);
printf("%x\n", m_short);
return 0;
}
On GCC 7.5.0 this program outputs:
ffae851c
ffff851c
My question is, where is the ffff actually coming from in the second hex number? If I'm correct, those fs should be outside the bounds of the short, but printf is getting them from somewhere.
When I properly format with specifier %hx, the output is rightly:
ffae851c
851c
As far as I have studied, the compiler simply truncates the top half of the number, as shown in the second output. So in the first output, are the first four fs from the program actually reading into memory that it shouldn't? Or does the C compiler behind-the-scenes still reserve a full integer even for a short, sign-extended, but the high half shall be undefined behavior, if used?
Note: I am performing research, in a real-world application, I would never try to abuse the language.
When a char or short (including signed and unsigned versions) is used as a function argument where there is no specific type (as with the ... arguments to printf(format,...))1, it is automatically promoted to an int (assuming it is not already as wide as an int2).
So printf("%x\n", m_short); has an int argument. What is the value of that argument? In the assignment m_short = m_int;, you attempted to assign it the value −5339876 (represented with bytes 0xffae851c). However, −5339876 will not fit in this 16-bit short. In assignments, a conversion is automatically performed, and, when a conversion of an integer to a signed integer type does not fit, the result is implementation-defined. It appears your implementation, as many do, uses two’s complement and simply takes the low bits of the integer. Thus, it puts the bytes 0x851c in m_short, representing the value −31460.
Recall that this is being promoted back to int for use as the argument to printf. In this case, it fits in an int, so the result is still −31460. In a two’s complement int, that is represented with the bytes 0xffff851c.
Now we know what is being passed to printf: An int with bytes 0xffff851c representing the value −31460. However, you are printing it with %x, which is supposed to receive an unsigned int. With this mismatch, the behavior is not defined by the C standard. However, it is a relatively minor mismatch, and many C implementations let it slide. (GCC and Clang do not warn even with -Wall.)
Let’s suppose your C implementation does not treat printf as a special known function and simply generates code for the call as you have written it, and that you later link this program with a C library. In this case, the compiler must pass the argument according to the specification of the Application Binary Interface (ABI) for your platform. (The ABI specifies, among other things, how arguments are passed to functions.) To conform to the ABI, the C compiler will put the address of the format string in one place and the bits of the int in another, and then it will call printf.
The printf routine will read the format string, see %x, and look for the corresponding argument, which should be an unsigned int. In every C implementation and ABI I know of, an int and an unsigned int are passed in the same place. It may be a processor register or a place on the stack. Let’s say it is in register r13. So the compiler designed your calling routine to put the int with bytes 0xffff851c in r13, and the printf routine looked for an unsigned int in r13 and found bytes 0xffff851c.
So the result is that printf interprets the bytes 0xffff851c as if they were an unsigned int, formats them with %x, and prints “ffff851c”.
Essentially, you got away with this because (a) a short is promoted to an int, which is the same size as the unsigned int that printf was expecting, and (b) most C implementations are not strict about mismatching integer types of the same width with printf. If you had instead tried printing an int using %ld, you might have gotten different results, such as “garbage” bits in the high bits of the printed value. Or you might have a case where the argument you passed is supposed to be in a completely different place from the argument printf expected, so none of the bits are correct. In some architectures, passing arguments incorrectly could corrupt the stack and break the program in a variety of ways.
Footnotes
1 This automatic promotion happens in many other expressions too.
2 There are some technical details regarding these automatic integer promotions that need not concern us at the moment.
I am new to embedded System. I would like to perform division between 2 unsigned 16 bit integer and display the answer(including the decimal values). I wonder how can I accomplish this in embedded-C. Float,double and unsigned long does not seem to work. I am using TI's TM4C launchpad.
uint8_t PPGMsg[5];
unsigned long PPG;
uint16_t IR_combined,RED_combined;
IR_combined = (PPGMsg[1]<< 8)|PPGMsg[2];
RED_combined = (PPGMsg[3]<< 8)|PPGMsg[4];
PPGMsg[0]=(RED_combined/IR_combined);
PPG=(RED_combined/IR_combined);
UARTprintf("IR_combined is: %d\n",IR_combined);
UARTprintf("RED_combined is: %d\n",RED_combined);
UARTprintf("PPG is: %d\n",PPGMsg[0]);
UARTprintf("long PPG is: %d\n",PPG);
For example when IR_combined is: 147 and RED_combined is: 1012, the PPG: 6.
However I would like the answer to be displayed as 6.88 instead.
For 2 decimals precision, you need to do (uint32_t)RED_combined*100/IR_combined. Then print the decimals as you would like them. Example:
#include <stdint.h>
#include <inttypes.h>
...
uint16_t RED_combined = 1012;
uint16_t IR_combined = 147;
uint16_t x = ((uint32_t)RED_combined*100u / IR_combined);
printf("%"PRIu16".%.2"PRIu16, x/100, x%100);
However, you also have lots of other problems/bugs:
IR_combined = (PPGMsg[1]<< 8)|PPGMsg[2]; is dangerous/buggy code. Since PPGMsg[1] is a small integer type, it gets promoted to int and you end up performing left shifts on a signed type. Similarly, the | invokes implicit promotion to signed type.
You must study Implicit type promotion rules.
(PPGMsg[3]<< 8)|PPGMsg[4]; Same bugs here.
PPGMsg[0]=(RED_combined/IR_combined); You store the result in a 8 bit variable that is too small to hold the result. I don't understand how this makes any sense. Are you trying to parse out the ls byte?
%d is used to print signed integers. UARTprintf("IR_combined is: %d\n",IR_combined); should be "IR_combined is: %"PRIu16 "\n",IR_combined. You find these format specifier macros in inttypes.h.
Same bug: UARTprintf("PPG is: %d\n",PPGMsg[0]);. Should be UARTprintf("PPG is: %"PRIu8 "\n",PPGMsg[0]);.
unsigned long is printed with %ld
Using the correct type matters, everywhere!
Also consider using a good compiler like gcc that does warn if you use the wrong format specifier. Or better yet, don't use printf-like functions at all - they are unsafe, slow and resource-heavy.
I reading a C book. To print out a memory address of a variable, sometimes the book uses:
printf("%u\n",&n);
Sometimes, the author wrote:
printf("%d\n",&n);
The result is always the same, but I do not understand the differences between the two (I know %u for unsigned).
Can anyone elaborate on this, please?
Thanks a lot.
%u treats the integer as unsigned, whereas %d treats the integer as signed. If the integer is between 0 an INT_MAX (which is 231-1 on 32-bit systems), then the output is identical for both cases.
It only makes a difference if the integer is negative (for signed inputs) or between INT_MAX+1 and UINT_MAX (e.g. between 231 and 232-1). In that case, if you use the %d specifier, you'll get a negative number, whereas if you use %u, you'll get a large positive number.
Addresses only make sense as unsigned numbers, so there's never any reason to print them out as signed numbers. Furthermore, when they are printed out, they're usually printed in hexadecimal (with the %x format specifier), not decimal.
You should really just use the %p format specifier for addresses, though—it's guaranteed to work for all valid pointers. If you're on a system with 32-bit integers but 64-bit pointers, if you attempt to print a pointer with any of %d, %u, or %x without the ll length modifier, you'll get the wrong result for that and anything else that gets printed later (because printf only read 4 of the 8 bytes of the pointer argument); if you do add the ll length modifier, then you won't be portable to 32-bit systems.
Bottom line: always use %p for printing out pointers/addresses:
printf("The address of n is: %p\n", &n);
// Output (32-bit system): "The address of n is: 0xbffff9ec"
// Output (64-bit system): "The address of n is: 0x7fff5fbff96c"
The exact output format is implementation-defined (C99 §7.19.6.1/8), but it will almost always be printed as an unsigned hexadecimal number, usually with a leading 0x.
%d and %u will print the same results when the most significant bit is not set. However, this isn't portable code at all, and is not good style. I hope your book is better than it seems from this example.
What value did you try? The difference unsigned vs. signed, just as you said you know. So what did it do and what did you expect?
Positive signed values look the same as unsigned so can I assume you used a smaller value to test? What about a negative value?
Finally, if you are trying to print the variable's address (as it appears you are), use %p instead.
All addresses are unsigned 32-bit or 64-bit depending on machine (can't write to a negative address). The use of %d isn't appropriate, but will usually work. It is recommended to use %u or %ul.
There is no such difference ,just don't get confused if u have just started learning pointers.
%u is for unsigned ones.And %d for signed ones