Thread: Help with complicated and strange magic

  1. #1
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92

    Help with complicated and strange magic

    I was going through and commenting c++ source code to gain a better understanding of it, when I came across this range checking code. I would like to know what the maximum call to LargeAllocate would be and how or why range checking might be done in this way. Also if you see errors in my comments please let me know.

    Thanks in advance

    dword declaration:
    Code:
    typedef unsigned int			dword;
    code (it stretches 160 lengthwise so you may want to copy it into you favorite text editor first)
    Code:
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //
    //  MEMBER FUNCTION: idHeap::Allocate
    //
    //  Allocate memory based off of the bytes needed. There is some funky magic here with checking ranges and I am not sure of the speed increase over
    //  the loss in readability
    //
    //  ~~ GLOBAL VARIABLE: c_heapAllocRunningCount
    //     Gets incremented to keep the count of heap allocations current.
    //
    //  ~~ MACRO: USE_LIBC_MALLOC
    //     Forces use of standard C allocation functions for debugging and preformance testing.
    //
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    void* idHeap::Allocate(const dword bytes){
    
      //Checks to see if bytes is a zero, if it is then there isn't anything to allocate
      if(!bytes){ //FIX. COULD WE NOT JUST CHECK TO SEE IF IT WAS LESS THAN 1 HERE AND AVOID THE MAGIC LATER? if(bytes < 1){
        return NULL;
      }
      
      //Increment the count of heap allocations
      c_heapAllocRunningCount++;
      
      //Allocate memory via our custom functions or standard C functions
      #if USE_LIBC_MALLOC
        return malloc(bytes);
      #else
      
        //Check if bytes is within the range 0 to 255 (it was checked earlier in the function to be non-zero so the desired range is actually 1 to 255). This is 
        //done by "not-ing" the value 255 (denoted by the ~) which is represented by the compiler as two's compliment -- meaning 255 in binary looks like 01111111.
        //Not-ing it would give the value 10000000 (-256). So if you preform a bitwise "and" on the number 'bytes' then only values within the range 0 to 255
        //would return 0. Also, 255 is the signed one byte integer maximum.
        if(!(bytes & ~255)){
          return SmallAllocate(bytes);
        }
        
        //Same as the previous check except that the desired range is 1 to the maximum value of a signed 2 byte integer.
        if(!(bytes & ~32767)){
          return MediumAllocate(bytes);
        }
        
        //This basically means that the unsigned 4 byte integer 'bytes' is greater than the range 1 to 32,767 (or over 15 bit in length). In turn that means bytes'
        //is in the range 32,768 (short int maximum) to 4,294,967,295 (unsigned int maximum) or 4gb. However, apparently c++ has it so you cant have constant decimal
        //numbers over 2,147,483,647 or 2gb in a function call or variable assignment -- so as of this revision I don't know what the maximum call to this
        //would be (2gb or 4gb).
        return LargeAllocate(bytes);
      #endif
    }
    Edit: I think I made a mistake in my comments. Is it true that the constants (255 and 32767) are up-converted for comparison to the length of dword, and if so would it be unsigned or signed?
    Last edited by 127.0.0.1; 12-11-2011 at 07:04 AM.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > code (it stretches 160 lengthwise so you may want to copy it into you favorite text editor first)
    Or wrap it yourself into the 80 to 100 columns range.
    If you make it hard for people to read, it won't get read.

    First, the dword value is an unsigned type, so forget all about signed values.

    > Not-ing it would give the value 10000000 (-256)
    0x000000FF (255)

    ~ of that gives you
    0xFFFFFF00

    Any value >= 256 will have at least 1 bit in common with the set bits in the mask, and the expression bytes & ~255 will be true (and !(e) will therefore be false).
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    Thanks for the quick response

    Or wrap it yourself into the 80 to 100 columns range.
    If you make it hard for people to read, it won't get read.
    Sorry about that. I will make sure to fix that in future posts.

    > Not-ing it would give the value 10000000 (-256)
    0x000000FF (255)

    ~ of that gives you
    0xFFFFFF00
    Ah okay, so the constant 255 is treated as a regular int. Are all constants in C assumed to be integers or are they converted to the number they are being compared to (i.e. if I was comparing a long int with a constant). Also, would you be able to shed any light on my question about the call to LargeAllocate?

  4. #4
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by 127.0.0.1 View Post
    Also, would you be able to shed any light on my question about the call to LargeAllocate?
    You can't really believe this???

    apparently c++ has it so you cant have constant decimal numbers over 2,147,483,647 or 2gb in a function call or variable assignment -- so as of this revision I don't know what the maximum call to this would be (2gb or 4gb).
    Code:
    #include <iostream>
    
    using namespace std;
    
    #define MAXUINT 4294967295
    
    void out (unsigned int x) {
    	if (x == MAXUINT) cout << x << endl;
    }
    
    int main(void) {
    	unsigned int n = MAXUINT;
    	out(n);
    
    	return 0;
    }
    Int values are limited by the number of bits, that's all. There is nothing arbitrary about it.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  5. #5
    Registered User
    Join Date
    May 2009
    Location
    Look in your attic, I am there...
    Posts
    92
    You can't really believe this???
    Well, I got warnings with code I wrote to test it and with the code you posted.

    Line 8: warning: this decimal constant is unsigned only in ISO C90
    Line 12: warning: this decimal constant is unsigned only in ISO C90
    And I had read a post I found on a google search big decimal integer constant warning - C / C++. So I was unsure :/

    I see why though I was wrong now and I understand fully how the I posted code works. Thanks again to everyone for the help.

    Sorry for the undescriptive thread title (I should have put something up about bitmasks or the correct notation for using an unsigned constant -- "ul" / "u")
    Last edited by 127.0.0.1; 12-11-2011 at 08:23 AM.

  6. #6
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    When in doubt specify the type of your constant:
    Code:
    const unsigned int MAXUINT = 4294967295U;
    Jim

  7. #7
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by 127.0.0.1 View Post
    Well, I got warnings with code I wrote to test it and with the code you posted.
    And I had read a post I found on a google search big decimal integer constant warning - C / C++. So I was unsure :/
    Hmmm, well, fair enough. I have not seen this before; the only compiler I use is gcc and it gives no such warning*, I usually only consult the C99 standard, and I haven't read most of it anyway.

    However,

    1) I didn't check, but generally C++ standards are more akin to C99 than C90. How are you compiling, or what did you compile to get that warning?

    2) Regardless, it does not mean that you cannot have decimal values over 2,147,483,647. It means that by C90 standards, anything over than can only be assigned to an unsigned type. Which you are. In theory, perhaps there is some remote possibility that because you didn't use UL, some theoretical compiler could convert this to an int, which would make it wrap around to negative, and then assign that value to -- wait, an unsigned int?? That won't work, it would still end up as the same positive value. And it's not the way numbers are treated anyway. They're bits, just some bits represent something different when treated as signed.

    So this could be a sort of very obscure and irrelevant "undefined behavior", hopefully someone will settle that for us, but I very much doubt it. You'd have to write a compiler that intentionally exploited the standard in a negative way to make it meaningful. If this is "undefined behavior", I bet $$ there's tons of code out there that does it anyway, and I would call it a mistake in the standard itself. Which I otherwise have not done...

    * so is the person in that thread, but a very old one (3.4.4). Even with "gcc -ansi -pedantic -Wall -Wextra" I don't get it, v. 4.4.5 (ie, on a C90 source, but I don't get it with g++ either).
    Last edited by MK27; 12-11-2011 at 08:34 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  8. #8
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    Actually I get this warning using g++ (C++), however after replacing the cout with printf I do not get these warnings with gcc, when compiling for C99.

    Edit: Here are the compile flags I normally use for C++:
    -Wshadow
    -Winit-self
    -Wredundant-decls
    -Wcast-align
    -Wundef
    -Wfloat-equal
    -Winline
    -Wunreachable-code
    -Wmissing-declarations
    -Wmissing-include-dirs
    -Wswitch-enum
    -Wswitch-default
    -Weffc++
    -Wmain
    -pedantic-errors
    -pedantic
    -std=c++0x
    -Wextra
    -Wall
    -pg
    -g
    Jim
    Last edited by jimblumberg; 12-11-2011 at 08:52 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Probably way too complicated for me.
    By Necrofear in forum Windows Programming
    Replies: 3
    Last Post: 05-21-2006, 05:41 AM
  2. complicated
    By ZakkWylde969 in forum A Brief History of Cprogramming.com
    Replies: 14
    Last Post: 07-12-2003, 09:15 AM
  3. Complicated but urgent!
    By aker_y3k in forum C++ Programming
    Replies: 11
    Last Post: 10-09-2002, 04:34 AM
  4. Nothing complicated, just...
    By SMurf in forum Windows Programming
    Replies: 1
    Last Post: 09-01-2002, 05:59 PM
  5. the magic of MAGIC numbers
    By borko_b in forum A Brief History of Cprogramming.com
    Replies: 8
    Last Post: 06-27-2002, 02:36 AM