Thread: How to silence integer overflow warning

  1. #1
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733

    How to silence integer overflow warning

    Managed to get a working macro that can calculate the size of an integer type based on the unsigned max given (up to supported size anyway), the problem I'm having is silencing the preprocessor warnings, I know in VC this could be circumvented by using hard integers (because it for some reason supports using them in the preprocessor, at least in the cases I tried anyways) but how would I go about silencing them in various other compilers (like gcc & clang)

    Incidentally I have -Wall and -Wextra set at the moment, also here's the snippet with an example usage:
    Code:
    #define MAX_FOR_SIZE(PRV) ((PRV * PRV) + PRV + PRV)
    #define MAX_FOR_1BYTE UCHAR_MAX
    #define MAX_FOR_2BYTE MAX_FOR_SIZE(MAX_FOR_1BYTE)
    #define MAX_FOR_4BYTE MAX_FOR_SIZE(MAX_FOR_2BYTE)
    #define MAX_FOR_8BYTE MAX_FOR_SIZE(MAX_FOR_4BYTE)
    
    #define _SIZEOF(UMAX,SIZE,TRUE) \
    	(((UMAX) > (MAX_FOR_##SIZE##BYTE)) ? (TRUE) : SIZE)
    #define SIZEOF(UMAX) \
    	_SIZEOF(UMAX,1,_SIZEOF(UMAX,2,_SIZEOF(UMAX,4,_SIZEOF(UMAX,8,16))))
    
    #ifndef SIZEOF_INTEGRAL
    #if 0
    #if MAX_FOR_2BYTE <= MAX_FOR_1BYTE
    #define SIZEOF_INTEGRAL 1
    #elif MAX_FOR_4BYTE <= MAX_FOR_2BYTE
    #define SIZEOF_INTEGRAL 2
    #elif MAX_FOR_8BYTE <= MAX_FOR_4BYTE
    #define SIZEOF_INTEGRAL 4
    #elif MAX_FOR_8BYTE <= ~0u
    #define SIZEOF_INTEGRAL 8
    #else
    #define SIZEOF_INTEGRAL 16
    #endif /* RESULT <= ORIGINAL */
    #else
    #define SIZEOF_INTEGRAL SIZEOF(~0u)
    #endif
    #endif /* SIZEOF_INTEGRAL */
    Edit: Also here's some output using those very values:
    Code:
    ...
    ./alu.AppImage
    test.c:257: main() MAX_FOR_1BYTE = FF
    test.c:258: main() MAX_FOR_2BYTE = FFFF
    test.c:259: main() MAX_FOR_4BYTE = FFFFFFFF
    test.c:260: main() MAX_FOR_8BYTE = FFFFFFFF
    test.c:261: main() '==========================================='
    test.c:262: main() SIZEOF_INTEGRAL = 4
    test.c:263: main() SIZEOF_SHRT = 2
    test.c:264: main() SIZEOF_INT = 4
    test.c:265: main() SIZEOF_LONG = 8
    test.c:266: main() '==========================================='
    test.c:267: main() UCHAR_MAX = FF
    test.c:268: main() USHRT_MAX = FFFF
    test.c:269: main() UINT_MAX = FFFFFFFF
    test.c:270: main() ULONG_MAX = FFFFFFFFFFFFFFFF
    test.c:271: main() '==========================================='
    test.c:273: main() 'Initiating ALU to 0...'
    test.c:276: main() 'Pre-allocating 16 ALU registers...'
    Compilation finished successfully.
    Last edited by awsdert; 08-04-2020 at 10:44 AM.

  2. #2
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Never mind, just thought of a solution:
    Code:
    #define MAX_FOR_SIZE(PRV) \
    	(((PRV) >= ~0u) ? ~0u : (((PRV) * (PRV)) + (PRV) + (PRV)))

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Is this just an exercise, or are you deliberately avoiding <limits.h> and <stdint.h>?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by laserlight View Post
    Is this just an exercise, or are you deliberately avoiding <limits.h> and <stdint.h>?
    Well limits.h doesn't always define the size and/or width of an integer, much less the preprocessor integer size/width (used integral since I remember a compiler - vc I think - defining some macro for it with that very name), as for stdint.h/inttypes.h I find they are also hit and miss, because of that I decided I wanted to make sure they are defined whether or not the headers in question are included, the only bottle neck for kernel usage as far as I know is mainly CHAR_BIT, if I could calculate that then I could design a header designed specifically to map to either user land or kernel land macros based on what is available then submit the header for usage in the main linux kernel headers, to that end the less fixated on external headers the macros are the better. Also I needed some of those macros to rid my ALU library code of the alu_seg_t type and it's various macros in favour of size_t and it's various macros

  5. #5
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    As far as calculating CHAR_BIT this is the best I got, lemme know if you see problems with it:
    Code:
    #ifndef CHAR_BIT
    #if ~0 << 8
    #define CHAR_BIT 8
    #elif ~0 << 7
    #define CHAR_BIT 7
    #elif ~0 << 6
    #define CHAR_BIT 6
    #elif ~0 << 5
    #define CHAR_BIT 5
    #else
    #define CHAR_BIT 4
    #endif
    #endif
    
    #ifndef CHAR_WIDTH
    #define CHAR_WIDTH CHAR_BIT
    #endif

  6. #6
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    CHAR_BIT can never be less than 8.
    See 5.2.4.2.1 of the C11 standard.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  7. #7
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    Quote Originally Posted by john.c View Post
    CHAR_BIT can never be less than 8.
    See 5.2.4.2.1 of the C11 standard.
    Even more: The pre-processor "code" below will always result in CHAR_BIT == 8:
    Code:
    #ifndef CHAR_BIT
    #if ~0 << 8
    #define CHAR_BIT 8
    #elif ~0 << 7
    #define CHAR_BIT 7
    #elif ~0 << 6
    #define CHAR_BIT 6
    #elif ~0 << 5
    #define CHAR_BIT 5
    #else
    #define CHAR_BIT 4
    #endif
    #endif
    Because ~0 will be, at least, of "int" type as per ISO 9989 6.4.4.1.5 (and INT_MIN is 15 bits long [plus the sign bit] as in 5.2.4.2.1, pointed by John). So since 'int' is, at least, 16 bits long, ~0 << 8 will always be "true" (not zero).

  8. #8
    Registered User Sir Galahad's Avatar
    Join Date
    Nov 2016
    Location
    The Round Table
    Posts
    277
    Quote Originally Posted by awsdert View Post
    Well limits.h doesn't always define the size and/or width of an integer, much less the preprocessor integer size/width (used integral since I remember a compiler - vc I think - defining some macro for it with that very name), as for stdint.h/inttypes.h I find they are also hit and miss, because of that I decided I wanted to make sure they are defined whether or not the headers in question are included
    Pretty sure 8 * sizeof(int) works equally well on all systems.

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by awsdert
    Well limits.h doesn't always define the size and/or width of an integer
    If a standard integer type is supported, then its limits would be defined in <limits.h>. The width wouldn't be defined there, but that's what sizeof and possibly CHAR_BIT is for.

    Quote Originally Posted by awsdert
    much less the preprocessor integer size/width (used integral since I remember a compiler - vc I think - defining some macro for it with that very name)
    By "preprocessor integer size/width" you mean "processor integer size/width", i.e., word size? If so, that's true, but I doubt your method of determining that is guaranteed to work: from what I see, with your _SIZEOF and SIZEOF macros applied to SIZEOF(~0u), you're just finding out the size of an unsigned int through a roundabout way, and then assuming that that's the word size.

    It is true that the C standard does say that int (and hence unsigned int) "has the natural size suggested by the architecture of the execution environment", but I don't think that's necessarily true in practice on modern 64-bit systems, where int might only be the natural step between short and long or long long.

    Furthermore, your code in post #2 ensures that MAX_FOR_8BYTE will not exceed ~0u, so for a 4-byte unsigned int, MAX_FOR_8BYTE will be UINT_MAX, even if unsigned long long is supported such that MAX_FOR_8BYTE should have been ULLONG_MAX. If I'm not wrong, what you're doing there is forcing a conversion from int to unsigned int, hence avoiding the signed integer overflow warnings, but in turn ensuring that integer types with arithmetic conversion ranks higher than unsigned int will never be involved.

    Quote Originally Posted by awsdert
    as for stdint.h/inttypes.h I find they are also hit and miss
    It is true that <stdint.h> doesn't necessarily provide certain definitions... but if it doesn't then you wouldn't be able to get it yourself either because it would mean that say, integer types with the given widths do not exist on that implementation. I was thinking that maybe you're trying to support old implementations that do not conform to C99 or later (at least IIRC, <stdint.h> was introduced in C99), but it has been a two decades.

    Quote Originally Posted by Sir Galahad
    Pretty sure 8 * sizeof(int) works equally well on all systems.
    I think there are still a few oddities among modern systems that have CHAR_BIT > 8, so you would need CHAR_BIT * sizeof(int) instead if you wish for it to work "equally well on all systems".
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Registered User Sir Galahad's Avatar
    Join Date
    Nov 2016
    Location
    The Round Table
    Posts
    277
    Quote Originally Posted by laserlight View Post
    I think there are still a few oddities among modern systems that have CHAR_BIT > 8, so you would need CHAR_BIT * sizeof(int) instead if you wish for it to work "equally well on all systems".
    In this day and age, I wouldn't even bother. No sane vendor would define CHAR_BIT as anything other than 8.

  11. #11
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by Sir Galahad View Post
    Pretty sure 8 * sizeof(int) works equally well on all systems.
    True, but that's runtime, I'm trying to make compile time constants

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by awsdert View Post
    True, but that's runtime, I'm trying to make compile time constants
    No, unless applied to a variable length array, sizeof is a compile-time operator.

    Quote Originally Posted by Sir Galahad
    In this day and age, I wouldn't even bother. No sane vendor would define CHAR_BIT as anything other than 8.
    You did say "all systems"
    Plus it is still good to bother since 8 is a magic number whose meaning is expressed clearly as CHAR_BIT.
    Last edited by laserlight; 08-05-2020 at 12:47 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by laserlight View Post
    If a standard integer type is supported, then its limits would be defined in <limits.h>. The width wouldn't be defined there, but that's what sizeof and possibly CHAR_BIT is for.
    Which works in runtime but not compile time, say you wanna wrap around stddef.h, stdint.h && intypes.h and then make sure everything is defined in the scenario none of them are available (such as the kernel - also I plan on doing just that), you would need those defines to work in #if/#elif statements which is why I'm trying to avoid things like sizeof, the tests I've been doing are just to make sure things work correctly in an environment where those limits happen to be the same and are thus easy to compare and spot incorrect results

    Quote Originally Posted by laserlight View Post
    By "preprocessor integer size/width" you mean "processor integer size/width", i.e., word size? If so, that's true, but I doubt your method of determining that is guaranteed to work: from what I see, with your _SIZEOF and SIZEOF macros applied to SIZEOF(~0u), you're just finding out the size of an unsigned int through a roundabout way, and then assuming that that's the word size.
    If I meant processor integer size/width I would've said that, that however would have to be detected through other macros since the compiler could itself be running in a different mode to what the cpu operates optimally at, if I remember rightly ARM processors are able to do just that and run under x64/x86 modes. No, in this case I'm purely looking for the limits of preprocessor math, I've since renamed the integral defines to CCINT and then added CCLONG, and CCLLONG respectively, those variable then become the default if INT_MAX & related are not defined (once again kernel land for example)

    Quote Originally Posted by laserlight View Post
    It is true that the C standard does say that int (and hence unsigned int) "has the natural size suggested by the architecture of the execution environment", but I don't think that's necessarily true in practice on modern 64-bit systems, where int might only be the natural step between short and long or long long.
    Already noticed that and started a workaround that looks like this for all sizes:
    Code:
    #ifndef UMAX_FOR_8BYTE
    #if UCCINT_MAX > UMAX_FOR_4BYTE
    #define UMAX_FOR_8BYTE UMAX_FOR_SIZE(UMAX_FOR_4BYTE)
    #else
    #define UMAX_FOR_8BYTE UCCLLONG_MAX
    #define UMAX_FOR_8BYTE_ASSUMED
    #endif
    #endif /* MAX_FOR_8BYTE */
    Quote Originally Posted by laserlight View Post
    Furthermore, your code in post #2 ensures that MAX_FOR_8BYTE will not exceed ~0u, so for a 4-byte unsigned int, MAX_FOR_8BYTE will be UINT_MAX, even if unsigned long long is supported such that MAX_FOR_8BYTE should have been ULLONG_MAX. If I'm not wrong, what you're doing there is forcing a conversion from int to unsigned int, hence avoiding the signed integer overflow warnings, but in turn ensuring that integer types with arithmetic conversion ranks higher than unsigned int will never be involved.
    Also made a workaround for:
    Code:
    #define UMAX_FOR_SIZE(PRV) \
    	(((PRV) >= UCCINT_MAX) ? PRV : (((PRV) * ((PRV) + 2))))
    
    #define MAX_FOR_SIZE(PRV) \
    	(((PRV) >= CCINT_MAX) ? PRV : ((PRV) * ((PRV) + (PRV) + 4)) + 1)
    I renamed the original to the UMAX version and the used the programming mode of the system calculator to figure out how to get 7FFF from 7F, have yet to check if it still works with 3F etc but I imagine that it should work given it's only a difference in bit count, not bit format, the only case I need to watch out for probably has defines I can use already, the trit environment where unlike bits that have only 0s and 1s the trit has -1s or 2s aswell (haven't actually tried programming for that environment yet so don't know the specifics)

    Quote Originally Posted by laserlight View Post
    It is true that <stdint.h> doesn't necessarily provide certain definitions... but if it doesn't then you wouldn't be able to get it yourself either because it would mean that say, integer types with the given widths do not exist on that implementation. I was thinking that maybe you're trying to support old implementations that do not conform to C99 or later (at least IIRC, <stdint.h> was introduced in C99), but it has been a two decades.


    I think there are still a few oddities among modern systems that have CHAR_BIT > 8, so you would need CHAR_BIT * sizeof(int) instead if you wish for it to work "equally well on all systems".
    Yeah for those I plan to just do a processor check, define something with the word size/width (& possibly other sizes depending on what this article says) and slap that as the default instead but that'll be done when I begin the porting process to those architectures and testing in VirtualBox or something similar
    Last edited by awsdert; 08-05-2020 at 01:27 AM.

  14. #14
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by laserlight View Post
    No, unless applied to a variable length array, sizeof is a compile-time operator.
    Not from my experience

    Quote Originally Posted by laserlight View Post
    You did say "all systems"
    Plus it is still good to bother since 8 is a magic number whose meaning is expressed clearly as CHAR_BIT.
    Precisely why I'm trying to program this around the worst case scenario where nothing is available

  15. #15
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by awsdert
    Which works in runtime but not compile time
    As I pointed out in my previous post, sizeof is a compile-time operator, except when its operand is a variable length array.

    Quote Originally Posted by awsdert
    Not from my experience
    The C standard states that you are wrong. You must be mistaken in your interpretation of your experience, or you have been using compilers that do not conform even to the earliest edition of the C standard in this very basic thing, i.e., we're talking about compilers with an obvious showstopper bug such that even your attempts to work around it could turn out to be runtime operations too.
    Last edited by laserlight; 08-05-2020 at 01:30 AM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Definitive Guide To Integer Overflow.
    By Dren in forum C Programming
    Replies: 4
    Last Post: 11-08-2019, 01:56 PM
  2. Replies: 6
    Last Post: 09-30-2015, 08:49 AM
  3. integer overflow
    By John Connor in forum C Programming
    Replies: 11
    Last Post: 02-11-2008, 05:30 PM
  4. silence warning when assigning pointers
    By eth0 in forum C Programming
    Replies: 5
    Last Post: 10-27-2005, 11:18 AM
  5. how to handle integer overflow in C
    By kate1234 in forum C Programming
    Replies: 8
    Last Post: 04-23-2003, 12:20 PM

Tags for this Thread