What is the reason for the double negation -(-n)? - c

I'm going through some legacy code and I've seen something like
char n = 65;
char str[1024];
sprintf(str, "%d", -(-n));
Why has the author (no longer present) written -(-n) rather than just n? Wouldn't --n suffice?

The first thing to note is that --n actually decreases n by 1 and evaluates to the new value, with the type char; so it does something very different to -(-n). Don't change the code to that!
-n performs a unary negation of n and is also an expresion of type int due to the type promotion rules of C. The further negation sets it back to the original value but with the type int retained.
So -(-n) is actually a verbose way of writing +n, which is often though to be a no-op but in this case it converts the type of n to an int.
I suspect the author is guarding themselves against errant refactoring and they were worried about mismatching the type of the argument with the format specifier %d.
But in this particular case it does not matter: sprintf will automatically promote the char type to an int, so it's perfectly safe to write
sprintf(str, "%d", n);
Do also consider reducing the size of the str buffer if that's "real" code, and consider using the safer snprintf variant.
(As a final remark note that a double negation can yield signed integral type overflow, so do use with caution.)

Related

Use of sizeof operator in C

I wrote a code to print size of different data types in C .
#include<stdio.h>
int main()
{
printf("%d", sizeof(int));//size of integer
printf("%d", sizeof(float));
printf("%d", sizeof(double));
printf("%d", sizeof(char));
}
This does not work , but if I replace %d with %ld, it works. I did not understand why I have to take long int to print a small range number.
Both of those are wrong you must use %zu to print values of type size_t, which is what sizeof return.
This is because different values have different size, and you must match them.
It's undefined behavior to mismatch like you do, so anything could happen.
This is because sizes mismatch. By either using %zu or using %u and casting to unsigned you may fix the problem.
Currently, your implementation is undefined behaviour.
printf("%u", (unsigned)sizeof(int));//size of integer
printf("%u", (unsigned)sizeof(float));
printf("%u", (unsigned)sizeof(double));
printf("%u", (unsigned)sizeof(char));
Since stdout is new line buffered, don't forget to print \n at the end to get anything to screen.
sizeof has the return type size_t. From the Standard,
6.5.3.4 The sizeof and _Alignof operators
5 The value of the result of both operators is
implementation-defined, and its type (an unsigned integer type) is
size_t, defined in <stddef.h> (and other headers).
size_t is implementation-defined. In my linux, size_t is defined as __SIZE_TYPE__. On this topic, one can find details here.
In your case, it happens that size_t is implemented as a long , longer than int.
I did not understand why I have to take long int to print a small range number.
Because size_t may represent values much larger than what an int can support; on my particular implementation, the max size value is 18446744073709551615, which definitely won't fit in an int.
Remember that the operand of sizeof may be a parenthesized type name or an object expression:
static long double really_big_array[100000000];
...
printf( "sizeof really_big_array = %zu\n", sizeof really_big_array );
size_t must be able to represent the size of the largest object the implementation allows.
You say it does not work, but you do not say what it does. The most probable reason for this unexpected behavior is:
the conversion specifier %d expects an int value. sizeof(int) has type size_t which is unsigned and, on many platforms, larger than int, causing undefined behavior.
The conversion specifier and the type of the passed argument must be consistent because different types are passed in different ways to a vararg function like printf(). If you pass a size_t and printf expects an int, it will retrieve the value from the wrong place and produce inconsistent output if at all.
You say it works if I put %ld. This conversion may work because size_t happens to have the same size as long for your platform, but it is only a coincidence, on 64-bit Windows, size_t is larger than long.
To correct the problem, you can either:
use the standard conversion specifier %zu or
cast the value as int.
The first is the correct fix but some C libraries do not support %zu, most notably Microsoft C runtime libraries prior to VS2013. Hence I recommend the second as more portable and sufficient for types and objects that obviously have a small size:
#include <stdio.h>
int main(void) {
printf("%d\n", (int)sizeof(int));
printf("%d\n", (int)sizeof(float));
printf("%d\n", (int)sizeof(double));
printf("%d\n", (int)sizeof(char));
return 0;
}
Also note that you do not output a newline: Depending on the environment, the output will not be visible to the user until a newline is output or fflush(stdout) is called. It is even possible that the output not be flushed to the console upon program exit, causing your observed behavior, but such environments are uncommon. It is recommended to output newlines at the end of meaningful pieces of output. In your case, not doing so would cause all sizes to be clumped together as a sequence of digits like 4481, which may or may not be what you expect.

Why would a type int variable be used in a string input in C?

I am working through methods of input and output in C, and I have been presented with a segment of code that has an element that I cannot understand. The purport of this code is to show how the 'echoing' and 'buffered' input/outputs work, and in the code, they have a type 'int' declared for, as I understand, characters:
#include <stdio.h>
int main(void){
int ch; //This is what I do not get: why is this type 'int'?
while((ch = getchar()) != '\n'){
putchar(ch);
}
return 0;
}
I'm not on firm footing with type casting as it is, and this 'int' / 'char' discrepancy is undermining all notions that I have regarding data types and compatibility.
getchar() returns an int type because it is designed to be able to return a value that cannot be represented by char to indicate EOF. (C.11 §7.21.1 ¶3 and §7.21.7.6 ¶3)
Your looping code should take into account that getchar() might return EOF:
while((ch = getchar()) != EOF){
if (ch != '\n') putchar(ch);
}
The getc, fgetc and getchar functions return int because they are capable of handling binary data, as well as providing an in-band signal of an error or end-of-data condition.
Except on certain embedded platforms which have an unusual byte size, the type int is capable of representing all of the byte values from 0 to UCHAR_MAX as positive values. In addition, it can represent negative values, such as the value of the constant EOF.
The type unsigned char would only be capable of representing the values 0 to UCHAR_MAX, and so the functions would not be able to use the return value as a way of indicating the inability to read another byte of data. The value EOF is convenient because it can be treated as if it were an input symbol; for instance it can be included in a switch statement which handles various characters.
There is a little bit more to this because in the design of C, values of short and char type (signed or unsigned) undergo promotion when they are evaluated in expressions.
In classic C, before prototypes were introduced, when you pass a char to a function, it's actually an int value which is passed. Concretely:
int func(c)
char c;
{
/* ... */
}
This kind of old style definition does not introduce information about the parameter types.
When we call this as func(c), where c has type char, the expression c is subject to the usual promotion, and becomes a value of type int. This is exactly the type which is expected by the above function definition. A parameter of type char actually passes through as a value of type int. If we write an ISO C prototype declaration for the above function, it has to be, guess what:
int func(int); /* not int func(char) */
Another legacy is that character constants like 'A' actually have type int and not char. It is noteworthy that this changes in C++, because C++ has overloaded functions. Given the overloads:
void f(int);
void f(char);
we want f(3) to call the former, and f('A') to call the latter.
So the point is that the designers of C basically regarded char as being oriented toward representing a compact storage location, and the smallest addressable unit of memory. But as far as data manipulation in the processor was concerned, they were thinking of the values as being word-sized int values: that character processing is essentially data manipulation based on int.
This is one of the low-level facets of C. In machine languages on byte-addressable machines, we usually think of bytes as being units of storage, and when we load the into registers to work with them, they occupy a full register, and so become 32 bit values (or what have you). This is mirrored in the concept of promotion in C.
The return type of getchar() is int. It returns the ASCII code of the character it's just read. This is (and I know someone's gonna correct me on this) the same as the char representation, so you can freely compare them and so on.
Why is it this way? The getchar() function is ancient -- from the very earliest days of K&R C. putchar() similarly takes an int argument, when you'd think it might take a char.
Hope that helps!

How is {int i=999; char c=i;} different from {char c=999;}?

My friend says he read it on some page on SO that they are different,but how could the two be possibly different?
Case 1
int i=999;
char c=i;
Case 2
char c=999;
In first case,we are initializing the integer i to 999,then initializing c with i,which is in fact 999.In the second case, we initialize c directly with 999.The truncation and loss of information aside, how on earth are these two cases different?
EDIT
Here's the link that I was talking of
why no overflow warning when converting int to char
One member commenting there says --It's not the same thing. The first is an assignment, the second is an initialization
So isn't it a lot more than only a question of optimization by the compiler?
They have the same semantics.
The constant 999 is of type int.
int i=999;
char c=i;
i created as an object of type int and initialized with the int value 999, with the obvious semantics.
c is created as an object of type char, and initialized with the value of i, which happens to be 999. That value is implicitly converted from int to char.
The signedness of plain char is implementation-defined.
If plain char is an unsigned type, the result of the conversion is well defined. The value is reduced modulo CHAR_MAX+1. For a typical implementation with 8-bit bytes (CHAR_BIT==8), CHAR_MAX+1 will be 256, and the value stored will be 999 % 256, or 231.
If plain char is a signed type, and 999 exceeds CHAR_MAX, the conversion yields an implementation-defined result (or, starting with C99, raises an implementation-defined signal, but I know of no implementations that do that). Typically, for a 2's-complement system with CHAR_BIT==8, the result will be -25.
char c=999;
c is created as an object of type char. Its initial value is the int value 999 converted to char -- by exactly the same rules I described above.
If CHAR_MAX >= 999 (which can happen only if CHAR_BIT, the number of bits in a byte, is at least 10), then the conversion is trivial. There are C implementations for DSPs (digital signal processors) with CHAR_BIT set to, for example, 32. It's not something you're likely to run across on most systems.
You may be more likely to get a warning in the second case, since it's converting a constant expression; in the first case, the compiler might not keep track of the expected value of i. But a sufficiently clever compiler could warn about both, and a sufficiently naive (but still fully conforming) compiler could warn about neither.
As I said above, the result of converting a value to a signed type, when the source value doesn't fit in the target type, is implementation-defined. I suppose it's conceivable that an implementation could define different rules for constant and non-constant expressions. That would be a perverse choice, though; I'm not sure even the DS9K does that.
As for the referenced comment "The first is an assignment, the second is an initialization", that's incorrect. Both are initializations; there is no assignment in either code snippet. There is a difference in that one is an initialization with a constant value, and the other is not. Which implies, incidentally, that the second snippet could appear at file scope, outside any function, while the first could not.
Any optimizing compiler will just make the int i = 999 local variable disappear and assign the truncated value directly to c in both cases. (Assuming that you are not using i anywhere else)
It depends on your compiler and optimization settings. Take a look at the actual assembly listing to see how different they are. For GCC and reasonable optimizations, the two blocks of code are probably equivalent.
Aside from the fact that the first also defines an object iof type int, the semantics are identical.
i,which is in fact 999
No, i is a variable. Semantically, it doesn't have a value at the point of the initialization of c ... the value won't be known until runtime (even though we can clearly see what it will be, and so can an optimizing compiler). But in case 2 you're assigning 999 to a char, which doesn't fit, so the compiler issues a warning.

C: gcc implicitly converts signed char to unsigned char and vice versa?

I'm trying to learn C at got stuck with datatype-sizes at the moment.
Have a look at this code snippet:
#include <stdio.h>
#include <limits.h>
int main() {
char a = 255;
char b = -128;
a = -128;
b = 255;
printf("size: %lu\n", sizeof(char));
printf("min: %d\n", CHAR_MIN);
printf("max: %d\n", CHAR_MAX);
}
The printf-output is:
size: 1
min: -128
max: 127
How is that possible? The size of char is 1 Byte and the default char seems to be signed (-128...127). So how can I assign a value > 127 without getting an overflow warning (which I get when I try to assign -128 or 256)? Is gcc automatically converting to unsigned char? And then, when I assign a negative value, does it convert back? Why does it do so? I mean, all this implicitness wouldn't make it easier to understand.
EDIT:
Okay, it's not converting anything:
char a = 255;
char b = 128;
printf("%d\n", a); /* -1 */
printf("%d\n", b); /* -128 */
So it starts counting from the bottom up. But why doesn't the compiler give me a warning? And why does it so, when I try to assign 256?
See 6.3.1.3/3 in the C99 Standard
... 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.
So, if you don't get a signal (if your program doesn't stop) read the documentation for your compiler to understand what it does.
gcc documents the behaviour ( in http://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation ) as
The result of, or the signal raised by, converting an integer to a signed integer type when the value cannot be represented in an object of that type (C90 6.2.1.2, C99 6.3.1.3).
For conversion to a type of width N, the value is reduced modulo 2^N to be within range of the type; no signal is raised.
how can I assign a value > 127
The result of converting an out-of-range integer value to a signed integer type is either an implementation-defined result or an implementation-defined signal (6.3.1.3/3). So your code is legal C, it just doesn't have the same behavior on all implementations.
without getting an overflow warning
It's entirely up to GCC to decide whether to warn or not about valid code. I'm not quite sure what its rules are, but I get a warning for initializing a signed char with 256, but not with 255. I guess that's because a warning for code like char a = 0xFF would normally not be wanted by the programmer, even when char is signed. There is a portability issue, in that the same code on another compiler might raise a signal or result in the value 0 or 23.
-pedantic enables a warning for this (thanks, pmg), which makes sense since -pedantic is intended to help write portable code. Or arguably doesn't make sense, since as R.. points out it's beyond the scope of merely putting the compiler into standard-conformance mode. However, the man page for gcc says that -pedantic enables diagnostics required by the standard. This one isn't, but the man page also says:
Some users try to use -pedantic to check programs for strict ISO C
conformance. They soon find that it does not do quite what they want:
it finds some non-ISO practices, but not all---only those for which
ISO C requires a diagnostic, and some others for which diagnostics
have been added.
This leaves me wondering what a "non-ISO practice" is, and suspecting that char a = 255 is one of the ones for which a diagnostic has been specifically added. Certainly "non-ISO" means more than just things for which the standard demands a diagnostic, but gcc obviously is not going so far as to diagnose all non-strictly-conforming code of this kind.
I also get a warning for initializing an int with ((long long)UINT_MAX) + 1, but not with UINT_MAX. Looks as if by default gcc consistently gives you the first power of 2 for free, but after that it thinks you've made a mistake.
Use -Wconversion to get a warning about all of those initializations, including char a = 255. Beware that will give you a boatload of other warnings that you may or may not want.
all this implicitness wouldn't make it easier to understand
You'll have to take that up with Dennis Ritchie. C is weakly-typed as far as arithmetic types are concerned. They all implicitly convert to each other, with various levels of bad behavior when the value is out of range depending on the types involved. Again, -Wconversion warns about the dangerous ones.
There are other design decisions in C that mean the weakness is quite important to avoid unwieldy code. For example, the fact that arithmetic is always done in at least an int means that char a = 1, b = 2; a = a + b involves an implicit conversion from int to char when the result of the addition is assigned to a. If you use -Wconversion, or if C didn't have the implicit conversion at all, you'd have to write a = (char)(a+b), which wouldn't be too popular. For that matter, char a = 1 and even char a = 'a' are both implicit conversions from int to char, since C has no literals of type char. So if it wasn't for all those implicit conversions either various other parts of the language would have to be different, or else you'd have to absolutely litter your code with casts. Some programmers want strong typing, which is fair enough, but you don't get it in C.
Simple solution :
see signed char can have value from -128 to 127 okey
so now when you are assigning 129 to any char value it will take
127(this is valid) + 2(this additional) = -127
(give char a=129 & print it value comes -127)
look char register can have value like..
...126,127,-128,-127,-126...-1,0,1,2....
which ever you will assign final value will come by this calculation ...!!

C datatype : Between Short and Int

I read a book talking about C , it's better for me to present the code first and question in the latter.
First Code
#include <stdio.h>
int main(void)
{
short num = 3;
printf("%hd\n" , num );
return 0;
}
Second Code
#include <stdio.h>
int main(void)
{
short num = 3;
printf("%d\n" , num );
return 0;
}
Special note: I'm using intel based pc so int size is 32-bit.
Question :
1.) The book mention this two code could run correctly although one of it uses the %hd specifier while the other uses %d specifier.
2.)The reason from the book is that because C mechanism would automatically convert the type short to int for faster computation,that is why by using the %d specifier or even %ld which is 32-bit would yield the correct result too.
3.)My question is , when does this conversion occurred??Is it during the time we passed it as an argument to the printf() function , just like how float variable is converted to double when it is passed as an expression or an argument, or by the time we initialize the variable with a value 3??
4.)Actually I've done a small experiment , that is by printing out the size of the variable num using the sizeof operator along with printf() function , and it shows me 2 bytes.But i still not sure when the conversion happen.
5.)If the conversion occurred during the time we assigned the value to the short variable,what's the point of creating a short variable??(**This question should be ignore if it's not the case)
Your help is much appreciated
Yes, %d and %hd are equivalent in this case. printf() is a variadic function, so the rules say that "integer promotions" are applied to the arguments. printf() doesn't see a short value at all, it just sees an int.
%ld is for long int. This could be bigger in size than a plain int, so here the book is wrong.
The conversion occurs in the call to printf(). Any short int passed to printf() is converted to int by the compiler. The short int is not changed of course (not sure what that means anyway!)
When you print the size using sizeof, you are printing a number that is the size of the short int (and the number is of type size_t). printf() doesn't even see the short int, sizeof operator does, and reports the correct size.
The point of creating a short variable is that if you want a short variable, you create one. This is true for most variables of course :-). But if you don't think you need a short int specifically, it's okay to just use int.
If you call a function without a prototype or a function with variable arguments, like printf(3), then C applies something called the default argument promotions.
These conversions promote float to double and anything smaller than int to int or unsigned int. This tends to harmonize most of the types.
This is an interesting feature that, possibly, C introduced to the world. It actually happens to some extent at the instruction set level or ABI level. Parameters are passed in registers or on the stack, and typically no one allows misaligning the stack or leaving junk in higher-order bits.
Just one more reason why C matches the hardware so well and runs so fast.
This conversion happens in the call to printf, because for variadic functions, all the arguments passed in as part of the ... get widened to int (or double, if the argument is a float) first.

Resources