如何获得SIZE

我试图在C89中获得SIZE_MAX

我想通过以下方式找到SIZE_MAX

const size_t SIZE_MAX = -1;

由于标准(§6.2.1.2ANSI C)说:

当一个有符号整数被转换为一个无符号整数,其大小相等或更大时,如果有符号整数的值是非负的,则其值不变。 否则:如果无符号整数具有更大的大小,则有符号整数首先被提升为与无符号整数相对应的有符号整数; 通过向无符号整数类型 28中表示的最大数量添加一个值,将该值转换为无符号

用脚注28:

在二进制补码表示中,除了用符号位的副本填充高位比特(如果无符号整数具有更大尺寸)之外,位模式中没有实际变化。

这似乎是这样定义的行为,但我不太确定是否正确理解了该段落的措辞。

请注意,这个问题明确地是关于C89的,所以这不能回答我的问题,因为标准有不同的措辞。

如果这不起作用,我想到的另一种方法是:

size_t get_size_max() {
    static size_t max = 0;
    if (max == 0) {
        max -= 1U;
    }

    return max;
}

但是我在标准中找不到任何关于无符号整数下溢的东西,所以我在黑暗中捅了一下。


你可以使用:

#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)(-1))
#endif

-1转换为无符号整数类型的行为在C11 6.3.1.3“转换 - 有符号和无符号整数”一节中定义。 C89有一个等效的定义,编号为3.2.1.2。 事实上,您在您的问题中引用了ISO C90定义6.2.1.2(ANSI C89和ISO C90之间的区别在于各部分的编号不同)。

我不会推荐使用const变量,因为它们不能在常量表达式中使用。


注意:这不能用于C90预处理器算术,它只适用于不包含转换或单词的整型常量表达式,所以我们不能使用任何sizeof技巧。 在这种情况下,您可能需要一个系统特定的定义; 预处理器没有检测typedef的标准方法。


我建议使用MM的答案中所述的宏定义。

在某些情况下,您可能需要一个类似的宏,但作为一个数值常量,以便您可以在#if VALUE > 42 ... #endif等预处理器指令中使用它。 我评论说在这种情况下,可以在编译时运行一个帮助程序,以计算并打印定义这些常量的头文件。

显然,交叉编译到不同的体系结构时,这是行不通的; 在这种情况下,头文件必须以其他方式提供。 (例如,项目可以有一个预生成头文件的子目录和每个已知体系结构的列表,以便用户可以简单地将头文件复制到适当位置。)

创建一个用于运行这些程序的Makefile和相关工具(并且只有当用户没有将头文件复制到位时)并不困难。

首先,假设您的程序由两个源文件foo.c组成

#include <stdlib.h>
extern void hello(void);

int main(void)
{
    hello();
    return EXIT_SUCCESS;
}

bar.c

#include <stdio.h>
#include "size_max.h"

#define  STRINGIFY_(s) #s
#define  STRINGIFY(s) STRINGIFY_(s)

void hello(void)
{
    fputs("SIZE_MAX = "" STRINGIFY(SIZE_MAX) "".n", stdout);
}

上面的bar.c将SIZE_MAX预处理器宏转换为一个字符串并打印出来。 如果我们有#define SIZE_MAX (size_t)(-1) ,它会打印SIZE_MAX = "(size_t)(-1)"

请注意,bar.c包含文件size_max.h,我们没有。 这是我们打算使用我们的帮助程序size_max.c生成的头文件:

#include <stdlib.h>
#include <stdio.h>

int main(void)
{
    printf("#ifndef SIZE_MAXn");
    printf("#define SIZE_MAX %lluUn", (unsigned long long)(size_t)(-1));
    printf("#endifn");
    return EXIT_SUCCESS;
}

chux在评论中指出u后缀(对于足够大的无符号整数类型)可能是必要的。 如果这不符合您的要求,我相信您可以修改宏生成器帮助器以满足您的需求。

MM在注释中指出%z不被ANSI C / ISO C90支持,所以上面的程序首先使用(size_t)(-1)创建常量,然后使用unsigned long long格式转换并打印它。

现在,Makefiles可以用操作系统不可知的方式编写,但我懒得在这里做,因此我将使用与GNU工具一起使用的值。 要使其在其他系统上工作,只需修改其值

  • CC ,以反映您使用的编译器

  • CFLAGS ,以反映您的首选编译器选项

  • LD ,以反映您的链接器,除非与CC相同

  • LDFLAGS ,如果你需要一些链接器标志(可能是-lm ?)

  • RM ,以反映删除不必要文件的命令

  • 文件名,如果你的编译系统需要一些可执行文件的时髦文件扩展名

  • 无论如何,这里是Makefile

    CC      := gcc
    CFLAGS  := -Wall -O2
    LD      := $(CC)
    LDFLAGS := $(CFLAGS)
    RM      := rm -f
    
    # Programs to be built
    PROGS   := example
    
    # Relative path to use for executing the header generator helper program
    HEADERGEN := ./headergen
    
    # Rules that do not correspond to actual files
    .PHONY: all clean headergen
    
    # Default rule is to build all binaries
    all: $(PROGS)
    
    # Clean rule removes build files and binaries
    clean:
        -$(RM) $(PROGS) $(HELPROG) *.o size_max.h
    
    # Rule to "rebuild" size_max.h
    size_max.h: size_max.c
        -@$(RM) $(HEADERGEN) size_max.h
        @$(CC) $(CFLAGS) $^ -o $(HEADERGEN)
        $(HEADERGEN) > size_max.h
        @$(RM) $(HEADERGEN)
    
    # Rule to build object files from .c source files
    %.o: %.c size_max.h
        $(CC) $(CFLAGS) -c $<
    
    # Example binary requires foo.o and bar.o:
    example: foo.o bar.o size_max.h
        $(LD) $(LDFLAGS) foo.o bar.o -o $@
    

    请注意,缩进应该使用制表符而不是空格,所以如果您复制粘贴上述内容,请运行例如sed -e 's|^ *|t|' -i Makefile sed -e 's|^ *|t|' -i Makefile来修复它。

    在对源代码树进行压缩或tar之前,请运行make clean以从中删除所有生成的文件。

    请注意配方先决条件中的额外size_max.h 。 它告诉make在可以完成配方之前确保size_max.h存在。

    这种方法的缺点是你不能在链接食谱中使用$^来引用所有先决条件文件名。 $<引用第一个必备文件名。 但是,如果您使用GNU make或兼容make,则可以使用$(filter-out %.h, %^) (列出除头文件之外的所有先决条件)。

    如果您的所有二进制文件都是使用同一个名称的单一来源构建的,则可以使用替换后两个配方

    # All programs are built from same name source files:
    $(PROGS): %: %.c size_max.h
        $(CC) $(CFLAGS) $< $(LDFLAGS) -o $@
    

    在我的系统上运行

    make clean all && ./example
    

    输出

    rm -f example  *.o size_max.h
    ./headergen > size_max.h
    gcc -Wall -O2 -c foo.c
    gcc -Wall -O2 -c bar.c
    gcc -Wall -O2 foo.o bar.o -o example
    SIZE_MAX = "18446744073709551615U".
    

    并跑步

    make CC="gcc-5" CFLAGS="-Wall -std=c99 -pedantic -m32" clean all && ./example
    

    输出

    rm -f example  *.o size_max.h
    ./headergen > size_max.h
    gcc-5 -Wall -std=c99 -pedantic -m32 -c foo.c
    gcc-5 -Wall -std=c99 -pedantic -m32 -c bar.c
    gcc-5 -Wall -std=c99 -pedantic -m32 foo.o bar.o -o example
    SIZE_MAX = "4294967295U".
    

    请注意,make不会检测您是否更改编译器选项,如果编辑Makefile或在运行make时使用不同的CFLAGS=CC=选项,则需要先指定clean目标,以确保从clean目标开始新的设置生效。

    在正常编辑和构建过程中,如果不更改编译器或编译器选项,则不需要在构建之间make clean

    链接地址: http://www.djcxy.com/p/40387.html

    上一篇: How to get SIZE

    下一篇: What is the difference between C, C99, ANSI C and GNU C?