Products > Programming

GCC ARM32 compiler too clever, or not clever enough?

(1/20) > >>

This code

--- Code: --- 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
--- End code ---

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: --- (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 );
--- End code ---

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.

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.

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: ---/*
 * 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##__
#define __STDINT_EXP(x) x
#include <limits.h>

/* 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

--- End code ---

(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.

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.

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?


[0] Message Index

[#] Next page

There was an error while thanking
Go to full version