This section describes a number of code changes you may need to make to ensure compatibility with GCC version 4.0. It also includes some changes related to switching from MSL libraries to the standard Mac OS X C and C++ libraries. See also “Code Differences” for a brief list of code differences.
Note: Some of the issues listed here are due to current GCC compiler bugs, which may be fixed in future releases.
Conform to the C99 Standard
Inlining Thresholds
Dealing With Pragmas
The Mach-O bool Type is Four Bytes, Not One
Guarding Header Includes for C++
Friend of Template Specialization Can’t Access Private Members
Float to Integer Conversions Give Incorrect Output
Some Casts Don’t Work in Function Lists
Standard C Library Functions Are in Global Namespace
Vector Load Indexed Intrinsic Is Not Const Correct
CodeWarrior Allows Anonymous Unused C Function Arguments
GCC Interprets Some #define Values Differently Than CodeWarrior
GCC asm Intrinsics are Preprocessor Macros
Xcode’s Rez tool Doesn’t Support Certain Operators
Applications that change from using Universal Interfaces to using framework-style include statements (in either CodeWarrior or Xcode), must conform to the C99 standard. This is required because the header MacTypes.h defines the bool type as defined in the C99 standard. This header is included into frameworks such as the Carbon and Cocoa frameworks, and thus a large percentage of Mac OS software projects. Projects that pick up the header MacTypes.h through framework headers (for example, with #include <Carbon/Carbon.h>) don't have a choice to not include individual header files.
Because C99 is largely a superset of the C89 standard, most code that conforms to the C89 standard should compile with the C99 setting. To avoid compilation errors, however, observe the following restrictions:
The main() function must be type int and have an argument list of either (void) or (int argc, char * argv).
Some implicit conversions that are valid in C89/C90 are illegal in C99.
Keywords (such as bool, true, and false) that are free for use by developer code in C89/C90 are defined by the compiler or standard headers in C99 and may cause redefined-symbol errors.
Inlining is an optimization the compiler performs to trade off code size for speed. On the theory that function call overhead can be high for small functions called within loops, inlining places the body of the function “in line” with the caller, so no function call overhead is needed.
The trade-off of code size for speed can backfire, however, if it generates too much inlined code; the bloat in code size can itself become a performance problem. Both CodeWarrior and GCC allow control of how much inlining is enough, but the two mechanisms differ substantially, and there's no direct correlation between them. When moving a project from CodeWarrior to GCC you may need to experiment with the inlining settings to get the results you want.
CodeWarrior allows control of inlining depth: if an inlined function calls another inlined function, both are expanded in line. CodeWarrior lets you set the depth at which inlining stops.
The GCC compiler has no specific control over inlining depth, but does let you control the total expanded size of inlined functions. By default, inlined functions over 600 “pseudo-instructions” will not be inlined, regardless of whether the size is a result of deep inlining or not. The custom compiler flag -finline-limit=n lets you control the maximum size of inlined functions. You can set this compiler flag in the Other C Flags build setting in the Build pane in the target inspector window.
Note: Between GCC 3.3 and GCC 4.0, significant improvements have been made to the algorithms for inlining functions. As a result, using the -finline-limit=n compiler flag produces different results when compiling with GCC 3.3 than when compiling with GCC 4.0, even for the same value of the -flnline-limit compiler flag. You should profile your code and test your inlining settings with the appropriate compiler version. For more information on differences in optimization between GCC 3.3 and GCC 4.0, see GCC Porting Guide.
Before reading this section, you should be familiar with the information in “Pragma Statements,” which describes some of the differences in how pragmas are used by the CodeWarrior and GCC compilers.
In general, GCC supports only a small number of pragmas, including those for structure alignment, and instead uses compiler settings to accomplish similar tasks. Unsupported pragma statements are generally ignored, depending on the current warning settings. Compiler settings can be set on a per-project or a per-file basis.
GCC does not support #pragma export on and #pragma export off. See “Exporting Symbols” for information on how to work with exported symbols.
If you have header files that use the statement #pragma options(!pack_enums), enum=int, enumsalwaysint on, you can instead add the flag -fshort-enums for those files by enabling the Short Enumeration Constants build setting.
If you need to isolate GCC-specific or CodeWarrior-specific code, use the conditional statements described in “Code Differences.”
This section lists some packing and alignment differences between the CodeWarrior compiler and GCC.
GCC gives all enums int (4-byte) size and alignment. By default, CodeWarrior bases the size and alignment of enums on the smallest integer type able to contain the declared range of values. However, you can use the CodeWarrior C/C++ Language setting “Enums Always Ints” to specify the use of int-sized enums.
GCC gives doubles 8-byte alignment only when they are the first member of a struct. CodeWarrior gives all doubles appearing at the “top level” in a struct 8-byte alignment if the first member of the struct is a double. In some unusual cases, such as the example shown in Listing 4-1, this can lead to different alignment.
Listing 4-1 A structure definition that is interpreted differently
struct s { double f1; char f2; double f3; }; |
With this code, GCC will give the variable f3 4-byte alignment, while CodeWarrior will give it 8-byte alignment.
When compiling the code in Listing 4-2, GCC and CodeWarrior disagree on the proper size of the following struct when compiled with power alignment. For CodeWarrior, sizeof(ValueRangeCriteriaData) = 68, while for GCC, sizeof(ValueRangeCriteriaData) = 72.
Listing 4-2 Code that generates a size incompatibility
#pragma options align=power |
struct ValueRangeCriteriaValue |
{ |
SInt64 value; |
SInt64 valueOffset; |
SInt64 valueOffsetMultiplier; |
}; |
typedef struct ValueRangeCriteriaValue ValueRangeCriteriaValue; |
struct ValueRangeCriteriaData |
{ |
ValueRangeCriteriaValue startValue; |
ValueRangeCriteriaValue endValue; |
UInt32 reserved[5]; |
}; |
typedef struct ValueRangeCriteriaData ValueRangeCriteriaData; |
When compiling the code in Listing 4-3, Codewarrior packs the data for the variable i into the high two bytes of the register, but GCC packs the data into the low two bytes of the register. This causes an incompatibility wherever a type like this is used.
Listing 4-3 Code that generates a register difference
union Opaque16 { |
char b[2]; |
short notanInt |
}; |
void bar (Opaque16 i) |
{ |
printf("i = %d\n"); |
} |
void main (void) |
{ |
Opaque16 i; |
i = 5; |
bar(i); |
} |
In GCC 4.0, the default size of a bool variable is four bytes. In CodeWarrior, the size is one byte. You should avoid using code that counts on the size of a bool. You should also use care in working with bool pointers.
Note: GCC does provide the flag -mone-byte-bool to force GCC to use one byte for bool types. However, code generated with this flag set may not be binary compatible with code generated without it or with Mac OS X frameworks. The Xcode build setting for setting this flag is Use One Byte 'bool' (GCC_ONE_BYTE_BOOL).
Note: The size and alignment of the bool data type is different for 32-bit and 64-bit architectures. This document assumes that you are building for a 32-bit architecture. For more information on building for a 64-bit architecture, see 64-Bit Transition Guide.
There are cases where if you explicitly include individual Mac OS X system headers from C++ code, you’ll get link failures with the system libraries. To prevent this, you should isolate your header includes by adding this at the beginning of your file, after the include guard:
#ifdef __cplusplus |
extern "C" { |
#endif |
and this at the end, before the include guard:
#ifdef __cplusplus |
} |
#endif |
With GCC, a class declared as a friend of a template specialization does not have access to private members.
The ANSI C standard states that the result of converting an unrepresentable floating point value to integer is undefined, but most implementations produce a result that can be usefully detected. However, for some such conversions, GCC 3.3 produces a meaningless result. For example, consider the results of the following casts:
d = -1.79769e+308; |
(long)d // result: -2147483648 (should be -2147483648) |
(int64_t)d // result: 1 (should be -9223372036854775808) |
(long long)d // result: 1 (should be -9223372036854775808) |
(unsigned char)d // result: 0 (should be 0) |
In some cases in GCC, C style casts or functional style casts do not work correctly in an argument list because argument conversions are applied before the cast conversion is applied.
With GCC, standard C library functions are in the global namespace, not in std::.
The vec_ld (vector load indexed) intrinsic is not const correct, and generates an unclear diagnostic message. For example, the code in Listing 4-4 generates the error message
invalid conversion from `vector <anonymous>*' to `vector <anonymous>*' |
As shown in the listing, you can use a cast to eliminate the warning.
Listing 4-4 Code that generates error
const vector unsigned char* srcPtr; |
... |
// This line gives an INCORRECT warning |
vector unsigned charv1 = vec_ld(0, srcPtr); |
// casting away the constness gets rid of the warning, |
// but shouldn’t be necessary and complicates the code |
vector unsigned charv2 = vec_ld(0, const_cast<vector unsigned char*>(srcPtr)); |
CodeWarrior allows unused arguments to C functions to have their names omitted.
int foo(float) |
{ |
return 0; |
} |
This is allowed by the C99 standard, but generates a warning in GCC.
The CodeWarrior compiler treats “true” the same as “1” in #define statements, but GCC treats them differently. For example, in Listing 4-5, both code snippets generate the same result in CodeWarrior. With GCC, however, <some code> doesn’t get executed in the first snippet.
Listing 4-5 #define test code
// Snippet 1: <some code> executed only in CodeWarrior |
#define MY_FEATURE true |
#if MY_FEATURE |
<some code> |
#endif |
// Snippet 2: <some code> executed in CodeWarrior or GCC |
#define MY_FEATURE 1 |
#if MY_FEATURE |
<some code> |
#endif |
GCC also does not currently provide a warning when an undefined identifier is evaluated in a #if directive (Snippet 1).
Compilers support intrinsics as an alternative to using asm statements within functions. However, in some cases GCC uses macros, not true functions, so they can’t substitute arguments. As a result, code that compiles on CodeWarrior generates an error with GCC.
For example, compiling the following line with GCC generates an error that the number of parameters does not match (expected 5, got 3):
sFlags = __rlwimi(sFlags, inValue, INSERT_HALT); |
However, INSERT_HALT is a #define:
#define INSERT_HALT 8,23,23 |
To work around this, you can replace the define with the actual value:
sFlags = __rlwimi(sFlags, inValue, 8,23,23); |
Note: If you use intrinsics in CodeWarrior, you can continue to do so in Xcode by including the file ppcintrinsics.h.
Para
In CodeWarrior, you can use << and >> as shift operators in a resource file, but Xcode’s version of Rez doesn’t currently support using these symbols as operators.
Last updated: 2006-10-26