[英]Function prototypes when using a shared library
I'm not sure of the correct terminology to use to describe this problem, but I will try my best. 我不确定用于描述此问题的正确术语,但是我会尽力而为。
I'm writing a toy program that prints the factorial of 12 and 13 in test.c: 我正在编写一个玩具程序,在test.c中打印出12和13的阶乘:
#include <stdio.h>
int main(void)
{
printf("%ld\n", factorial(12));
printf("%ld\n", factorial(13));
return 0;
}
The factorial function is defined in a shared library with source fact.c 阶乘函数在带有源fact.c的共享库中定义
long factorial(int n)
{
long r = 1;
while (n > 1) r *= n--;
return r;
}
I am compiling the shared library and my program with the following commands: 我正在使用以下命令编译共享库和程序:
$ gcc -shared -fPIC -o libfact.so fact.c
$ gcc -L. -lfact test.c
I am on x86-64, so I expect that factorial(13)
(13! = 6227020800) does not overflow a 64-bit long. 我使用的是x86-64,因此我希望
factorial(13)
(13!= 6227020800)不会溢出64位长。 However, I get a strange result. 但是,我得到一个奇怪的结果。
$ LD_LIBRARY_PATH=. ./a.out
479001600
1932053504
Here, 1932053504 happens to be the decimal value of the lower 32 bits of the correct result. 在这里,1932053504恰好是正确结果的低32位的十进制值。 If, however, I insert the function prototype
long factorial(int)
at the top of test.c and recompile, I get the correct result. 但是,如果我在test.c的顶部插入函数原型
long factorial(int)
并重新编译,则会得到正确的结果。
$ LD_LIBRARY_PATH=. ./a.out
479001600
6227020800
This leaves me with a couple questions: 这给我留下了两个问题:
factorial
. factorial
。 Is this related to this question about C void arguments and this question about function prototypes ? As of the 1990 version of the C standard, if you call a function with no visible declaration the compiler assumes that it returns type int
. 从C标准的1990版本开始,如果您调用的函数没有可见的声明,则编译器会假定其返回的类型为
int
。 So for the calls to factorial()
in your main program, the compiler will most likely interpret the long
value it returns as if it were an int
value. 因此,对于主程序中的
factorial()
调用,编译器很可能会将返回的long
值解释为 int
值。 If long
and int
happen to have the same representation, this is likely to work. 如果
long
和int
碰巧具有相同的表示形式,则可能会起作用。 If long
is wider than int
, it might happen to work, or it can fail. 如果
long
大于int
,则它可能会起作用,否则可能会失败。 But the behavior is undefined either way. 但是无论哪种方式,行为都是不确定的。
The 1999 version of the C standard (C99) removed the "implicit int" rule. C版本(C99)的1999年版本删除了“隐式int”规则。 Calling a function with no visible declaration is a constraint violation , requiring a compiler diagnostic.
调用没有可见声明的函数是违反约束的 ,需要编译器诊断。 The compiler may then either reject the program, or continue to compile it -- but if it does, the behavior is undefined.
然后,编译器可能拒绝该程序,或者继续对其进行编译-但是,如果这样做,则行为是不确定的。
To correct this, you need to have a visible declaration of factorial()
before you call it. 若要更正此问题,您需要在调用前有一个可见的
factorial()
声明。 The best way to do this is to create a header file, factorial.h
: 最好的方法是创建头文件
factorial.h
:
factorial.h: factorial.h:
#ifndef FACTORIAL_H
#define FACTORIAL_H
long factorial(int n);
#endif
factorial.c: factorial.c:
#include <stdio.h>
#include "factorial.h"
long factorial(int n)
{
printf("factorial(%d)", n);
long r = 1;
while (n > 1) r *= n--;
printf(" --> %ld\n", r);
return r;
}
main.c: main.c:
#include <stdio.h>
#include "factorial.h"
int main(void)
{
printf("%ld\n", factorial(12));
printf("%ld\n", factorial(13));
return 0;
}
Note that this still won't work if long
is only 32 bits, since 13 factorial exceeds 2 31 -1. 请注意,如果
long
只有32位,则这仍然行不通,因为13阶乘超过2 31 -1。 Check the value of LONG_MAX
and/or sizeof (long)
on your system: 检查系统上
LONG_MAX
的值和/或sizeof (long)
整数sizeof (long)
:
printf("LONG_MAX = %ld, sizeof (long) = %d\n", LONG_MAX, (int)sizeof (long));
Consider using long long
rather than long
-- or, better yet, int64_t
or uint64_t
, defined in <stdint.h>
. 考虑使用
long long
而不是long
-或,更好的是, int64_t
或uint64_t
所定义<stdint.h>
。
(As far as I know, your use of a shared library doesn't affect any of this.) (据我所知,您对共享库的使用不会对此产生任何影响。)
int
. int
。 The cast that occurs in this case explains the wired output of your printf
statement. printf
语句的有线输出。 Anyhow, prefer using long long int
, as long int
are defined in the standard to handle as maximal value minimum 2^31 - 1
long long int
,因为标准中将long int
定义为最大值2^31 - 1
§5.2.4.2.1 §5.2.4.2.1
— maximum value for an object of type long int
— long int类型的对象的最大值
LONG_MAX +2147483647 // 2^31− 1
LONG_MAX +2147483647 // 2 ^ 31− 1
long
doesn't have to be 8 bytes on 64-bit architecture, standard requires it to be not less than 4 bytes. long
在64位体系结构上不必为8个字节,标准要求它不少于4个字节。 You have an overflow. 你溢出了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.