Ver Fonte

- an attempt at portable endianness macros: __IS_LITTLE_ENDIAN,
__IS_BIG_ENDIAN and runtime check/sanity functions

Andrei Pelinescu-Onciul há 17 anos atrás
pai
commit
9137544e15
3 ficheiros alterados com 358 adições e 0 exclusões
  1. 45 0
      endianness.c
  2. 140 0
      endianness.h
  3. 173 0
      test/endian_test.c

+ 45 - 0
endianness.c

@@ -0,0 +1,45 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2008 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ *  endianness compile and runtime  tests
+ * 
+ * History:
+ * --------
+ *  2008-06-13  created by andrei
+ */
+
+#include "endianness.h"
+
+int _endian_test_int=1 /* used for the runtime endian tests */;
+
+
+/* return 0 on success, -1 on error (compile time detected endianness is
+ * different from run time)
+ */
+int endianness_sanity_check()
+{
+#ifdef __IS_LITTLE_ENDIAN
+	return is_little_endian()-1;
+#elif defined __IS_BIG_ENDIAN
+	return is_big_endian()-1;
+#else
+#warning BUG: endianness macro are not defined
+	return -1;
+#endif
+}
+

+ 140 - 0
endianness.h

@@ -0,0 +1,140 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2008 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ *  endianness compile and runtime  tests
+ * 
+ * History:
+ * --------
+ *  2008-06-13  created by andrei
+ */
+
+/*
+ * Defines:
+ *    __IS_LITTLE_ENDIAN if the system is little endian and
+ *    __IS_BIG_ENDIAN    if it's big endian
+ * Function/macros:
+ *     is_big_endian()  - runtime test for big endian
+ *     is_little_endian() - runtime test for little endian
+ *     endianness_sanity_check() - returns 0 if the compile time
+ *                                  detected endianness corresponds to
+ *                                  the runtime detected one and -1 on 
+ *                                  error (recommended action: bail out)
+ */
+/*
+ * Implementation notes:
+ * Endian macro names/tests for different OSes:
+ * linux:  __BYTE_ORDER == __LITTLE_ENDIAN | __BIG_ENDIAN
+ *           BYTE_ORDER == LITTLE_ENDIAN | BIG_ENDIAN
+ * bsd:     _BYTE_ORDER == _LITTLE_ENDIAN | _BIG_ENDIAN
+ *           BYTE_ORDER == LITTLE_ENDIAN | BIG_ENDIAN
+ * solaris: _LITTLE_ENDIAN | _BIG_ENDIAN
+ *
+ * Include file for the endian macros:
+ * linux: <endian.h> (glibc), <sys/param.h>
+ * bsd:   <sys/param.h>, <sys/endian.h>
+ * solaris: <sys/param.h>
+ *
+ * Note: BIG_ENDIAN, LITTLE_ENDIAN, _BIG_ENDIAN, _LITTLE_ENDIAN cannot be 
+ *       used always,  some OSes define both of them for BYTE_ORDER use
+ *       (e.g. linux defines both BIG_ENDIAN & LITTLE_ENDIAN, bsds define
+ *          _BIG_ENDIAN, _LITTLE_ENDIAN, BIG_ENDIAN, LITTLE_ENDIAN)
+ *
+ */
+
+
+#ifndef _endianness_h
+#define _endianness_h
+
+/* use bsd includes: they work everywhere */
+#include <sys/types.h>
+#include <sys/param.h>
+
+
+
+extern int _endian_test_int;
+
+/* returns 1 for little endian, 0 for big endian */
+#define endian_test()		(*(char*)&_endian_test_int==1)
+#define is_big_endian()		(!endian_test())
+#define is_little_endian()	endian_test()
+
+
+extern int endianness_sanity_check();
+
+/* detect compile time endianess */
+#if defined __BYTE_ORDER && defined __LITTLE_ENDIAN && defined __BIG_ENDIAN
+/* linux */
+#if __BYTE_ORDER == __LITTLE_ENDIAN && ! defined __IS_LITTLE_ENDIAN
+	#define __IS_LITTLE_ENDIAN 0x01020304
+#endif
+#if __BYTE_ORDER == __BIG_ENDIAN && ! defined __IS_BIG_ENDIAN
+	#define __IS_BIG_ENDIAN 0x01020304
+#endif
+#elif defined _BYTE_ORDER && defined _LITTLE_ENDIAN && defined _BIG_ENDIAN
+/* bsd */
+#if _BYTE_ORDER == _LITTLE_ENDIAN && ! defined __IS_LITTLE_ENDIAN
+	#define __IS_LITTLE_ENDIAN 0x01020304
+#endif
+#if _BYTE_ORDER == _BIG_ENDIAN && ! defined __IS_BIG_ENDIAN
+	#define __IS_BIG_ENDIAN 0x01020304
+#endif
+#elif defined BYTE_ORDER && defined LITTLE_ENDIAN && defined BIG_ENDIAN
+/* bsd old/deprecated */
+#if BYTE_ORDER == LITTLE_ENDIAN && ! defined __IS_LITTLE_ENDIAN
+	#define __IS_LITTLE_ENDIAN 0x01020304
+#endif
+#if BYTE_ORDER == BIG_ENDIAN && ! defined __IS_BIG_ENDIAN
+	#define __IS_BIG_ENDIAN 0x01020304
+#endif
+#elif !(defined _LITTLE_ENDIAN && defined _BIG_ENDIAN) && \
+		(defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
+/* OSes that don't define BYTE_ORDER (sanity check above makes sure
+ *   little & big endian are not defined in the same time )*/
+/* solaris */
+#if defined _LITTLE_ENDIAN && !defined __IS_LITLE_ENDIAN
+	#define __IS_LITTLE_ENDIAN 0x01020304
+#endif
+#if defined _BIG_ENDIAN && !defined __IS_BIG_ENDIAN
+	#define __IS_BIG_ENDIAN 0x04030201
+#endif
+#elif !(defined LITTLE_ENDIAN && defined BIG_ENDIAN) && \
+		(defined LITTLE_ENDIAN || defined BIG_ENDIAN)
+/* OSes that don't define BYTE_ORDER (sanity check above makes sure
+ *   little & big endian are not defined in the same time )*/
+#if defined LITTLE_ENDIAN && !defined __IS_LITLE_ENDIAN
+	#define __IS_LITTLE_ENDIAN 0x01020304
+#endif
+#if defined BIG_ENDIAN && !defined __IS_BIG_ENDIAN
+	#define __IS_BIG_ENDIAN 0x04030201
+#endif
+
+#else
+#error could not detect endianess
+#endif
+
+#if !defined __IS_LITTLE_ENDIAN && !defined __IS_BIG_ENDIAN
+#error BUG: could not detect endianess
+#endif
+
+#if defined __IS_LITTLE_ENDIAN && defined __IS_BIG_ENDIAN
+#error BUG: both little & big endian detected in the same time
+#endif
+
+
+#endif /* _endianness_h */
+

+ 173 - 0
test/endian_test.c

@@ -0,0 +1,173 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2008 iptelorg GmbH
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ *  endianness.h tests
+ *  compile/run with:
+ *  gcc  -Wall endian_test.c ../endianness.c  -o endian_test; ./endian_test
+ */
+/* 
+ * History:
+ * --------
+ *  2008-06-13  created by andrei
+ */
+
+/*
+ *
+ * Macro names:
+ * linux:  __BYTE_ORDER == __LITTLE_ENDIAN | __BIG_ENDIAN
+ *           BYTE_ORDER == LITTLE_ENDIAN | BIG_ENDIAN
+ * bsd:     _BYTE_ORDER == _LITTLE_ENDIAN | _BIG_ENDIAN
+ *           BYTE_ORDER == LITTLE_ENDIAN | BIG_ENDIAN
+ * solaris: _LITTLE_ENDIAN | _BIG_ENDIAN
+ *
+ * Note: BIG_ENDIAN, LITTLE_ENDIAN, _BIG_ENDIAN, _LITTLE_ENDIAN cannot be 
+ *       used always,  some OSes define both of them for BYTE_ORDER use
+ *       (e.g. linux defines both BIG_ENDIAN & LITTLE_ENDIAN, bsds define
+ *          _BIG_ENDIAN, _LITTLE_ENDIAN, BIG_ENDIAN, LITTLE_ENDIAN)
+ *
+ * is sys/param.h universal ?
+ */
+
+#include <stdio.h>
+#include "../endianness.h"
+/* 
+ * Tested:
+ * linux:   y
+ * freebsd: y
+ * openbsd:
+ * netbsd:
+ * solaris: y
+ * darwin: 
+ * cygwin:
+ *
+ * Header files:
+ * linux:  <endian.h> , <sys/param.h>
+ * bsd:    <sys/param.h> or <sys/endian.h>
+ * solaris: <sys/param.h>
+ * openbsd
+ * netbsd
+ * solaris
+ * cywin
+ */
+
+/*
+ *
+ * Macro names:
+ * linux:  __BYTE_ORDER == __LITTLE_ENDIAN | __BIG_ENDIAN
+ *           BYTE_ORDER == LITTLE_ENDIAN | BIG_ENDIAN
+ * bsd:     _BYTE_ORDER == _LITTLE_ENDIAN | _BIG_ENDIAN
+ *           BYTE_ORDER == LITTLE_ENDIAN | BIG_ENDIAN
+ * solaris: _LITTLE_ENDIAN | _BIG_ENDIAN
+ *
+ * Note: BIG_ENDIAN, LITTLE_ENDIAN, _BIG_ENDIAN, _LITTLE_ENDIAN cannot be 
+ *       used always,  some OSes define both of them for BYTE_ORDER use
+ *       (e.g. linux defines both BIG_ENDIAN & LITTLE_ENDIAN, bsds define
+ *          _BIG_ENDIAN, _LITTLE_ENDIAN, BIG_ENDIAN, LITTLE_ENDIAN)
+ *
+ * is sys/param.h universal ?
+ */
+
+/* test only */
+#if defined __BYTE_ORDER && defined __LITTLE_ENDIAN 
+#if	__BYTE_ORDER == __LITTLE_ENDIAN
+#warning little endian (via __BYTE_ORDER)
+#define __BYTE_ORDER_FOUND
+#endif
+#endif
+#if defined __BYTE_ORDER && defined __BIG_ENDIAN
+#if	__BYTE_ORDER == __BIG_ENDIAN
+#warning big endian (via __BYTE_ORDER)
+#define __BYTE_ORDER_FOUND
+#endif
+#endif
+#if defined __BYTE_ORDER && !defined __BYTE_ORDER_FOUND
+#error __BYTE_ORDER defined, but w/ a strange value
+#endif
+
+#if defined _BYTE_ORDER && defined _LITTLE_ENDIAN
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+#warning little endian (via _BYTE_ORDER)
+#define _BYTE_ORDER_FOUND
+#endif
+#endif
+#if defined _BYTE_ORDER && defined _BIG_ENDIAN 
+#if _BYTE_ORDER == _BIG_ENDIAN
+#warning big endian (via _BYTE_ORDER)
+#define _BYTE_ORDER_FOUND
+#endif
+#endif
+#if defined _BYTE_ORDER && !defined _BYTE_ORDER_FOUND
+#error _BYTE_ORDER defined, but w/ a strange value
+#endif
+
+#if defined BYTE_ORDER && defined LITTLE_ENDIAN 
+#if BYTE_ORDER == LITTLE_ENDIAN
+#warning little endian (via BYTE_ORDER)
+#define BYTE_ORDER_FOUND
+#endif
+#endif
+#if defined BYTE_ORDER && defined BIG_ENDIAN 
+#if BYTE_ORDER == BIG_ENDIAN
+#warning big endian (via BYTE_ORDER)
+#define BYTE_ORDER_FOUND
+#endif
+#endif
+#if defined BYTE_ORDER && !defined BYTE_ORDER_FOUND
+#error BYTE_ORDER defined, but w/ a strange value
+#endif
+
+#if defined _LITTLE_ENDIAN
+#warning _LITTLE_ENDIAN defined
+#endif
+#if defined _BIG_ENDIAN
+#warning _BIG_ENDIAN defined
+#endif
+#if defined LITTLE_ENDIAN
+#warning LITTLE_ENDIAN defined
+#endif
+#if defined BIG_ENDIAN
+#warning BIG_ENDIAN defined
+#endif
+
+
+int main(int argc, char** argv)
+{
+	int ret;
+	
+	ret=0;
+	if (endianness_sanity_check()!=0){
+		printf("ERROR: sanity checks failed\n");
+		ret=-1;
+	}
+	if (is_little_endian()){
+#ifdef __IS_LITTLE_ENDIAN
+		printf("OK: little endian confirmed\n");
+#else 
+		printf("ERROR: macro claims BIG ENDIAN, but it's little\n");
+		return -1;
+#endif
+	}else{
+#ifdef __IS_BIG_ENDIAN
+		printf("OK: big endian confirmed\n");
+#else 
+		printf("ERROR: macro claims LITTLE ENDIAN, but it's big\n");
+		return -1;
+#endif
+	}
+	return ret;
+}