简体   繁体   English

Memory 浪费? 如果 main() 应该只返回 0 或 1,为什么 main 声明为 int 而不是 short int 甚至 char?

[英]Memory waste? If main() should only return 0 or 1, why is main declared with int and not short int or even char?

For example:例如:

#include <stdio.h> 
int main (void)                         /* Why int and not short int? - Waste of Memory */ 
{
     printf("Hello World!");
     return 0; 
}

Why main() is conventional defined with int type, which allocates 4 bytes in memory on 32-bit, if it usually returns only 0 or 1, while other types such as short int (2 bytes,32-bit) or even char (1 byte,32-bit) would be more memory saving?为什么main()是常规定义为int类型,它在 32 位上分配 memory 中的 4 个字节,如果它通常只返回 0 或 1,而其他类型如short int (2 bytes,32-bit) 甚至char ( 1 字节,32 位)会更节省 memory 吗?

It is wasting memory space.它正在浪费 memory 空间。

NOTE: The question is not a duplicate of the thread given;注意:这个问题不是给定线程的重复; its answers only correspond to the return value itself but not its datatype at explicit focus.它的答案只对应于返回值本身,而不对应于其明确关注的数据类型。

The Question is for C and C++.问题是针对 C 和 C++。 If the answers between those alter, share your wisdom with the mention of the context of which language in particular is focused.如果这些之间的答案发生变化,请分享您的智慧,并提及特别关注哪种语言的上下文。

Usually assemblers use their registers to return a value (for example the register AX in Intel processors).通常汇编器使用它们的寄存器来返回一个值(例如 Intel 处理器中的寄存器AX )。 The type int corresponds to the machine word That is, it is not required to convert, for example, a byte that corresponds to the type char to the machine word. int 类型对应于机器字,即不需要将例如char 类型对应的字节转换为机器字。

And in fact, main can return any integer value.事实上, main 可以返回任何 integer 值。

It's because of a machine that's half a century old.这是因为一台有半个世纪历史的机器。

Back in the day when C was created, an int was a machine word on the PDP-11 - sixteen bits - and it was natural and efficient to have main return that.早在创建 C 的那一天, int是 PDP-11 上的机器字 - 16 位 - 拥有main返回是自然而有效的。

The "machine word" was the only type in the B language, which Ritchie and Thompson had developed earlier, and which C grew out of. “机器字”是 B 语言中唯一的类型,它是 Ritchie 和 Thompson 较早开发的,并且是从 C 发展而来的。
When C added types, not specifying one gave you a machine word - an int .当 C 添加类型时,不指定一个给你一个机器字 - 一个int
(It was very important at the time to save space, so not requiring the most common type to be spelled out was a Very Good Thing.) (当时节省空间非常重要,所以不需要拼出最常见的类型是一件非常好的事情。)

So, since a B program started with因此,由于 B 程序以

main()

and programmers are generally language-conservative, C did the same and returned an int .程序员通常是语言保守的,C 做了同样的事情并返回了一个int

There are two reasons I would not consider this a waste:我不认为这是浪费的原因有两个:

1 practical use of 4 byte exit code 1 4字节退出码的实际使用

If you want to return an exit code that exactly describes an error you want more than 8 bit.如果要返回一个准确描述错误的退出代码,则需要超过 8 位。

As an example you may want to group errors: the first byte could describe the vague type of error, the second byte could describe the function that caused the error, the third byte could give information about the cause of the error and the fourth byte describes additional debug information.例如,您可能希望对错误进行分组:第一个字节可以描述模糊的错误类型,第二个字节可以描述导致错误的 function,第三个字节可以提供有关错误原因的信息,第四个字节描述额外的调试信息。

2 Padding 2 填充

If you pass a single short or char they will still be aligned to fit into a machine word, which is often 4 Byte/32 bit depending on architecture.如果您传递单个short 或 char,它们仍将对齐以适合机器字,这通常是 4 字节/32 位,具体取决于架构。 This is called padding and means, that you will most likely still need 32 bit of memory to return a single short or char.这称为填充,意味着您很可能仍需要 32 位 memory 来返回单个短字符或字符。

The old-fashioned convention with most shells is to use the least significant 8 bits of int , not just 0 or 1. 16 bits is increasingly common due to that being the minimum size of an int allowed by the standard.大多数 shell 的老式约定是使用int的最低有效 8 位,而不仅仅是 0 或 1。16 位越来越普遍,因为这是标准允许的int的最小大小。

And what would the issue be with wasting space?浪费空间会有什么问题? Is the space really wasted?空间真的浪费了吗? Is your computer so full of "stuff" that the remaining sizeof(int) * CHAR_BIT - 8 would make a difference?您的计算机是否充满了“东西”,以至于剩余的sizeof(int) * CHAR_BIT - 8会有所作为? Could the architecture exploit that and use those remaining bits for something else?该架构能否利用这一点并将剩余的部分用于其他用途? I very much doubt it.我非常怀疑。

So I wouldn't say the memory is at all wasted since you get it back from the operating system when the program finishes.所以我不会说 memory 完全被浪费了,因为你在程序完成时从操作系统中取回它。 Perhaps extravagent ?也许奢侈 A bit like using a large wine glass for a small tipple perhaps?有点像用一个大酒杯喝一小杯酒?

1st: Alone your assumption/statement if it usually returns only 0 or 1 is wrong.第一: if it usually returns only 0 or 1单独你的假设/陈述是错误的。

Usually the return code is expected to be 0 if no error occurred but otherwise it can return any number to represent different errors.通常,如果没有发生错误,则返回代码应为0 ,否则它可以返回任何数字来表示不同的错误。 And most (at least command line programs) do so.大多数(至少命令行程序)都这样做。 Many programs also output negative numbers.许多程序还 output 负数。

However there are a few common used codes https://www.tldp.org/LDP/abs/html/exitcodes.html also here another SO member points to a unix header that contains some codes https://stackoverflow.com/a/24121322/2331592 However there are a few common used codes https://www.tldp.org/LDP/abs/html/exitcodes.html also here another SO member points to a unix header that contains some codes https://stackoverflow.com/a /24121322/2331592

So after all it is not just a C or C++ type thing but also has historical reasons how most operating systems work and expect the programs to behave and since that the languages have to support that and so at least C like languages do that by using an int main(...) .因此,毕竟它不仅仅是CC++类型的东西,而且还有大多数操作系统如何工作并期望程序运行的历史原因,因为语言必须支持这一点,所以至少C使用 an12F80B84D1 之类的语言这样做int main(...)

2nd: your conclusion It is wasting memory space is wrong.第二:你的结论It is wasting memory space是错误的。

  1. Using an int in comparison to a shorter type does not involve any waste.与较短的类型相比,使用int不会造成任何浪费。 Memory is usually handled in word-size (that that mean may depend from your architecture) anyway无论如何,Memory 通常以字长处理(这意味着可能取决于您的架构)
  2. working with sub-word-types involves computation overheand on some architecture (read: load, word, mask out unrelated bits; store: load memory, mask out variable bits, or them with the new value, write the word back)使用子字类型涉及某些架构上的计算开销(读取:加载,字,屏蔽无关位;存储:加载 memory,屏蔽变量位,或者使用新值,写回字)
  3. the memory is not wasted unless you use it.除非您使用它,否则不会浪费 memory。 if you write return 0;如果你写return 0; no memory is ever used at this point.此时从未使用过 memory。 if you return myMemorySaving8bitVar;如果您return myMemorySaving8bitVar; you only have 1 byte used (most probable on the stack (if not optimized out at all))您只使用了 1 个字节(最有可能在堆栈上(如果根本没有优化))

The answer is "because it usually doesn't return only 0 or 1."答案是“因为它通常不会返回 0 或 1”。 I found this thread from software engineering community that at least partially answers your question.我从软件工程社区找到了这个帖子,它至少部分回答了你的问题。 Here are the two highlights, first from the accepted answer:以下是两个亮点,首先来自已接受的答案:

An integer gives more room than a byte for reporting the error. integer 为报告错误提供了比一个字节更多的空间。 It can be enumerated (return of 1 means XYZ, return of 2 means ABC, return of 3, means DEF, etc..) or used as flags ( 0x0001 means this failed, 0x0002 means that failed, 0x0003 means both this and that failed).它可以被枚举(返回 1 表示 XYZ,返回 2 表示 ABC,返回 3,表示 DEF 等)或用作标志( 0x0001表示失败, 0x0002表示失败, 0x0003表示失败和失败)。 Limiting this to just a byte could easily run out of flags (only 8), so the decision was probably to use an integer.将其限制为仅一个字节很容易用完标志(只有 8 个),因此决定可能是使用 integer。

An interesting point is also raised by Keith Thompson : Keith Thompson还提出了一个有趣的观点:

For example, in the dialect of C used in the Plan 9 operating system main is normally declared as a void function, but the exit status is returned to the calling environment by passing a string pointer to the exits() function.例如,在Plan 9操作系统中使用的 C 的方言中, main通常声明为void function,但是通过将字符串指针传递给exits() ZC1C425268E68A47,将退出状态返回给调用环境。 The empty string denotes success, and any non-empty string denotes some kind of failure.空字符串表示成功,任何非空字符串表示某种失败。 This could have been implemented by having main return a char* result.可以通过让main返回一个char*结果来实现。

Here's another interesting bit from a unix.com forum :这是来自unix.com 论坛的另一个有趣的部分:

(Some of the following may be x86 specific.) (以下一些可能是 x86 特定的。)

Returning to the original question: Where is the exit status stored?回到原来的问题:退出状态存储在哪里? Inside the kernel. kernel 内部。

When you call exit(n), the least significant 8 bits of the integer n are written to a cpu register.当您调用 exit(n) 时,integer n 的最低有效 8 位被写入 cpu 寄存器。 The kernel system call implementation will then copy it to a process-related data structure.然后 kernel 系统调用实现会将其复制到与流程相关的数据结构中。

What if your code doesn't call exit()?如果你的代码没有调用exit()怎么办? The c runtime library responsible for invoking main() will call exit() (or some variant thereof) on your behalf.负责调用 main() 的 c 运行时库将代表您调用 exit() (或其一些变体)。 The return value of main(), which is passed to the c runtime in a register, is used as the argument to the exit() call. main() 的返回值在寄存器中传递给 c 运行时,用作 exit() 调用的参数。

Related to the last quote, here's another from cppreference.com与最后一个报价相关,这是来自cppreference.com的另一个报价

5) Execution of the return (or the implicit return upon reaching the end of main) is equivalent to first leaving the function normally (which destroys the objects with automatic storage duration) and then calling std::exit with the same argument as the argument of the return. 5) 执行返回(或到达 main 结束时的隐式返回)等价于先正常离开 function(这会破坏具有自动存储持续时间的对象),然后使用与参数相同的参数调用 std::exit的回报。 (std::exit then destroys static objects and terminates the program) (std::exit 然后销毁 static 对象并终止程序)

Lastly, I found this really cool example here (although the author of the post is wrong in saying that the result returned is the returned value modulo 512).最后,我在这里找到了这个非常酷的示例(尽管帖子的作者说返回的结果是返回值模 512 是错误的)。 After compiling and executing the following:编译并执行以下命令后:

int main() {
    return 42001;
}

on a POSIX compliant my* system, echo $? 符合 POSIX 的 my* 系统上, echo $? returns 17. That is because 42001 % 256 == 17 which shows that 8 bits of data are actually used.返回 17。那是因为42001 % 256 == 17这表明实际使用了 8 位数据。 With that in mind, choosing int ensures that enough storage is available for passing the program's exit status information, because, as per this answer , compliance to the C++ standard guarantees that size of int (in bits)考虑到这一点,选择int可确保有足够的存储空间可用于传递程序的退出状态信息,因为根据此答案,符合 C++ 标准可确保int的大小(以位为单位)

can't be less than 8. That's because it must be large enough to hold "the eight-bit code units of the Unicode UTF-8 encoding form."不能小于8。这是因为它必须足够大以容纳“Unicode UTF-8编码形式的八位代码单元”。

EDIT:编辑:

*As Andrew Henle pointed out in the comment: *正如Andrew Henle在评论中指出的那样:

A fully POSIX compliant system makes the entire int return value available, not just 8 bits.完全符合 POSIX 的系统使整个int返回值可用,而不仅仅是 8 位。 See pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html : "If si_code is equal to CLD_EXITED , then si_status holds the exit value of the process; otherwise, it is equal to the signal that caused the process to change state. The exit value in si_status shall be equal to the full exit value (that is, the value passed to _exit() , _Exit() , or exit() , or returned from main() ); it shall not be limited to the least significant eight bits of the value."请参阅pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html :“如果si_code等于CLD_EXITED ,则si_status保存进程的退出值;否则,它等于导致进程更改 state. si_status中的退出值应等于完整退出值(即传递给_exit()_Exit()exit()的值,或从main()返回的值);不受限制到该值的最低有效八位。”

I think this makes for an even stronger argument for the use of int over data types of smaller sizes.我认为这为使用int而不是较小大小的数据类型提供了更强有力的论据。

You're either working in or learning C, so I think it's a Real Good Idea that you are concerned with efficiency.您正在工作或学习 C,所以我认为您关心效率是一个真正的好主意。 However, it seems that there are a few things that seem to need clarifying here.但是,这里似乎有几件事需要澄清。

First, the int data type is not an never was intended to mean "32 bits".首先, int 数据类型并不是“32 位”的意思。 The idea was that int would be the most natural binary integer type on the target machine--usually the size of a register.这个想法是 int 将是目标机器上最自然的二进制 integer 类型——通常是寄存器的大小。

Second, the return value from main() is meant to accommodate a wide range of implementations on different operating systems.其次,来自 main() 的返回值旨在适应不同操作系统上的各种实现。 A POSIX system uses an unsigned 8-bit return code. POSIX 系统使用无符号的 8 位返回码。 Windows uses 32-bits that are interpreted by the CMD shell as 2's complement signed. Windows 使用由 CMD shell 解释为 2 的补码符号的 32 位。 Another OS might choose something else.另一个操作系统可能会选择其他东西。

And finally, if you're worried about memory "waste", that's an implementation issue that isn't even an issue in this case.最后,如果您担心 memory “浪费”,那么在这种情况下,这是一个实现问题,甚至不是问题。 Return codes from main are typically returned in machine registers, not in memory, so there is no cost or savings involved.来自 main 的返回码通常在机器寄存器中返回,而不是在 memory 中,因此不涉及成本或节省。 Even if there were, saving 2 bytes in the run of a nontrivial program is not worth any developer's time.即使有,在运行一个重要程序时节省 2 个字节也不值得任何开发人员的时间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在 function 'int main(int, char**), 'MIN' 没有声明 - In function ‘int main(int, char**), ‘MIN’ was not declared 错误:重新定义“int main()”,即使“int main()”只出现一次 - error: redefinition of 'int main()' even if "int main()" apperas only once 为什么 main 函数输出 73.4 即使它的返回类型是 int? - Why the main function output 73.4 even if it's return type is int? int main()中的内存限制 - Memory limit in int main() int main(int argc,char * argv []) - int main(int argc, char *argv[]) 将值传递给main(int,char **) - Passing values to main(int, char**) 具有“ int main(int argc,char ** argv)”的VideoCapture - VideoCapture with “ int main(int argc, char **argv) ” 警告:“ int main(int,char ***)”的第二个参数应为“ char **” [-Wmain](GNU C ++编译器; Ubuntu 12.10) - warning: second argument of ‘int main(int, char***)’ should be ‘char **’ [-Wmain] (GNU C++ compiler; Ubuntu 12.10) 使用int main(void)编译失败; main(int argc,char * argv [])成功。 为什么? - Compiling with int main(void) fails; main(int argc, char *argv[]) succeeds. Why? int转换运算符&#39;Class后跟int是非法的&#39;main的返回类型应为&#39;int&#39;而不是&#39;class&#39; - int conversion operator 'Class followed by int is illegal' return type of main should be 'int' not 'class'
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM