How does casting really work for primitive data types? [closed]

Complications of displaced core material?

Storing voxels for a voxel Engine in C++

Why does the painters tape have to be blue?

To exponential digit growth and beyond!

What is the purpose of the yellow wired panels on the IBM 360 Model 20?

What could be my risk mitigation strategies if my client wants to contract UAT?

Determine direction of mass transfer

Alexandrov's generalization of Cauchy's rigidity theorem

Is it normal to "extract a paper" from a master thesis?

Is it safe to redirect stdout and stderr to the same file without file descriptor copies?

Who wrote “A writer only begins a book. A reader finishes it.”

Why Emacs (dired+) asks me twice to delete file?

"Official wife" or "Formal wife"?

Are cells guaranteed to get at least one mitochondrion when they divide?

Seeking closure over someone I have unblocked but whom I learned have passed on

Did significant numbers of Japanese officers escape prosecution during the Tokyo Trials?

Why is the Eisenstein ideal paper so great?

Did Game of Thrones end the way that George RR Martin intended?

Why is unzipped directory exactly 4.0K (much smaller than zipped file)?

Are PMR446 walkie-talkies legal in Switzerland?

Python script to extract text from PDF with images

What is to the west of Westeros?

Using too much dialogue?

Why did other houses not demand this?



How does casting really work for primitive data types? [closed]














1












$begingroup$


I have written the following C code which purpose it is to flip an unsigned number in binary representation and give back an unsigned number:



long flippingBits(long n) 
return (unsigned)(~n);


int main()
long a = flippingBits(someNumber);
...



This code does work fine. What about this code?



unsigned long flippingBits(long n) 
return (~n);


int main()
unsigned long a = flippingBits(someNumber);
...



This code indeed prints out negative numbers. WTF. This is beyond my intuition. So is there an (architectural) way, to explain this phenomenon? How does the casting of primitive data types work?










share|cite|improve this question











$endgroup$



closed as off-topic by David Richerby, xskxzr, chi, Evil, Gilles May 15 at 21:50


This question appears to be off-topic. The users who voted to close gave this specific reason:


  • "Questions about software development or programming tools are off-topic here, but can be asked on Stack Overflow." – David Richerby, xskxzr, chi, Evil
If this question can be reworded to fit the rules in the help center, please edit the question.











  • 5




    $begingroup$
    This isn’t Computer Science, but very basic C programming. But since you are here, I’d advise you to google for “C Standard Draft” and use the document you find.
    $endgroup$
    – gnasher729
    May 15 at 15:09






  • 1




    $begingroup$
    There is no print command in the second example. What do you mean by "the code indeed prints out negative numbers"?
    $endgroup$
    – JiK
    May 15 at 19:24















1












$begingroup$


I have written the following C code which purpose it is to flip an unsigned number in binary representation and give back an unsigned number:



long flippingBits(long n) 
return (unsigned)(~n);


int main()
long a = flippingBits(someNumber);
...



This code does work fine. What about this code?



unsigned long flippingBits(long n) 
return (~n);


int main()
unsigned long a = flippingBits(someNumber);
...



This code indeed prints out negative numbers. WTF. This is beyond my intuition. So is there an (architectural) way, to explain this phenomenon? How does the casting of primitive data types work?










share|cite|improve this question











$endgroup$



closed as off-topic by David Richerby, xskxzr, chi, Evil, Gilles May 15 at 21:50


This question appears to be off-topic. The users who voted to close gave this specific reason:


  • "Questions about software development or programming tools are off-topic here, but can be asked on Stack Overflow." – David Richerby, xskxzr, chi, Evil
If this question can be reworded to fit the rules in the help center, please edit the question.











  • 5




    $begingroup$
    This isn’t Computer Science, but very basic C programming. But since you are here, I’d advise you to google for “C Standard Draft” and use the document you find.
    $endgroup$
    – gnasher729
    May 15 at 15:09






  • 1




    $begingroup$
    There is no print command in the second example. What do you mean by "the code indeed prints out negative numbers"?
    $endgroup$
    – JiK
    May 15 at 19:24













1












1








1





$begingroup$


I have written the following C code which purpose it is to flip an unsigned number in binary representation and give back an unsigned number:



long flippingBits(long n) 
return (unsigned)(~n);


int main()
long a = flippingBits(someNumber);
...



This code does work fine. What about this code?



unsigned long flippingBits(long n) 
return (~n);


int main()
unsigned long a = flippingBits(someNumber);
...



This code indeed prints out negative numbers. WTF. This is beyond my intuition. So is there an (architectural) way, to explain this phenomenon? How does the casting of primitive data types work?










share|cite|improve this question











$endgroup$




I have written the following C code which purpose it is to flip an unsigned number in binary representation and give back an unsigned number:



long flippingBits(long n) 
return (unsigned)(~n);


int main()
long a = flippingBits(someNumber);
...



This code does work fine. What about this code?



unsigned long flippingBits(long n) 
return (~n);


int main()
unsigned long a = flippingBits(someNumber);
...



This code indeed prints out negative numbers. WTF. This is beyond my intuition. So is there an (architectural) way, to explain this phenomenon? How does the casting of primitive data types work?







c






share|cite|improve this question















share|cite|improve this question













share|cite|improve this question




share|cite|improve this question








edited May 15 at 21:50









Gilles

33.8k797164




33.8k797164










asked May 15 at 15:00









TVSuchtyTVSuchty

614




614




closed as off-topic by David Richerby, xskxzr, chi, Evil, Gilles May 15 at 21:50


This question appears to be off-topic. The users who voted to close gave this specific reason:


  • "Questions about software development or programming tools are off-topic here, but can be asked on Stack Overflow." – David Richerby, xskxzr, chi, Evil
If this question can be reworded to fit the rules in the help center, please edit the question.







closed as off-topic by David Richerby, xskxzr, chi, Evil, Gilles May 15 at 21:50


This question appears to be off-topic. The users who voted to close gave this specific reason:


  • "Questions about software development or programming tools are off-topic here, but can be asked on Stack Overflow." – David Richerby, xskxzr, chi, Evil
If this question can be reworded to fit the rules in the help center, please edit the question.







  • 5




    $begingroup$
    This isn’t Computer Science, but very basic C programming. But since you are here, I’d advise you to google for “C Standard Draft” and use the document you find.
    $endgroup$
    – gnasher729
    May 15 at 15:09






  • 1




    $begingroup$
    There is no print command in the second example. What do you mean by "the code indeed prints out negative numbers"?
    $endgroup$
    – JiK
    May 15 at 19:24












  • 5




    $begingroup$
    This isn’t Computer Science, but very basic C programming. But since you are here, I’d advise you to google for “C Standard Draft” and use the document you find.
    $endgroup$
    – gnasher729
    May 15 at 15:09






  • 1




    $begingroup$
    There is no print command in the second example. What do you mean by "the code indeed prints out negative numbers"?
    $endgroup$
    – JiK
    May 15 at 19:24







5




5




$begingroup$
This isn’t Computer Science, but very basic C programming. But since you are here, I’d advise you to google for “C Standard Draft” and use the document you find.
$endgroup$
– gnasher729
May 15 at 15:09




$begingroup$
This isn’t Computer Science, but very basic C programming. But since you are here, I’d advise you to google for “C Standard Draft” and use the document you find.
$endgroup$
– gnasher729
May 15 at 15:09




1




1




$begingroup$
There is no print command in the second example. What do you mean by "the code indeed prints out negative numbers"?
$endgroup$
– JiK
May 15 at 19:24




$begingroup$
There is no print command in the second example. What do you mean by "the code indeed prints out negative numbers"?
$endgroup$
– JiK
May 15 at 19:24










2 Answers
2






active

oldest

votes


















2












$begingroup$

Casting of primitive datatypes works in a very simple way:




Under the hood, values don't have types. Casting does absolutely nothing.




As a simple example, let us consider casting 65 to an ASCII character, thus obtaining the symbol A. What happens under the hood? Absolutely nothing. The only thing that changes is how the program treats the value. When it thinks of it as an integer, it sees 65; when it thinks of it as an ASCII character it sees A.



The CPU does accommodate different datatypes when performing various operations. For example, it has separate instructions for signed and unsigned integer arithmetic, and for floating point arithmetic. Moreover, there are different instruction for different lengths (i.e. 16-bit vs. 32-bit vs. 64-bit for integers). But it is up to the programmer to instruct the CPU which instruction to use. The CPU doesn't keep track of datatypes, which are a higher-level concept.



Modern CPUs do keep a distinction between code and data to some extent, for security purposes. But otherwise the semantics of data is up to the programmer.



Sometimes casting does have an actual effect, and this is during promotion. When casting an integer to a floating point number, or a 32-bit integer to a 64-bit integer, the program calls some instruction which effects this conversion (in the second case, the exact instruction depends on whether the integer is signed or unsigned).



When casting a signed integer to an unsigned integer of the same length (or vice versa), probably nothing happens. This is exactly your case.






share|cite|improve this answer











$endgroup$








  • 3




    $begingroup$
    "Casting does absolutely nothing" is too broad a statement to lead with. It only does nothing for this particular cast, and only because of the signed and unsigned integer representations we've chosen. Especially for integer->floating or floating->integer casts, the new and old bit patterns in memory could be completely different. If offset binary had somehow become the standard for signed integers, unsigned->signed and signed->unsigned would change the bit pattern too.
    $endgroup$
    – user2357112
    May 15 at 19:02






  • 1




    $begingroup$
    (We don't have to worry about offset binary in our timeline, and it's forbidden by the C standard, but if things had played out differently, we could have had to deal with integer formats where the signed and unsigned representations of the same nonnegative number don't match.)
    $endgroup$
    – user2357112
    May 15 at 19:02










  • $begingroup$
    The main point is that datatypes are an artificial construct. Down below it's just bits. Only the program can give them meaning.
    $endgroup$
    – Yuval Filmus
    May 15 at 19:03






  • 1




    $begingroup$
    Plenty of things are misleading or inaccurate in this answer. You're describing a sort of idealized 1970s C on a typical byte-oriented machine, but modern compilers have optimizations that make the semantics of practical-C a lot more subtle, while remaining compliant with the semantics defined by the C standard. “Casting does absolutely nothing” is wrong by any perspective. Between integer types of different ranges, it can apply a modulo operation (or sometimes other effects). When floating point is involved, it can approximate.
    $endgroup$
    – Gilles
    May 15 at 21:58






  • 1




    $begingroup$
    (cont.) Promotion is a technical term for certain automatic conversions. (A conversion is basically an implicit cast, and a cast is basically an explicit conversion.) There is no casting between 'A' and 65: both are literals of type int. When casting a signed integer to an unsigned integer, the value and (on virtually all implementations) the bit pattern are preserved only if the value is non-negative.
    $endgroup$
    – Gilles
    May 15 at 22:00


















1












$begingroup$


How does the casting of primitive datatypes works?




The restriction "primitive datatype" is not enough:



Casting from a 16-bit integer to a 32-bit integer works differently than casting between integer types of the same size. And casting between integer and floating-point types is even more complex.




This Code does work fine. What about this code?




Both code examples will work differently on different CPUs, operating systems and possibly using different compilers.



This is because under some operating systems (e.g. 32-bit Windows) long and unsigned data types have the same number of bits; under other operating systems (e.g. 64-bit Windows) long has twice as many bits as unsigned.



And you use the ~ operator (~n) on a signed data type which may cause different results depending on the compiler you use.




This code indeed prints out negative numbers.



So is there an (architectural) way, to explain this phenomenon?




There are two effects:



The first effect is:



If you pass a value of a wrong data type to some function, C will automatically cast the value.



And if you are casting a value that is outside the range of the data type you are casting to, the result will typically not be what you are intuitively expecting.



In the case of two integer data types, normally the "rightmost" bits of the value are copied to the new value.



Let's take (signed char)3478 as an example:



The number 3478 is written as 110110010110 in binary. signed char is an 8 bit data type. The rightmost 8 bits of 1101 10010110 are 10010110. And the value (-106) is stored as 10010110 in a signed char variable.



Therefore (signed char)3478 will result in (-106).



The value a is stored in an unsigned long variable which means that it cannot be negative!



However, you say that you "print out" the value of a. This means you pass the value to some function that prints it to the screen.



Obviously that function expects some signed data type. C will cast the value stored in a to the signed data type and as in the example with the number 3478, the result of casting may be a negative number.



If you use printf you may see a second effect:



If some function (such as printf) has a variable number of parameters, the way the parameters are passed to the function is depending on the data types passed. (The details may also vary from OS to OS.)



You may now pass the wrong data type to the function; for example you use "%d" (signed int) in the printf format string but you pass an unsigned long.



If you do this, the compiler will write the value of a to some data storage (memory or register) which is suitable for unsigned long values before actually calling the function. (For such functions the compiler is not able to find out which data type is really expected by the function, so it has to assume that the function expects the data type you are passing to the function.)



However, printf will look for a value in some data storage suitable for signed int values which might be located somewhere completely different. That data storage does not contain any useful value because the compiler wrote the value of a somewhere else!






share|cite|improve this answer











$endgroup$



















    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    2












    $begingroup$

    Casting of primitive datatypes works in a very simple way:




    Under the hood, values don't have types. Casting does absolutely nothing.




    As a simple example, let us consider casting 65 to an ASCII character, thus obtaining the symbol A. What happens under the hood? Absolutely nothing. The only thing that changes is how the program treats the value. When it thinks of it as an integer, it sees 65; when it thinks of it as an ASCII character it sees A.



    The CPU does accommodate different datatypes when performing various operations. For example, it has separate instructions for signed and unsigned integer arithmetic, and for floating point arithmetic. Moreover, there are different instruction for different lengths (i.e. 16-bit vs. 32-bit vs. 64-bit for integers). But it is up to the programmer to instruct the CPU which instruction to use. The CPU doesn't keep track of datatypes, which are a higher-level concept.



    Modern CPUs do keep a distinction between code and data to some extent, for security purposes. But otherwise the semantics of data is up to the programmer.



    Sometimes casting does have an actual effect, and this is during promotion. When casting an integer to a floating point number, or a 32-bit integer to a 64-bit integer, the program calls some instruction which effects this conversion (in the second case, the exact instruction depends on whether the integer is signed or unsigned).



    When casting a signed integer to an unsigned integer of the same length (or vice versa), probably nothing happens. This is exactly your case.






    share|cite|improve this answer











    $endgroup$








    • 3




      $begingroup$
      "Casting does absolutely nothing" is too broad a statement to lead with. It only does nothing for this particular cast, and only because of the signed and unsigned integer representations we've chosen. Especially for integer->floating or floating->integer casts, the new and old bit patterns in memory could be completely different. If offset binary had somehow become the standard for signed integers, unsigned->signed and signed->unsigned would change the bit pattern too.
      $endgroup$
      – user2357112
      May 15 at 19:02






    • 1




      $begingroup$
      (We don't have to worry about offset binary in our timeline, and it's forbidden by the C standard, but if things had played out differently, we could have had to deal with integer formats where the signed and unsigned representations of the same nonnegative number don't match.)
      $endgroup$
      – user2357112
      May 15 at 19:02










    • $begingroup$
      The main point is that datatypes are an artificial construct. Down below it's just bits. Only the program can give them meaning.
      $endgroup$
      – Yuval Filmus
      May 15 at 19:03






    • 1




      $begingroup$
      Plenty of things are misleading or inaccurate in this answer. You're describing a sort of idealized 1970s C on a typical byte-oriented machine, but modern compilers have optimizations that make the semantics of practical-C a lot more subtle, while remaining compliant with the semantics defined by the C standard. “Casting does absolutely nothing” is wrong by any perspective. Between integer types of different ranges, it can apply a modulo operation (or sometimes other effects). When floating point is involved, it can approximate.
      $endgroup$
      – Gilles
      May 15 at 21:58






    • 1




      $begingroup$
      (cont.) Promotion is a technical term for certain automatic conversions. (A conversion is basically an implicit cast, and a cast is basically an explicit conversion.) There is no casting between 'A' and 65: both are literals of type int. When casting a signed integer to an unsigned integer, the value and (on virtually all implementations) the bit pattern are preserved only if the value is non-negative.
      $endgroup$
      – Gilles
      May 15 at 22:00















    2












    $begingroup$

    Casting of primitive datatypes works in a very simple way:




    Under the hood, values don't have types. Casting does absolutely nothing.




    As a simple example, let us consider casting 65 to an ASCII character, thus obtaining the symbol A. What happens under the hood? Absolutely nothing. The only thing that changes is how the program treats the value. When it thinks of it as an integer, it sees 65; when it thinks of it as an ASCII character it sees A.



    The CPU does accommodate different datatypes when performing various operations. For example, it has separate instructions for signed and unsigned integer arithmetic, and for floating point arithmetic. Moreover, there are different instruction for different lengths (i.e. 16-bit vs. 32-bit vs. 64-bit for integers). But it is up to the programmer to instruct the CPU which instruction to use. The CPU doesn't keep track of datatypes, which are a higher-level concept.



    Modern CPUs do keep a distinction between code and data to some extent, for security purposes. But otherwise the semantics of data is up to the programmer.



    Sometimes casting does have an actual effect, and this is during promotion. When casting an integer to a floating point number, or a 32-bit integer to a 64-bit integer, the program calls some instruction which effects this conversion (in the second case, the exact instruction depends on whether the integer is signed or unsigned).



    When casting a signed integer to an unsigned integer of the same length (or vice versa), probably nothing happens. This is exactly your case.






    share|cite|improve this answer











    $endgroup$








    • 3




      $begingroup$
      "Casting does absolutely nothing" is too broad a statement to lead with. It only does nothing for this particular cast, and only because of the signed and unsigned integer representations we've chosen. Especially for integer->floating or floating->integer casts, the new and old bit patterns in memory could be completely different. If offset binary had somehow become the standard for signed integers, unsigned->signed and signed->unsigned would change the bit pattern too.
      $endgroup$
      – user2357112
      May 15 at 19:02






    • 1




      $begingroup$
      (We don't have to worry about offset binary in our timeline, and it's forbidden by the C standard, but if things had played out differently, we could have had to deal with integer formats where the signed and unsigned representations of the same nonnegative number don't match.)
      $endgroup$
      – user2357112
      May 15 at 19:02










    • $begingroup$
      The main point is that datatypes are an artificial construct. Down below it's just bits. Only the program can give them meaning.
      $endgroup$
      – Yuval Filmus
      May 15 at 19:03






    • 1




      $begingroup$
      Plenty of things are misleading or inaccurate in this answer. You're describing a sort of idealized 1970s C on a typical byte-oriented machine, but modern compilers have optimizations that make the semantics of practical-C a lot more subtle, while remaining compliant with the semantics defined by the C standard. “Casting does absolutely nothing” is wrong by any perspective. Between integer types of different ranges, it can apply a modulo operation (or sometimes other effects). When floating point is involved, it can approximate.
      $endgroup$
      – Gilles
      May 15 at 21:58






    • 1




      $begingroup$
      (cont.) Promotion is a technical term for certain automatic conversions. (A conversion is basically an implicit cast, and a cast is basically an explicit conversion.) There is no casting between 'A' and 65: both are literals of type int. When casting a signed integer to an unsigned integer, the value and (on virtually all implementations) the bit pattern are preserved only if the value is non-negative.
      $endgroup$
      – Gilles
      May 15 at 22:00













    2












    2








    2





    $begingroup$

    Casting of primitive datatypes works in a very simple way:




    Under the hood, values don't have types. Casting does absolutely nothing.




    As a simple example, let us consider casting 65 to an ASCII character, thus obtaining the symbol A. What happens under the hood? Absolutely nothing. The only thing that changes is how the program treats the value. When it thinks of it as an integer, it sees 65; when it thinks of it as an ASCII character it sees A.



    The CPU does accommodate different datatypes when performing various operations. For example, it has separate instructions for signed and unsigned integer arithmetic, and for floating point arithmetic. Moreover, there are different instruction for different lengths (i.e. 16-bit vs. 32-bit vs. 64-bit for integers). But it is up to the programmer to instruct the CPU which instruction to use. The CPU doesn't keep track of datatypes, which are a higher-level concept.



    Modern CPUs do keep a distinction between code and data to some extent, for security purposes. But otherwise the semantics of data is up to the programmer.



    Sometimes casting does have an actual effect, and this is during promotion. When casting an integer to a floating point number, or a 32-bit integer to a 64-bit integer, the program calls some instruction which effects this conversion (in the second case, the exact instruction depends on whether the integer is signed or unsigned).



    When casting a signed integer to an unsigned integer of the same length (or vice versa), probably nothing happens. This is exactly your case.






    share|cite|improve this answer











    $endgroup$



    Casting of primitive datatypes works in a very simple way:




    Under the hood, values don't have types. Casting does absolutely nothing.




    As a simple example, let us consider casting 65 to an ASCII character, thus obtaining the symbol A. What happens under the hood? Absolutely nothing. The only thing that changes is how the program treats the value. When it thinks of it as an integer, it sees 65; when it thinks of it as an ASCII character it sees A.



    The CPU does accommodate different datatypes when performing various operations. For example, it has separate instructions for signed and unsigned integer arithmetic, and for floating point arithmetic. Moreover, there are different instruction for different lengths (i.e. 16-bit vs. 32-bit vs. 64-bit for integers). But it is up to the programmer to instruct the CPU which instruction to use. The CPU doesn't keep track of datatypes, which are a higher-level concept.



    Modern CPUs do keep a distinction between code and data to some extent, for security purposes. But otherwise the semantics of data is up to the programmer.



    Sometimes casting does have an actual effect, and this is during promotion. When casting an integer to a floating point number, or a 32-bit integer to a 64-bit integer, the program calls some instruction which effects this conversion (in the second case, the exact instruction depends on whether the integer is signed or unsigned).



    When casting a signed integer to an unsigned integer of the same length (or vice versa), probably nothing happens. This is exactly your case.







    share|cite|improve this answer














    share|cite|improve this answer



    share|cite|improve this answer








    edited May 15 at 21:41









    z3p5e6

    31




    31










    answered May 15 at 15:23









    Yuval FilmusYuval Filmus

    200k15190354




    200k15190354







    • 3




      $begingroup$
      "Casting does absolutely nothing" is too broad a statement to lead with. It only does nothing for this particular cast, and only because of the signed and unsigned integer representations we've chosen. Especially for integer->floating or floating->integer casts, the new and old bit patterns in memory could be completely different. If offset binary had somehow become the standard for signed integers, unsigned->signed and signed->unsigned would change the bit pattern too.
      $endgroup$
      – user2357112
      May 15 at 19:02






    • 1




      $begingroup$
      (We don't have to worry about offset binary in our timeline, and it's forbidden by the C standard, but if things had played out differently, we could have had to deal with integer formats where the signed and unsigned representations of the same nonnegative number don't match.)
      $endgroup$
      – user2357112
      May 15 at 19:02










    • $begingroup$
      The main point is that datatypes are an artificial construct. Down below it's just bits. Only the program can give them meaning.
      $endgroup$
      – Yuval Filmus
      May 15 at 19:03






    • 1




      $begingroup$
      Plenty of things are misleading or inaccurate in this answer. You're describing a sort of idealized 1970s C on a typical byte-oriented machine, but modern compilers have optimizations that make the semantics of practical-C a lot more subtle, while remaining compliant with the semantics defined by the C standard. “Casting does absolutely nothing” is wrong by any perspective. Between integer types of different ranges, it can apply a modulo operation (or sometimes other effects). When floating point is involved, it can approximate.
      $endgroup$
      – Gilles
      May 15 at 21:58






    • 1




      $begingroup$
      (cont.) Promotion is a technical term for certain automatic conversions. (A conversion is basically an implicit cast, and a cast is basically an explicit conversion.) There is no casting between 'A' and 65: both are literals of type int. When casting a signed integer to an unsigned integer, the value and (on virtually all implementations) the bit pattern are preserved only if the value is non-negative.
      $endgroup$
      – Gilles
      May 15 at 22:00












    • 3




      $begingroup$
      "Casting does absolutely nothing" is too broad a statement to lead with. It only does nothing for this particular cast, and only because of the signed and unsigned integer representations we've chosen. Especially for integer->floating or floating->integer casts, the new and old bit patterns in memory could be completely different. If offset binary had somehow become the standard for signed integers, unsigned->signed and signed->unsigned would change the bit pattern too.
      $endgroup$
      – user2357112
      May 15 at 19:02






    • 1




      $begingroup$
      (We don't have to worry about offset binary in our timeline, and it's forbidden by the C standard, but if things had played out differently, we could have had to deal with integer formats where the signed and unsigned representations of the same nonnegative number don't match.)
      $endgroup$
      – user2357112
      May 15 at 19:02










    • $begingroup$
      The main point is that datatypes are an artificial construct. Down below it's just bits. Only the program can give them meaning.
      $endgroup$
      – Yuval Filmus
      May 15 at 19:03






    • 1




      $begingroup$
      Plenty of things are misleading or inaccurate in this answer. You're describing a sort of idealized 1970s C on a typical byte-oriented machine, but modern compilers have optimizations that make the semantics of practical-C a lot more subtle, while remaining compliant with the semantics defined by the C standard. “Casting does absolutely nothing” is wrong by any perspective. Between integer types of different ranges, it can apply a modulo operation (or sometimes other effects). When floating point is involved, it can approximate.
      $endgroup$
      – Gilles
      May 15 at 21:58






    • 1




      $begingroup$
      (cont.) Promotion is a technical term for certain automatic conversions. (A conversion is basically an implicit cast, and a cast is basically an explicit conversion.) There is no casting between 'A' and 65: both are literals of type int. When casting a signed integer to an unsigned integer, the value and (on virtually all implementations) the bit pattern are preserved only if the value is non-negative.
      $endgroup$
      – Gilles
      May 15 at 22:00







    3




    3




    $begingroup$
    "Casting does absolutely nothing" is too broad a statement to lead with. It only does nothing for this particular cast, and only because of the signed and unsigned integer representations we've chosen. Especially for integer->floating or floating->integer casts, the new and old bit patterns in memory could be completely different. If offset binary had somehow become the standard for signed integers, unsigned->signed and signed->unsigned would change the bit pattern too.
    $endgroup$
    – user2357112
    May 15 at 19:02




    $begingroup$
    "Casting does absolutely nothing" is too broad a statement to lead with. It only does nothing for this particular cast, and only because of the signed and unsigned integer representations we've chosen. Especially for integer->floating or floating->integer casts, the new and old bit patterns in memory could be completely different. If offset binary had somehow become the standard for signed integers, unsigned->signed and signed->unsigned would change the bit pattern too.
    $endgroup$
    – user2357112
    May 15 at 19:02




    1




    1




    $begingroup$
    (We don't have to worry about offset binary in our timeline, and it's forbidden by the C standard, but if things had played out differently, we could have had to deal with integer formats where the signed and unsigned representations of the same nonnegative number don't match.)
    $endgroup$
    – user2357112
    May 15 at 19:02




    $begingroup$
    (We don't have to worry about offset binary in our timeline, and it's forbidden by the C standard, but if things had played out differently, we could have had to deal with integer formats where the signed and unsigned representations of the same nonnegative number don't match.)
    $endgroup$
    – user2357112
    May 15 at 19:02












    $begingroup$
    The main point is that datatypes are an artificial construct. Down below it's just bits. Only the program can give them meaning.
    $endgroup$
    – Yuval Filmus
    May 15 at 19:03




    $begingroup$
    The main point is that datatypes are an artificial construct. Down below it's just bits. Only the program can give them meaning.
    $endgroup$
    – Yuval Filmus
    May 15 at 19:03




    1




    1




    $begingroup$
    Plenty of things are misleading or inaccurate in this answer. You're describing a sort of idealized 1970s C on a typical byte-oriented machine, but modern compilers have optimizations that make the semantics of practical-C a lot more subtle, while remaining compliant with the semantics defined by the C standard. “Casting does absolutely nothing” is wrong by any perspective. Between integer types of different ranges, it can apply a modulo operation (or sometimes other effects). When floating point is involved, it can approximate.
    $endgroup$
    – Gilles
    May 15 at 21:58




    $begingroup$
    Plenty of things are misleading or inaccurate in this answer. You're describing a sort of idealized 1970s C on a typical byte-oriented machine, but modern compilers have optimizations that make the semantics of practical-C a lot more subtle, while remaining compliant with the semantics defined by the C standard. “Casting does absolutely nothing” is wrong by any perspective. Between integer types of different ranges, it can apply a modulo operation (or sometimes other effects). When floating point is involved, it can approximate.
    $endgroup$
    – Gilles
    May 15 at 21:58




    1




    1




    $begingroup$
    (cont.) Promotion is a technical term for certain automatic conversions. (A conversion is basically an implicit cast, and a cast is basically an explicit conversion.) There is no casting between 'A' and 65: both are literals of type int. When casting a signed integer to an unsigned integer, the value and (on virtually all implementations) the bit pattern are preserved only if the value is non-negative.
    $endgroup$
    – Gilles
    May 15 at 22:00




    $begingroup$
    (cont.) Promotion is a technical term for certain automatic conversions. (A conversion is basically an implicit cast, and a cast is basically an explicit conversion.) There is no casting between 'A' and 65: both are literals of type int. When casting a signed integer to an unsigned integer, the value and (on virtually all implementations) the bit pattern are preserved only if the value is non-negative.
    $endgroup$
    – Gilles
    May 15 at 22:00











    1












    $begingroup$


    How does the casting of primitive datatypes works?




    The restriction "primitive datatype" is not enough:



    Casting from a 16-bit integer to a 32-bit integer works differently than casting between integer types of the same size. And casting between integer and floating-point types is even more complex.




    This Code does work fine. What about this code?




    Both code examples will work differently on different CPUs, operating systems and possibly using different compilers.



    This is because under some operating systems (e.g. 32-bit Windows) long and unsigned data types have the same number of bits; under other operating systems (e.g. 64-bit Windows) long has twice as many bits as unsigned.



    And you use the ~ operator (~n) on a signed data type which may cause different results depending on the compiler you use.




    This code indeed prints out negative numbers.



    So is there an (architectural) way, to explain this phenomenon?




    There are two effects:



    The first effect is:



    If you pass a value of a wrong data type to some function, C will automatically cast the value.



    And if you are casting a value that is outside the range of the data type you are casting to, the result will typically not be what you are intuitively expecting.



    In the case of two integer data types, normally the "rightmost" bits of the value are copied to the new value.



    Let's take (signed char)3478 as an example:



    The number 3478 is written as 110110010110 in binary. signed char is an 8 bit data type. The rightmost 8 bits of 1101 10010110 are 10010110. And the value (-106) is stored as 10010110 in a signed char variable.



    Therefore (signed char)3478 will result in (-106).



    The value a is stored in an unsigned long variable which means that it cannot be negative!



    However, you say that you "print out" the value of a. This means you pass the value to some function that prints it to the screen.



    Obviously that function expects some signed data type. C will cast the value stored in a to the signed data type and as in the example with the number 3478, the result of casting may be a negative number.



    If you use printf you may see a second effect:



    If some function (such as printf) has a variable number of parameters, the way the parameters are passed to the function is depending on the data types passed. (The details may also vary from OS to OS.)



    You may now pass the wrong data type to the function; for example you use "%d" (signed int) in the printf format string but you pass an unsigned long.



    If you do this, the compiler will write the value of a to some data storage (memory or register) which is suitable for unsigned long values before actually calling the function. (For such functions the compiler is not able to find out which data type is really expected by the function, so it has to assume that the function expects the data type you are passing to the function.)



    However, printf will look for a value in some data storage suitable for signed int values which might be located somewhere completely different. That data storage does not contain any useful value because the compiler wrote the value of a somewhere else!






    share|cite|improve this answer











    $endgroup$

















      1












      $begingroup$


      How does the casting of primitive datatypes works?




      The restriction "primitive datatype" is not enough:



      Casting from a 16-bit integer to a 32-bit integer works differently than casting between integer types of the same size. And casting between integer and floating-point types is even more complex.




      This Code does work fine. What about this code?




      Both code examples will work differently on different CPUs, operating systems and possibly using different compilers.



      This is because under some operating systems (e.g. 32-bit Windows) long and unsigned data types have the same number of bits; under other operating systems (e.g. 64-bit Windows) long has twice as many bits as unsigned.



      And you use the ~ operator (~n) on a signed data type which may cause different results depending on the compiler you use.




      This code indeed prints out negative numbers.



      So is there an (architectural) way, to explain this phenomenon?




      There are two effects:



      The first effect is:



      If you pass a value of a wrong data type to some function, C will automatically cast the value.



      And if you are casting a value that is outside the range of the data type you are casting to, the result will typically not be what you are intuitively expecting.



      In the case of two integer data types, normally the "rightmost" bits of the value are copied to the new value.



      Let's take (signed char)3478 as an example:



      The number 3478 is written as 110110010110 in binary. signed char is an 8 bit data type. The rightmost 8 bits of 1101 10010110 are 10010110. And the value (-106) is stored as 10010110 in a signed char variable.



      Therefore (signed char)3478 will result in (-106).



      The value a is stored in an unsigned long variable which means that it cannot be negative!



      However, you say that you "print out" the value of a. This means you pass the value to some function that prints it to the screen.



      Obviously that function expects some signed data type. C will cast the value stored in a to the signed data type and as in the example with the number 3478, the result of casting may be a negative number.



      If you use printf you may see a second effect:



      If some function (such as printf) has a variable number of parameters, the way the parameters are passed to the function is depending on the data types passed. (The details may also vary from OS to OS.)



      You may now pass the wrong data type to the function; for example you use "%d" (signed int) in the printf format string but you pass an unsigned long.



      If you do this, the compiler will write the value of a to some data storage (memory or register) which is suitable for unsigned long values before actually calling the function. (For such functions the compiler is not able to find out which data type is really expected by the function, so it has to assume that the function expects the data type you are passing to the function.)



      However, printf will look for a value in some data storage suitable for signed int values which might be located somewhere completely different. That data storage does not contain any useful value because the compiler wrote the value of a somewhere else!






      share|cite|improve this answer











      $endgroup$















        1












        1








        1





        $begingroup$


        How does the casting of primitive datatypes works?




        The restriction "primitive datatype" is not enough:



        Casting from a 16-bit integer to a 32-bit integer works differently than casting between integer types of the same size. And casting between integer and floating-point types is even more complex.




        This Code does work fine. What about this code?




        Both code examples will work differently on different CPUs, operating systems and possibly using different compilers.



        This is because under some operating systems (e.g. 32-bit Windows) long and unsigned data types have the same number of bits; under other operating systems (e.g. 64-bit Windows) long has twice as many bits as unsigned.



        And you use the ~ operator (~n) on a signed data type which may cause different results depending on the compiler you use.




        This code indeed prints out negative numbers.



        So is there an (architectural) way, to explain this phenomenon?




        There are two effects:



        The first effect is:



        If you pass a value of a wrong data type to some function, C will automatically cast the value.



        And if you are casting a value that is outside the range of the data type you are casting to, the result will typically not be what you are intuitively expecting.



        In the case of two integer data types, normally the "rightmost" bits of the value are copied to the new value.



        Let's take (signed char)3478 as an example:



        The number 3478 is written as 110110010110 in binary. signed char is an 8 bit data type. The rightmost 8 bits of 1101 10010110 are 10010110. And the value (-106) is stored as 10010110 in a signed char variable.



        Therefore (signed char)3478 will result in (-106).



        The value a is stored in an unsigned long variable which means that it cannot be negative!



        However, you say that you "print out" the value of a. This means you pass the value to some function that prints it to the screen.



        Obviously that function expects some signed data type. C will cast the value stored in a to the signed data type and as in the example with the number 3478, the result of casting may be a negative number.



        If you use printf you may see a second effect:



        If some function (such as printf) has a variable number of parameters, the way the parameters are passed to the function is depending on the data types passed. (The details may also vary from OS to OS.)



        You may now pass the wrong data type to the function; for example you use "%d" (signed int) in the printf format string but you pass an unsigned long.



        If you do this, the compiler will write the value of a to some data storage (memory or register) which is suitable for unsigned long values before actually calling the function. (For such functions the compiler is not able to find out which data type is really expected by the function, so it has to assume that the function expects the data type you are passing to the function.)



        However, printf will look for a value in some data storage suitable for signed int values which might be located somewhere completely different. That data storage does not contain any useful value because the compiler wrote the value of a somewhere else!






        share|cite|improve this answer











        $endgroup$




        How does the casting of primitive datatypes works?




        The restriction "primitive datatype" is not enough:



        Casting from a 16-bit integer to a 32-bit integer works differently than casting between integer types of the same size. And casting between integer and floating-point types is even more complex.




        This Code does work fine. What about this code?




        Both code examples will work differently on different CPUs, operating systems and possibly using different compilers.



        This is because under some operating systems (e.g. 32-bit Windows) long and unsigned data types have the same number of bits; under other operating systems (e.g. 64-bit Windows) long has twice as many bits as unsigned.



        And you use the ~ operator (~n) on a signed data type which may cause different results depending on the compiler you use.




        This code indeed prints out negative numbers.



        So is there an (architectural) way, to explain this phenomenon?




        There are two effects:



        The first effect is:



        If you pass a value of a wrong data type to some function, C will automatically cast the value.



        And if you are casting a value that is outside the range of the data type you are casting to, the result will typically not be what you are intuitively expecting.



        In the case of two integer data types, normally the "rightmost" bits of the value are copied to the new value.



        Let's take (signed char)3478 as an example:



        The number 3478 is written as 110110010110 in binary. signed char is an 8 bit data type. The rightmost 8 bits of 1101 10010110 are 10010110. And the value (-106) is stored as 10010110 in a signed char variable.



        Therefore (signed char)3478 will result in (-106).



        The value a is stored in an unsigned long variable which means that it cannot be negative!



        However, you say that you "print out" the value of a. This means you pass the value to some function that prints it to the screen.



        Obviously that function expects some signed data type. C will cast the value stored in a to the signed data type and as in the example with the number 3478, the result of casting may be a negative number.



        If you use printf you may see a second effect:



        If some function (such as printf) has a variable number of parameters, the way the parameters are passed to the function is depending on the data types passed. (The details may also vary from OS to OS.)



        You may now pass the wrong data type to the function; for example you use "%d" (signed int) in the printf format string but you pass an unsigned long.



        If you do this, the compiler will write the value of a to some data storage (memory or register) which is suitable for unsigned long values before actually calling the function. (For such functions the compiler is not able to find out which data type is really expected by the function, so it has to assume that the function expects the data type you are passing to the function.)



        However, printf will look for a value in some data storage suitable for signed int values which might be located somewhere completely different. That data storage does not contain any useful value because the compiler wrote the value of a somewhere else!







        share|cite|improve this answer














        share|cite|improve this answer



        share|cite|improve this answer








        edited May 15 at 20:09

























        answered May 15 at 20:04









        Martin RosenauMartin Rosenau

        1755




        1755













            Popular posts from this blog

            Grendel Contents Story Scholarship Depictions Notes References Navigation menu10.1093/notesj/gjn112Berserkeree

            Area configuration aggregation error after install Porto themeMagento 2.1 CE Installed but front/backend not loading/workingCSS not loading on page within Magento 2 pageCannot install module in Magento 2no commands defined in the “setup” namespace. in Magento2Magento 2: Static files are present but shows 404Why do i have to always run the commands to clean cache in Magento 2.1.8?Failure reason: 'Unable to unserialize value.'Error 500 after magento migrationIn production mode the site does not loadMagento 2 : Error 500 after installing

            Middle Expansion Olielle Resaix Definition: Uttering songs of triumph shouting with joy triumphant exulting Sejunction Journal 붙다 달 고급 품목 외출 The stretch trades the screeching tin. Definition: The act of speaking with a drawl a drawl Cough Sand Definition: An uproar a quarrel a noisy outbreak Shake Iron Publicize Horse House Baby 사과 Resaix Flaggy Jelly Temporary Unequaled Puppet A drop in the bucket Shrew 성격 회원 성질 미팅 The burn frames the tacky quality. Materialistic The smoke reduces the way. Yammoe Nondescript Cheek 얼굴 배 약하다 날리다 타다 The illegal country shows the iron. Help Rule Drearien Smoke Teaching Meaty Wasp Abraham Lincoln Jaws 진심 수리하다 Size Cork Idea Convert Think Lark John Lennon 거울 청소 군 추천하다 아이스크림