JavaScript is required to for searching.
跳过导航链接
退出打印视图
Oracle Solaris Studio 12.3:C 用户指南     Oracle Solaris Studio 12.3 Information Library (简体中文)
search filter icon
search icon

文档信息

前言

1.  C 编译器介绍

2.  特定于 C 编译器实现的信息

3.  并行化 C 代码

4.  lint 源代码检验器

5.  基于类型的别名分析

6.  转换为 ISO C

6.1 基本模式

6.1.1 -Xc

6.1.2 -Xa

6.1.3 -Xt

6.1.4 -Xs

6.2 新式函数原型

6.2.1 编写新代码

6.2.2 更新现有代码

6.2.3 混合使用的注意事项

6.3 带有可变参数的函数

6.4 提升:无符号保留与值保留

6.4.1 一些历史背景

6.4.2 编译行为

6.4.3 示例:强制类型转换的使用

6.4.4 示例:相同的结果,不发出警告

6.4.5 整型常量

6.4.6 示例:整形常量

6.5 标记化和预处理

6.5.1 ISO C 转换阶段

6.5.2 旧 C 转换阶段

6.5.3 逻辑源代码行

6.5.4 宏替换

6.5.5 使用字符串

6.5.6 标记粘贴

6.6 constvolatile

6.6.1 仅适用于 lvalue 的类型

6.6.2 派生类型中的类型限定符

6.6.3 const 意味着 readonly

6.6.4 const 用法示例

6.6.5 volatile 用法示例

6.7 多字节字符和宽字符

6.7.1 亚洲语言需要多字节字符

6.7.2 编码变化 (Encoding Variations)

6.7.3 宽字符

6.7.4 C 语言特征

6.8 标准头文件和保留名称

6.8.1 标准头文件

6.8.2 保留供实现使用的名称

6.8.3 保留供扩展使用的名称

6.8.4 可安全使用的名称

6.9 国际化

6.9.1 语言环境

6.9.2 setlocale() 函数

6.9.3 更改的函数

6.9.4 新函数

6.10 表达式中的分组和求值

6.10.1 表达式定义

6.10.2 K&R C 重新整理许可证

6.10.3 ISO C 规则

6.10.4 括号用法

6.10.5 As If 规则

6.11 不完全类型

6.11.1 类型

6.11.2 完成不完全类型

6.11.3 声明

6.11.4 表达式

6.11.5 使用原因

6.11.6 示例:不完全类型

6.12 兼容类型和复合类型

6.12.1 多个声明

6.12.2 分别编译兼容性

6.12.3 单编译兼容性

6.12.4 兼容指针类型

6.12.5 兼容数组类型

6.12.6 兼容函数类型

6.12.7 特殊情况

6.12.8 复合类型

7.  转换应用程序以适用于 64 位环境

8.  cscope:交互检查 C 程序

A.  按功能分组的编译器选项

B.  C 编译器选项参考

C.  实现定义的 ISO/IEC C99 行为

D.  C99 的功能

E.  实现定义的 ISO/IEC C90 行为

F.  ISO C 数据表示法

G.  性能调节

H.  Oracle Solaris Studio C:K&R C 与 ISO C 之间的差异

索引

6.2 新式函数原型

1990 ISO C 标准在语言方面的最大变化是借鉴了 C++ 语言的函数原型。通过为每个函数指定其参数的数目和类型,各常规编译获得对每个函数调用的形参 (argument) 和实参 (parameter) 检查(类似于 lint 的参数检查)的益处,而参数自动转换(就如同赋值一样)为函数预期的类型。由于存在许许多多可以而且应该转换为使用原型的现有 C 代码行,因此 1990 ISO C 标准包括了控制旧式和新式函数声明混合的规则。

1999 ISO C 标准使得旧式函数声明被废弃。

6.2.1 编写新代码

编写全新的程序时,在头文件中使用新式函数声明(函数原型),在其他 C 源文件中使用新式函数声明和定义。但是,如果有人将代码移植到某个系统而该系统使用的编译器是 ISO C 之前的版本,请在头文件和源文件中使用宏 __STDC__(仅为 ISO C 编译系统定义)。有关示例,请参阅6.2.3 混合使用的注意事项

只要同一对象或函数的两个不兼容声明处于同一作用域中,符合 ISO C 的编译器就必须发出诊断。如果使用原型来声明和定义所有函数,并且相应的头文件包含在正确的源文件中,则所有调用应与函数的定义一致。此协议消除一种最常见的 C 编程错误。

6.2.2 更新现有代码

如果您已有一个应用程序并且想利用函数原型,则有多种更新选项可供选择,具体取决于您要更改的代码量:

  1. 重新编译而不进行任何更改。

    如果使用 – v 选项进行调用,即使不更改代码,编译器也会对参数类型和数目的不匹配发出警告。

  2. 仅在头文件中增加函数原型。

    包括所有全局函数调用。

  3. 在头文件中增加函数原型,并使每个源文件以其局部(静态)函数的函数原型开头。

    包括所有函数调用,但此方法需要在源文件中为每个局部函数键入两次接口。

  4. 更改所有函数声明和定义以使用函数原型。

对于大多数程序员,第 2 种选择和第 3 种选择可能最具成本效益。遗憾的是,这些选项要求程序员详细了解混合新旧风格的规则。

6.2.3 混合使用的注意事项

为了使函数原型声明适用于旧式函数定义,两者都必须使用 ISO C 术语指定功能相同的接口或必须具有兼容类型

对于具有可变参数的函数,不能混合 ISO C 的省略号表示法和旧式 varargs() 函数定义。对于具有固定数目参数的函数,可以指定在先前实现中传递的参数的类型。

在 K&R C 中,根据缺省参数提升,就在将每个参数传递到被调用函数之前对其进行转换。这些提升规定,所有比 int 短的整数类型均要提升为 int 长度,并且任何 float 参数均要提升为 double,从而简化了编译器和库。函数原型更具有表现力,指定的参数类型即为传递给函数的类型。

因此,如果为现有的(旧式)函数定义编写函数原型,则函数原型不应包含具有以下任意类型的任何参数:char、signed char、unsigned char、float、short、signed short、unsigned short

在编写原型方面仍存在两个复杂因素:typedef 名称以及短的无符号类型的提升规则。

如果旧式函数中的参数是使用 typedef 名称(如 off_tino_t)声明的,则必须知道 typedef 名称指定的类型是否受到缺省参数提升的影响。对于这两个名称,off_tlong 类型的,因此可以在函数原型中使用它;ino_t 过去是 unsigned short 类型的,因此如果在原型中使用它,则编译器将发出诊断,因为旧式定义和原型指定的接口不同且不兼容。

确定应使用什么替代 unsigned short 比较复杂。K&R C 和 1990 ISO C 编译器之间最大的不兼容性是用于将 unsigned charunsigned short 展宽为 int 值的提升规则。(请参见6.4 提升:无符号保留与值保留。)与此旧式参数匹配的参数类型取决于编译时使用的编译模式:

最佳方法是将旧式定义更改为指定 intunsigned int 并使用函数原型中的匹配类型。如有必要,在输入函数后,您可以始终将其值赋给具有更窄类型的局部变量。

请注意原型中 ID 的使用,它可能受预处理的影响。请看以下示例:

#define status 23
void my_exit(int status);   /* Normally, scope begins */
                            /* and ends with prototype */

不要将函数原型与包含窄类型的旧式函数声明混合在一起。

void foo(unsigned char, unsigned short);
void foo(i, j) unsigned char i; unsigned short j; {...}

正确使用 __STDC__ 可生成一个可用于新旧编译器的头文件:

header.h:
    struct s { /* .  .  .  */ };
    #ifdef __STDC__
       void errmsg(int, ...);
       struct s *f(const char *);
       int g(void);
    #else
      void errmsg();
      struct s *f();
      int g();
    #endif

以下函数使用原型,但仍可在较旧的系统中编译:

struct s *
#ifdef __STDC__
    f(const char *p)
#else
    f(p) char *p;
#endif
{
    /* .  .  .  */
}

以下示例说明了更新的源文件(与上面的选项 3 相同)。局部函数仍使用旧式定义,但包括了原型供较新的编译器使用:

source.c:
   #include “header.h”
      typedef /* .  .  .  */ MyType;
   #ifdef __STDC__
      static void del(MyType *);
      /* .  .  .  */
      static void
      del(p)
      MyType *p;
      {
      /* .  .  .  */
      }
      /* .  .  .  */