Author Topic: GCC ARM32 compiler too clever, or not clever enough?  (Read 13895 times)

0 Members and 1 Guest are viewing this topic.

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3697
  • Country: gb
  • Doing electronics since the 1960s...
GCC ARM32 compiler too clever, or not clever enough?
« on: April 15, 2022, 08:54:45 pm »
This code

Code: [Select]
struct tm boot_time;
  char dtbuf [20];
getrtc (&boot_time);
snprintf( dtbuf,16,"%02d%02d%04d %02d%02d%02d", \
boot_time.tm_mday, boot_time.tm_mon+1, boot_time.tm_year+1900, \
boot_time.tm_hour, boot_time.tm_min, boot_time.tm_sec );
dtbuf[15]=0; // just in case

is generating a warning:

'%02d' directive writing between 2 and 11 bytes into a region of size between 0 and 14 [-Wformat-overflow=]

Lots of people have been up this path and clearly outputting an int (which in ARM32GCC is defined as 16 bits, believe it or not, not 32) %02d is the problem because it can generate 5 digits, even though the actual value cannot be bigger than say 31 for day of month.

So I changed it to limit the values explicitly

Code: [Select]
(boot_time.tm_mday)%32, (boot_time.tm_mon+1)%13, (boot_time.tm_year+1900)%2099, \
(boot_time.tm_hour)%24, (boot_time.tm_min)%60, (boot_time.tm_sec)%60 );

but the compiler is not realising that e.g. the MOD 32 is limiting the range to 2 digits.

What is the cleanest way to fix this (without a command line option to suppress the warning)?

The final string being generated is

15042022 204415

i.e. ddmmyyyy hhmmss

EDIT: I found that using %02u instead of %02d suppresses the warnings, but I can't see how. Using a much bigger buffer probably also works.
« Last Edit: April 15, 2022, 09:06:44 pm by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11258
  • Country: us
    • Personal site
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #1 on: April 15, 2022, 09:24:41 pm »
Int in ARM GCC is 32 bits, you have a broken compiler if it is not the case for yours.

The warning comes from the format checker, it only knows types, it does not have any information from the optimizer on the possible range of the values, so it assumes the worst case scenario.
Alex
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3697
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #2 on: April 15, 2022, 09:33:33 pm »
How does %02u stop the warning? From an int, that could be 128, no? 3 digits.

Re the int, very good question. "int" is defined in this file

Code: [Select]
/*
 * Copyright (c) 2004, 2005 by
 * Ralf Corsepius, Ulm/Germany. All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * is freely granted, provided that this notice is preserved.
 */

#ifndef _SYS__INTSUP_H
#define _SYS__INTSUP_H

#include <sys/features.h>

#if __GNUC_PREREQ (3, 2)
/* gcc > 3.2 implicitly defines the values we are interested */
#define __STDINT_EXP(x) __##x##__
#else
#define __STDINT_EXP(x) x
#include <limits.h>
#endif

/* Determine how intptr_t and intN_t fastN_t and leastN_t are defined by gcc
   for this target.  This is used to determine the correct printf() constant in
   inttypes.h and other  constants in stdint.h.
   So we end up with
   ?(signed|unsigned) char == 0
   ?(signed|unsigned) short == 1
   ?(signed|unsigned) int == 2
   ?(signed|unsigned) short int == 3
   ?(signed|unsigned) long == 4
   ?(signed|unsigned) long int == 6
   ?(signed|unsigned) long long == 8
   ?(signed|unsigned) long long int == 10
 */
#pragma push_macro("signed")
#pragma push_macro("unsigned")
#pragma push_macro("char")
#pragma push_macro("short")
#pragma push_macro("__int20")
#pragma push_macro("__int20__")
#pragma push_macro("int")
#pragma push_macro("long")
#undef signed
#undef unsigned
#undef char
#undef short
#undef int
#undef __int20
#undef __int20__
#undef long
#define signed +0
#define unsigned +0
#define char +0
#define short +1
#define __int20 +2
#define __int20__ +2
#define int +2
#define long +4
etc
etc

(last-1 line) which AFAIK came with Cube IDE from ST.

The reason this was not discovered for years was that we never use int except in trivial for() loops; always use uint8_t, uint16_t, uint32_t, int32_t, char, etc.
« Last Edit: April 15, 2022, 09:36:10 pm by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11258
  • Country: us
    • Personal site
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #3 on: April 15, 2022, 09:46:55 pm »
I have not tried to calculate all the possible lengths variations, but unsigned values will not have a sign, so they are one byte shorter. Adding a bunch of values that are shorter by one byte, saves a lot of bytes.

No idea what that file is,  but int is always 4 bytes on ARM. It is trivial to check.
Alex
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3697
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #4 on: April 15, 2022, 10:09:34 pm »
OK so it is warning on the total snprintf output size versus the [20] buffer, or the 16 byte limit, not on the fact that %02d could itself output more than 2 digits?

« Last Edit: April 15, 2022, 10:16:10 pm by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14471
  • Country: fr
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #5 on: April 15, 2022, 10:32:41 pm »
I've never encountered a C compiler for a 32-bit target that would have 16-bit 'int'. Unless maybe through some odd compiler flag.

That said, yes it's on the total size of the buffer, it just tried to estimate the max length based on the format, adding up the max for all parts of it. From my experience with GCC, it's not completely foolproof.

Note (probably obvious, but just thought I'd mention it) that %02d (or u) doesn't guarantee that the integer will be formatted with 2 chars only. It just fills the string with leading zeros if the resulting string would be shorter than 2 chars (excluding the sign, if I'm correct), but if it's longer, then it does nothing that I know of. So a typical 32-bit int with this format could yield up to 10 chars if positive, or 11 if negative. Correct me if I'm wrong.

Also, I'm not sure (or rather, I'm almost sure of the opposite) that using a modulo would change anything here as you noticed, as the result will be promoted to int anyway when being passed as an argument to snprintf, so I don't think the integrated static analyzer is smart enough to go deeper than this.

 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11258
  • Country: us
    • Personal site
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #6 on: April 15, 2022, 10:34:30 pm »
Yes, the warning is for the whole string. That's why it says that at some point you may need to write at least two bytes, but based on the previous stuff written into the buffer you will only have 0 to 14 bytes left. And having 0 bytes left is an issue here.

This is actually a very good feature of the compiler. It is one of those things that makes things safer for no run-time cost.
Alex
 

Offline TheCalligrapher

  • Regular Contributor
  • *
  • Posts: 151
  • Country: us
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #7 on: April 16, 2022, 12:21:58 am »
So I changed it to limit the values explicitly

Code: [Select]
(boot_time.tm_mday)%32, (boot_time.tm_mon+1)%13, (boot_time.tm_year+1900)%2099, \
(boot_time.tm_hour)%24, (boot_time.tm_min)%60, (boot_time.tm_sec)%60 );

but the compiler is not realising that e.g. the MOD 32 is limiting the range to 2 digits.

It doesn't limit it to 2 characters.

C and C++ integer division is not Euclidean division, it is round-to-zero division. This means that in signed context the remainder might end up being negative. E.g. `-45 / 32` produces `-1` and `-45 % 32` produces `-13`.

Fields in `struct tm` are declared as `int`, so in your case the compiler has to assume that the negative argument might produce 3 characters in the output, not 2. This is apparently why using format `u` instead of `d` suppresses the warning.
« Last Edit: April 16, 2022, 01:43:17 am by TheCalligrapher »
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11258
  • Country: us
    • Personal site
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #8 on: April 16, 2022, 12:47:23 am »
%02d guarantees a minimum of 2 characters, there is no limit on the maximum. If the value is bigger, then entire value would be printed. That's why the warning clearly says "writing between 2 and 11 bytes".
Alex
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4036
  • Country: nz
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #9 on: April 16, 2022, 01:29:18 am »
How does %02u stop the warning? From an int, that could be 128, no? 3 digits.

%02u can print 10 digits, %02d can print a - and then 10 digits.

Quote
Re the int, very good question. "int" is defined in this file

Code: [Select]
/*
/* Determine how intptr_t and intN_t fastN_t and leastN_t are defined by gcc
   for this target.  This is used to determine the correct printf() constant in
   inttypes.h and other  constants in stdint.h.
   So we end up with
   ?(signed|unsigned) char == 0
   ?(signed|unsigned) short == 1
   ?(signed|unsigned) int == 2
   ?(signed|unsigned) short int == 3
   ?(signed|unsigned) long == 4
   ?(signed|unsigned) long int == 6
   ?(signed|unsigned) long long == 8
   ?(signed|unsigned) long long int == 10
 */

:

#define int +2
#define long +4

(last-1 line) which AFAIK came with Cube IDE from ST.

I don't know where the heck that comes from but it's clear it's defining something that is essentially like an enum, probably to select something from a table/array at some point.

It is clearly *not* the size of data types in bytes.

"short int" being a bigger number than "int" (and different to "short") and "long" and "long int" not being the same gives that away.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3697
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #10 on: April 16, 2022, 06:40:19 am »
Thank you all. I am happy with %02u :)

The values in tm cannot be negative in this case.

Re the 16 bit "int", I don't know how to find out where this is defined, other than by swiping an instance of "int" and doing a right click to see the Declaration, and that takes me to that file of unknown origin. This project was set up by someone else ~3 years ago.

I tend to use uint32_t etc anyway.

Looking at say uint32_t, these are declared in _stdint.h which is this one

Code: [Select]
/*
 * Copyright (c) 2004, 2005 by
 * Ralf Corsepius, Ulm/Germany. All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * is freely granted, provided that this notice is preserved.
 */

#ifndef _SYS__STDINT_H
#define _SYS__STDINT_H

#include <machine/_default_types.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifdef ___int8_t_defined
#ifndef _INT8_T_DECLARED
typedef __int8_t int8_t ;
#define _INT8_T_DECLARED
#endif
#ifndef _UINT8_T_DECLARED
typedef __uint8_t uint8_t ;
#define _UINT8_T_DECLARED
#endif
#define __int8_t_defined 1
#endif /* ___int8_t_defined */

#ifdef ___int16_t_defined
#ifndef _INT16_T_DECLARED
typedef __int16_t int16_t ;
#define _INT16_T_DECLARED
#endif
#ifndef _UINT16_T_DECLARED
typedef __uint16_t uint16_t ;
#define _UINT16_T_DECLARED
#endif
#define __int16_t_defined 1
#endif /* ___int16_t_defined */

#ifdef ___int32_t_defined
#ifndef _INT32_T_DECLARED
typedef __int32_t int32_t ;
#define _INT32_T_DECLARED
#endif
#ifndef _UINT32_T_DECLARED
typedef __uint32_t uint32_t ;
#define _UINT32_T_DECLARED
#endif
#define __int32_t_defined 1
#endif /* ___int32_t_defined */

#ifdef ___int64_t_defined
#ifndef _INT64_T_DECLARED
typedef __int64_t int64_t ;
#define _INT64_T_DECLARED
#endif
#ifndef _UINT64_T_DECLARED
typedef __uint64_t uint64_t ;
#define _UINT64_T_DECLARED
#endif
#define __int64_t_defined 1
#endif /* ___int64_t_defined */

#ifndef _INTMAX_T_DECLARED
typedef __intmax_t intmax_t;
#define _INTMAX_T_DECLARED
#endif

#ifndef _UINTMAX_T_DECLARED
typedef __uintmax_t uintmax_t;
#define _UINTMAX_T_DECLARED
#endif

#ifndef _INTPTR_T_DECLARED
typedef __intptr_t intptr_t;
#define _INTPTR_T_DECLARED
#endif

#ifndef _UINTPTR_T_DECLARED
typedef __uintptr_t uintptr_t;
#define _UINTPTR_T_DECLARED
#endif

#ifdef __cplusplus
}
#endif

#endif /* _SYS__STDINT_H */


and the _default_types.h file (included in above) is

Code: [Select]
/*
 *  $Id$
 */

#ifndef _MACHINE__DEFAULT_TYPES_H
#define _MACHINE__DEFAULT_TYPES_H

#include <sys/features.h>

/*
 * Guess on types by examining *_MIN / *_MAX defines.
 */
#if __GNUC_PREREQ (3, 3)
/* GCC >= 3.3.0 has __<val>__ implicitly defined. */
#define __EXP(x) __##x##__
#else
/* Fall back to POSIX versions from <limits.h> */
#define __EXP(x) x
#include <limits.h>
#endif

/* Check if "long long" is 64bit wide */
/* Modern GCCs provide __LONG_LONG_MAX__, SUSv3 wants LLONG_MAX */
#if ( defined(__LONG_LONG_MAX__) && (__LONG_LONG_MAX__ > 0x7fffffff) ) \
  || ( defined(LLONG_MAX) && (LLONG_MAX > 0x7fffffff) )
#define __have_longlong64 1
#endif

/* Check if "long" is 64bit or 32bit wide */
#if __EXP(LONG_MAX) > 0x7fffffff
#define __have_long64 1
#elif __EXP(LONG_MAX) == 0x7fffffff && !defined(__SPU__)
#define __have_long32 1
#endif

#ifdef __cplusplus
extern "C" {
#endif

#ifdef __INT8_TYPE__
typedef __INT8_TYPE__ __int8_t;
#ifdef __UINT8_TYPE__
typedef __UINT8_TYPE__ __uint8_t;
#else
typedef unsigned __INT8_TYPE__ __uint8_t;
#endif
#define ___int8_t_defined 1
#elif __EXP(SCHAR_MAX) == 0x7f
typedef signed char __int8_t ;
typedef unsigned char __uint8_t ;
#define ___int8_t_defined 1
#endif

#ifdef __INT16_TYPE__
typedef __INT16_TYPE__ __int16_t;
#ifdef __UINT16_TYPE__
typedef __UINT16_TYPE__ __uint16_t;
#else
typedef unsigned __INT16_TYPE__ __uint16_t;
#endif
#define ___int16_t_defined 1
#elif __EXP(INT_MAX) == 0x7fff
typedef signed int __int16_t;
typedef unsigned int __uint16_t;
#define ___int16_t_defined 1
#elif __EXP(SHRT_MAX) == 0x7fff
typedef signed short __int16_t;
typedef unsigned short __uint16_t;
#define ___int16_t_defined 1
#elif __EXP(SCHAR_MAX) == 0x7fff
typedef signed char __int16_t;
typedef unsigned char __uint16_t;
#define ___int16_t_defined 1
#endif

#ifdef __INT32_TYPE__
typedef __INT32_TYPE__ __int32_t;
#ifdef __UINT32_TYPE__
typedef __UINT32_TYPE__ __uint32_t;
#else
typedef unsigned __INT32_TYPE__ __uint32_t;
#endif
#define ___int32_t_defined 1
#elif __EXP(INT_MAX) == 0x7fffffffL
typedef signed int __int32_t;
typedef unsigned int __uint32_t;
#define ___int32_t_defined 1
#elif __EXP(LONG_MAX) == 0x7fffffffL
typedef signed long __int32_t;
typedef unsigned long __uint32_t;
#define ___int32_t_defined 1
#elif __EXP(SHRT_MAX) == 0x7fffffffL
typedef signed short __int32_t;
typedef unsigned short __uint32_t;
#define ___int32_t_defined 1
#elif __EXP(SCHAR_MAX) == 0x7fffffffL
typedef signed char __int32_t;
typedef unsigned char __uint32_t;
#define ___int32_t_defined 1
#endif

#ifdef __INT64_TYPE__
typedef __INT64_TYPE__ __int64_t;
#ifdef __UINT64_TYPE__
typedef __UINT64_TYPE__ __uint64_t;
#else
typedef unsigned __INT64_TYPE__ __uint64_t;
#endif
#define ___int64_t_defined 1
#elif __EXP(LONG_MAX) > 0x7fffffff
typedef signed long __int64_t;
typedef unsigned long __uint64_t;
#define ___int64_t_defined 1

/* GCC has __LONG_LONG_MAX__ */
#elif  defined(__LONG_LONG_MAX__) && (__LONG_LONG_MAX__ > 0x7fffffff)
typedef signed long long __int64_t;
typedef unsigned long long __uint64_t;
#define ___int64_t_defined 1

/* POSIX mandates LLONG_MAX in <limits.h> */
#elif  defined(LLONG_MAX) && (LLONG_MAX > 0x7fffffff)
typedef signed long long __int64_t;
typedef unsigned long long __uint64_t;
#define ___int64_t_defined 1

#elif  __EXP(INT_MAX) > 0x7fffffff
typedef signed int __int64_t;
typedef unsigned int __uint64_t;
#define ___int64_t_defined 1
#endif

#ifdef __INT_LEAST8_TYPE__
typedef __INT_LEAST8_TYPE__ __int_least8_t;
#ifdef __UINT_LEAST8_TYPE__
typedef __UINT_LEAST8_TYPE__ __uint_least8_t;
#else
typedef unsigned __INT_LEAST8_TYPE__ __uint_least8_t;
#endif
#define ___int_least8_t_defined 1
#elif defined(___int8_t_defined)
typedef __int8_t __int_least8_t;
typedef __uint8_t __uint_least8_t;
#define ___int_least8_t_defined 1
#elif defined(___int16_t_defined)
typedef __int16_t __int_least8_t;
typedef __uint16_t __uint_least8_t;
#define ___int_least8_t_defined 1
#elif defined(___int32_t_defined)
typedef __int32_t __int_least8_t;
typedef __uint32_t __uint_least8_t;
#define ___int_least8_t_defined 1
#elif defined(___int64_t_defined)
typedef __int64_t __int_least8_t;
typedef __uint64_t __uint_least8_t;
#define ___int_least8_t_defined 1
#endif

#ifdef __INT_LEAST16_TYPE__
typedef __INT_LEAST16_TYPE__ __int_least16_t;
#ifdef __UINT_LEAST16_TYPE__
typedef __UINT_LEAST16_TYPE__ __uint_least16_t;
#else
typedef unsigned __INT_LEAST16_TYPE__ __uint_least16_t;
#endif
#define ___int_least16_t_defined 1
#elif defined(___int16_t_defined)
typedef __int16_t __int_least16_t;
typedef __uint16_t __uint_least16_t;
#define ___int_least16_t_defined 1
#elif defined(___int32_t_defined)
typedef __int32_t __int_least16_t;
typedef __uint32_t __uint_least16_t;
#define ___int_least16_t_defined 1
#elif defined(___int64_t_defined)
typedef __int64_t __int_least16_t;
typedef __uint64_t __uint_least16_t;
#define ___int_least16_t_defined 1
#endif

#ifdef __INT_LEAST32_TYPE__
typedef __INT_LEAST32_TYPE__ __int_least32_t;
#ifdef __UINT_LEAST32_TYPE__
typedef __UINT_LEAST32_TYPE__ __uint_least32_t;
#else
typedef unsigned __INT_LEAST32_TYPE__ __uint_least32_t;
#endif
#define ___int_least32_t_defined 1
#elif defined(___int32_t_defined)
typedef __int32_t __int_least32_t;
typedef __uint32_t __uint_least32_t;
#define ___int_least32_t_defined 1
#elif defined(___int64_t_defined)
typedef __int64_t __int_least32_t;
typedef __uint64_t __uint_least32_t;
#define ___int_least32_t_defined 1
#endif

#ifdef __INT_LEAST64_TYPE__
typedef __INT_LEAST64_TYPE__ __int_least64_t;
#ifdef __UINT_LEAST64_TYPE__
typedef __UINT_LEAST64_TYPE__ __uint_least64_t;
#else
typedef unsigned __INT_LEAST64_TYPE__ __uint_least64_t;
#endif
#define ___int_least64_t_defined 1
#elif defined(___int64_t_defined)
typedef __int64_t __int_least64_t;
typedef __uint64_t __uint_least64_t;
#define ___int_least64_t_defined 1
#endif

#if defined(__INTMAX_TYPE__)
typedef __INTMAX_TYPE__ __intmax_t;
#elif __have_longlong64
typedef signed long long __intmax_t;
#else
typedef signed long __intmax_t;
#endif

#if defined(__UINTMAX_TYPE__)
typedef __UINTMAX_TYPE__ __uintmax_t;
#elif __have_longlong64
typedef unsigned long long __uintmax_t;
#else
typedef unsigned long __uintmax_t;
#endif

#ifdef __INTPTR_TYPE__
typedef __INTPTR_TYPE__ __intptr_t;
#ifdef __UINTPTR_TYPE__
typedef __UINTPTR_TYPE__ __uintptr_t;
#else
typedef unsigned __INTPTR_TYPE__ __uintptr_t;
#endif
#elif defined(__PTRDIFF_TYPE__)
typedef __PTRDIFF_TYPE__ __intptr_t;
typedef unsigned __PTRDIFF_TYPE__ __uintptr_t;
#else
typedef long __intptr_t;
typedef unsigned long __uintptr_t;
#endif

#undef __EXP

#ifdef __cplusplus
}
#endif

#endif /* _MACHINE__DEFAULT_TYPES_H */


How should one define an int? to be an int32_t?
« Last Edit: April 16, 2022, 06:43:23 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11258
  • Country: us
    • Personal site
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #11 on: April 16, 2022, 06:49:39 am »
You can't define an "int" to be anything other than compiler needs it to be without breaking a bunch of stuff. It is a fundamental basic type.

But on ARM32 it is already equivalent to int32_t.
Alex
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3697
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #12 on: April 16, 2022, 09:30:36 am »
Well, what does

   volatile uint32_t fred=sizeof(int);

return for fred?

4 :)

Yet, in this POS called Cube IDE, it takes you somewhere else. A right-click on it here



and going here



takes you to _intsup.h and

Code: [Select]
#define int +2
which is some irrelevant BS.

Anyway, learnt something else today :)
« Last Edit: April 16, 2022, 09:36:42 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 26906
  • Country: nl
    • NCT Developments
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #13 on: April 16, 2022, 12:57:49 pm »
BTW: snprintf is guaranteed to have 0 at the end of the string (which is why I typically use snprintf instead of strcpy / strcat). There is no need to put a zero at the end of the string.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 
The following users thanked this post: peter-h

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3697
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #14 on: April 16, 2022, 01:08:08 pm »
You mean if you specify a max length of 16 then snprintf is going to always drop a 0 into buf[15] regardless of whether the buffer overflowed? That's clever.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11258
  • Country: us
    • Personal site
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #15 on: April 16, 2022, 04:08:15 pm »
You mean if you specify a max length of 16 then snprintf is going to always drop a 0 into buf[15] regardless of whether the buffer overflowed? That's clever.
And it would always return the number of bytes it would have written if it had space. This way if you are using dynamic allocations and you don't know the final length of the string, you can make a reasonable guess, do a printf, check if it fit, if it did not - allocate more memory and try again.
Alex
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11258
  • Country: us
    • Personal site
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #16 on: April 16, 2022, 04:11:52 pm »
Yet, in this POS called Cube IDE, it takes you somewhere else. A right-click on it here
It is not POS, you are just asking it to do nonsense and it does if for you. All IDEs with this feature would do the same. Using an IDE does not free you from responsibility to think if things it shows you make sense.

It is not illegal to define "int" to be anything you want. But if you actually include that file in your code, everything will break. IDE does not know if this file is ultimately included in that place, so it just searches all the files for the definition.

You can type #define int "Cube Rulez" in some file, and it will get you there as well.
Alex
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14471
  • Country: fr
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #17 on: April 16, 2022, 05:10:46 pm »
How does %02u stop the warning? From an int, that could be 128, no? 3 digits.

%02u can print 10 digits, %02d can print a - and then 10 digits.

Quote
Re the int, very good question. "int" is defined in this file

Code: [Select]
/*
/* Determine how intptr_t and intN_t fastN_t and leastN_t are defined by gcc
   for this target.  This is used to determine the correct printf() constant in
   inttypes.h and other  constants in stdint.h.
   So we end up with
   ?(signed|unsigned) char == 0
   ?(signed|unsigned) short == 1
   ?(signed|unsigned) int == 2
   ?(signed|unsigned) short int == 3
   ?(signed|unsigned) long == 4
   ?(signed|unsigned) long int == 6
   ?(signed|unsigned) long long == 8
   ?(signed|unsigned) long long int == 10
 */

:

#define int +2
#define long +4

(last-1 line) which AFAIK came with Cube IDE from ST.

I don't know where the heck that comes from

Me neither. But redefining "int" as "+2"? What the f*cking heck! :-DD
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11258
  • Country: us
    • Personal site
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #18 on: April 16, 2022, 05:19:36 pm »
Me neither. But redefining "int" as "+2"? What the f*cking heck! :-DD
This is often done in places where you need to fill out some structures based on the type name. This file is not meant to be included in the normal program, it is meant to be included in the structure initialization or something like this. All of the things would be undefed for the rest of the flow.

This is an internal file not meant to be used by normal programs.
Alex
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14471
  • Country: fr
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #19 on: April 16, 2022, 05:27:02 pm »
Wherever you'd do that is freaking retarded. There is never a *good* reason for redefining a language's keyword. Never. It's just atrocious and shows you're doing something pretty wrong.
All the more if it's strictly some "internal" use - meaning restricted to a limited set of your own files - where you'd be free to do things "right".

Many people seem to hate C macros. As often discussed, I personally do not and find them pretty flexible and useful, but this one type of use: nope. Never. Please.

And here we even have a perfect illustration of even the OP not quite knowing what int is in their context and what is happening. :-DD
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11258
  • Country: us
    • Personal site
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #20 on: April 16, 2022, 05:35:22 pm »
Again, this is an internal GCC thing. You have to use stuff like this sometimes to make compilers work. You should not look at those files unless you are a compiler developer.
Alex
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14471
  • Country: fr
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #21 on: April 16, 2022, 05:36:47 pm »
Again, this is an internal GCC thing.

Is it? Can you point us to this?

Oh, and for the OP, the way to make sure of a given type's size would be to use sizeof and compile instead of trying to guess through incomprehensible header files.
« Last Edit: April 16, 2022, 05:39:08 pm by SiliconWizard »
 

Offline ataradov

  • Super Contributor
  • ***
  • Posts: 11258
  • Country: us
    • Personal site
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #22 on: April 16, 2022, 05:52:46 pm »
Is it? Can you point us to this?
The file name starts with "_", which generally denotes internal implementation files. The file specifically belongs to newlib, not even GCC itself.

But also, "#pragma push_macro" and "#pragma pop_macro" limit all the changes to the scope of this file.

It looks like this file figures out how size-independent format specifiers like PRId64() correspond to the actual standard format specifiers like "%lld". It is messy, but the whole C is messy on the low level.

The actual useful output of this file is defines like __FAST8, __LEAST16, etc. It does not leave any other stuff in the outside scope.
« Last Edit: April 16, 2022, 05:54:30 pm by ataradov »
Alex
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14471
  • Country: fr
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #23 on: April 16, 2022, 06:01:43 pm »
Is it? Can you point us to this?
The file name starts with "_", which generally denotes internal implementation files. The file specifically belongs to newlib, not even GCC itself.

Ah, that would already make more sense, as I've never seen such a thing in GCC.

But as I said, just use sizeof if in doubt, and call it a day. newlib's code is even messier than GCC's code.
 

Offline peter-hTopic starter

  • Super Contributor
  • ***
  • Posts: 3697
  • Country: gb
  • Doing electronics since the 1960s...
Re: GCC ARM32 compiler too clever, or not clever enough?
« Reply #24 on: April 16, 2022, 08:38:48 pm »
Quote
This is an internal file not meant to be used by normal programs.

Well, yes, I already knew that the IDE often identifies relationships differently from the real build process. It works mostly ok for functions (it finds the .h file - unless there is more than one and then it offers you the whole list, which happens a lot with ST stuff where you have multiple CPUs #defined in .h files) and if you do it on the invocation of a function, it finds the actual function. And it correctly digs out the "source" for a uint32_t, but it breaks with a lot of other stuff. Another one is the References feature, which is supposed to find all code referencing that name; this often fails and I have to use a Search. And the Search itself sometimes fails and I have to use a Windows text search :)

Basically this IDE stuff is a tool which got put together by real men, for real men, and anybody who doesn't like it gets beaten up :)

I just don't have time to become an expert in all this. I've been doing hardware+asm for 40+ years. I have a rock solid working 32F417 project in Cube IDE, now v1.9.0, and Cube does what I need. Every so often it does something really weird. But much of this was done here
https://www.eevblog.com/forum/microcontrollers/is-st-cube-ide-a-piece-of-buggy-crap/msg4083625/#msg4083625
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf