To get number of elements in an array git use the ARRAY_SIZE macro defined as: #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) The problem with it is a possibility of mistakenly passing to it a pointer instead an array. Use instead a different but compatible ARRAY_SIZE() macro, which (given a good compiler) will also break compile if you try to use it on a pointer. This can ensure your code is robust to changes, without needing a gratuitous macro or constant. A similar ARRAY_SIZE implementation also exists in the linux kernel. Credits to Rusty Russell and his ccan library. Signed-off-by: Elia Pinto <gitter.spiros@xxxxxxxxx> --- Makefile | 7 +++++++ configure.ac | 24 ++++++++++++++++++++++++ git-compat-util.h | 36 +++++++++++++++++++++++++++++++++++- 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 827006b..37eb1e1 100644 --- a/Makefile +++ b/Makefile @@ -339,6 +339,9 @@ all:: # return NULL when it receives a bogus time_t. # # Define HAVE_CLOCK_GETTIME if your platform has clock_gettime in librt. +# +# Define SUPPORT__BUILTIN_TYPES_COMPATIBLE_P if your compiler support +# the builtin function __builtin_types_compatible_ GIT-VERSION-FILE: FORCE @$(SHELL_PATH) ./GIT-VERSION-GEN @@ -1382,6 +1385,10 @@ ifdef HAVE_CLOCK_GETTIME EXTLIBS += -lrt endif +ifdef SUPPORT__BUILTIN_TYPES_COMPATIBLE_P + BASIC_CFLAGS += -DSUPPORT__BUILTIN_TYPES_COMPATIBLE_P +endif + ifeq ($(TCLTK_PATH),) NO_TCLTK = NoThanks endif diff --git a/configure.ac b/configure.ac index 6af9647..9d489c1 100644 --- a/configure.ac +++ b/configure.ac @@ -139,6 +139,28 @@ if test -n "$1"; then fi ]) +AC_DEFUN([GIT_FUNC_TYPES_COMPATIBLE_P], [ + AC_CACHE_CHECK([if compiler has __builtin_types_compatible_p function], + [cc_cv_func_types_compatible_p], + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Werror" + AC_COMPILE_IFELSE([AC_LANG_SOURCE( + [int some_function(); + int some_function() { + return __builtin_types_compatible_p(char *, int) ? 1 : 0; + }])], + [cc_cv_func_types_compatible_p=yes], + [cc_cv_func_types_compatible_p=no]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([test "x$cc_cv_func_types_compatible_p" = "xyes"], + [GIT_CONF_SUBST([SUPPORT__BUILTIN_TYPES_COMPATIBLE_P], [YesPlease])], + [$2]) +]) + + + ## Configure body starts here. AC_PREREQ(2.59) @@ -874,6 +896,8 @@ else fi GIT_CONF_SUBST([SNPRINTF_RETURNS_BOGUS]) +GIT_FUNC_TYPES_COMPATIBLE_P + ## Checks for library functions. ## (in default C library and libraries checked by AC_CHECK_LIB) diff --git a/git-compat-util.h b/git-compat-util.h index 400e921..cb45886 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -25,7 +25,41 @@ #endif #endif -#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) + +/* + * BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression. + * @cond: the compile-time condition which must be true. + * + * Your compile will fail if the condition isn't true, or can't be evaluated + * by the compiler. This can be used in an expression: its value is "0". + * + * Example: + * #define foo_to_char(foo) \ + * ((char *)(foo) \ + * + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0)) + */ +#define BUILD_ASSERT_OR_ZERO(cond) \ + (sizeof(char [1 - 2*!(cond)]) - 1) + + +#if SUPPORT__BUILTIN_TYPES_COMPATIBLE_P +/* &arr[0] degrades to a pointer: a different type from an array */ +#define _array_size_chk(arr) \ + BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(typeof(arr), \ + typeof(&(arr)[0]))) +#else +#define _array_size_chk(arr) 0 +#endif + +/* + * ARRAY_SIZE - get the number of elements in a visible array + * <at> x: the array whose size you want. + * + * This does not work on pointers, or arrays declared as [], or + * function parameters. With correct compiler support, such usage + * will cause a build error (see build_assert). + */ +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]) + _array_size_chk(x)) #define bitsizeof(x) (CHAR_BIT * sizeof(x)) #define maximum_signed_value_of_type(a) \ -- 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html