GCC interprets uint8_t and uint16_t as signed? [duplicate] - linux

This question already has answers here:
Format specifiers for uint8_t, uint16_t, ...?
(7 answers)
Closed 3 years ago.
My test code:
#include <cstdint>
#include <cstdio>
int main() {
const constexpr uint8_t x = 64;
printf("%u", x);
}
Here is how I compiled with GCC 8.2:
g++ -Wall test_format.cpp -o test_format -O3 -std=c++17 -Wformat-signedness
And here is GCC's output:
test_format.cpp: In function ‘int main()’:
test_format.cpp:6:9: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘int’ [-Wformat=]
printf("%u", x);
^~~~
Tho, if I try to print an uint32_t, it has no error/warning.
I wonder why GCC expects uint8_t to be signed int.
Thanks.

Default argument promotions are applied to operands of a variadic function. Under these, an expression of type unsigned char is promoted to int.

In C and C++ types narrower than int are always promoted to int. See Why must a short be converted to an int before arithmetic operations in C and C++?
And inside variadic functions default promotion also applies, which means you can't pass types narrower than int to vararg functions. So uint8_t must be printed with %d, not %u. But anyway you're printing it the wrong way. The correct way is to use PRIu8
printf("%" PRIu8 "\n", x);
Format specifiers for uint8_t, uint16_t, ...?
printing the uint8_t
Why is the format specifier for uint8_t and uint16_t the same (%u)?
How do I print uint32_t and uint16_t variables value?

To print a uint8_t variable with printf(), you should do something like the following:
#include <cinttypes>
#include <cstdio>
int print_u8(std::uint8_t x) {
return std::printf("%" PRIu8 "\n", x);
}
The <cinttypes> header includes printf and scanf format specifiers for all the <cstdint> types (and explicitly includes that header) that should be used for maximum portability.

Related

why typedef throwing error :(S) Initializer must be a valid constant expression

in f1.h header using typedef for structure. sample code snippet shown below
typedef struct{
int a;
union u
{
int x;
char y;
}xyz;
}mystruct;
In f2.h header using the structure mysturct to get the offset. Code snippet shown below
static mystruct ktt
//#define OFFSET_T(b, c) ((int*)((&((mystruct*)0)->b)) - (int*)((&((mystruct*)0)->c)))
#define OFFSET_T(b, c) ((char*) &ktt.b - (char *) &ktt.c)
static struct Mystruct1{
int n;
}mystruct1 = {OFFSET_T(xyz,a)};
when i'm doing compilation in AIX machine using xlc compiler it is throwing the error as "1506-221(S) Initializer must be a valid constant expression".
i tried both the macro's but both are getting same error. Is there anything wrong in f2.h macro while performing size of structure to get offset ??
The expression in question needs to be an arithmetic constant expression in order to be portable. Neither macro qualifies, since operands of pointer type are involved and arithmetic constant expressions are restricted such that those operands are not allowed. In C11, this is found in subclause 6.6 paragraph 8.
That said, the code using the first macro (source reproduced below) does compile on multiple versions of the xlc compiler on AIX.
typedef struct{
int a;
union u
{
int x;
char y;
}xyz;
}mystruct;
static mystruct ktt;
#define OFFSET_T(b, c) ((int*)((&((mystruct*)0)->b)) - (int*)((&((mystruct*)0)->c)))
//#define OFFSET_T(b, c) ((char*) &ktt.b - (char *) &ktt.c)
static struct Mystruct1{
int n;
}mystruct1 = {OFFSET_T(xyz,a)};
The compiler invocation I used was:
xlc offsetcalc.c -c -o /dev/null
The version information for one of the older versions I tried is:
IBM XL C/C++ for AIX, V10.1
Version: 10.01.0000.0021
The version information for one of the newest versions I tried is:
IBM XL C/C++ for AIX, V13.1.3 (5725-C72, 5765-J07)
Version: 13.01.0003.0004

Compiler Support of members of SSE vector types like m128_f32[x]

This might sound stupid but is there a way to activate support of the inner members of an SSE vector type ?
I know this works fine on MSVC, And I ve found some comments on forums and SO like this.
The question, is can I activate this on CLang at least without creating my own unions ?
Thank you
[edit, workaround]
Currently I decided to create a vec4 type to help me.
here is the code
#include <emmintrin.h>
#include <cstdint>
#ifdef _WIN32
typedef __m128 vec4;
typedef __m128i vec4i;
typedef __m128d vec4d;
#else
typedef union __declspec(align(16)) vec4{
float m128_f32[4];
uint64_t m128_u64[2];
int8_t m128_i8[16];
int16_t m128_i16[8];
int32_t m128_i32[4];
int64_t m128_i64[2];
uint8_t m128_u8[16];
uint16_t m128_u16[8];
uint32_t m128_u32[4];
} vec4;
typedef union __declspec(align(16)) vec4i{
uint64_t m128i_u64[2];
int8_t m128i_i8[16];
int16_t m128i_i16[8];
int32_t m128i_i32[4];
int64_t m128i_i64[2];
uint8_t m128i_u8[16];
uint16_t m128i_u16[8];
uint32_t m128i_u32[4];
} vec4i;
typedef union __declspec(align(16)) vec4d{
double m128d_f64[2];
} vec4d;
#endif
On recent clangs, this Just Works without you needing to do anything at all:
#include <immintrin.h>
float foo(__m128 x) {
return x[1];
}
AFAIK it Just Works in recent GCC builds as well.
However, I should note the following:
Consider carefully whether or not you really need to do element-wise access in your vector code. If you can keep your operations in-lane, they will almost certainly be significantly more efficient.
If you really do need to do a significant number of lanewise or horizontal operations, and you don’t need portability, consider using Clang extended vectors (or “OpenCL vectors") instead of the basic SSE intrinsic types. You can pass them to intrinsics just like __m128 and friends, but they also have much nicer syntax for vector-scalar operations, lane wise operations, vector literals, etc.

Why does this code work on Linux but not on SunOS?

#include <stdio.h>
int main() {
char *str = "11111111-22222222 r-xp 00000000 00:0e 1843624 /lib/libdl.so.0";
unsigned long long start_addr, stop_addr, offset;
char* access = NULL;
char* filename = NULL;
sscanf(str, "%llx-%llx %m[-rwxp] %llx %*[:0-9a-f] %*d %ms",
&start_addr, &stop_addr, &access, &offset, &filename);
printf("\n start : %x, stop : %x, offset : %x\n",start_addr,stop_addr,offset);
printf("\n Permission : %s\n",access);
printf("\n Filename : %s\n",filename);
return 0;
}
On Linux this gives the correct output but on Solaris the file is called libdl.so (there is no libdl.so.0 on Solaris) so I wonder what makes this difference, there is not this file on Solaris and if I change to the filename of the Solaris installation (libdl.so) then it generates a segmentation fault.
$ cc Cperm.c ;./a.out
Cperm.c: I funktion "main":
Cperm.c:11:3: varning: format "%x" förväntar sig argument av typen "unsigned int", men argument 2 har typen "long long unsigned int" [-Wformat]
Cperm.c:11:3: varning: format "%x" förväntar sig argument av typen "unsigned int", men argument 3 har typen "long long unsigned int" [-Wformat]
Cperm.c:11:3: varning: format "%x" förväntar sig argument av typen "unsigned int", men argument 4 har typen "long long unsigned int" [-Wformat]
start : 11111111, stop : 22222222, offset : 0
Permission : r-xp
Filename : /lib/libdl.so.0
The above is on ubuntu and here is on Solaris where it compiles without warnings but generates a segmentation fault:
uname -a
SunOS 5.10 Generic_148888-03 sun4u sparc SUNW,Ultra-4
my:~>cc Cperm.c;./a.out
start : 0, stop : 11111111, offset : 0
Segmentation fault
Update
my:~>uname -a;gcc -Wall Cperm.c
SunOS 5.10 Generic_148888-03 sun4u sparc SUNW,Ultra-4
Cperm.c: In function `main':
Cperm.c:9: warning: unknown conversion type character `m' in format
Cperm.c:9: warning: long long unsigned int format, pointer arg (arg 5)
Cperm.c:9: warning: unknown conversion type character `m' in format
Cperm.c:9: warning: too many arguments for format
Cperm.c:11: warning: unsigned int format, different type arg (arg 2)
Cperm.c:11: warning: unsigned int format, different type arg (arg 3)
Cperm.c:11: warning: unsigned int format, different type arg (arg 4)
my:~>gcc Cperm.c
my:~>
Check the man page for Solaris 10 sscanf. The %m modifier is not supported there.
You should also check the return value of sscanf.
Your compiler (on Ubuntu, and probably Solaris if you enabled the warning) told you what is wrong:
Cperm.c:11:3: varning: format "%x" förväntar sig argument av typen "unsigned int", men argument 2 har typen "long long unsigned int" [-Wformat]
⋮
You need to use %llx in your printf, just like you did in your sscanf.
Passing the wrong type of argument is undefined behavior. On Linux, it happened to work (this time); on Solaris, it didn't.
[You're really asking a question about the C language and libraries, you'd probably have better luck searching Stack Overflow for answers, rather than here.]
edit: see also msw's answer, which points out another problem, at least as important as this one.
It's actually much simpler than it might look. Your code has never allocated space to store the string results into. This shorter code has the same defect:
#include <stdio.h>
int main() {
char *word = NULL;
sscanf("hello world", "%s", &word);
printf("%s\n", *word);
return 0;
}
The reason it may "work" on one compiler but not another may have to do with how storage is allocated. Here is the error generated by that code:
cperm.c:5:5: error: format ‘%s’ expects argument of type ‘char *’,
but argument 3 has type ‘char **’
Which doesn't seem horrible, but it's actually fatal. Running gcc with the -Werror option would make that warning stop compilation and not create an a.out. Defining and using word properly
char word[64];
sscanf("hello world", "%63s", word);
printf("%s\n", word);
compiles without error and works.

sprintf (convert int to char[])

In my program I try to convert a int to a char[20];
I try to do this in the following way:
char str[20];
sprintf(str, "%d", timer);
in which timer is the int.
But when I build this code, I get the following warnings.
Type implicit declaration of function 'sprintf' [-Wimplicit-function-declaration]
incompatible implicit declaration of built-in function 'sprintf' [enabled by default]
what does that mean?
note:( I have included string.h and stdlib.h).
great, I added stdio.h to my code and now the warnings disappeared only to give me a even harder error.
undefined reference to `_sbrk'
You have to #include <stdio.h> to use sprintf()
you want to make sure you also add reference to stdio.h see this ref
You probably need to put sprintf(str, "%d", timer) inside a function (not on the global part of the source code).
Something like:
#include <stdlib.h>
char str[20];
// SPOT #1
int f() {
sprintf(str, "%d", timer); // this won't work if placed on SPOT #1
}

ICU library in Android NDK

I am trying to create a JNI wrapper for a C library that depends on the ICU libraries (libicuuc.so and libicui18n.so).
I tried building ICU4C in my NDK (both standard and CrystaX versions, on a Mac OS X machine) and kept running into linking issues like this:
/Users/kyip/KyVmShared/KyAndroid/myproject/obj/local/armeabi/objs/icuuc/udata.o: In function `openCommonData':
/Users/kyip/KyVmShared/KyAndroid/myproject/jni/icu4c/common/udata.c:836: undefined reference to `icudt42_dat'
/Users/kyip/KyVmShared/KyAndroid/myproject/obj/local/armeabi/objs/icuuc/ustr_wcs.o: In function `_strFromWCS':
/Users/kyip/KyVmShared/KyAndroid/myproject/jni/icu4c/common/ustr_wcs.c:365: undefined reference to `wcstombs'
/Users/kyip/KyVmShared/KyAndroid/myproject/jni/icu4c/common/ustr_wcs.c:415: undefined reference to `wcstombs'
/Users/kyip/KyVmShared/KyAndroid/myproject/jni/icu4c/common/ustr_wcs.c:314: undefined reference to `wcstombs'
/Users/kyip/KyVmShared/KyAndroid/myproject/obj/local/armeabi/objs/icuuc/ustr_wcs.o: In function `_strToWCS':
/Users/kyip/KyVmShared/KyAndroid/myproject/jni/icu4c/common/ustr_wcs.c:164: undefined reference to `mbstowcs'
collect2: ld returned 1 exit status
I also tried the suggestion given at unicode support in android ndk but no luck. I got stuck at:
arm-eabi-g++ -I/ky/crystax/android-ndk-r4-crystax/build/platforms/android-8/arch-arm/usr/include/ -O3 -fno-short-wchar -DU_USING_ICU_NAMESPACE=0 -DU_GNUC_UTF16_STRING=0 -fno-short-enums -nostdlib -fPIC -DU_COMMON_IMPLEMENTATION -D_REENTRANT -I../common -I../../icu/source/common -I../../icu/source/i18n "-DDEFAULT_ICU_PLUGINS=\"/usr/local/lib/icu\" " -DU_COMMON_IMPLEMENTATION -DHAVE_CONFIG_H -I/ky/crystax/android-ndk-r4-crystax/build/platforms/android-8/arch-arm/usr/include/ -O3 -fno-short-wchar -DU_USING_ICU_NAMESPACE=0 -DU_GNUC_UTF16_STRING=0 -fno-short-enums -nostdlib -fPIC -DU_COMMON_IMPLEMENTATION -std=c++0x -fvisibility=hidden -c -o errorcode.ao ../../icu/source/common/errorcode.cpp
In file included from ../../icu/source/common/unicode/ptypes.h:23,
from ../../icu/source/common/unicode/umachine.h:52,
from ../../icu/source/common/unicode/utypes.h:36,
from ../../icu/source/common/errorcode.cpp:17:
/ky/crystax/android-ndk-r4-crystax/build/platforms/android-8/arch-arm/usr/include/sys/types.h:122: error: 'uint64_t' does not name a type
make[1]: *** [errorcode.ao] Error 1
make: *** [all-recursive] Error 2
Any help would be appreciated.
It seems that two files are involved in this issue. icu/source/common/unicode/ptypes.h which calls sys/types.h includes
#if ! U_HAVE_UINT64_T
typedef unsigned long long uint64_t;
/* else we may not have a 64-bit type */
#endif
By including sys/types.h from Android, we involve (near line 122/124)
#ifdef __BSD_VISIBLE
typedef unsigned char u_char;
typedef unsigned short u_short;
typedef unsigned int u_int;
typedef unsigned long u_long;
typedef uint32_t u_int32_t;
typedef uint16_t u_int16_t;
typedef uint8_t u_int8_t;
typedef uint64_t u_int64_t;
#endif
It seems that uint64_t has not been declared when it is assigned to u_int64_t. Indeed, sys/types.h includes stdint.h which has the following:
#if !defined __STRICT_ANSI__ || __STDC_VERSION__ >= 199901L
# define __STDC_INT64__
#endif
typedef __int8_t int8_t;
typedef __uint8_t uint8_t;
typedef __int16_t int16_t;
typedef __uint16_t uint16_t;
typedef __int32_t int32_t;
typedef __uint32_t uint32_t;
#if defined(__STDC_INT64__)
typedef __int64_t int64_t;
typedef __uint64_t uint64_t;
#endif
Likely STRICT_ANSI is not defined. Seems like this is a bug in the Android code in sys/types.h. If STDC_INT64 is not defined, it will not define uint64_t so it can't define u_int64_t. Perhaps the real solution is to have sys/types.h modified so that it has
#ifdef __BSD_VISIBLE
typedef unsigned char u_char;
typedef unsigned short u_short;
typedef unsigned int u_int;
typedef unsigned long u_long;
typedef uint32_t u_int32_t;
typedef uint16_t u_int16_t;
typedef uint8_t u_int8_t;
$if defined(__STDC_INT64__)
typedef uint64_t u_int64_t;
#endif
#endif
If you fix this, the next error will be in cstring.h:109
icu/source/common/cstring.h:109: error: 'int64_t' has not been declared
If you instead #define STDC_INT64 in common/unicode/ptypes.h it will go substantially farther, but will end at
icu/source/common/ustrenum.cpp:118: error: must #include <typeinfo> before using typeid
with more info here: http://groups.google.com/group/android-ndk/browse_thread/thread/2ec9dc289d815ba3?pli=1 but no real solutions
I also had this issue:
undefined reference to `mbstowcs'
You should build and link with higher version of android api.
Note:
I tried to link it with libraries from android-ndk/platforms/android-4... I had thought that 4 is version of Android, but 4 is version of Android API. And Android API 4 corresponds to Android 1.6 witch is very very old there is really no mbstowcs function in libc
Here is how i solved the problem. It is dirty but it works. The lib got compiled:
1. file: /icu4c/common/cwchar.h
comment out the #if U_HAVE_WCHAR_H and the respective #endif so the <wchar.h> is always included.
replace the previous uprv_wcstombs definition with:
#define uprv_wcstombs(mbstr, wcstr, count) U_STANDARD_CPP_NAMESPACE wcs2mbs(mbstr, wcstr, count)
replace the previous uprv_mbstowcs definition with:
#define uprv_mbstowcs(wcstr, mbstr, count) U_STANDARD_CPP_NAMESPACE mbs2wcs(wcstr, mbstr, count)
2. file: /icu4c/common/ustr_wcs.cpp
somewhere at the top, under the already existing includes add the line:
#include "../wcsmbs.h"
3. create new file "icu4c/wcsmbs.h"
size_t mbs2wcs(wchar_t * __ restrict pwcs, const char * __ restrict s, size_t n)
{
mbstate_t mbs;
const char *sp;
memset(&mbs, 0, sizeof(mbs));
sp=s;
return (mbsrtowcs(pwcs,&sp,n,&mbs));
}
size_t wcs2mbs(char * __restrict s, const wchar_t * __restrict pwcs, size_t n)
{
mbstate_t mbs;
const wchar_t *pwcsp;
memset(&mbs,0,sizeof(mbs));
pwcsp = pwcs;
return (wcsrtombs(s,&pwcsp,n,&mbs));
}
Hope it helps.
There has been an effort to provide NDK wrappers for the ICU libraries that are part of the system: https://android-review.googlesource.com/c/153001/.

Resources