【问题标题】:do you have to declare functions in C? [duplicate]你必须在C中声明函数吗? [复制]
【发布时间】:2011-02-22 19:50:18
【问题描述】:

可能重复:
Must declare function prototype in C?

我正在学习 C,在我正在阅读的这本书中,我正在阅读这段代码,其中包含 void scalarMultiply(int nRows, int nCols, int matrix[nRows][nCols], int scalar); 的声明。即使我不包括这一行,该程序似乎也能工作?

    int main(void)
    {

        void scalarMultiply(int nRows, int nCols, int matrix[nRows][nCols], int scalar);
        void displayMatrix(int nRows, int nCols, int matrix[nRows][nCols]);
    int sampleMatrix[3][5] = {
        { 7, 16, 55, 13, 12},
        { 12, 10, 52, 0, 7 },
        { -2, 1, 2, 4, 9   }

    };

    scalarMultiply(3, 5, sampleMatrix, 2);


}    void scalarMultiply(int nRows, int nCols, int matrix[nRows][nCols], int scalar){
        int row, column;

        for (row = 0; row < nRows; ++row)
            for (column = 0; column < nCols; ++column)
                matrix[row][column] *= scalar;

    }

【问题讨论】:

  • 重复Must declare function prototype in C? [我特别推荐AndreyT的回答]
  • 标题说C,问题说C,标签有C++。为什么?
  • @GMan:吸引 C++ 的人们。
  • @Emile:为什么? C 不是 C++。只需用您使用的语言标记它,合适的人就会看到它,而不会欺骗其他人。
  • @GMan:我的评论很刻薄。我也不喜欢被骗。

标签: c


【解决方案1】:

如果您没有在使用之前声明函数,编译器可能会尝试猜测函数的签名,这可能会起作用。

无论如何,如果编译器猜测的函数与实际函数不同,您可能会得到非常奇怪的结果:例如,如果您将 long long 作为第一个参数传递给 scalarMultiply,它不会被转换为 @987654323 @,这将导致未定义的行为:很可能你会破坏你的堆栈(函数会以不同的方式读取参数)并且一切都会崩溃。


看:

#include <stdio.h>
int main( ) {
    f( (long long int) -1 );
    g( 1, 1 );
    return 0;
}
void f( int a, int b ) {
    printf( "%d, %d\n", a, b );
}
void g( long long int a ) {
    printf( "%lld\n", a );
}

输出将是:

-1, -1
4294967297

很奇怪,嗯?

【讨论】:

    【解决方案2】:

    如果你想在定义之前调用一个函数,你必须声明一个原型。否则,没有。这就是为什么许多 C 程序在底部使用 main 而在顶部使用小辅助函数编写的原因。在编译单元中唯一真正需要函数原型的时候是相互递归。

    【讨论】:

    • @David:重新考虑什么?我有什么地方不清楚吗?
    • @David:我不了解 C++,但是如果在声明之前使用了函数,我的 C99 编译器会报错。
    【解决方案3】:

    只要调用和以后的声明不冲突,您的传统 C 编译器不需要原型设计和调用函数并稍后声明就可以工作。 C++ 并非如此。

    警告:我已经有一段时间没有编写纯 C 模块了,所以我不知道最新版本的 gcc 在这种情况下会对 .c 文件做什么。

    【讨论】:

      【解决方案4】:

      当遇到没有可用定义或原型的函数调用时,C89 所需的行为是假设它返回一个 int 并具有您在调用中提供的参数的数量和类型。如果您随后使用无法合法隐式强制转换的不同参数类型或不同数量的参数调用它,编译器将拒绝该代码。

      当编译器或链接器最终发现不匹配的定义时,它会报错。原型的使用允许编译器在尝试从另一个模块链接定义时在调用而不是定义时生成错误。所以简而言之,如果您希望编译器帮助您编写工作代码,请不要这样做!

      在 C99 和 C++ 中,如果定义尚不可见,则需要原型。

      【讨论】:

      • C99 需要声明,但不需要原型。定义满足需求。
      • @R.:这就是我所说的“如果定义尚不可见”的意思
      • 我的意思是不需要原型。可以接受非原型声明。
      猜你喜欢
      • 2011-02-04
      • 1970-01-01
      • 2018-07-03
      • 2012-07-16
      • 2017-07-16
      • 1970-01-01
      • 1970-01-01
      • 2018-10-13
      • 2016-11-01
      相关资源
      最近更新 更多