Apple Developer Connection
Member Login Log In | Not a Member? Contact ADC

< Previous PageNext Page > Hide TOC

Make Code Changes for GCC Compatibility

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.

In this section:

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


Conform to the C99 Standard

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:

Inlining Thresholds

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.

Dealing With Pragmas

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.”

Packing and Alignment Differences

This section lists some packing and alignment differences between the CodeWarrior compiler and GCC.

Different size and alignment of enums

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.

Different alignment of doubles

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.

Code size incompatibility with power 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;
Data packed differently in a register

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);
}

The Mach-O bool Type is Four Bytes, Not One

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.

Guarding Header Includes for C++

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

Friend of Template Specialization Can’t Access Private Members

With GCC, a class declared as a friend of a template specialization does not have access to private members.

Float to Integer Conversions Give Incorrect Output

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)

Some Casts Don’t Work in Function Lists

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.

Standard C Library Functions Are in Global Namespace

With GCC, standard C library functions are in the global namespace, not in std::.

Vector Load Indexed Intrinsic Is Not Const Correct

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 Anonymous Unused C Function Arguments

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.

GCC Interprets Some #define Values Differently Than CodeWarrior

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).

GCC asm Intrinsics are Preprocessor Macros

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

Xcode’s Rez tool Doesn’t Support Certain Operators

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.



< Previous PageNext Page > Hide TOC


Last updated: 2006-10-26




Did this document help you?
Yes: Tell us what works for you.

It’s good, but: Report typos, inaccuracies, and so forth.

It wasn’t helpful: Tell us what would have helped.
Get information on Apple products.
Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Copyright © 2007 Apple Inc.
All rights reserved. | Terms of use | Privacy Notice