memset보다 bzero를 사용하는 이유는 무엇입니까?


156

시스템 프로그래밍 클래스에서이 전 학기를 수강했습니다. C에서 기본 클라이언트 / 서버를 구현해야했습니다. sock_addr_in, 또는 버퍼 버퍼 (클라이언트와 서버간에 데이터를주고받는 데 사용 된) 와 같은 구조체를 초기화 할 때 교수 초기화 만하지 bzero말라고 지시 memset했습니다. 그는 왜 그런지 설명하지 않았으며, 이것에 대한 정당한 이유가 있는지 궁금합니다.

나는 여기를 참조하십시오 : http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown 그것은 bzero단지 제로 메모리가 될 것이라는 사실 때문에 더 효율적이므로, 그렇지 않습니다 추가 점검을 memset수행해야합니다. 그래도 memset메모리를 제로화 하는 데 절대 사용하지 않는 이유는 아닙니다 .

bzero는 더 이상 사용되지 않으며 표준 C 함수가 아닙니다. 매뉴얼에 따르면 이러한 이유로 memset선호 bzero됩니다. 그렇다면 왜 아직도 사용 bzero하고 memset싶습니까? 효율성 향상을위한 것입니까, 아니면 더 많은 것입니까? 마찬가지로 새로운 프로그램에 대해 실제로 선호되는 옵션이되는 것 memset이상의 장점은 무엇 bzero입니까?


28
"왜 memset보다 bzero를 사용합니까?" - 하지마 Memset은 표준이며 bzero는 그렇지 않습니다.

30
bzero는 BSDism ()입니다. memset ()은 ansi-c입니다. 요즘, bzero ()는 아마도 매크로로 구현 될 것입니다. 교수님에게 면도를하고 책을 읽어달라고 부탁하십시오. 효율성 은 가짜 주장입니다. syscall 또는 context-switch는 버스 속도로 실행되는 버퍼를 통과하는 1 만 개의 클럭 틱을 쉽게 소비 할 수 있습니다. 네트워크 프로그램을 최적화하려면 : 더 큰 청크를 읽거나 쓰는 방식으로 syscall 수를 최소화하십시오
— wildplasser

7
memset"조금 더 많은 검사가 진행됨"으로 인해 약간 덜 효율적 이라는 아이디어 는 분명히 조기 최적화의 경우입니다. 암호. bzero사용되지 않는 충분한 이유입니다.
— dasblinkenlight 2016 년

4
종종 이니셜 라이저`= {0}`을 추가하고 함수를 전혀 호출하지 않을 수 있습니다. C는 세기 초경에 지역 변수에 대한 사전 선언이 필요하지 않을 때 쉬워졌습니다. 일부 정말 오래된 paperware하지만, 여전히 이전 세기에 붙어 깊은이다.
— MSalters

1
@ SSAnne 아니오, 그러나 아래 답변 중 하나에서 언급 한 것처럼 영향을받는 과정에 대한 권장 책에서 시작되었을 가능성이 큽니다. stackoverflow.com/a/17097072/1428743
— PseudoPsyche

답변:


152

bzero이상 을 선호 할 이유가 없습니다 memset.

memset반면 표준 C의 함수이다 bzero는 C 표준 기능 적이있다. 이론적 근거는 아마도 함수를 사용하여 정확히 동일한 기능을 달성 할 수 있기 때문일 것입니다 memset.

이제 효율성과 관련하여 컴파일러 는 상수 가 감지 될 때 특정 구현으로 전환 gcc하는 내장 구현을 사용 합니다. 내장 기능이 비활성화 된 경우 와 동일합니다 .memset0glibc


감사. 이것은 말이됩니다. 나는 memset이 경우에 항상 사용해야한다고 확신 했지만, 왜 우리가 그것을 사용하지 않는지 혼란 스러웠습니다. 의견을 명확히하고 다시 한 번 감사드립니다.
— PseudoPsyche 2016 년

1
깨진 bzero구현에 많은 문제가있었습니다 . 정렬되지 않은 배열에서는 제공된 길이를 오버 슛하고 약간 더 많은 바이트를 0으로 만들었습니다. 으로 전환 한 후 이러한 문제가 발생하지 않았습니다 memset.
— rustyx

memset_s컴파일러가 보안 관련 목적 (예 : 민감한 부분이 포함 된 메모리 영역을 비우는 등)을 위해 "스크럽 (scrub)"메모리 호출을 조용히 최적화하지 않으려면 어떤 것을 사용해야하는지 잊지 마십시오. 일반 텍스트 비밀번호와 같은 정보).
— Christopher Schultz

69

W. Richard Stevens의 UNIX 네트워크 프로그래밍 을 사용했거나 교사의 영향을 받았다고 생각합니다 . 그는 최신 버전에서도 bzero자주 사용하지 memset않습니다. 이 책은 매우 인기가 많기 때문에 네트워크 프로그래밍의 관용구가 된 것 같습니다.

더 이상 사용되지 않으며 이식성이 줄어들 memset기 때문에 간단하게 고수 할 것 bzero입니다. 나는 당신이 하나를 다른 것보다 사용함으로써 실질적인 이익을 볼 것이라고 의심합니다.


4
당신은 맞을 것입니다. 우리는이 과정에 필요한 교과서를 필요로하지 않았지만, 강의 계획서를 다시 확인했고 유닉스 네트워크 프로그래밍 은 실제로 선택적인 자료로 나열되어 있습니다. 감사.
— PseudoPsyche 2016 년

9
실제로 그것보다 더 나쁩니다. POSIX.1-2001에서 폐기되었으며 POSIX.1-2008에서 제거 되었습니다.
— paxdiablo

9
W. Richard Stevens 의 UNIX 네트워크 프로그래밍 제 3 판 8 페이지 인용 - 실제로 TCPv3의 저자는 두 번째와 세 번째 인수를 첫 번째 인쇄에서 10 번씩 memset으로 바꾸는 실수를했습니다. AC 컴파일러는 두 가지 발생이 동일하기 때문에이 오류를 포착 할 수 없습니다. 오류입니다. 함수 프로토 타입을 사용하는 경우 두 인수를 bzero로 교체하면 항상 C 컴파일러가이를 포착하므로 bzero를 사용하여 피할 수 있습니다. 그러나 paxdiablo가 지적했듯이 bzero는 더 이상 사용되지 않습니다.
— Aaron Newton

@AaronNewton, Michael의 답변에 추가해야합니다 .
— Synetech

52

내가 생각하는 장점 중 하나 bzero()이상이 memset()제로에 메모리를 설정 만들어지고 실수의 감소 가능성이 있다는 것이다.

한 번 이상 다음과 같은 버그가 발생했습니다.

memset(someobject, size_of_object, 0);    // clear object

컴파일러는 불만을 제기하지 않으며 (어쩌면 일부 컴파일러에서 경고 수준을 높이면 일부 메모리가 지워질 수 있음) 영향을받습니다. 이것은 객체를 휴지통에 버리지 않기 때문에 그냥 내버려두기 때문에 버그가 분명하게 나타나지 않을 가능성이 있습니다.

bzero()표준이 아니라는 사실 은 사소한 자극입니다. (FWIW, 프로그램에서 대부분의 함수 호출이 표준이 아닌 경우 놀라지 않을 것입니다. 사실 그러한 함수를 작성하는 것이 일종의 일입니다).

또 다른 답변에 대한 언급에서 Aaron Newton은 Stevens 등의 1.2 절 (강조 추가)에 의해 Unix Network Programming, Volume 1, 3rd Edition에서 다음을 인용했습니다.

bzeroANSI C 함수가 아닙니다. 초기 Berkely 네트워킹 코드에서 파생되었습니다. 그럼에도 불구하고, 우리는 ANSI C memset함수 대신 텍스트 전체에서 그것을 사용합니다 . 왜냐하면 (세 bzero개의 인수로)보다 memset( 두 개의 인수로) 기억 하기 가 쉽기 때문 입니다 . 소켓 API를 지원하는 거의 모든 벤더는 또한을 제공 bzero하며, 그렇지 않은 경우 unp.h헤더에 매크로 정의를 제공합니다 .

실제로, TCPv3의 저자 [TCP / IP Illustrated, Volume 3-Stevens 1996]는 memset첫 번째 인쇄에서 두 번째와 세 번째 인수를 10 번 으로 바꾸는 실수를 했습니다 . 두 인수가 모두 같은 유형이므로 AC 컴파일러는이 오류를 포착 할 수 없습니다. 실제로 두 번째 인수는 일반 int적이고 세 번째 인수는 size_t일반적으로 unsigned int이지만 다른 유형의 인수에는 각각 0과 16으로 지정된 값을 memset여전히 사용할 수 있습니다. 소켓 함수 중 일부는 실제로 인터넷 소켓 주소 구조의 마지막 8 바이트를 0으로 설정해야합니다. 그럼에도 불구하고 오류이며이를 사용하여 피할 수 있습니다 bzerobzero함수 프로토 타입을 사용하는 경우 두 인수를 서로 바꾸면 항상 C 컴파일러에서 잡을 수 있기 때문 입니다.

또한 대부분의 호출 memset()은 메모리를 0으로 하는 것이라고 생각 하므로 해당 사용 사례에 맞는 API를 사용하지 않겠습니까?

가능한 단점 bzero()은 컴파일러가 memcpy()표준이기 때문에 최적화 할 가능성이 높기 때문에이를 인식하도록 작성 될 수 있다는 것입니다. 그러나 올바른 코드는 여전히 최적화 된 잘못된 코드보다 낫습니다. 대부분 bzero()의 bzero()경우을 사용 하면 프로그램 성능에 눈에 띄는 영향을 미치지 않으며으로 확장되는 매크로 또는 인라인 함수일 수 있습니다 memcpy().


그렇습니다. 교실 환경에서 일할 때 이것이 학생들에게 혼란을 줄 이도록 추론 할 수 있다고 생각합니다. 그러나 이것이 교수님의 경우라고 생각하지 않습니다. 그는 매우 큰 RTFM 교사였습니다. 매뉴얼로 대답 할 수있는 질문이있는 경우, 그는 수업 시간에 프로젝터의 매뉴얼 페이지를 가져 와서 보여줍니다. 그는 매뉴얼을 읽고 대부분의 질문에 대답해야한다는 모든 사람들의 마음에 깊이 빠져 들었습니다. 다른 교수 들과는 달리 이것에 감사합니다.
— PseudoPsyche 2016 년

5
나는 이것이 교실 밖에서도 할 수있는 논쟁이라고 생각합니다. 제작 코드 에서이 버그를 보았습니다. 그것은 쉬운 실수라고 생각합니다. 또한 대부분의 memset()호출은 단순히 메모리 블록을 제로화하는 것입니다 bzero(). bzero()어쨌든 'b'는 무엇을 의미 합니까?
— Michael Burr

7
+1. 즉 memset그것은 특히 오류가 발생하기 쉬운 IMO한다 "BUFFER_SIZE, 버퍼"의 공통 매개 변수 순서를 위반합니다.
— jamesdlin

파스칼에서는 "fillchar"라고 부르는 것을 피하고 문자를 취합니다. 대부분의 C / C ++ 컴파일러는 그 중 하나를 선택합니다. 컴파일러가 왜 "바이트가 예상되는 곳에 32/64 비트 포인터를 전달하고있다"고 말하지 않고 컴파일러 오류를 확실하게하게되는 이유가 궁금합니다.
— Móż

1
@Gewure 두 번째 및 세 번째 인수의 순서가 잘못되었습니다. 인용 된 함수 호출은 정확히 아무 것도
— Ichthyo

4

bzero 대 memset 인수에 대해 언급하고 싶었습니다. ltrace를 설치 한 후 후드에서 수행하는 작업을 비교하십시오. libc6 (2.19-0ubuntu6.6)을 사용하는 Linux에서 호출은을 통해 정확히 동일합니다 ltrace ./test123.

long m[] = {0}; // generates a call to memset(0x7fffefa28238, '\0', 8)
int* p;
bzero(&p, 4);   // generates a call to memset(0x7fffefa28230, '\0', 4)

나는 libc 의 깊은 창 이나 많은 커널 / 시스템 콜 인터페이스에서 작업하지 않는 한 걱정할 필요 가 없다고 들었 습니다. 내가 걱정해야 할 것은 호출이 버퍼 제로화 요구 사항을 충족한다는 것입니다. 다른 사람들은 어느 것이 다른 것보다 선호되는지 언급 했으므로 여기서 멈 춥니 다.


이것은 GCC의 일부 버전에서 코드를 memset(ptr, 0, n)보고 bzero(ptr, n)인라인 코드로 변환 할 수 없기 때문에 발생 합니다.
— zwol

@zwol 실제로는 매크로입니다.
— SS Anne

1
내 컴퓨터의 @SSAnne gcc 9.3은 시스템 헤더의 매크로의 도움 없이이 변환 자체를 수행합니다. extern void bzero(void *, size_t); void clear(void *p, size_t n) { bzero(p, n); }에 대한 호출을 생성합니다 memset. (포함 stddef.h에 대한 size_t방해 할 수있는 다른 것없이.)
— zwol

4

당신은 아마 안 사용 bzero사실은 표준 C 아니다, 그것은 POSIX 일이었다.

그리고 단어 "했다"참고 - 그것이 되지 POSIX.1-2001과 제거 당신은 더 나은 표준 C 함수를 사용하여 길 이죠, 그래서 memset 함수에 복종에 POSIX.1-2008에.


표준 C의 의미는 무엇입니까? 표준 C 라이브러리에서 찾을 수 없다는 것을 의미합니까?
— Koray Tugay

@Koray, 표준 C는 ISO 표준을 의미하며 그렇습니다 bzero.
— paxdiablo

아니, 난 당신이 어떤 표준에 의해 무슨 뜻인지 모르겠어요. ISO 표준이 표준 C 라이브러리를 의미합니까? 언어와 함께 제공됩니까? 우리가 알고있는 최소한의 도서관이 있을까요?
— Koray Tugay

2
@Koray, ISO는 C 표준, 현재 C11, 이전 C99 및 C89를 담당하는 표준 조직입니다. 그들은 C로 간주되기 위해 구현이 따라야하는 규칙을 제시합니다. 따라서 표준이 구현이 memset을 제공해야한다고 말한다면 그것은 당신을 위해있을 것입니다. 그렇지 않으면 C가 아닙니다.
— paxdiablo

2

memset 함수 함수, 제 2 인수가 인 int세 번째 인자 인 size_t,

void *memset(void *s, int c, size_t n);

이것은 일반적으로 unsigned int이지만 0 and 16두 번째 및 세 번째 인수에 대한 값이 각각 16 및 0과 같은 잘못된 순서로 입력되면 memset에 대한 호출은 여전히 ​​작동 할 수 있지만 아무것도하지 않습니다. 초기화 할 바이트 수는로 지정되어 있기 때문 0입니다.

void bzero(void *s, size_t n)

함수 프로토 타입을 사용하는 경우 두 인수를 bzero로 바꾸는 것은 항상 C 컴파일러에 의해 잡히므로 bzero를 사용하면 이러한 오류를 피할 수 있습니다.


1
호출을 "이 크기에 대해이 메모리를이 값으로 설정"이라고 생각하거나 프로토 타입을 제공하는 IDE가 있거나 자신이 무엇을 알고 있는지 알고있는 경우 memset을 사용하면 이러한 오류를 피할 수 있습니다. :-)
— paxdiablo 1

동의하지만이 기능은 인텔리전트 IDE를 지원할 수 없을 때 만들어졌습니다.
— havish

2

한마디로 : memset 더 많은 어셈블리 작업이 필요합니다 bzero.

이것은 소스입니다 : http://fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown


예, 이것이 OP에서 언급 한 것 중 하나입니다. 나는 실제로 그 정확한 페이지에 연결했습니다. 일부 컴파일러 최적화로 인해 실제로 큰 차이가없는 것으로 나타났습니다. 자세한 내용은 ouah의 수락 된 답변을 참조하십시오.
— PseudoPsyche

6
이것은 단지 memset의 하나의 쓰레기 구현이 느리다는 것을 보여줍니다. MacOS X 및 일부 다른 시스템에서 memset은 사용중인 프로세서에 따라 부팅시 설정된 코드를 사용하고 벡터 레지스터를 최대한 활용하며, 큰 크기의 경우 프리 페치 명령어를 사용하여 마지막 비트를 얻기 위해 영리한 방법으로 사용합니다 속도.
— gnasher729

명령이 적다고해서 실행 속도가 빠르지는 않습니다. 사실 최적화는 종종 인해 루프 언 롤링, 기능 인라인, 루프 정렬 ... 어떤 점잖은 최적화 된 코드를보고 명령의 바이너리 크기와 수를 증가하고 당신은 종종 훨씬 더 엿 구현에 비해 지침이 나타납니다
— phuclv

2

원하는 방식으로 사용하십시오. :-)

#ifndef bzero
#define bzero(d,n) memset((d),0,(n))
#endif

참고 :

  1. 원본 bzero은 아무것도 반환하지 않고 memsetvoid 포인터 ( d)를 반환합니다 . 이것은 정의에서 void에 typecast를 추가하여 해결할 수 있습니다.
  2. #ifndef bzero원래 기능이 존재하더라도 숨길 수는 없습니다. 매크로가 있는지 테스트합니다. 이것은 많은 혼란을 야기 할 수 있습니다.
  3. 매크로에 대한 함수 포인터를 만드는 것은 불가능합니다. bzerovia 함수 포인터를 사용하면 작동하지 않습니다.

1
@Leeor 문제가 무엇입니까? 매크로에 대한 일반적인 반감? 아니면이 매크로가 함수와 혼동 될 수 있다는 사실을 싫어합니까?
— Palec

1
@Palec, 후자. 재정의를 매크로로 숨기면 많은 혼란이 생길 ​​수 있습니다. 이 코드를 사용하는 다른 프로그래머는 자신이 한 가지를 사용하고 있다고 생각하고 모르고 다른 것을 사용해야합니다. 그것은 시한 폭탄입니다.
— Leeor

1
다른 생각을 한 후에 나는 이것이 실제로 나쁜 해결책이라는 데 동의합니다. 무엇보다도 기술적 인 이유를 발견했습니다. bzero비아 함수 포인터를 사용할 때 작동하지 않습니다.
— Palec

매크로가 아닌 다른 매크로를 호출해야합니다 bzero. 이것은 곤란하다.
— Dan Bechard

-2

memset은 3 개의 매개 변수를 사용하고, bzero는 메모리에서 2를 사용하고, 추가 매개 변수는 4 바이트를 더 필요로하고 대부분의 경우 모든 것을 0으로 설정하는 데 사용됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.