Clang and Visual C++ struct alignment compatibility issues - android

We're having a problem struct memory packing and alignment.
Android is not honoring the #pragma pack(push, <n>) which is in several hundred places in our code base. This is causes segfault.
The Android Clang compiler requires an __ attribute __ decorator on the struct or class, for example:
struct __attribute__((packed, aligned(8))) Test
{
char a;
char b;
double d;
};
As opposed to this for Visual C++ that honors the pragma:
#pragma pack(push, 8)
struct Test
{
char a;
char b;
double d;
};
#pragma pack(pop)
Since the use of #pragma pack is so widespread, it will be a time-consuming task to fix.
We tried using the -mms-bitfields compiler flag which sets the default structure layout to be compatible with the Microsoft compiler standard (i.e. it honors the #pragma pack). However this only works for trivial structs and not classes with base classes or virtual functions. We get the following error with these type of classes.
“error : ms_struct may not produce Microsoft-compatible layouts for classes with base classes or virtual functions [-Wincompatible-ms-struct]”
How can we mitigate this issue - is there any workaround to make #pragma pack work for non-trivial structs/classes other than to go over all the classes/struct between push and pop pragmas and add the packed attribute?
Thanks

First of all, I have the impression, that you are doing something fundamentally wrong, when you have "several hundred places" in your code, where you need to define alignment to prevent a segfault. This pragma is non standard and it is not widespread to use it. Most noticeably it is not widespread to use it as extensive as you do. It is not in the standard as well.
Anyway, since clang will ignore the pragma and msvcc will ignore the attributes, I'd put both in the code. You might use e.g. grep and sed to prevent a lot of manual work.

Related

Android NDK problems related to stdarg.h

I'm trying to make native (C++) cross-platform logging for desktop and Android. For that I made an abstract native Logger class, and the appropriate inherited classes (StdoutLogger, AndroidLogger, etc.) with the implemented log methods.
So since what Android supports for native logging is the __android_log_print(int prio, const char *tag, const char *fmt, ...) method which works with a printf-like syntax with indefinite number of arguments, I made the abstract log method to work with a similar syntax:
virtual void log(int aLogLevel, const char *tag, const char *format, ...)=0;
Well, for passing these indefinite numbers of arguments to the Android logging method I found I need to use another method which does the same but takes a va_list instead of the indefinite number of parameters. It also exists in log.h and is called __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap), so I just have to pass the arguments for that method instead.
The problem is that for all this to work I need stdarg.h which contains all the stuff I need for this (like the declaration for va_list, etc.), but by default Eclipse can't find it:
Unresolved inclusion:
In Eclipse project settings my include directories include:
${NDKROOT}/platforms/android-9/arch-arm/usr/include
${NDKROOT}/sources/cxx-stl/gnu-libstdc++/4.6/include
${NDKROOT}/sources/cxx-stl/gnu-libstdc++/4.6/libs/armeabi-v7a/include
It's pretty strange that it's missing, because stdarg.h is part of the C standard library.
So I searched and found it here so I added it to the include directories:
${NDKROOT}/toolchains/arm-linux-androideabi-4.6/prebuilt/windows-x86_64/lib/gcc/arm-linux-androideabi/4.6/include
After this I got it working nicely, but I'm unsure if this is the correct way to do it.
Anyway, later (when implementing the log method in another inherited class) I ran into another problem regarding vfprintf method:
virtual void Log(int aLogLevel, const char *tag, const char *format, ...)
{
if (aLogLevel >= loglevel)
{
va_list args;
va_start (args, format);
vfprintf (stdout, format, args);
va_end (args);
}
}
Eclipse indicated an error:
Invalid arguments ' Candidates are: int vfprintf(__sFILE *, const char *, char *) '
I checked and apparently it wanted a __va_list (with __ at the beginning), not a va_list and it looked like they apparently weren't compatible (according to Eclipse). This vfprintf was in stdio.h, so I started searching and found another stdio.h in a similar folder I found stdarg.h, so I added it to include directories too (and moved it to top) :
${NDKROOT}/toolchains/arm-linux-androideabi-4.6/prebuilt/windows-x86_64/lib/gcc/arm-linux-androideabi/4.6/include-fixed
Now all errors are gone and everything seem to be working, but I'm really unsure if this was really the correct way to do it.
I have latest Eclipse/CDT/NDK/etc.
Any help would be appreciated.
Edit:
fadden: Thanks for the answer. This comment would have been too long so I put it here.
Yes, I use ${NDKROOT}/ndk-build.cmd to build the native part.
Yeah, I noticed cases when Eclipse would indicate errors so it wouldn't even let me start to build the app, but when I restart Eclipse without opening the file where the error was, it actually builds successfully. But when I open the file which it thinks has errors, it wouldn't let me start to build again. So it really looks like there's quite some inconsistency between errors indicated by Eclipse and actual errors (preventing building). Maybe I should just find a way to let it build regardless of indicated errors, though it could be annoying having errors in the project that should be just ignored, not knowing what are real and what are not so real errors... Or just add everything that is needed to include directories to keep Eclipse happy, so far it seems to be working, just wasn't sure if this was really the right way to do it. Thanks for the help.
Making Eclipse + CDT happy with Android is largely a matter of trial and error. (Days or perhaps weeks have been irrevocably lost trying to get size_t to work right.) Ultimately you should be building with the NDK toolchain, not Eclipse, so as long as Eclipse seems to be happy you're probably in good shape because ultimately it won't affect your binaries.
As you've noticed, some of the headers (like stdarg.h) are provided by gcc, not bionic, so it is necessary to dig around a bit. I expect there's a define somewhere that equates __va_list to va_list if you have the right #defines set (maybe __need___va_list??).

Is there any renderscript documentation on datatype convertion functions?

After watching Jeff Sharkey great Google I/O presentation and kicking to write some renderscript to speed up my existing audio processing project. The first problem comes in is that in the example code given, the conversion function in the very first line of code isn't documented anywhere. As least not in http://developer.android.com/guide/topics/renderscript/reference.html
float4 inColor = convert_float4(*inPixel);
Well the function convert_float4() in the example is obvious enough to understand what it does. But in my case I would like to know if it exists other built-in conversions like from a char to a float which I guess could be convert_float(char*) ?
The generic answer is RS support conversion from all basic vector numeric types to other types of the same vector size. The casts are done as if they were a normal C cast for rounding.
The form is:
convert_[dest type](source type)
(2,3,4) vectors of char,uchar,int,uint,short,ushort, and float are supported.
Avoid:
float4 f = (float4)myInt4;
It doesn't do what you expect it to do.
Looks like there are no such built-ins. convert_float4() is the only conversion function declared in rc_core.c.

Android - cross-platform friendly debug/logger macro

I am building C++ code that is used on both android and iOS. I need some form of debugger macro to insert debugging easily into the code.
For example, I was thinking of something like this:
#ifdef ANDROID
# define MY_DEBUG(debugmsg) __android_log_print(ANDROID_LOG_INFO, ANDROID_DEBUG_TAG,debugmsg)
# define MY_DEBUG(debugmsg, mystr) __android_log_print(ANDROID_LOG_INFO, ANDROID_DEBUG_TAG,debugmsg,mystr)
#elif defined (iOS)
# define MY_DEBUG(debugmsg) printf(debugmsg)
# define MY_DEBUG(debugmsg, mystr) printf(debugmsg, mystr)
#endif
So for example I could use MY_DEBUG("hello %s","world") and MY_DEBUG("hello")
However it complains about macro redefinition (and rightfully so). How do I make a macro.. 'overload', or accept more than one parameter if entered?
Also - does printf() send data to the iOS console?
You can't overload macros the way you can with functions because the preprocessor has not changed significantly, if at all, since C. A common approach is to use MY_DEBUG and MY_DEBUG2 etc.
There are variatic macros but I avoid them in multi-platform code.

What's the difference in GCC between -std=gnu++0x and -std=c++0x and which one should be used?

I'm having troubles with <stdint.h> when using -std=c++0x in GCC 4.4.3 (for Android):
// using -std=c++0x
#include <stdint.h>
uint64_t value; // error: 'uint64_t' does not name a type
But using -std=gnu++0x works:
// using -std=gnu++0x
#include <stdint.h>
uint64_t value; // OK
Is <stdint.h> incompatible with C++0x?
So far as I can tell, I think this could be argued an implementation bug (or actually, since C++0x isn't published, not a bug per se but an incomplete implementation of the current state of the upcoming standard).
Here's why, referring to n3225 for the expected behavior of -std=c++0x:
D.7 says
Every C header, each of which has a
name of the form name.h, behaves as if
each name placed in the standard
library namespace by the corresponding
cname header is placed within the
global namespace scope
OK, so far so easy. What does <cstdint> place in the standard library namespace?
18.4.1:
typedef unsigned integer type uint64_t; // optional
How optional? 18.4.1/2:
The header defines all functions,
types, and macros the same as 7.18 in
the C standard
Drat. What does the C standard say? Taking out n1256, 7.18.1.1/3:
These types are optional. However,
if an implementation provides integer
types with widths of 8, 16, 32, or 64
bits, no padding bits, and (for the
signed types) that have a
two's complement representation, it
shall define the corresponding typedef
names
But hang on, surely on Android with -std=c++0x GCC does provide a 64 bit unsigned type with no padding bits: unsigned long long. So <cstdint> is required to provide std::uint64_t and hence stdint.h is required to provide uint64_t in the global namespace.
Go on, someone tell me why I'm wrong :-) One possibility is that C++0x refers to "ISO/IEC 9899:1999 Programming languages — C" without specifying a version. Can it really be that (a) 7.18.1.1/3 was added in one of the TCs, and also (b) C++0x intends to reference the original standard as of 1999, not the amendments since then? I doubt either of these is the case, but I don't have the original C99 on hand to check (a) and I'm not even sure how to check (b).
Edit: oh, as for which one should be used -std=c++0x isn't really a strict standards-compliant mode yet, since there isn't a strict standard yet. And even if there was a standard, gcc 4.4.3 certainly isn't a finished implementation of it. So I see no great need to use it if -std=gnu++0x is actually more complete, at least in this respect for your combination of gcc version and platform.
However, gnu++0x will enable other GNU extensions, that you might not want your code to use. If you're aiming to write portable C++0x, then eventually you'd want to switch to -std=c++0x. But I don't think GCC 4.4 or any other C++0x implementation-in-progress is complete enough yet for it to be practical to write code from the (draft) standard, such that you could say with a straight face "I'm programming C++0x, and it's only 2011!". So I'd say, use whichever one works, and understand that whichever one you use now, you'll probably be switching to -std=c++11 eventually anyway.

Is the binary representation of native types guaranteed the same on all targets?

I"m planning to store my data in a binary format as a resource, read it into an int buffer and basically pass it straight down to a native C++ function, which might cast it to a struct/class and work with it. No pointers, obviously, just ints and floats.
The question is - what kind of fixing up do I need to do? I suppose that I need to check ByteOrder.nativeOrder(), figure out if it's big endian or little endian, and perform byte-swapping if need be.
Other than that, floats are presumably guaranteed to be expected in IEEE 754 format? Are there any other caveats I'm completely overlooking here?
(Also - since I'm compiling using the NDK, I know what architecture it is already (ARMv7-A, in my case), so can I technically skip the endian shenanigans and just take the data the way it is?)
ARM support both big and little endian. This will most probably be set by the OS so it might be worth while checking this out beforehand.
There is also the issue of padding to word size in a struct:
struct st
{
char a;
int b;
};
will have a sizeof 8 and not the expected 5 bytes. This is so that the int will be word aligned. Generally align everything to 4 bytes and probably use the gcc packed attribute (struct my_packed_struct __attribute__ ((__packed__))
) as well. This will ensure that the internals of the struct are as you expect.
Alternatively use the Android Simulator to generate the data file for you.

Categories

Resources