C api同时兼容32位和64位整数

时间:2017-01-19 19:37:52

标签: c api gcc platform

我有一个使用int类型的共享(或静态)库的C api,并希望升级到int64_t。 这样做,我想确保我以前的用户仍然可以升级库,而不必重写他们的整个代码。

我已经提出了这个要点的解决方案,它复制了我的代码行为(使用回调):https://git.io/vMy8G -

example.c

// User defines a different type
#define MYLONG int

#include "interface.h"
#include "stdio.h"

// User callback using his own type
int test(const int i, const my_long var, const int j) {
    printf("i   = %d\n",i);
    printf("var = %lld\n",(long long) var);
    printf("j   = %d\n",j);
    printf("%lld\n", 2LL*var-11);
    return var - 7;
}

int main() {
    // This is what user sees
    api_func functionPtr = &test;
    define_callback(functionPtr);

    // Simulate callback call
    call_callback();
    return 0;
}

interface.h

#pragma once

// MYLONG is defined differently internally and externally (before importing this file)
typedef MYLONG my_long;

// Callback definition
typedef int (*api_func)(const int, const my_long, const int); // surround by int to test alignment issues

void define_callback(api_func fptr);
void call_callback();

internal.c

#define MYLONG long long

#include "interface.h"

// Callback handling
api_func callback_ptr = 0;

void define_callback(api_func fptr) {
    callback_ptr = fptr;
}

void call_callback() {
    (*callback_ptr)(1000, 100000, 100);
    (*callback_ptr)(1000, 10000000000, 100); // will overflow when user uses int
}

该库总是使用#define MYLONG int64_t进行编译,而用户将使用#define MYLONG int64_t#define MYLONG int(这将根据其他一些设置自动完成)。最新的定义将确保向后兼容性。

Valgrind检查通过所有构建。

我的问题如下:

  • 安全吗?
  • 我是否依赖编译器的任何非保证行为?
  • 为什么(或不会)有效? (关于这个标准的任何段落?)
  • 你认为有更好的方法吗?

请注意,如果可能,我想避免编写所有函数的64位版本。此外,这必须适用于Linux(gcc),Mac(gcc)和Windows(Visual Studio)。

2 个答案:

答案 0 :(得分:0)

编写最佳移植代码的最佳方法是不依赖于大小。如果您明确使用uint32_tint64_t

否则使用原生intlong

请求用户为完全不必要的东西定义宏是容易出错和错误的。

答案 1 :(得分:0)

  1. 安全吗?
  2. 没有。 example.c 中的用户将callback_ptr设置为:

    int test(const int i, const int var, const int j)
    

    ...和call_callback()将其称为:

    int (*api_func)(const int, const int64_t, const int)
    

    intint64_t的类型不同时,这是UB(不溢出)。

    1. 我是否依赖编译器的任何非保证行为?
      1. 为什么(或者不会)有效? (关于这个标准的任何段落?)
      2. 未定义的行为(UB)。代码调用具有一个签名的函数,但该函数可能具有不兼容的函数。

        1. 你认为有更好的方法吗?
        2. 是。
          答:当然不要使用不匹配的功能签名进行编码 B.最后,我认为OP需要一种新的方法。我建议添加一项功能define_callback64(),然后让用户像以前一样使用define_callback64()int (*f)(const int, int64_t, const int)致电define_callback()。然后call_callback()可以使用已设置的那个。

          代码评论

            

          请注意,如果可能,我想避免编写所有函数的64位版本。

          OP希望"想要升级到int64_t"但是"避免编写所有函数的64位版本"。这是最奇怪的,显然是矛盾的。

          也许将internal.c重写为int64_t,然后调用select call back函数。

          const中的3 typedef int (*api_func)(const int, const my_long, const int)没有任何意义。

          OP似乎假定int在给定标题时为32位。最好编写不承担此问题的代码。 int 至少 16位。 OTOH,我认为假设int不比int64_t宽,我没有看到一个很大的问题,但即使这个问题也没有被C规范定义。

          OP似乎还假设long longint64_t给定代码#define MYLONG long long而且#34;库总是用#define MYLONG int64_t"编译。 OP需要在代码和文档中正确且一致地使用类型。